diff --git a/.ddev/config.yaml b/.ddev/config.yaml new file mode 100644 index 000000000..3d0e1970e --- /dev/null +++ b/.ddev/config.yaml @@ -0,0 +1,16 @@ +name: charcoal +type: php +docroot: "" +php_version: "8.5" +webserver_type: apache-fpm +xdebug_enabled: true +additional_hostnames: [] +additional_fqdns: [] +database: + type: mariadb + version: "10.11" +use_dns_when_possible: true +composer_version: "2" +web_environment: + - XDEBUG_MODE=coverage,debug,develop +corepack_enable: false diff --git a/.ddev/php/php-xdebug.ini b/.ddev/php/php-xdebug.ini new file mode 100644 index 000000000..c9a635b8c --- /dev/null +++ b/.ddev/php/php-xdebug.ini @@ -0,0 +1,2 @@ +[PHP] +xdebug.mode=coverage,debug,develop diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index f2cd9f660..9a3f2a034 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -2,7 +2,7 @@ name: PHP Testing on: push: - branches: [ main ] +# branches: [ main ] pull_request: branches: [ main ] @@ -28,7 +28,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.0 + php-version: 8.5 coverage: none - name: Install Composer dependencies @@ -36,7 +36,7 @@ jobs: - name: Output list of packages as JSON id: output_data - run: echo "matrix=$(vendor/bin/monorepo-builder packages-json)" >> $GITHUB_OUTPUT + run: echo "matrix=$(./monorepo packages -t json)" >> $GITHUB_OUTPUT outputs: matrix: ${{ steps.output_data.outputs.matrix }} @@ -48,7 +48,13 @@ jobs: strategy: matrix: - php-versions: ['7.4', '8.0'] + php-versions: + - '8.3' + - '8.4' + - '8.5' + include: + - php-versions: '8.3' + dependencies: 'highest' package: ${{fromJson(needs.provide_packages_json.outputs.matrix)}} steps: @@ -67,6 +73,8 @@ jobs: - name: Install Composer dependencies uses: ramsey/composer-install@v2 + with: + dependency-versions: ${{ matrix.dependencies }} - name: Install ImageMagick if: ${{ matrix.package == 'image' }} @@ -82,4 +90,6 @@ jobs: run: tests/script/phpcs --ci ${{ matrix.package }} - name: Run PHPunit for all packages + env: + TEST_MODE: PACKAGE run: tests/script/phpunit --ci ${{ matrix.package }} diff --git a/.gitignore b/.gitignore index 119d860c5..e53552d75 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .phpunit.result.cache +phpunit.xml.dist.bak +.phpunit.cache charcoal_test node_modules/ packages/**/composer.lock @@ -7,3 +9,6 @@ phpstan.neon phpunit.xml psalm.xml vendor/ +tests/logs +build/report/ +packages/**/build/report diff --git a/composer.json b/composer.json index 5fa2a7da2..3f49bedc3 100644 --- a/composer.json +++ b/composer.json @@ -32,17 +32,18 @@ } ], "require": { - "php": "^7.4 || ^8.0", + "php": "^8.3", "ext-fileinfo": "*", "ext-json": "*", "ext-mbstring": "*", "ext-pdo": "*", + "ext-pdo_mysql": "*", "ext-simplexml": "*", "ext-spl": "*", + "assetic/framework": "^3.1", "barryvdh/elfinder-flysystem-driver": "^0.3", "erusev/parsedown": "^1.7", "guzzlehttp/guzzle": "^6.0 || ^7.0", - "kriswallsmith/assetic": "^1.4", "laminas/laminas-permissions-acl": "^2.8", "league/climate": "^3.2", "league/flysystem": "^1.0", @@ -50,15 +51,16 @@ "monolog/monolog": "^1.17", "phpmailer/phpmailer": "~6.0", "pimple/pimple": "^3.0", - "psr/cache": "^1.0", + "psr/cache": "^2.0", "psr/container": "^1.0", "psr/http-message": "^1.0", "psr/log": "^1.0", "seld/jsonlint": "^1.9", - "slim/slim": "^3.7", - "studio-42/elfinder": "2.1.64", - "symfony/translation": "^3.4", - "tedivm/stash": "~0.16", + "slim/slim": "^3.13", + "studio-42/elfinder": "^2.1.64", + "symfony/polyfill-php85": "^1.37", + "symfony/translation": "^7.2", + "tedivm/stash": "^1.1", "vlucas/phpdotenv": "^5.4" }, "require-dev": { @@ -68,14 +70,16 @@ "league/flysystem-memory": "^1.0", "league/flysystem-sftp": "^1.0", "mockery/mockery": "^1.0", - "mustache/mustache": "^2.11", + "mustache/mustache": "^3.2", "php-coveralls/php-coveralls": "^2.2", - "phpstan/phpstan": "^1.6", - "phpunit/phpunit": "^9.5", - "squizlabs/php_codesniffer": "^3.5", - "symfony/yaml": "^3.0", - "symplify/monorepo-builder": "^10.2", - "twig/twig": "^3.4" + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^12.5", + "rector/rector": "^2.4", + "squizlabs/php_codesniffer": "^4.0", + "symfony/yaml": "^7.2", + "symplify/monorepo-builder": "^12.7", + "twig/twig": "^3.4", + "yoast/phpunit-polyfills": "^4.0" }, "autoload": { "psr-4": { @@ -123,6 +127,9 @@ "packages/ui/tests/Charcoal", "packages/user/tests/Charcoal/", "packages/view/tests/Charcoal" + ], + "Charcoal\\Rector\\Property\\": [ + "src/Rector/Property/" ] } }, diff --git a/composer.lock b/composer.lock index fdd9567eb..d8d440581 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,97 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "29faccd918f465a35b04d246acab37e4", + "content-hash": "606558ecf298822aace0fbfc62f5c9bf", "packages": [ + { + "name": "assetic/framework", + "version": "v3.1.5", + "source": { + "type": "git", + "url": "https://github.com/assetic-php/assetic.git", + "reference": "0dc41d117ac679dc21f46b7022d393ef02b3f781" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/assetic-php/assetic/zipball/0dc41d117ac679dc21f46b7022d393ef02b3f781", + "reference": "0dc41d117ac679dc21f46b7022d393ef02b3f781", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-simplexml": "*", + "php": "^7.3 || ^8.0", + "symfony/deprecation-contracts": "^2.2.0 || ^3.0", + "symfony/process": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "replace": { + "kriswallsmith/assetic": "1.4.0" + }, + "require-dev": { + "meenie/javascript-packer": "^1.1", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5.8", + "psr/log": "^1.0", + "ptachoire/cssembed": "^1.0", + "scssphp/scssphp": "^1.0", + "symfony/phpunit-bridge": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0", + "twig/twig": "^2.11", + "wikimedia/less.php": "^3.0 || ^5.0", + "wikimedia/minify": "^2.2" + }, + "suggest": { + "meenie/javascript-packer": "The Assetic\\Filter\\PackerFilter requires meenie/javascript-packer", + "ptachoire/cssembed": "The Assetic\\Filter\\PhpCssEmbedFilter requires ptachoire/cssembed", + "scssphp/scssphp": "The Assetic\\Filter\\ScssphpFilter requires scssphp/scssphp", + "twig/twig": "Assetic provides an integration with the Twig templating engine", + "wikimedia/less.php": "The Assetic\\Filter\\LessphpFilter requires wikimedia/less.php", + "wikimedia/minify": "The Assetic\\Filter\\JavaScriptMinifierFilter && Assetic\\Filter\\CSSMinFilter requires wikimedia/minify" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/aliasing.php" + ], + "psr-0": { + "Assetic": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kris Wallsmith", + "email": "kris.wallsmith@gmail.com", + "homepage": "http://kriswallsmith.net/" + }, + { + "name": "Jack Wilkinson", + "email": "me@jackwilky.com", + "homepage": "https://jackwilky.com/" + }, + { + "name": "Luke Towers", + "email": "octobercms@luketowers.ca", + "homepage": "https://luketowers.ca" + } + ], + "description": "Asset Management for PHP", + "homepage": "https://github.com/assetic-php/assetic", + "keywords": [ + "assets", + "compression", + "minification" + ], + "support": { + "issues": "https://github.com/assetic-php/assetic/issues", + "source": "https://github.com/assetic-php/assetic/tree/v3.1.5" + }, + "time": "2026-04-23T03:30:22+00:00" + }, { "name": "barryvdh/elfinder-flysystem-driver", "version": "v0.3.0", @@ -68,24 +157,24 @@ }, { "name": "erusev/parsedown", - "version": "1.7.4", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/erusev/parsedown.git", - "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" + "reference": "96baaad00f71ba04d76e45b4620f54d3beabd6f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", - "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/96baaad00f71ba04d76e45b4620f54d3beabd6f7", + "reference": "96baaad00f71ba04d76e45b4620f54d3beabd6f7", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": ">=5.3.0" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35" + "phpunit/phpunit": "^7.5|^8.5|^9.6" }, "type": "library", "autoload": { @@ -112,30 +201,36 @@ ], "support": { "issues": "https://github.com/erusev/parsedown/issues", - "source": "https://github.com/erusev/parsedown/tree/1.7.x" + "source": "https://github.com/erusev/parsedown/tree/1.8.0" }, - "time": "2019-12-30T22:54:17+00:00" + "funding": [ + { + "url": "https://github.com/erusev", + "type": "github" + } + ], + "time": "2026-02-16T11:41:01+00:00" }, { "name": "graham-campbell/result-type", - "version": "v1.1.2", + "version": "v1.1.4", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862" + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/fbd48bce38f73f8a4ec8583362e732e4095e5862", - "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.2" + "phpoption/phpoption": "^1.9.5" }, "require-dev": { - "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" }, "type": "library", "autoload": { @@ -164,7 +259,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.2" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" }, "funding": [ { @@ -176,26 +271,26 @@ "type": "tidelift" } ], - "time": "2023-11-12T22:16:48+00:00" + "time": "2025-12-27T19:43:20+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "7.8.1", + "version": "7.10.5", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" + "reference": "7c8d84b39e680315f687e8662a9d6fb0865c5148" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", - "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7c8d84b39e680315f687e8662a9d6fb0865c5148", + "reference": "7c8d84b39e680315f687e8662a9d6fb0865c5148", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.1", - "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -206,9 +301,10 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", - "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "guzzle/client-integration-tests": "3.0.2", + "guzzlehttp/test-server": "^0.4", "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "phpunit/phpunit": "^8.5.52 || ^9.6.34", "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { @@ -286,7 +382,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.8.1" + "source": "https://github.com/guzzle/guzzle/tree/7.10.5" }, "funding": [ { @@ -302,20 +398,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:35:24+00:00" + "time": "2026-05-27T11:53:46+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.0.2", + "version": "2.4.1", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" + "reference": "09e8a212562fb1fb6a512c4156ed71525969d6c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", - "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", + "url": "https://api.github.com/repos/guzzle/promises/zipball/09e8a212562fb1fb6a512c4156ed71525969d6c2", + "reference": "09e8a212562fb1fb6a512c4156ed71525969d6c2", "shasum": "" }, "require": { @@ -323,7 +419,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.36 || ^9.6.15" + "phpunit/phpunit": "^8.5.52 || ^9.6.34" }, "type": "library", "extra": { @@ -369,7 +465,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.2" + "source": "https://github.com/guzzle/promises/tree/2.4.1" }, "funding": [ { @@ -385,20 +481,20 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:19:20+00:00" + "time": "2026-05-20T22:57:30+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.6.2", + "version": "2.10.4", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" + "reference": "d2a1a094e396da8957e797489fddaf860c340cfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", - "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/d2a1a094e396da8957e797489fddaf860c340cfc", + "reference": "d2a1a094e396da8957e797489fddaf860c340cfc", "shasum": "" }, "require": { @@ -413,8 +509,9 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.36 || ^9.6.15" + "http-interop/http-factory-tests": "1.1.0", + "jshttp/mime-db": "1.54.0.1", + "phpunit/phpunit": "^8.5.52 || ^9.6.34" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -485,7 +582,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.6.2" + "source": "https://github.com/guzzle/psr7/tree/2.10.4" }, "funding": [ { @@ -501,7 +598,7 @@ "type": "tidelift" } ], - "time": "2023-12-03T20:05:35+00:00" + "time": "2026-05-29T12:59:07+00:00" }, { "name": "intervention/image", @@ -533,16 +630,16 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "2.4-dev" - }, "laravel": { - "providers": [ - "Intervention\\Image\\ImageServiceProvider" - ], "aliases": { "Image": "Intervention\\Image\\Facades\\Image" - } + }, + "providers": [ + "Intervention\\Image\\ImageServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "2.4-dev" } }, "autoload": { @@ -587,114 +684,34 @@ ], "time": "2022-05-21T17:30:32+00:00" }, - { - "name": "kriswallsmith/assetic", - "version": "v1.4.0", - "source": { - "type": "git", - "url": "https://github.com/kriswallsmith/assetic.git", - "reference": "e911c437dbdf006a8f62c2f59b15b2d69a5e0aa1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kriswallsmith/assetic/zipball/e911c437dbdf006a8f62c2f59b15b2d69a5e0aa1", - "reference": "e911c437dbdf006a8f62c2f59b15b2d69a5e0aa1", - "shasum": "" - }, - "require": { - "php": ">=5.3.1", - "symfony/process": "~2.1|~3.0" - }, - "conflict": { - "twig/twig": "<1.27" - }, - "require-dev": { - "leafo/lessphp": "^0.3.7", - "leafo/scssphp": "~0.1", - "meenie/javascript-packer": "^1.1", - "mrclay/minify": "<2.3", - "natxet/cssmin": "3.0.4", - "patchwork/jsqueeze": "~1.0|~2.0", - "phpunit/phpunit": "~4.8 || ^5.6", - "psr/log": "~1.0", - "ptachoire/cssembed": "~1.0", - "symfony/phpunit-bridge": "~2.7|~3.0", - "twig/twig": "~1.23|~2.0", - "yfix/packager": "dev-master" - }, - "suggest": { - "leafo/lessphp": "Assetic provides the integration with the lessphp LESS compiler", - "leafo/scssphp": "Assetic provides the integration with the scssphp SCSS compiler", - "leafo/scssphp-compass": "Assetic provides the integration with the SCSS compass plugin", - "patchwork/jsqueeze": "Assetic provides the integration with the JSqueeze JavaScript compressor", - "ptachoire/cssembed": "Assetic provides the integration with phpcssembed to embed data uris", - "twig/twig": "Assetic provides the integration with the Twig templating engine" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-0": { - "Assetic": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kris Wallsmith", - "email": "kris.wallsmith@gmail.com", - "homepage": "http://kriswallsmith.net/" - } - ], - "description": "Asset Management for PHP", - "homepage": "https://github.com/kriswallsmith/assetic", - "keywords": [ - "assets", - "compression", - "minification" - ], - "support": { - "issues": "https://github.com/kriswallsmith/assetic/issues", - "source": "https://github.com/kriswallsmith/assetic/tree/master" - }, - "time": "2016-11-11T18:43:20+00:00" - }, { "name": "laminas/laminas-permissions-acl", - "version": "2.10.0", + "version": "2.18.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-permissions-acl.git", - "reference": "e927ae0a3001655fea97eb240eeea9d10638e82f" + "reference": "5940f6e7b9e2e3eba671f13dd26e610d2fe9acc3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-permissions-acl/zipball/e927ae0a3001655fea97eb240eeea9d10638e82f", - "reference": "e927ae0a3001655fea97eb240eeea9d10638e82f", + "url": "https://api.github.com/repos/laminas/laminas-permissions-acl/zipball/5940f6e7b9e2e3eba671f13dd26e610d2fe9acc3", + "reference": "5940f6e7b9e2e3eba671f13dd26e610d2fe9acc3", "shasum": "" }, "require": { - "php": "^7.4 || ~8.0.0 || ~8.1.0" + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" }, "conflict": { "laminas/laminas-servicemanager": "<3.0", "zendframework/zend-permissions-acl": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "~2.3.0", - "laminas/laminas-servicemanager": "^3.15.1", - "phpunit/phpunit": "^9.5.0", - "psalm/plugin-phpunit": "^0.17.0", - "vimeo/psalm": "^4.24.0" + "laminas/laminas-coding-standard": "^3.0.1", + "laminas/laminas-servicemanager": "^3.21", + "phpbench/phpbench": "^1.2.10", + "phpunit/phpunit": "^10.5.58", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^6.13.1" }, "suggest": { "laminas/laminas-servicemanager": "To support Laminas\\Permissions\\Acl\\Assertion\\AssertionManager plugin manager usage" @@ -729,20 +746,20 @@ "type": "community_bridge" } ], - "time": "2022-07-21T09:23:39+00:00" + "time": "2025-11-03T09:15:20+00:00" }, { "name": "league/climate", - "version": "3.8.2", + "version": "3.10.1", "source": { "type": "git", "url": "https://github.com/thephpleague/climate.git", - "reference": "a785a3ac8f584eed4abd45e4e16fe64c46659a28" + "reference": "f2d78fbc504740bcd0209e40a4586c886567ddc9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/climate/zipball/a785a3ac8f584eed4abd45e4e16fe64c46659a28", - "reference": "a785a3ac8f584eed4abd45e4e16fe64c46659a28", + "url": "https://api.github.com/repos/thephpleague/climate/zipball/f2d78fbc504740bcd0209e40a4586c886567ddc9", + "reference": "f2d78fbc504740bcd0209e40a4586c886567ddc9", "shasum": "" }, "require": { @@ -751,9 +768,10 @@ "seld/cli-prompt": "^1.0" }, "require-dev": { - "mikey179/vfsstream": "^1.6.10", - "mockery/mockery": "^1.4.2", - "phpunit/phpunit": "^9.5.10" + "mikey179/vfsstream": "^1.6.12", + "mockery/mockery": "^1.6.12", + "phpunit/phpunit": "^9.6.21", + "squizlabs/php_codesniffer": "^3.10" }, "suggest": { "ext-mbstring": "If ext-mbstring is not available you MUST install symfony/polyfill-mbstring" @@ -792,9 +810,9 @@ ], "support": { "issues": "https://github.com/thephpleague/climate/issues", - "source": "https://github.com/thephpleague/climate/tree/3.8.2" + "source": "https://github.com/thephpleague/climate/tree/3.10.1" }, - "time": "2022-06-18T14:42:08+00:00" + "time": "2026-03-19T19:32:55+00:00" }, { "name": "league/flysystem", @@ -892,26 +910,26 @@ }, { "name": "league/flysystem-cached-adapter", - "version": "1.1.0", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", - "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff" + "reference": "7bb5cd9d996904cf43d7da8ba45a724ff8c7ef14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/d1925efb2207ac4be3ad0c40b8277175f99ffaff", - "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/7bb5cd9d996904cf43d7da8ba45a724ff8c7ef14", + "reference": "7bb5cd9d996904cf43d7da8ba45a724ff8c7ef14", "shasum": "" }, "require": { - "league/flysystem": "~1.0", - "psr/cache": "^1.0.0" + "league/flysystem": "~1.0" }, "require-dev": { + "henrikbjorn/phpspec-code-coverage": "~1.0@dev", "mockery/mockery": "~0.9", - "phpspec/phpspec": "^3.4", - "phpunit/phpunit": "^5.7", + "phpspec/phpspec": "~2.1", + "phpunit/phpunit": "~4.1", "predis/predis": "~1.0", "tedivm/stash": "~0.12" }, @@ -939,20 +957,20 @@ "issues": "https://github.com/thephpleague/flysystem-cached-adapter/issues", "source": "https://github.com/thephpleague/flysystem-cached-adapter/tree/master" }, - "time": "2020-07-25T15:56:04+00:00" + "time": "2015-07-09T21:00:39+00:00" }, { "name": "league/mime-type-detection", - "version": "1.14.0", + "version": "1.16.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "b6a5854368533df0295c5761a0253656a2e52d9e" + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/b6a5854368533df0295c5761a0253656a2e52d9e", - "reference": "b6a5854368533df0295c5761a0253656a2e52d9e", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", "shasum": "" }, "require": { @@ -983,7 +1001,7 @@ "description": "Mime-type detection for Flysystem", "support": { "issues": "https://github.com/thephpleague/mime-type-detection/issues", - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.14.0" + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" }, "funding": [ { @@ -995,25 +1013,25 @@ "type": "tidelift" } ], - "time": "2023-10-17T14:13:20+00:00" + "time": "2024-09-21T08:32:55+00:00" }, { "name": "mcaskill/php-html-build-attributes", - "version": "v1.3.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/mcaskill/php-html-build-attributes.git", - "reference": "2f0390b856610b7da2c235263a5a7d90bade64e4" + "reference": "ae8753fcfccec6f5aa08392b95a4fc949ce870cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mcaskill/php-html-build-attributes/zipball/2f0390b856610b7da2c235263a5a7d90bade64e4", - "reference": "2f0390b856610b7da2c235263a5a7d90bade64e4", + "url": "https://api.github.com/repos/mcaskill/php-html-build-attributes/zipball/ae8753fcfccec6f5aa08392b95a4fc949ce870cb", + "reference": "ae8753fcfccec6f5aa08392b95a4fc949ce870cb", "shasum": "" }, "require": { "ext-json": "*", - "php": ">=5.4.0" + "php": ">=7.1.0" }, "require-dev": { "pestphp/pest": "^1.22", @@ -1044,9 +1062,9 @@ ], "support": { "issues": "https://github.com/mcaskill/php-html-build-attributes/issues", - "source": "https://github.com/mcaskill/php-html-build-attributes/tree/v1.3.0" + "source": "https://github.com/mcaskill/php-html-build-attributes/tree/v1.4.0" }, - "time": "2023-08-09T03:09:43+00:00" + "time": "2025-07-18T17:25:44+00:00" }, { "name": "monolog/monolog", @@ -1186,16 +1204,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.9.1", + "version": "v6.12.0", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "039de174cd9c17a8389754d3b877a2ed22743e18" + "reference": "d1ac35d784bf9f5e61b424901d5a014967f15b12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/039de174cd9c17a8389754d3b877a2ed22743e18", - "reference": "039de174cd9c17a8389754d3b877a2ed22743e18", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/d1ac35d784bf9f5e61b424901d5a014967f15b12", + "reference": "d1ac35d784bf9f5e61b424901d5a014967f15b12", "shasum": "" }, "require": { @@ -1255,7 +1273,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.1" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.12.0" }, "funding": [ { @@ -1263,20 +1281,20 @@ "type": "github" } ], - "time": "2023-11-25T22:23:28+00:00" + "time": "2025-10-15T16:49:08+00:00" }, { "name": "phpoption/phpoption", - "version": "1.9.2", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820" + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/80735db690fe4fc5c76dfa7f9b770634285fa820", - "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", "shasum": "" }, "require": { @@ -1284,13 +1302,13 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" }, "type": "library", "extra": { "bamarni-bin": { "bin-links": true, - "forward-command": true + "forward-command": false }, "branch-alias": { "dev-master": "1.9-dev" @@ -1326,7 +1344,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.2" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" }, "funding": [ { @@ -1338,20 +1356,20 @@ "type": "tidelift" } ], - "time": "2023-11-12T21:59:55+00:00" + "time": "2025-12-27T19:41:33+00:00" }, { "name": "pimple/pimple", - "version": "v3.5.0", + "version": "v3.6.2", "source": { "type": "git", "url": "https://github.com/silexphp/Pimple.git", - "reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed" + "reference": "8cfe7f74ac22a433d303914eba9ea4c2a834edce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a94b3a4db7fb774b3d78dad2315ddc07629e1bed", - "reference": "a94b3a4db7fb774b3d78dad2315ddc07629e1bed", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/8cfe7f74ac22a433d303914eba9ea4c2a834edce", + "reference": "8cfe7f74ac22a433d303914eba9ea4c2a834edce", "shasum": "" }, "require": { @@ -1359,12 +1377,12 @@ "psr/container": "^1.1 || ^2.0" }, "require-dev": { - "symfony/phpunit-bridge": "^5.4@dev" + "phpunit/phpunit": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { @@ -1389,26 +1407,26 @@ "dependency injection" ], "support": { - "source": "https://github.com/silexphp/Pimple/tree/v3.5.0" + "source": "https://github.com/silexphp/Pimple/tree/v3.6.2" }, - "time": "2021-10-28T11:13:42+00:00" + "time": "2026-02-26T08:23:44+00:00" }, { "name": "psr/cache", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/cache.git", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "url": "https://api.github.com/repos/php-fig/cache/zipball/213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { @@ -1428,7 +1446,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for caching libraries", @@ -1438,9 +1456,9 @@ "psr-6" ], "support": { - "source": "https://github.com/php-fig/cache/tree/master" + "source": "https://github.com/php-fig/cache/tree/2.0.0" }, - "time": "2016-08-06T20:24:11+00:00" + "time": "2021-02-03T23:23:37+00:00" }, { "name": "psr/container", @@ -1544,20 +1562,20 @@ }, { "name": "psr/http-factory", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "e616d01114759c4c489f93b099585439f795fe35" + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", - "reference": "e616d01114759c4c489f93b099585439f795fe35", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "php": ">=7.0.0", + "php": ">=7.1", "psr/http-message": "^1.0 || ^2.0" }, "type": "library", @@ -1581,7 +1599,7 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interfaces for PSR-7 HTTP message factories", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ "factory", "http", @@ -1593,9 +1611,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2023-04-10T20:10:41+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { "name": "psr/http-message", @@ -1801,23 +1819,23 @@ }, { "name": "seld/jsonlint", - "version": "1.10.1", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "76d449a358ece77d6f1d6331c68453e657172202" + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/76d449a358ece77d6f1d6331c68453e657172202", - "reference": "76d449a358ece77d6f1d6331c68453e657172202", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", "shasum": "" }, "require": { "php": "^5.3 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.5", + "phpstan/phpstan": "^1.11", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" }, "bin": [ @@ -1849,7 +1867,7 @@ ], "support": { "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.10.1" + "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" }, "funding": [ { @@ -1861,20 +1879,20 @@ "type": "tidelift" } ], - "time": "2023-12-18T13:03:25+00:00" + "time": "2024-07-11T14:55:45+00:00" }, { "name": "slim/slim", - "version": "3.12.5", + "version": "3.13.0", "source": { "type": "git", "url": "https://github.com/slimphp/Slim.git", - "reference": "565632b2d9b64ecedf89546edbbf4f3648089f0c" + "reference": "f899a6e0be000b9e56d164a4241aa60ab8f33c7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim/zipball/565632b2d9b64ecedf89546edbbf4f3648089f0c", - "reference": "565632b2d9b64ecedf89546edbbf4f3648089f0c", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/f899a6e0be000b9e56d164a4241aa60ab8f33c7f", + "reference": "f899a6e0be000b9e56d164a4241aa60ab8f33c7f", "shasum": "" }, "require": { @@ -1882,7 +1900,7 @@ "ext-libxml": "*", "ext-simplexml": "*", "nikic/fast-route": "^1.0", - "php": ">=5.5.0", + "php": "^8.1", "pimple/pimple": "^3.0", "psr/container": "^1.0", "psr/http-message": "^1.0" @@ -1891,7 +1909,8 @@ "psr/http-message-implementation": "1.0" }, "require-dev": { - "phpunit/phpunit": "^4.0", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^10.5", "squizlabs/php_codesniffer": "^3.6.0" }, "type": "library", @@ -1936,7 +1955,7 @@ ], "support": { "issues": "https://github.com/slimphp/Slim/issues", - "source": "https://github.com/slimphp/Slim/tree/3.12.5" + "source": "https://github.com/slimphp/Slim/tree/3.13.0" }, "funding": [ { @@ -1948,20 +1967,20 @@ "type": "tidelift" } ], - "time": "2023-07-23T04:32:51+00:00" + "time": "2026-04-28T08:53:26+00:00" }, { "name": "studio-42/elfinder", - "version": "2.1.64", + "version": "2.1.69", "source": { "type": "git", "url": "https://github.com/Studio-42/elFinder.git", - "reference": "deaa6797df1c6f288238b47284c9b593174bfc0f" + "reference": "8f2c3ffafcdd52cf4515f1eec172f4eee44552ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Studio-42/elFinder/zipball/deaa6797df1c6f288238b47284c9b593174bfc0f", - "reference": "deaa6797df1c6f288238b47284c9b593174bfc0f", + "url": "https://api.github.com/repos/Studio-42/elFinder/zipball/8f2c3ffafcdd52cf4515f1eec172f4eee44552ad", + "reference": "8f2c3ffafcdd52cf4515f1eec172f4eee44552ad", "shasum": "" }, "require": { @@ -2008,7 +2027,7 @@ "homepage": "http://elfinder.org", "support": { "issues": "https://github.com/Studio-42/elFinder/issues", - "source": "https://github.com/Studio-42/elFinder/tree/2.1.64" + "source": "https://github.com/Studio-42/elFinder/tree/2.1.69" }, "funding": [ { @@ -2016,33 +2035,33 @@ "type": "github" } ], - "time": "2023-12-20T07:43:10+00:00" + "time": "2026-05-07T12:53:30+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.2", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b", + "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.1" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" } }, "autoload": { @@ -2067,7 +2086,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0" }, "funding": [ { @@ -2078,29 +2097,33 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2026-04-13T15:52:40+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.28.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" + "reference": "141046a8f9477948ff284fa65be2095baafb94f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -2110,12 +2133,9 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -2149,7 +2169,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" }, "funding": [ { @@ -2160,29 +2180,34 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", + "version": "v1.38.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" + "reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/14c5439eec4ccff081ac14eca2dc57feb2a66d92", + "reference": "14c5439eec4ccff081ac14eca2dc57feb2a66d92", "shasum": "" }, "require": { - "php": ">=7.1" + "ext-iconv": "*", + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -2192,12 +2217,9 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -2232,7 +2254,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.1" }, "funding": [ { @@ -2243,38 +2265,39 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-07-28T09:04:16+00:00" + "time": "2026-05-26T12:51:13+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.28.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -2315,7 +2338,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0" }, "funding": [ { @@ -2326,37 +2349,50 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { - "name": "symfony/process", - "version": "v3.4.47", + "name": "symfony/polyfill-php85", + "version": "v1.38.1", "source": { "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca" + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/b8648cf1d5af12a44a51d07ef9bf980921f15fca", - "reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1", + "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": ">=7.2" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Component\\Process\\": "" + "Symfony\\Polyfill\\Php85\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2365,18 +2401,24 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Process Component", + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], "support": { - "source": "https://github.com/symfony/process/tree/v3.4.47" + "source": "https://github.com/symfony/polyfill-php85/tree/v1.38.1" }, "funding": [ { @@ -2387,55 +2429,38 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2026-05-26T02:25:22+00:00" }, { - "name": "symfony/translation", - "version": "v3.4.47", + "name": "symfony/process", + "version": "v7.4.13", "source": { "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "be83ee6c065cb32becdb306ba61160d598b1ce88" + "url": "https://github.com/symfony/process.git", + "reference": "f5804be144caceb570f6747519999636b664f24c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/be83ee6c065cb32becdb306ba61160d598b1ce88", - "reference": "be83ee6c065cb32becdb306ba61160d598b1ce88", + "url": "https://api.github.com/repos/symfony/process/zipball/f5804be144caceb570f6747519999636b664f24c", + "reference": "f5804be144caceb570f6747519999636b664f24c", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.4", - "symfony/yaml": "<3.4" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/http-kernel": "~3.4|~4.0", - "symfony/intl": "^2.8.18|^3.2.5|~4.0", - "symfony/var-dumper": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" - }, - "suggest": { - "psr/log-implementation": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" + "php": ">=8.2" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Translation\\": "" + "Symfony\\Component\\Process\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -2455,10 +2480,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Translation Component", + "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v3.4.47" + "source": "https://github.com/symfony/process/tree/v7.4.13" }, "funding": [ { @@ -2469,111 +2494,296 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2026-05-23T16:05:06+00:00" }, { - "name": "tedivm/stash", - "version": "v0.17.6", + "name": "symfony/translation", + "version": "v7.4.10", "source": { "type": "git", - "url": "https://github.com/tedious/Stash.git", - "reference": "a2c9df16c77b13e1f90462f30597a772166eea8f" + "url": "https://github.com/symfony/translation.git", + "reference": "ada7578c30dd5feaa8259cff3e885069ea81ddde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tedious/Stash/zipball/a2c9df16c77b13e1f90462f30597a772166eea8f", - "reference": "a2c9df16c77b13e1f90462f30597a772166eea8f", + "url": "https://api.github.com/repos/symfony/translation/zipball/ada7578c30dd5feaa8259cff3e885069ea81ddde", + "reference": "ada7578c30dd5feaa8259cff3e885069ea81ddde", "shasum": "" }, "require": { - "php": ">7.0", - "psr/cache": "~1.0" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5.3|^3.3" + }, + "conflict": { + "nikic/php-parser": "<5.0", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" }, "provide": { - "psr/cache-implementation": "1.0.0" + "symfony/translation-implementation": "2.3|3.0" }, "require-dev": { - "dms/phpunit-arraysubset-asserts": "^0.4.0", - "friendsofphp/php-cs-fixer": "^2.8", - "php": "^7.2|^8.0", - "php-coveralls/php-coveralls": "^2.0", - "phpunit/phpunit": "^9.0" + "nikic/php-parser": "^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { - "Stash\\": "src/Stash/" - } + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Robert Hafner", - "email": "tedivm@tedivm.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { - "name": "Josh Hall-Bachner", - "email": "charlequin@gmail.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "The place to keep your cache.", - "homepage": "http://github.com/tedious/Stash", - "keywords": [ - "apc", - "cache", - "caching", - "memcached", - "psr-6", - "psr6", - "redis", - "sessions" - ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/tedious/Stash/issues", - "source": "https://github.com/tedious/Stash/tree/v0.17.6" + "source": "https://github.com/symfony/translation/tree/v7.4.10" }, "funding": [ { - "url": "https://github.com/tedivm", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-06T11:19:24+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.7.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "0ab302977a952b42fd51475c4ebac81f8da0a95d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/0ab302977a952b42fd51475c4ebac81f8da0a95d", + "reference": "0ab302977a952b42fd51475c4ebac81f8da0a95d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.7.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-05T13:30:16+00:00" + }, + { + "name": "tedivm/stash", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/tedious/Stash.git", + "reference": "39c426ed180f25a40c973608370191dacd5e0b56" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tedious/Stash/zipball/39c426ed180f25a40c973608370191dacd5e0b56", + "reference": "39c426ed180f25a40c973608370191dacd5e0b56", + "shasum": "" + }, + "require": { + "php": "^8.0", + "psr/cache": "^2|^3" + }, + "provide": { + "psr/cache-implementation": "2.0|3.0" + }, + "require-dev": { + "dms/phpunit-arraysubset-asserts": "^0.5.0", + "friendsofphp/php-cs-fixer": "^2.8", + "php-coveralls/php-coveralls": "^2.0", + "phpunit/phpunit": "^9.0|^10" + }, + "type": "library", + "autoload": { + "psr-4": { + "Stash\\": "src/Stash/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Robert Hafner", + "email": "tedivm@tedivm.com" + }, + { + "name": "Josh Hall-Bachner", + "email": "charlequin@gmail.com" + } + ], + "description": "The place to keep your cache.", + "homepage": "http://github.com/tedious/Stash", + "keywords": [ + "apc", + "cache", + "caching", + "memcached", + "psr-6", + "psr6", + "redis", + "sessions" + ], + "support": { + "issues": "https://github.com/tedious/Stash/issues", + "source": "https://github.com/tedious/Stash/tree/v1.2.2" + }, + "funding": [ + { + "url": "https://github.com/tedivm", + "type": "github" }, { "url": "https://tidelift.com/funding/github/packagist/tedivm/stash", "type": "tidelift" } ], - "time": "2022-07-26T14:15:03+00:00" + "time": "2025-12-27T14:08:18+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.6.0", + "version": "v5.6.3", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4" + "reference": "955e7815d677a3eaa7075231212f2110983adecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", - "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.1.2", + "graham-campbell/result-type": "^1.1.4", "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.2", - "symfony/polyfill-ctype": "^1.24", - "symfony/polyfill-mbstring": "^1.24", - "symfony/polyfill-php80": "^1.24" + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", @@ -2587,7 +2797,7 @@ "extra": { "bamarni-bin": { "bin-links": true, - "forward-command": true + "forward-command": false }, "branch-alias": { "dev-master": "5.6-dev" @@ -2622,7 +2832,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.0" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" }, "funding": [ { @@ -2634,22 +2844,22 @@ "type": "tidelift" } ], - "time": "2023-11-12T22:43:29+00:00" + "time": "2025-12-27T19:49:13+00:00" } ], "packages-dev": [ { "name": "aws/aws-crt-php", - "version": "v1.2.4", + "version": "v1.2.7", "source": { "type": "git", "url": "https://github.com/awslabs/aws-crt-php.git", - "reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2" + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/eb0c6e4e142224a10b08f49ebf87f32611d162b2", - "reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/d71d9906c7bb63a28295447ba12e74723bd3730e", + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e", "shasum": "" }, "require": { @@ -2688,22 +2898,22 @@ ], "support": { "issues": "https://github.com/awslabs/aws-crt-php/issues", - "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.4" + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.7" }, - "time": "2023-11-08T00:42:13+00:00" + "time": "2024-10-18T22:15:13+00:00" }, { "name": "aws/aws-sdk-php", - "version": "3.294.2", + "version": "3.383.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "e6a63e39fed0fd9fb553af42e99aaf8d7c104c88" + "reference": "56b7ff3ff9e086eb3945bf31e75c97cde5ab531a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/e6a63e39fed0fd9fb553af42e99aaf8d7c104c88", - "reference": "e6a63e39fed0fd9fb553af42e99aaf8d7c104c88", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/56b7ff3ff9e086eb3945bf31e75c97cde5ab531a", + "reference": "56b7ff3ff9e086eb3945bf31e75c97cde5ab531a", "shasum": "" }, "require": { @@ -2711,37 +2921,36 @@ "ext-json": "*", "ext-pcre": "*", "ext-simplexml": "*", - "guzzlehttp/guzzle": "^6.5.8 || ^7.4.5", - "guzzlehttp/promises": "^1.4.0 || ^2.0", - "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", - "mtdowling/jmespath.php": "^2.6", - "php": ">=7.2.5", - "psr/http-message": "^1.0 || ^2.0" + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/promises": "^2.0", + "guzzlehttp/psr7": "^2.4.5", + "mtdowling/jmespath.php": "^2.8.0", + "php": ">=8.1", + "psr/http-message": "^1.0 || ^2.0", + "symfony/filesystem": "^v5.4.45 || ^v6.4.3 || ^v7.1.0 || ^v8.0.0" }, "require-dev": { "andrewsville/php-token-reflection": "^1.4", "aws/aws-php-sns-message-validator": "~1.0", "behat/behat": "~3.0", - "composer/composer": "^1.10.22", - "dms/phpunit-arraysubset-asserts": "^0.4.0", + "composer/composer": "^2.7.8", + "dms/phpunit-arraysubset-asserts": "^v0.5.0", "doctrine/cache": "~1.4", "ext-dom": "*", "ext-openssl": "*", - "ext-pcntl": "*", "ext-sockets": "*", - "nette/neon": "^2.3", - "paragonie/random_compat": ">= 2", - "phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5", - "psr/cache": "^1.0", - "psr/simple-cache": "^1.0", - "sebastian/comparator": "^1.2.3 || ^4.0", - "yoast/phpunit-polyfills": "^1.0" + "phpunit/phpunit": "^10.0", + "psr/cache": "^2.0 || ^3.0", + "psr/simple-cache": "^2.0 || ^3.0", + "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0", + "yoast/phpunit-polyfills": "^2.0" }, "suggest": { "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", "doctrine/cache": "To use the DoctrineCacheAdapter", "ext-curl": "To send requests using cURL", "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-pcntl": "To use client-side monitoring", "ext-sockets": "To use client-side monitoring" }, "type": "library", @@ -2756,7 +2965,10 @@ ], "psr-4": { "Aws\\": "src/" - } + }, + "exclude-from-classmap": [ + "src/data/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2765,11 +2977,11 @@ "authors": [ { "name": "Amazon Web Services", - "homepage": "http://aws.amazon.com" + "homepage": "https://aws.amazon.com" } ], "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", - "homepage": "http://aws.amazon.com/sdkforphp", + "homepage": "https://aws.amazon.com/sdk-for-php", "keywords": [ "amazon", "aws", @@ -2781,11 +2993,11 @@ "sdk" ], "support": { - "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", + "forum": "https://github.com/aws/aws-sdk-php/discussions", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.294.2" + "source": "https://github.com/aws/aws-sdk-php/tree/3.383.1" }, - "time": "2023-12-18T19:11:16+00:00" + "time": "2026-05-29T18:13:12+00:00" }, { "name": "cache/adapter-common", @@ -3047,92 +3259,22 @@ }, "time": "2022-01-15T15:47:19+00:00" }, - { - "name": "doctrine/instantiator", - "version": "1.5.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9 || ^11", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^0.16 || ^1", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.30 || ^5.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.5.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2022-12-30T00:15:36+00:00" - }, { "name": "hamcrest/hamcrest-php", - "version": "v2.0.1", + "version": "v2.1.1", "source": { "type": "git", "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3" + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", - "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", "shasum": "" }, "require": { - "php": "^5.3|^7.0|^8.0" + "php": "^7.4|^8.0" }, "replace": { "cordoval/hamcrest-php": "*", @@ -3140,8 +3282,8 @@ "kodova/hamcrest-php": "*" }, "require-dev": { - "phpunit/php-file-iterator": "^1.4 || ^2.0", - "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0" + "phpunit/php-file-iterator": "^1.4 || ^2.0 || ^3.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0" }, "type": "library", "extra": { @@ -3164,41 +3306,48 @@ ], "support": { "issues": "https://github.com/hamcrest/hamcrest-php/issues", - "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.0.1" + "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.1.1" }, - "time": "2020-07-09T08:09:16+00:00" + "time": "2025-04-30T06:54:44+00:00" }, { "name": "league/csv", - "version": "9.8.0", + "version": "9.28.0", "source": { "type": "git", "url": "https://github.com/thephpleague/csv.git", - "reference": "9d2e0265c5d90f5dd601bc65ff717e05cec19b47" + "reference": "6582ace29ae09ba5b07049d40ea13eb19c8b5073" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/csv/zipball/9d2e0265c5d90f5dd601bc65ff717e05cec19b47", - "reference": "9d2e0265c5d90f5dd601bc65ff717e05cec19b47", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/6582ace29ae09ba5b07049d40ea13eb19c8b5073", + "reference": "6582ace29ae09ba5b07049d40ea13eb19c8b5073", "shasum": "" }, "require": { - "ext-json": "*", - "ext-mbstring": "*", - "php": "^7.4 || ^8.0" + "ext-filter": "*", + "php": "^8.1.2" }, "require-dev": { - "ext-curl": "*", "ext-dom": "*", - "friendsofphp/php-cs-fixer": "^v3.4.0", - "phpstan/phpstan": "^1.3.0", - "phpstan/phpstan-phpunit": "^1.0.0", - "phpstan/phpstan-strict-rules": "^1.1.0", - "phpunit/phpunit": "^9.5.11" + "ext-xdebug": "*", + "friendsofphp/php-cs-fixer": "^3.92.3", + "phpbench/phpbench": "^1.4.3", + "phpstan/phpstan": "^1.12.32", + "phpstan/phpstan-deprecation-rules": "^1.2.1", + "phpstan/phpstan-phpunit": "^1.4.2", + "phpstan/phpstan-strict-rules": "^1.6.2", + "phpunit/phpunit": "^10.5.16 || ^11.5.22 || ^12.5.4", + "symfony/var-dumper": "^6.4.8 || ^7.4.0 || ^8.0" }, "suggest": { - "ext-dom": "Required to use the XMLConverter and or the HTMLConverter classes", - "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters" + "ext-dom": "Required to use the XMLConverter and the HTMLConverter classes", + "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters", + "ext-mbstring": "Needed to ease transcoding CSV using mb stream filters", + "ext-mysqli": "Requiered to use the package with the MySQLi extension", + "ext-pdo": "Required to use the package with the PDO extension", + "ext-pgsql": "Requiered to use the package with the PgSQL extension", + "ext-sqlite3": "Required to use the package with the SQLite3 extension" }, "type": "library", "extra": { @@ -3250,7 +3399,7 @@ "type": "github" } ], - "time": "2022-01-04T00:13:07+00:00" + "time": "2025-12-27T15:18:42+00:00" }, { "name": "league/flysystem-aws-s3-v3", @@ -3435,16 +3584,16 @@ }, { "name": "mockery/mockery", - "version": "1.6.7", + "version": "1.6.12", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06" + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06", - "reference": "0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06", + "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", "shasum": "" }, "require": { @@ -3456,8 +3605,8 @@ "phpunit/phpunit": "<8.0" }, "require-dev": { - "phpunit/phpunit": "^8.5 || ^9.6.10", - "symplify/easy-coding-standard": "^12.0.8" + "phpunit/phpunit": "^8.5 || ^9.6.17", + "symplify/easy-coding-standard": "^12.1.14" }, "type": "library", "autoload": { @@ -3514,20 +3663,20 @@ "security": "https://github.com/mockery/mockery/security/advisories", "source": "https://github.com/mockery/mockery" }, - "time": "2023-12-10T02:24:34+00:00" + "time": "2024-05-16T03:13:13+00:00" }, { "name": "mtdowling/jmespath.php", - "version": "2.7.0", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/jmespath/jmespath.php.git", - "reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b" + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/bbb69a935c2cbb0c03d7f481a238027430f6440b", - "reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc", "shasum": "" }, "require": { @@ -3544,7 +3693,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -3578,36 +3727,39 @@ ], "support": { "issues": "https://github.com/jmespath/jmespath.php/issues", - "source": "https://github.com/jmespath/jmespath.php/tree/2.7.0" + "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0" }, - "time": "2023-08-25T10:54:48+00:00" + "time": "2024-09-04T18:46:31+00:00" }, { "name": "mustache/mustache", - "version": "v2.14.2", + "version": "v3.2.0", "source": { "type": "git", "url": "https://github.com/bobthecow/mustache.php.git", - "reference": "e62b7c3849d22ec55f3ec425507bf7968193a6cb" + "reference": "bd4fb2e45ac2df0570c0f4da6898054a950d1ed0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/e62b7c3849d22ec55f3ec425507bf7968193a6cb", - "reference": "e62b7c3849d22ec55f3ec425507bf7968193a6cb", + "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/bd4fb2e45ac2df0570c0f4da6898054a950d1ed0", + "reference": "bd4fb2e45ac2df0570c0f4da6898054a950d1ed0", "shasum": "" }, "require": { - "php": ">=5.2.4" + "php": ">=5.6" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~1.11", - "phpunit/phpunit": "~3.7|~4.0|~5.0" + "friendsofphp/php-cs-fixer": "~2.19.3", + "yoast/phpunit-polyfills": "^2.0" }, "type": "library", "autoload": { - "psr-0": { - "Mustache": "src/" - } + "psr-4": { + "Mustache\\": "src/" + }, + "classmap": [ + "src/compat.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3628,22 +3780,22 @@ ], "support": { "issues": "https://github.com/bobthecow/mustache.php/issues", - "source": "https://github.com/bobthecow/mustache.php/tree/v2.14.2" + "source": "https://github.com/bobthecow/mustache.php/tree/v3.2.0" }, - "time": "2022-08-23T13:07:01+00:00" + "time": "2026-05-10T04:13:08+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.11.1", + "version": "1.13.4", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { @@ -3651,11 +3803,12 @@ }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { "doctrine/collections": "^1.6.8", "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", @@ -3681,7 +3834,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, "funding": [ { @@ -3689,29 +3842,122 @@ "type": "tidelift" } ], - "time": "2023-03-08T13:26:56+00:00" + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nette/utils", + "version": "v4.1.4", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "7da6c396d7ebe142bc857c20479d5e70a5e1aac7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/7da6c396d7ebe142bc857c20479d5e70a5e1aac7", + "reference": "7da6c396d7ebe142bc857c20479d5e70a5e1aac7", + "shasum": "" + }, + "require": { + "php": "8.2 - 8.5" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.5", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.1.4" + }, + "time": "2026-05-11T20:49:54+00:00" }, { "name": "nikic/php-parser", - "version": "v4.18.0", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -3719,7 +3965,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.x-dev" } }, "autoload": { @@ -3743,26 +3989,27 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2023-12-10T21:03:43+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -3803,14 +4050,20 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" - }, - { - "name": "phar-io/version", - "version": "3.2.1", - "source": { + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { "type": "git", "url": "https://github.com/phar-io/version.git", "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" @@ -3860,32 +4113,32 @@ }, { "name": "php-coveralls/php-coveralls", - "version": "v2.7.0", + "version": "v2.9.1", "source": { "type": "git", "url": "https://github.com/php-coveralls/php-coveralls.git", - "reference": "b36fa4394e519dafaddc04ae03976bc65a25ba15" + "reference": "916bdb118597f61ce6715fb738ab8f234b89a2cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-coveralls/php-coveralls/zipball/b36fa4394e519dafaddc04ae03976bc65a25ba15", - "reference": "b36fa4394e519dafaddc04ae03976bc65a25ba15", + "url": "https://api.github.com/repos/php-coveralls/php-coveralls/zipball/916bdb118597f61ce6715fb738ab8f234b89a2cb", + "reference": "916bdb118597f61ce6715fb738ab8f234b89a2cb", "shasum": "" }, "require": { "ext-json": "*", "ext-simplexml": "*", "guzzlehttp/guzzle": "^6.0 || ^7.0", - "php": "^7.0 || ^8.0", - "psr/log": "^1.0 || ^2.0", - "symfony/config": "^2.1 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/console": "^2.1 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/stopwatch": "^2.0 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "symfony/yaml": "^2.0.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0" + "php": "^7.4 || ^8.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/config": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/console": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/stopwatch": "^5.4 || ^6.4 || ^7.0 || ^8.0", + "symfony/yaml": "^5.4 || ^6.4 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.4.3 || ^6.0 || ^7.0 || >=8.0 <8.5.29 || >=9.0 <9.5.23", - "sanmai/phpunit-legacy-adapter": "^6.1 || ^8.0" + "phpspec/prophecy-phpunit": "^2.4", + "phpunit/phpunit": "^9.6.29 || ^10.5.58 || ^11.5.43" }, "suggest": { "symfony/http-kernel": "Allows Symfony integration" @@ -3937,22 +4190,22 @@ ], "support": { "issues": "https://github.com/php-coveralls/php-coveralls/issues", - "source": "https://github.com/php-coveralls/php-coveralls/tree/v2.7.0" + "source": "https://github.com/php-coveralls/php-coveralls/tree/v2.9.1" }, - "time": "2023-11-22T10:21:01+00:00" + "time": "2025-12-18T13:08:37+00:00" }, { "name": "phpseclib/phpseclib", - "version": "2.0.45", + "version": "2.0.54", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "28d8f438a0064c9de80857e3270d071495544640" + "reference": "a96a835067c39ee7a709329fe70869817da18081" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/28d8f438a0064c9de80857e3270d071495544640", - "reference": "28d8f438a0064c9de80857e3270d071495544640", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/a96a835067c39ee7a709329fe70869817da18081", + "reference": "a96a835067c39ee7a709329fe70869817da18081", "shasum": "" }, "require": { @@ -3960,7 +4213,7 @@ }, "require-dev": { "phing/phing": "~2.7", - "phpunit/phpunit": "^4.8.35|^5.7|^6.0|^9.4", + "phpunit/phpunit": "^4.8.35|^5.7|^6.0|^8.5|^9.4", "squizlabs/php_codesniffer": "~2.0" }, "suggest": { @@ -4033,7 +4286,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/2.0.45" + "source": "https://github.com/phpseclib/phpseclib/tree/2.0.54" }, "funding": [ { @@ -4049,24 +4302,19 @@ "type": "tidelift" } ], - "time": "2023-09-15T20:55:47+00:00" + "time": "2026-04-27T06:59:24+00:00" }, { "name": "phpstan/phpstan", - "version": "1.10.50", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" - }, + "version": "2.2.1", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dea9c8f2d25cc849391042b71e429c1a4bf82660", + "reference": "dea9c8f2d25cc849391042b71e429c1a4bf82660", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^7.4|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -4085,6 +4333,17 @@ "license": [ "MIT" ], + "authors": [ + { + "name": "OndÅ™ej Mirtes" + }, + { + "name": "Markus Staab" + }, + { + "name": "Vincent Langlet" + } + ], "description": "PHPStan - PHP Static Analysis Tool", "keywords": [ "dev", @@ -4105,45 +4364,39 @@ { "url": "https://github.com/phpstan", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" } ], - "time": "2023-12-13T10:59:42+00:00" + "time": "2026-05-28T14:44:12+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.29", + "version": "12.5.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + "reference": "876099a072646c7745f673d7aeab5382c4439691" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/876099a072646c7745f673d7aeab5382c4439691", + "reference": "876099a072646c7745f673d7aeab5382c4439691", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "nikic/php-parser": "^5.7.0", + "php": ">=8.3", + "phpunit/php-text-template": "^5.0", + "sebastian/complexity": "^5.0", + "sebastian/environment": "^8.0.3", + "sebastian/lines-of-code": "^4.0", + "sebastian/version": "^6.0", + "theseer/tokenizer": "^2.0.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.1" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -4152,7 +4405,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "12.5.x-dev" } }, "autoload": { @@ -4181,40 +4434,52 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.6" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" } ], - "time": "2023-09-19T04:57:46+00:00" + "time": "2026-04-15T08:23:17+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.6", + "version": "6.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + "reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5", + "reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -4241,36 +4506,49 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" } ], - "time": "2021-12-02T12:48:52+00:00" + "time": "2026-02-02T14:04:18+00:00" }, { "name": "phpunit/php-invoker", - "version": "3.1.1", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "suggest": { "ext-pcntl": "*" @@ -4278,7 +4556,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -4304,7 +4582,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0" }, "funding": [ { @@ -4312,32 +4591,32 @@ "type": "github" } ], - "time": "2020-09-28T05:58:55+00:00" + "time": "2025-02-07T04:58:58+00:00" }, { "name": "phpunit/php-text-template", - "version": "2.0.4", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -4363,7 +4642,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0" }, "funding": [ { @@ -4371,32 +4651,32 @@ "type": "github" } ], - "time": "2020-10-26T05:33:50+00:00" + "time": "2025-02-07T04:59:16+00:00" }, { "name": "phpunit/php-timer", - "version": "5.0.3", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -4422,7 +4702,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0" }, "funding": [ { @@ -4430,54 +4711,49 @@ "type": "github" } ], - "time": "2020-10-26T13:16:10+00:00" + "time": "2025-02-07T04:59:38+00:00" }, { "name": "phpunit/phpunit", - "version": "9.6.15", + "version": "12.5.28", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1" + "reference": "5895d05f5bf421ed230fbd76e1277e4b8955def4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5895d05f5bf421ed230fbd76e1277e4b8955def4", + "reference": "5895d05f5bf421ed230fbd76e1277e4b8955def4", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", - "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", - "sebastian/version": "^3.0.2" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.3", + "phpunit/php-code-coverage": "^12.5.6", + "phpunit/php-file-iterator": "^6.0.1", + "phpunit/php-invoker": "^6.0.0", + "phpunit/php-text-template": "^5.0.0", + "phpunit/php-timer": "^8.0.0", + "sebastian/cli-parser": "^4.2.1", + "sebastian/comparator": "^7.1.8", + "sebastian/diff": "^7.0.0", + "sebastian/environment": "^8.1.2", + "sebastian/exporter": "^7.0.3", + "sebastian/global-state": "^8.0.2", + "sebastian/object-enumerator": "^7.0.0", + "sebastian/recursion-context": "^7.0.1", + "sebastian/type": "^6.0.4", + "sebastian/version": "^6.0.0", + "staabm/side-effects-detector": "^1.0.5" }, "bin": [ "phpunit" @@ -4485,7 +4761,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.6-dev" + "dev-main": "12.5-dev" } }, "autoload": { @@ -4517,40 +4793,32 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.28" }, "funding": [ { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" + "url": "https://phpunit.de/sponsoring.html", + "type": "other" } ], - "time": "2023-12-01T16:55:19+00:00" + "time": "2026-05-27T14:01:10+00:00" }, { - "name": "psr/simple-cache", - "version": "1.0.1", + "name": "psr/event-dispatcher", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/php-fig/simple-cache.git", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.2.0" }, "type": "library", "extra": { @@ -4560,7 +4828,7 @@ }, "autoload": { "psr-4": { - "Psr\\SimpleCache\\": "src/" + "Psr\\EventDispatcher\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -4573,155 +4841,153 @@ "homepage": "http://www.php-fig.org/" } ], - "description": "Common interfaces for simple caching", + "description": "Standard interfaces for event handling.", "keywords": [ - "cache", - "caching", + "events", "psr", - "psr-16", - "simple-cache" + "psr-14" ], "support": { - "source": "https://github.com/php-fig/simple-cache/tree/master" + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" }, - "time": "2017-10-23T01:57:42+00:00" + "time": "2019-01-08T18:20:26+00:00" }, { - "name": "sebastian/cli-parser", + "name": "psr/simple-cache", "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", "shasum": "" }, "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" + "php": ">=5.3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/php-fig/simple-cache/tree/master" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2017-10-23T01:57:42+00:00" }, { - "name": "sebastian/code-unit", - "version": "1.0.8", + "name": "rector/rector", + "version": "2.4.5", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + "url": "https://github.com/rectorphp/rector.git", + "reference": "cbd86024be5014d3c14d9f0b3f7aae8ecbffd62c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/cbd86024be5014d3c14d9f0b3f7aae8ecbffd62c", + "reference": "cbd86024be5014d3c14d9f0b3f7aae8ecbffd62c", "shasum": "" }, "require": { - "php": ">=7.3" + "php": "^7.4|^8.0", + "phpstan/phpstan": "^2.1.56" }, - "require-dev": { - "phpunit/phpunit": "^9.3" + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" }, + "bin": [ + "bin/rector" + ], + "type": "library", "autoload": { - "classmap": [ - "src/" + "files": [ + "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "homepage": "https://getrector.com/", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/2.4.5" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "url": "https://github.com/tomasvotruba", "type": "github" } ], - "time": "2020-10-26T13:08:54+00:00" + "time": "2026-05-26T21:03:22+00:00" }, { - "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", + "name": "sebastian/cli-parser", + "version": "4.2.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "7d05781b13f7dec9043a629a21d086ed74582a15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/7d05781b13f7dec9043a629a21d086ed74582a15", + "reference": "7d05781b13f7dec9043a629a21d086ed74582a15", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.25" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "4.2-dev" } }, "autoload": { @@ -4736,49 +5002,68 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser", + "type": "tidelift" } ], - "time": "2020-09-28T05:30:19+00:00" + "time": "2026-05-17T05:29:34+00:00" }, { "name": "sebastian/comparator", - "version": "4.0.8", + "version": "7.1.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + "reference": "7c65c1e79836812819705b473a90c12399542485" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/7c65c1e79836812819705b473a90c12399542485", + "reference": "7c65c1e79836812819705b473a90c12399542485", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/diff": "^7.0", + "sebastian/exporter": "^7.0.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.25" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "7.1-dev" } }, "autoload": { @@ -4817,41 +5102,54 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.8" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" } ], - "time": "2022-09-14T12:41:17+00:00" + "time": "2026-05-21T04:45:25+00:00" }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", - "php": ">=7.3" + "nikic/php-parser": "^5.0", + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -4874,7 +5172,8 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0" }, "funding": [ { @@ -4882,33 +5181,33 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2025-02-07T04:55:25+00:00" }, { "name": "sebastian/diff", - "version": "4.0.5", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + "reference": "7ab1ea946c012266ca32390913653d844ecd085f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^12.0", + "symfony/process": "^7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -4940,7 +5239,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0" }, "funding": [ { @@ -4948,27 +5248,27 @@ "type": "github" } ], - "time": "2023-05-07T05:35:17+00:00" + "time": "2025-02-07T04:55:46+00:00" }, { "name": "sebastian/environment", - "version": "5.1.5", + "version": "8.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + "reference": "9d32c685773823b1983e256ae4ecd48a10d6e439" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/9d32c685773823b1983e256ae4ecd48a10d6e439", + "reference": "9d32c685773823b1983e256ae4ecd48a10d6e439", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.26" }, "suggest": { "ext-posix": "*" @@ -4976,7 +5276,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-main": "8.1-dev" } }, "autoload": { @@ -4995,7 +5295,7 @@ } ], "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", + "homepage": "https://github.com/sebastianbergmann/environment", "keywords": [ "Xdebug", "environment", @@ -5003,42 +5303,55 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/8.1.2" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" } ], - "time": "2023-02-03T06:03:51+00:00" + "time": "2026-05-25T13:40:20+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.5", + "version": "7.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "reference": "c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23", + "reference": "c5e21b5de653ce0a769fb36f5cdfcb5e7a32cf23", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/recursion-context": "^7.0.1" }, "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.25" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -5080,46 +5393,56 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.3" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2026-05-20T04:37:17+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.6", + "version": "8.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" + "reference": "ef1377171613d09edd25b7816f05be8313f9115d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d", + "reference": "ef1377171613d09edd25b7816f05be8313f9115d", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-uopz": "*" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "8.0-dev" } }, "autoload": { @@ -5138,47 +5461,60 @@ } ], "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", "keywords": [ "global state" ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.2" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" } ], - "time": "2023-08-02T09:26:13+00:00" + "time": "2025-08-29T11:29:25+00:00" }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "d543b8ef219dcd8da262cbb958639a96bedba10e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d543b8ef219dcd8da262cbb958639a96bedba10e", + "reference": "d543b8ef219dcd8da262cbb958639a96bedba10e", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", - "php": ">=7.3" + "nikic/php-parser": "^5.7.0", + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.5.25" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -5201,42 +5537,55 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/lines-of-code", + "type": "tidelift" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2026-05-19T16:22:07+00:00" }, { "name": "sebastian/object-enumerator", - "version": "4.0.4", + "version": "7.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -5258,7 +5607,8 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0" }, "funding": [ { @@ -5266,32 +5616,32 @@ "type": "github" } ], - "time": "2020-10-26T13:12:34+00:00" + "time": "2025-02-07T04:57:48+00:00" }, { "name": "sebastian/object-reflector", - "version": "2.0.4", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + "reference": "4bfa827c969c98be1e527abd576533293c634f6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -5313,7 +5663,8 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0" }, "funding": [ { @@ -5321,32 +5672,32 @@ "type": "github" } ], - "time": "2020-10-26T13:14:26+00:00" + "time": "2025-02-07T04:58:17+00:00" }, { "name": "sebastian/recursion-context", - "version": "4.0.5", + "version": "7.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "7.0-dev" } }, "autoload": { @@ -5376,40 +5727,53 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" } ], - "time": "2023-02-03T06:07:39+00:00" + "time": "2025-08-13T04:44:59+00:00" }, { - "name": "sebastian/resource-operations", - "version": "3.0.3", + "name": "sebastian/type", + "version": "6.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "82ff822c2edc46724be9f7411d3163021f602773" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/82ff822c2edc46724be9f7411d3163021f602773", + "reference": "82ff822c2edc46724be9f7411d3163021f602773", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^12.5.25" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -5424,48 +5788,58 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/6.0.4" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" } ], - "abandoned": true, - "time": "2020-09-28T06:45:17+00:00" + "time": "2026-05-20T06:45:45+00:00" }, { - "name": "sebastian/type", - "version": "3.2.1", + "name": "sebastian/version", + "version": "6.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c", "shasum": "" }, "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" + "php": ">=8.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -5484,11 +5858,12 @@ "role": "lead" } ], - "description": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/6.0.0" }, "funding": [ { @@ -5496,94 +5871,36 @@ "type": "github" } ], - "time": "2023-02-03T06:13:03+00:00" - }, - { - "name": "sebastian/version", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:39:44+00:00" + "time": "2025-02-07T05:00:38+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.8.0", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7" + "reference": "0525c73950de35ded110cffafb9892946d7771b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5805f7a4e4958dbb5e944ef1e6edae0a303765e7", - "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0525c73950de35ded110cffafb9892946d7771b5", + "reference": "0525c73950de35ded110cffafb9892946d7771b5", "shasum": "" }, "require": { "ext-simplexml": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "php": ">=5.4.0" + "php": ">=7.2.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^8.4.0 || ^9.3.4 || ^10.5.32 || 11.3.3 - 11.5.28 || ^11.5.31" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" @@ -5602,7 +5919,7 @@ "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "description": "PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.", "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ "phpcs", @@ -5627,44 +5944,95 @@ { "url": "https://opencollective.com/php_codesniffer", "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-11-10T16:43:36+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" } ], - "time": "2023-12-08T12:32:31+00:00" + "time": "2024-10-20T05:08:20+00:00" }, { "name": "symfony/config", - "version": "v5.4.31", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9" + "reference": "429783a0c649696f2058ea5ab5315f082dba6de9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", - "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", + "url": "https://api.github.com/repos/symfony/config/zipball/429783a0c649696f2058ea5ab5315f082dba6de9", + "reference": "429783a0c649696f2058ea5ab5315f082dba6de9", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/filesystem": "^4.4|^5.0|^6.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22" + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^7.4|^8.0", + "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/finder": "<4.4" + "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/messenger": "^4.4|^5.0|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -5692,7 +6060,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.31" + "source": "https://github.com/symfony/config/tree/v8.1.0" }, "funding": [ { @@ -5703,58 +6071,62 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-11-09T08:22:43+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { "name": "symfony/console", - "version": "v4.4.49", + "version": "v8.1.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9" + "reference": "f5a856c6ecb56b3c21ed94a5b7bf940d857d110a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", - "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", + "url": "https://api.github.com/repos/symfony/console/zipball/f5a856c6ecb56b3c21ed94a5b7bf940d857d110a", + "reference": "f5a856c6ecb56b3c21ed94a5b7bf940d857d110a", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2" + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php85": "^1.32", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.4.6|^8.0.6" }, "conflict": { - "psr/log": ">=3", - "symfony/dependency-injection": "<3.4", - "symfony/event-dispatcher": "<4.3|>=5", - "symfony/lock": "<4.4", - "symfony/process": "<3.3" + "symfony/dependency-injection": "<8.1", + "symfony/event-dispatcher": "<8.1" }, "provide": { - "psr/log-implementation": "1.0|2.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { - "psr/log": "^1|^2", - "symfony/config": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/event-dispatcher": "^4.3", - "symfony/lock": "^4.4|^5.0", - "symfony/process": "^3.4|^4.0|^5.0", - "symfony/var-dumper": "^4.3|^5.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" + "psr/log": "^1|^2|^3", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^8.1", + "symfony/event-dispatcher": "^8.1", + "symfony/filesystem": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/lock": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/uid": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" }, "type": "library", "autoload": { @@ -5781,8 +6153,14 @@ ], "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], "support": { - "source": "https://github.com/symfony/console/tree/v4.4.49" + "source": "https://github.com/symfony/console/tree/v8.1.0" }, "funding": [ { @@ -5793,37 +6171,54 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2022-11-05T17:10:16+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { - "name": "symfony/filesystem", - "version": "v5.4.25", + "name": "symfony/dependency-injection", + "version": "v8.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364" + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "b6ba1f45127106885de4b77558c5ecca8feb1e1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/b6ba1f45127106885de4b77558c5ecca8feb1e1b", + "reference": "b6ba1f45127106885de4b77558c5ecca8feb1e1b", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.4.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/service-contracts": "^3.6", + "symfony/var-exporter": "^8.1" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "symfony/service-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "symfony/config": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/yaml": "^7.4|^8.0" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Filesystem\\": "" + "Symfony\\Component\\DependencyInjection\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -5843,10 +6238,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Provides basic utilities for the filesystem", + "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.25" + "source": "https://github.com/symfony/dependency-injection/tree/v8.1.0" }, "funding": [ { @@ -5857,49 +6252,57 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-05-31T13:04:02+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { - "name": "symfony/polyfill-php73", - "version": "v1.28.0", + "name": "symfony/error-handler", + "version": "v8.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" + "url": "https://github.com/symfony/error-handler.git", + "reference": "d8aeb1abd3fef84795567850d3a567bdb5945ee5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", - "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/d8aeb1abd3fef84795567850d3a567bdb5945ee5", + "reference": "d8aeb1abd3fef84795567850d3a567bdb5945ee5", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.4.1", + "psr/log": "^1|^2|^3", + "symfony/polyfill-php85": "^1.32", + "symfony/var-dumper": "^7.4|^8.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } + "conflict": { + "symfony/deprecation-contracts": "<2.5" + }, + "require-dev": { + "symfony/console": "^7.4|^8.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/webpack-encore-bundle": "^1.0|^2.0" }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" + "Symfony\\Component\\ErrorHandler\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5908,24 +6311,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0" + "source": "https://github.com/symfony/error-handler/tree/v8.1.0" }, "funding": [ { @@ -5936,49 +6333,62 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { - "name": "symfony/polyfill-php81", - "version": "v1.28.0", + "name": "symfony/event-dispatcher", + "version": "v8.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "f249ae3f680958b6f1f9dd76e5747cf0695b4102" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f249ae3f680958b6f1f9dd76e5747cf0695b4102", + "reference": "f249ae3f680958b6f1f9dd76e5747cf0695b4102", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/event-dispatcher-contracts": "^2.5|^3" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } + "conflict": { + "symfony/security-http": "<7.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/error-handler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/framework-bundle": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^7.4|^8.0" }, + "type": "library", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" + "Symfony\\Component\\EventDispatcher\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5987,24 +6397,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v8.1.0" }, "funding": [ { @@ -6015,51 +6419,48 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { - "name": "symfony/service-contracts", - "version": "v2.5.2", + "name": "symfony/event-dispatcher-contracts", + "version": "v3.7.0", "source": { "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/ccba7060602b7fed0b03c85bf025257f76d9ef32", + "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1|^3" - }, - "conflict": { - "ext-psr": "<1.1|>=2" - }, - "suggest": { - "symfony/service-implementation": "" + "php": ">=8.1", + "psr/event-dispatcher": "^1" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" } }, "autoload": { "psr-4": { - "Symfony\\Contracts\\Service\\": "" + "Symfony\\Contracts\\EventDispatcher\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -6076,7 +6477,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to writing services", + "description": "Generic abstractions related to dispatching event", "homepage": "https://symfony.com", "keywords": [ "abstractions", @@ -6087,7 +6488,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.0" }, "funding": [ { @@ -6098,35 +6499,44 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2022-05-30T19:17:29+00:00" + "time": "2026-01-05T13:30:16+00:00" }, { - "name": "symfony/stopwatch", - "version": "v5.4.21", + "name": "symfony/filesystem", + "version": "v8.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/stopwatch.git", - "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee" + "url": "https://github.com/symfony/filesystem.git", + "reference": "99aec13b82b4967ec5088222c4a3ecca955949c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/f83692cd869a6f2391691d40a01e8acb89e76fee", - "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/99aec13b82b4967ec5088222c4a3ecca955949c2", + "reference": "99aec13b82b4967ec5088222c4a3ecca955949c2", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/service-contracts": "^1|^2|^3" + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^7.4|^8.0" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Stopwatch\\": "" + "Symfony\\Component\\Filesystem\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -6146,10 +6556,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Provides a way to profile code", + "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.4.21" + "source": "https://github.com/symfony/filesystem/tree/v8.1.0" }, "funding": [ { @@ -6160,44 +6570,41 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-02-14T08:03:56+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { - "name": "symfony/yaml", - "version": "v3.4.47", + "name": "symfony/finder", + "version": "v8.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "88289caa3c166321883f67fe5130188ebbb47094" + "url": "https://github.com/symfony/finder.git", + "reference": "58d2e767a66052c1487356f953445634a8194c64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/88289caa3c166321883f67fe5130188ebbb47094", - "reference": "88289caa3c166321883f67fe5130188ebbb47094", + "url": "https://api.github.com/repos/symfony/finder/zipball/58d2e767a66052c1487356f953445634a8194c64", + "reference": "58d2e767a66052c1487356f953445634a8194c64", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "symfony/console": "<3.4" + "php": ">=8.4.1" }, "require-dev": { - "symfony/console": "~3.4|~4.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" + "symfony/filesystem": "^7.4|^8.0" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Yaml\\": "" + "Symfony\\Component\\Finder\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -6217,10 +6624,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Yaml Component", + "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v3.4.47" + "source": "https://github.com/symfony/finder/tree/v8.1.0" }, "funding": [ { @@ -6231,78 +6638,1050 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2026-05-29T05:06:50+00:00" }, { - "name": "symplify/monorepo-builder", - "version": "10.3.3", + "name": "symfony/http-foundation", + "version": "v8.1.0", "source": { "type": "git", - "url": "https://github.com/symplify/monorepo-builder.git", - "reference": "5f97613a2015b74aa86a7330b47a88c283877fd4" + "url": "https://github.com/symfony/http-foundation.git", + "reference": "af11474600f06718086c2cda4fa6fa8d0a672e7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/monorepo-builder/zipball/5f97613a2015b74aa86a7330b47a88c283877fd4", - "reference": "5f97613a2015b74aa86a7330b47a88c283877fd4", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/af11474600f06718086c2cda4fa6fa8d0a672e7e", + "reference": "af11474600f06718086c2cda4fa6fa8d0a672e7e", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "^1.1" + }, + "conflict": { + "doctrine/dbal": "<4.3" + }, + "require-dev": { + "doctrine/dbal": "^4.3", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^7.4|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/mime": "^7.4|^8.0", + "symfony/rate-limiter": "^7.4|^8.0" }, - "bin": [ - "bin/monorepo-builder" - ], "type": "library", - "extra": { - "branch-alias": { - "dev-main": "10.3-dev" - } + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Prefixed version of Not only Composer tools to build a Monorepo.", - "support": { - "source": "https://github.com/symplify/monorepo-builder/tree/10.3.3" - }, - "funding": [ + "authors": [ { - "url": "https://www.paypal.me/rectorphp", - "type": "custom" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v8.1.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-29T05:06:50+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v8.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "cefeb37c82eed3e0c42fa25ba64cd3a908d90f39" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/cefeb37c82eed3e0c42fa25ba64cd3a908d90f39", + "reference": "cefeb37c82eed3e0c42fa25ba64cd3a908d90f39", + "shasum": "" + }, + "require": { + "php": ">=8.4.1", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/dependency-injection": "<8.1", + "symfony/flex": "<2.10", + "symfony/http-client-contracts": "<2.5", + "symfony/translation-contracts": "<2.5", + "symfony/var-dumper": "<8.1", + "symfony/web-profiler-bundle": "<8.1", + "twig/twig": "<3.21" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^7.4|^8.0", + "symfony/clock": "^7.4|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/console": "^7.4|^8.0", + "symfony/css-selector": "^7.4|^8.0", + "symfony/dependency-injection": "^8.1", + "symfony/dom-crawler": "^7.4|^8.0", + "symfony/expression-language": "^7.4|^8.0", + "symfony/finder": "^7.4|^8.0", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/process": "^7.4|^8.0", + "symfony/property-access": "^7.4|^8.0", + "symfony/rate-limiter": "^7.4|^8.0", + "symfony/routing": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/translation": "^7.4|^8.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^7.4|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^8.1", + "symfony/var-exporter": "^7.4|^8.0", + "twig/twig": "^3.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v8.1.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-29T08:46:08+00:00" + }, + { + "name": "symfony/polyfill-deepclone", + "version": "v1.37.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-deepclone.git", + "reference": "2ca9e9e75ead5174f2b44613a646bdc9338b8eb4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-deepclone/zipball/2ca9e9e75ead5174f2b44613a646bdc9338b8eb4", + "reference": "2ca9e9e75ead5174f2b44613a646bdc9338b8eb4", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "provide": { + "ext-deepclone": "*" + }, + "suggest": { + "ext-deepclone": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\DeepClone\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the deepclone extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "deepclone", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-deepclone/tree/v1.37.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-04-26T13:03:27+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.38.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "e9247d281d694a5120554d9afaf54e070e88a603" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603", + "reference": "e9247d281d694a5120554d9afaf54e070e88a603", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-26T05:58:03+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.38.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b", + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-25T13:48:31+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.7.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a", + "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.7.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-03-28T09:44:51+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v8.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "21c07b026905d596e8379caeb115d87aa479499d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/21c07b026905d596e8379caeb115d87aa479499d", + "reference": "21c07b026905d596e8379caeb115d87aa479499d", + "shasum": "" + }, + "require": { + "php": ">=8.4.1", + "symfony/service-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v8.1.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-29T05:06:50+00:00" + }, + { + "name": "symfony/string", + "version": "v8.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/afd5944f4005862d961efb85c8bbd5c523c4e3c9", + "reference": "afd5944f4005862d961efb85c8bbd5c523c4e3c9", + "shasum": "" + }, + "require": { + "php": ">=8.4.1", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-intl-grapheme": "^1.33", + "symfony/polyfill-intl-normalizer": "^1.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^7.4|^8.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v8.1.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-29T05:06:50+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v8.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "c2c4df1d21477cc21c9f6dc1b14d07c3abc4963e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c2c4df1d21477cc21c9f6dc1b14d07c3abc4963e", + "reference": "c2c4df1d21477cc21c9f6dc1b14d07c3abc4963e", + "shasum": "" + }, + "require": { + "php": ">=8.4.1", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/console": "<7.4", + "symfony/error-handler": "<7.4" + }, + "require-dev": { + "symfony/console": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/uid": "^7.4|^8.0", + "twig/twig": "^3.12" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v8.1.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-29T05:06:50+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v8.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "2dd18582c5f6c024db9fc0ff9c76d873af726f34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/2dd18582c5f6c024db9fc0ff9c76d873af726f34", + "reference": "2dd18582c5f6c024db9fc0ff9c76d873af726f34", + "shasum": "" + }, + "require": { + "php": ">=8.4.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-deepclone": "^1.37" + }, + "require-dev": { + "symfony/property-access": "^7.4|^8.0", + "symfony/serializer": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to export, instantiate, hydrate, clone and lazy-load PHP objects", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "deep-clone", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v8.1.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-29T05:06:50+00:00" + }, + { + "name": "symfony/yaml", + "version": "v7.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "a7ec3b1156faf8815db7683ec7c1e7338e6f977c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/a7ec3b1156faf8815db7683ec7c1e7338e6f977c", + "reference": "a7ec3b1156faf8815db7683ec7c1e7338e6f977c", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-25T06:06:12+00:00" + }, + { + "name": "symplify/monorepo-builder", + "version": "12.7.1", + "source": { + "type": "git", + "url": "https://github.com/symplify/monorepo-builder.git", + "reference": "a5ae1abc3ea97e540d1dec496f1b16f768d77562" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symplify/monorepo-builder/zipball/a5ae1abc3ea97e540d1dec496f1b16f768d77562", + "reference": "a5ae1abc3ea97e540d1dec496f1b16f768d77562", + "shasum": "" + }, + "require": { + "nette/utils": "^4.0.5", + "phar-io/version": "^3.2", + "php": ">=8.2", + "sebastian/diff": "^6.0 || ^7.0 || ^8.0", + "symfony/config": "^7.0 || ^8.0", + "symfony/console": "^7.0 || ^8.0", + "symfony/dependency-injection": "^7.0 || ^8.0", + "symfony/filesystem": "^7.0 || ^8.0", + "symfony/finder": "^7.0 || ^8.0", + "symfony/http-kernel": "^7.0 || ^8.0", + "symfony/process": "^7.0 || ^8.0", + "webmozart/assert": "^1.11 || ^2.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpstan/extension-installer": "1.4.3", + "phpstan/phpstan": "^2.1.22", + "phpunit/phpunit": "^11.0", + "rector/rector": "^2.1.3", + "symplify/easy-ci": "^11.3", + "symplify/easy-coding-standard": "^12.0", + "symplify/phpstan-extensions": "^12.0.1", + "symplify/phpstan-rules": "^14.6.12", + "tomasvotruba/class-leak": "^2.0.5", + "tomasvotruba/unused-public": "^2.0.1", + "tracy/tracy": "^2.9" + }, + "bin": [ + "bin/monorepo-builder", + "src-deps/easy-testing/bin/easy-testing" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symplify\\EasyTesting\\": "src-deps/easy-testing/src", + "Symplify\\PackageBuilder\\": "src-deps/package-builder/src", + "Symplify\\SymplifyKernel\\": "src-deps/symplify-kernel/src", + "Symplify\\MonorepoBuilder\\": [ + "src", + "packages" + ], + "Symplify\\SmartFileSystem\\": "src-deps/smart-file-system/src", + "Symplify\\AutowireArrayParameter\\": "src-deps/autowire-array-parameter/src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Not only Composer tools to build a Monorepo.", + "support": { + "issues": "https://github.com/symplify/monorepo-builder/issues", + "source": "https://github.com/symplify/monorepo-builder/tree/12.7.1" + }, + "funding": [ + { + "url": "https://www.paypal.me/rectorphp", + "type": "custom" }, { "url": "https://github.com/tomasvotruba", "type": "github" } ], - "time": "2022-06-13T14:01:16+00:00" + "time": "2026-05-20T01:27:41+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.2", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4", "shasum": "" }, "require": { "ext-dom": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" + "php": "^8.1" }, "type": "library", "autoload": { @@ -6324,7 +7703,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.2" + "source": "https://github.com/theseer/tokenizer/tree/2.0.1" }, "funding": [ { @@ -6332,34 +7711,42 @@ "type": "github" } ], - "time": "2023-11-20T00:12:19+00:00" + "time": "2025-12-08T11:19:18+00:00" }, { "name": "twig/twig", - "version": "v3.8.0", + "version": "v3.27.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d" + "reference": "04ae1bfe9463c816cf72ca0abe7eae2c77a9a9ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/04ae1bfe9463c816cf72ca0abe7eae2c77a9a9ed", + "reference": "04ae1bfe9463c816cf72ca0abe7eae2c77a9a9ed", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php80": "^1.22" + "symfony/polyfill-mbstring": "^1.3" }, "require-dev": { + "php-cs-fixer/shim": "^3.0@stable", + "phpstan/phpstan": "^2.0@stable", "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0" + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], "psr-4": { "Twig\\": "src/" } @@ -6392,7 +7779,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.8.0" + "source": "https://github.com/twigphp/Twig/tree/v3.27.0" }, "funding": [ { @@ -6404,23 +7791,153 @@ "type": "tidelift" } ], - "time": "2023-11-21T18:54:41+00:00" + "time": "2026-05-27T13:05:51+00:00" + }, + { + "name": "webmozart/assert", + "version": "2.4.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "9007ea6f45ecf352a9422b36644e4bfc039b9155" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/9007ea6f45ecf352a9422b36644e4bfc039b9155", + "reference": "9007ea6f45ecf352a9422b36644e4bfc039b9155", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", + "php": "^8.2" + }, + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" + }, + "type": "library", + "extra": { + "psalm": { + "pluginClass": "Webmozart\\Assert\\PsalmPlugin" + }, + "branch-alias": { + "dev-master": "2.0-dev", + "dev-feature/2-0": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/2.4.0" + }, + "time": "2026-05-20T13:07:01+00:00" + }, + { + "name": "yoast/phpunit-polyfills", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", + "reference": "134921bfca9b02d8f374c48381451da1d98402f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/134921bfca9b02d8f374c48381451da1d98402f9", + "reference": "134921bfca9b02d8f374c48381451da1d98402f9", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.0 || ^11.0 || ^12.0" + }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "yoast/yoastcs": "^3.1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.x-dev" + } + }, + "autoload": { + "files": [ + "phpunitpolyfills-autoload.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Team Yoast", + "email": "support@yoast.com", + "homepage": "https://yoast.com" + }, + { + "name": "Contributors", + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills/graphs/contributors" + } + ], + "description": "Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit cross-version compatible tests", + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills", + "keywords": [ + "phpunit", + "polyfill", + "testing" + ], + "support": { + "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", + "security": "https://github.com/Yoast/PHPUnit-Polyfills/security/policy", + "source": "https://github.com/Yoast/PHPUnit-Polyfills" + }, + "time": "2025-02-09T18:58:54+00:00" } ], "aliases": [], "minimum-stability": "dev", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^7.4 || ^8.0", + "php": "^8.3", "ext-fileinfo": "*", "ext-json": "*", "ext-mbstring": "*", "ext-pdo": "*", + "ext-pdo_mysql": "*", "ext-simplexml": "*", "ext-spl": "*" }, - "platform-dev": [], - "plugin-api-version": "2.6.0" + "platform-dev": {}, + "plugin-api-version": "2.9.0" } diff --git a/monorepo b/monorepo new file mode 100755 index 000000000..478d90581 --- /dev/null +++ b/monorepo @@ -0,0 +1,88 @@ +#!/bin/sh + +# Monorepo utility toolbox - Helper script for managing monorepo packages + +# Function to list all monorepo packages in pretty format +packages_pretty() { + echo "Monorepo packages:" + find packages -maxdepth 2 -name "composer.json" -type f | while read -r composer_file; do + package_dir=$(dirname "$composer_file") + package_name=$(basename "$package_dir") + echo " - $package_name" + done +} + +# Function to list packages as JSON array +packages_json() { + packages=$(find packages -maxdepth 2 -name "composer.json" -type f | while read -r composer_file; do + package_dir=$(dirname "$composer_file") + basename "$package_dir" + done | awk 'BEGIN{printf "["} {printf "%s\"%s\"", (NR>1?",":""), $0} END{printf "]\n"}') + echo "$packages" +} + +# Function to list package names only (space-separated) - default +packages_default() { + find packages -maxdepth 2 -name "composer.json" -type f | while read -r composer_file; do + package_dir=$(dirname "$composer_file") + basename "$package_dir" + done | tr '\n' ' ' | sed 's/ $/\n/' +} + +# Parse command and options +command="${1:-}" +type_flag="" + +# Parse flags for packages command +if [ "$command" = "packages" ]; then + shift + while [ $# -gt 0 ]; do + case "$1" in + --type=*) + type_flag="${1#*=}" + shift + ;; + -t) + type_flag="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac + done +fi + +# Execute command +case "$command" in + packages) + case "$type_flag" in + json) + packages_json + ;; + pretty) + packages_pretty + ;; + "") + packages_default + ;; + *) + echo "Unknown type: $type_flag" + echo "Valid types: json, pretty" + exit 1 + ;; + esac + ;; + *) + echo "Monorepo utility toolbox - Helper script for managing monorepo packages" + echo "" + echo "Usage: $0 packages [--type=TYPE|-t TYPE]" + echo "Commands:" + echo " packages List package names (space-separated, default)" + echo " packages -t json List packages as JSON array" + echo " packages -t pretty List all monorepo packages in pretty format" + exit 1 + ;; +esac + diff --git a/monorepo-builder.php b/monorepo-builder.php index 86910891a..575f39d82 100644 --- a/monorepo-builder.php +++ b/monorepo-builder.php @@ -3,7 +3,7 @@ declare(strict_types=1); use Charcoal\MonorepoBuilder\Release\ReleaseWorker\UpdateBranchAliasReleaseWorker; -use Symplify\ComposerJsonManipulator\ValueObject\ComposerJsonSection; +use Symplify\MonorepoBuilder\ComposerJsonManipulator\ValueObject\ComposerJsonSection; use Symplify\MonorepoBuilder\Config\MBConfig; use Symplify\MonorepoBuilder\Release\ReleaseWorker\SetCurrentMutualDependenciesReleaseWorker; @@ -13,11 +13,10 @@ // default value __DIR__ . '/packages', ]); - // for "merge" command. $mbConfig->dataToAppend([ ComposerJsonSection::REQUIRE_DEV => [ - 'phpunit/phpunit' => '^9.5', + 'phpunit/phpunit' => '^12.5', ], ]); diff --git a/packages/admin/composer.json b/packages/admin/composer.json index baef4cfc2..f39b02563 100644 --- a/packages/admin/composer.json +++ b/packages/admin/composer.json @@ -1,8 +1,11 @@ { - "type": "library", "name": "charcoal/admin", "description": "The Charcoal Administration Dashboard", - "keywords": ["charcoal", "admin", "cms"], + "keywords": [ + "charcoal", + "admin", + "cms" + ], "homepage": "https://charcoal.locomotive.ca", "license": "MIT", "authors": [ @@ -15,20 +18,10 @@ "homepage": "https://locomotive.ca" } ], - "config": { - "sort-packages": true - }, - "extra": { - "branch-alias": { - "dev-main": "5.x-dev" - } - }, + "type": "library", "require": { - "php": "^7.4 || ^8.0", + "php": "^8.3", "barryvdh/elfinder-flysystem-driver": "^0.3", - "guzzlehttp/guzzle": "^6.0 || ^7.0", - "kriswallsmith/assetic": "^1.4", - "laminas/laminas-permissions-acl": "^2.8", "charcoal/app": "^5.1", "charcoal/cache": "^5.1", "charcoal/cms": "^5.1", @@ -38,25 +31,24 @@ "charcoal/translator": "^5.1", "charcoal/ui": "^5.1", "charcoal/user": "^5.1", + "guzzlehttp/guzzle": "^6.0 || ^7.0", + "kriswallsmith/assetic": "^1.4", + "laminas/laminas-permissions-acl": "^2.8", "mcaskill/php-html-build-attributes": "^1.0", - "psr/cache": "^1.0", + "psr/cache": "^2.0", "psr/http-message": "^1.0", "psr/log": "^1.0", - "studio-42/elfinder": "2.1.64" + "studio-42/elfinder": "^2.1.64" }, "require-dev": { "league/csv": "^9.5", "mockery/mockery": "^1.0", "mustache/mustache": "^2.11", "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^9.5", + "phpunit/phpunit": "^12.5", "seld/jsonlint": "^1.9", "squizlabs/php_codesniffer": "^3.5", - "tedivm/stash": "~0.16" - }, - "suggest": { - "league/csv": "To use the exporter (to CSV).", - "fabpot/goutte": "To use the various crawler-based tools." + "tedivm/stash": "^1.1" }, "autoload": { "psr-4": { @@ -68,8 +60,10 @@ "Charcoal\\Tests\\": "tests/Charcoal/" } }, - "replace": { - "locomotivemtl/charcoal-admin": "*" + "extra": { + "branch-alias": { + "dev-main": "5.x-dev" + } }, "scripts": { "test": [ @@ -87,6 +81,16 @@ "phpcbf": "php vendor/bin/phpcbf -ps --colors src/ tests/", "phpunit": "php vendor/bin/phpunit --coverage-text" }, + "suggest": { + "league/csv": "To use the exporter (to CSV).", + "fabpot/goutte": "To use the various crawler-based tools." + }, + "config": { + "sort-packages": true + }, + "replace": { + "locomotivemtl/charcoal-admin": "*" + }, "minimum-stability": "dev", "prefer-stable": true } diff --git a/packages/admin/phpunit.xml.dist b/packages/admin/phpunit.xml.dist index 5c94aaf08..93e59b0cb 100644 --- a/packages/admin/phpunit.xml.dist +++ b/packages/admin/phpunit.xml.dist @@ -1,32 +1,33 @@ + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - - ./src/Charcoal - - + + + ./src/Charcoal + + diff --git a/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php b/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php index 2b4d5dd38..359531324 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php @@ -40,15 +40,11 @@ class LostPasswordAction extends AdminAction { /** * Store the factory instance for the current class. - * - * @var FactoryInterface */ - private $emailFactory; + private ?\Charcoal\Factory\FactoryInterface $emailFactory = null; - /** - * @return boolean - */ - public function authRequired() + #[\Override] + public function authRequired(): bool { return false; } @@ -65,7 +61,7 @@ public function run(RequestInterface $request, ResponseInterface $response) { $translator = $this->translator(); - $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null; + $ip = ($_SERVER['REMOTE_ADDR'] ?? null); $email = $request->getParam('email'); if (!$email) { @@ -94,7 +90,8 @@ public function run(RequestInterface $request, ResponseInterface $response) return $response; } - $doneMessage = $translator->translate('If a registered user matches the given email address, instructions to reset your password will be sent to the email address registered with that account.'); + $doneMessage = $translator->translate('If a registered user matches the given email address, instructions' . + ' to reset your password will be sent to the email address registered with that account.'); $failMessage = $translator->translate('An error occurred while processing the password reset request.'); $authenticator = $this->authenticator(); @@ -160,23 +157,20 @@ public function run(RequestInterface $request, ResponseInterface $response) } } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { - $ret = [ + return [ 'success' => $this->success(), 'feedbacks' => $this->feedbacks(), ]; - - return $ret; } /** * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -187,13 +181,12 @@ protected function setDependencies(Container $container) * Retrieve the email model factory. * * @throws RuntimeException If the model factory was not previously set. - * @return FactoryInterface */ - protected function emailFactory() + protected function emailFactory(): \Charcoal\Factory\FactoryInterface { - if (!isset($this->emailFactory)) { + if (!$this->emailFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException( - sprintf('Email Factory is not defined for "%s"', get_class($this)) + sprintf('Email Factory is not defined for "%s"', static::class) ); } @@ -204,9 +197,8 @@ protected function emailFactory() * Set an email model factory. * * @param FactoryInterface $factory The email factory, to create emails. - * @return self */ - private function setEmailFactory(FactoryInterface $factory) + private function setEmailFactory(FactoryInterface $factory): static { $this->emailFactory = $factory; @@ -231,9 +223,8 @@ private function generateLostPasswordToken(User $user) * @todo Implement `$container['admin/config']['user.lost_password_email']` * @param User $user The user to send the lost-password email to. * @param string $token The lost-password token, as string. - * @return void */ - private function sendLostPasswordEmail(User $user, $token) + private function sendLostPasswordEmail(User $user, $token): void { $translator = $this->translator(); $userEmail = $user['email']; @@ -268,7 +259,7 @@ private function sendLostPasswordEmail(User $user, $token) 'adminUrl' => $this->adminUrl(), 'urlResetPassword' => $this->adminUrl() . 'account/reset-password/' . $token->id(), 'expiry' => $token->expiry()->format('Y-m-d H:i:s'), - 'ipAddress' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '', + 'ipAddress' => ($_SERVER['REMOTE_ADDR'] ?? ''), ], ]); $emailObj->send(); diff --git a/packages/admin/src/Charcoal/Admin/Action/Account/ResetPasswordAction.php b/packages/admin/src/Charcoal/Admin/Action/Account/ResetPasswordAction.php index 37dd376ad..84737473f 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Account/ResetPasswordAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Account/ResetPasswordAction.php @@ -34,10 +34,8 @@ */ class ResetPasswordAction extends AdminAction { - /** - * @return boolean - */ - public function authRequired() + #[\Override] + public function authRequired(): bool { return false; } @@ -55,7 +53,7 @@ public function run(RequestInterface $request, ResponseInterface $response) { $translator = $this->translator(); - $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null; + $ip = ($_SERVER['REMOTE_ADDR'] ?? null); $token = $request->getParam('token'); $email = $request->getParam('email'); @@ -191,17 +189,13 @@ public function run(RequestInterface $request, ResponseInterface $response) return $response; } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { - $ret = [ + return [ 'success' => $this->success(), 'feedbacks' => $this->feedbacks(), ]; - - return $ret; } /** @@ -216,9 +210,8 @@ public function results() * @see \Charcoal\Admin\Template\Account::validateToken() * @param string $token The token to validate. * @param string $userId The user ID that should match the token. - * @return boolean */ - private function validateToken($token, $userId) + private function validateToken($token, $userId): bool { $obj = $this->modelFactory()->create(LostPasswordToken::class); $sql = strtr('SELECT * FROM `%table` WHERE `token` = :token AND `user` = :userId AND `expiry` > NOW()', [ @@ -229,16 +222,15 @@ private function validateToken($token, $userId) 'userId' => $userId, ]); - return !!$obj->token(); + return (bool)$obj->token(); } /** * Delete the given password reset token. * * @param string $token The token to delete. - * @return void */ - private function deleteToken($token) + private function deleteToken($token): void { $obj = $this->modelFactory()->create(LostPasswordToken::class); $obj->setToken($token); diff --git a/packages/admin/src/Charcoal/Admin/Action/ElfinderConnectorAction.php b/packages/admin/src/Charcoal/Admin/Action/ElfinderConnectorAction.php index a1b37ca7d..1c0f7b642 100644 --- a/packages/admin/src/Charcoal/Admin/Action/ElfinderConnectorAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/ElfinderConnectorAction.php @@ -34,6 +34,11 @@ class ElfinderConnectorAction extends AdminAction { use CallableResolverAwareTrait; + /** + * @var \elFinderConnector + */ + public $connector; + /** * The default relative path (from filesystem's root) to the storage directory. * @@ -123,9 +128,9 @@ class ElfinderConnectorAction extends AdminAction * Sets the action data from a PSR Request object. * * @param RequestInterface $request A PSR-7 compatible Request instance. - * @return self */ - protected function setDataFromRequest(RequestInterface $request) + #[\Override] + protected function setDataFromRequest(RequestInterface $request): static { $keys = $this->validDataFromRequest(); $data = $request->getParams($keys); @@ -150,7 +155,8 @@ protected function setDataFromRequest(RequestInterface $request) * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return [ 'obj_type', @@ -162,9 +168,8 @@ protected function validDataFromRequest() /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -177,9 +182,8 @@ public function run(RequestInterface $request, ResponseInterface $response) * Setup the elFinder connector. * * @param array|null $extraOptions Additional settings to pass to elFinder. - * @return elFinderConnector */ - public function setupElfinder(array $extraOptions = []) + public function setupElfinder(array $extraOptions = []): \elFinderConnector { if (!defined('ELFINDER_IMG_PARENT_URL')) { // Ensure images injected by elFinder are relative to its assets directory @@ -219,9 +223,8 @@ public function getConnectorOptions() * your application's admin configuration. * * @param array $extraOptions Additional settings to pass to elFinder. - * @return array */ - public function buildConnectorOptions(array $extraOptions = []) + public function buildConnectorOptions(array $extraOptions = []): array { $options = [ 'debug' => false, @@ -251,7 +254,7 @@ public function buildConnectorOptions(array $extraOptions = []) * @param array $options2 The settings from which data is extracted. * @return array The merged settings. */ - protected function mergeConnectorOptions(array $options1, array $options2) + protected function mergeConnectorOptions(array $options1, array $options2): array { return array_replace_recursive($options1, $options2); } @@ -262,7 +265,7 @@ protected function mergeConnectorOptions(array $options1, array $options2) * @param array $options The admin settings to parse. * @return array The parsed settings. */ - protected function parseAdminOptionsForConnectorBuild(array $options) + protected function parseAdminOptionsForConnectorBuild(array $options): array { // Root settings are already merged when retrieving available roots. unset($options['roots']); @@ -276,7 +279,7 @@ protected function parseAdminOptionsForConnectorBuild(array $options) * @param array $options The extra settings to parse. * @return array The parsed settings. */ - protected function parseExtraOptionsForConnectorBuild(array $options) + protected function parseExtraOptionsForConnectorBuild(array $options): array { // Resolve callbacks on extra options if (isset($options['roots'])) { @@ -290,10 +293,8 @@ protected function parseExtraOptionsForConnectorBuild(array $options) * Retrieve the admin's elFinder Connector options. * * Path: `config.admin.elfinder.connector` - * - * @return array */ - public function getAdminConnectorOptions() + public function getAdminConnectorOptions(): array { $config = $this->elfinderConfig('connector'); if (!is_array($config)) { @@ -305,10 +306,8 @@ public function getAdminConnectorOptions() /** * Retrieve the default elFinder Connector options. - * - * @return array */ - protected function getDefaultElfinderRootSettings() + protected function getDefaultElfinderRootSettings(): array { return [ 'driver' => 'LocalFileSystem', @@ -322,17 +321,15 @@ protected function getDefaultElfinderRootSettings() 'uploadDeny' => $this->defaultUploadDeny(), 'uploadAllow' => $this->defaultUploadAllow(), 'uploadOrder' => [ 'deny', 'allow' ], - 'accessControl' => [ $this, 'checkAccess' ], + 'accessControl' => $this->checkAccess(...), 'duplicateSuffix' => '_%s_', ]; } /** * Retrieve the default Flysystem / elFinder options. - * - * @return array */ - protected function getDefaultFlysystemRootSettings() + protected function getDefaultFlysystemRootSettings(): array { return [ 'driver' => 'Flysystem', @@ -348,18 +345,13 @@ protected function getDefaultFlysystemRootSettings() * Retrieve the default Flysystem / elFinder options. * * @param string $ident The disk identifier. - * @return array */ - protected function resolveFallbackRootSettings($ident) + protected function resolveFallbackRootSettings($ident): array { $fsConfig = $this->getFilesystemConfig($ident); $uploadPath = $this->defaultUploadPath(); - if (isset($fsConfig['base_url'])) { - $baseUrl = rtrim($fsConfig['base_url'], '/') . '/'; - } else { - $baseUrl = $this->baseUrl(); - } + $baseUrl = isset($fsConfig['base_url']) ? rtrim($fsConfig['base_url'], '/') . '/' : $this->baseUrl(); return [ 'URL' => $baseUrl . '/' . $uploadPath, @@ -378,14 +370,14 @@ protected function resolveFallbackRootSettings($ident) * @param string $ident The disk identifier. * @return array|null Returns an elFinder root structure or NULL. */ - public function getNamedRoot($ident) + public function getNamedRoot($ident): ?array { if ($this->hasFilesystem($ident) === false) { return null; } - $filesystem = $this->getFilesystem($ident); - $fsConfig = $this->getFilesystemConfig($ident); + $this->getFilesystem($ident); + $this->getFilesystemConfig($ident); $elfConfig = $this->getFilesystemAdminConfig($ident); $immutableSettings = [ @@ -410,10 +402,8 @@ public function getNamedRoot($ident) /** * Retrieve only the public elFinder root volumes. - * - * @return array */ - public function getPublicRoots() + public function getPublicRoots(): array { $roots = []; foreach ($this->filesystems->keys() as $ident) { @@ -430,10 +420,8 @@ public function getPublicRoots() /** * Retrieve all elFinder root volumes. - * - * @return array */ - public function getAllRoots() + public function getAllRoots(): array { $roots = []; foreach ($this->filesystems->keys() as $ident) { @@ -452,7 +440,7 @@ public function getAllRoots() * @return array Returns all public root volumes * or a subset if the context has a related form property. */ - public function getCurrentRoots() + public function getCurrentRoots(): array { $formProperty = $this->formProperty(); $targetFilesystem = $formProperty ? $formProperty['filesystem'] : null; @@ -475,9 +463,7 @@ public function getCurrentRoots() if ($acceptedMimetypes) { $disk['uploadAllow'] = array_merge( - isset($disk['uploadAllow']) - ? $disk['uploadAllow'] - : [], + ($disk['uploadAllow'] ?? []), $acceptedMimetypes ); } @@ -493,7 +479,7 @@ public function getCurrentRoots() * @param array $roots One or many roots with possible unresolved callables. * @return array Returns the root(s) with resolved callables. */ - protected function resolveCallbacksForRoots(array $roots) + protected function resolveCallbacksForRoots(array $roots): array { foreach ($roots as $i => $root) { $roots[$i] = $this->resolveCallbacksForRoot($root); @@ -508,7 +494,7 @@ protected function resolveCallbacksForRoots(array $roots) * @param array $root A root structure with possible unresolved callables. * @return array Returns the root with resolved callables. */ - protected function resolveCallbacksForRoot(array $root) + protected function resolveCallbacksForRoot(array $root): array { if (isset($root['accessControl'])) { $callable = $root['accessControl']; @@ -526,14 +512,14 @@ protected function resolveCallbacksForRoot(array $root) * @param array $toResolve One or many pairs of callbacks. * @return array Returns the parsed event listeners. */ - protected function resolveCallbacksForBindOption(array $toResolve) + protected function resolveCallbacksForBindOption(array $toResolve): array { $resolved = $toResolve; foreach ($toResolve as $actions => $callables) { foreach ($callables as $i => $callable) { if (!is_callable($callable) && is_string($callable)) { - if (0 === strpos($callable, 'Plugin.')) { + if (str_starts_with($callable, 'Plugin.')) { continue; } @@ -557,9 +543,8 @@ protected function resolveCallbacksForBindOption(array $toResolve) * @param array $args The command arguments from the client. * @param object $elfinder The elFinder instance. * @param object $volume The current volume instance. - * @return void|bool|array */ - public function translateDirectoriesOnAnyCommand($cmd, &$result, $args, $elfinder, $volume) + public function translateDirectoriesOnAnyCommand($cmd, array &$result, $args, object $elfinder, $volume): void { // To please PHPCS unset($cmd, $args, $volume); @@ -587,7 +572,6 @@ public function translateDirectoriesOnAnyCommand($cmd, &$result, $args, $elfinde * @param array $stat The directory reference. * @param object $elfinder The elFinder instance or volume instance. * @throws UnexpectedValueException If the related volume is not found. - * @return array */ protected function translateDirectoryStat(array $stat, object $elfinder): array { @@ -608,7 +592,6 @@ protected function translateDirectoryStat(array $stat, object $elfinder): array * @param object $elfinder The elFinder instance or volume instance. * @throws InvalidArgumentException If the elFinder client or volume is not provided. * @throws UnexpectedValueException If the related volume is not found. - * @return ?string */ protected function getVolumeNameFromHash(string $hash, object $elfinder): ?string { @@ -635,7 +618,6 @@ protected function getVolumeNameFromHash(string $hash, object $elfinder): ?strin * Attempts to retrieve the filesystem name. * * @param string $ident The filesystem identifier. - * @return ?string */ protected function getFilesystemName(string $ident): ?string { @@ -655,7 +637,6 @@ protected function getFilesystemName(string $ident): ?string * Attempts to localize the filesystem identifier. * * @param string $ident The filesystem identifier. - * @return ?string */ protected function translateFilesystemName(string $ident): ?string { @@ -684,7 +665,7 @@ protected function translateFilesystemName(string $ident): ?string * @param object $volume The current volume instance. * @return void|bool|array */ - public function sanitizeOnUploadPreSave(&$path, &$name, $src, $elfinder, $volume) + public function sanitizeOnUploadPreSave(&$path, &$name, $src, $elfinder, $volume): bool { // To please PHPCS unset($path, $src, $elfinder, $volume); @@ -712,11 +693,7 @@ public function sanitizeOnUploadPreSave(&$path, &$name, $src, $elfinder, $volume */ protected function sanitizeFileName(string $name, array $options): string { - if (is_array($options['replace'])) { - $mask = implode($options['replace']); - } else { - $mask = $options['replace']; - } + $mask = is_array($options['replace']) ? implode('', $options['replace']) : $options['replace']; $ext = '.' . pathinfo($name, PATHINFO_EXTENSION); @@ -725,8 +702,8 @@ protected function sanitizeFileName(string $name, array $options): string // Squeeze multiple delimiters and whitespace with a single separator $name = preg_replace( - '![' . preg_quote($mask, '!') . '\.\s]{2,}!', - $options['replace'], + '![' . preg_quote((string)$mask, '!') . '\.\s]{2,}!', + (string)$options['replace'], $name ); @@ -751,7 +728,7 @@ protected function sanitizeFileName(string $name, array $options): string * started with directory separator. * @return boolean|null TRUE to allow, FALSE to deny, NULL to let elFinder decide. **/ - public function checkAccess($attr, $path, $data, elFinderVolumeDriver $volume, $isDir, $relPath) + public function checkAccess($attr, $path, $data, elFinderVolumeDriver $volume, $isDir, $relPath): ?bool { unset($data, $volume, $isDir); @@ -763,7 +740,7 @@ public function checkAccess($attr, $path, $data, elFinderVolumeDriver $volume, $ * set to NULL to let elFinder decide itself. */ return ($basename[0] === '.' && strlen($relPath) !== 1) - ? !($attr === 'read' || $attr === 'write') + ? $attr !== 'read' && $attr !== 'write' : null; } @@ -825,20 +802,16 @@ public function formProperty() /** * Retrieve the default root path. - * - * @return string */ - public function defaultUploadPath() + public function defaultUploadPath(): string { return self::DEFAULT_STORAGE_PATH; } /** * Allow upload for a subset MIME types. - * - * @return array */ - protected function defaultUploadAllow() + protected function defaultUploadAllow(): array { // By default, all images, PDF, and plain-text files are allowed. return [ @@ -850,10 +823,8 @@ protected function defaultUploadAllow() /** * Deny upload for all MIME types. - * - * @return array */ - protected function defaultUploadDeny() + protected function defaultUploadDeny(): array { // By default, all files are rejected. return [ @@ -863,10 +834,8 @@ protected function defaultUploadDeny() /** * Default attributes for files and directories. - * - * @return array */ - protected function attributesForHiddenFiles() + protected function attributesForHiddenFiles(): array { return [ // Block access to all hidden files and directories (anything starting with ".") @@ -882,9 +851,9 @@ protected function attributesForHiddenFiles() * Inject dependencies from a DI Container. * * @param Container $container A dependencies container instance. - * @return void */ - public function setDependencies(Container $container) + #[\Override] + public function setDependencies(Container $container): void { parent::setDependencies($container); @@ -908,11 +877,7 @@ public function setDependencies(Container $container) */ protected function getFilesystem($ident) { - if (isset($this->filesystems[$ident])) { - return $this->filesystems[$ident]; - } - - return null; + return ($this->filesystems[$ident] ?? null); } /** @@ -921,7 +886,7 @@ protected function getFilesystem($ident) * @param string $ident The filesystem identifier. * @return boolean TRUE if the filesystem instance exists, otherwise FALSE. */ - protected function hasFilesystem($ident) + protected function hasFilesystem($ident): bool { return ($this->getFilesystem($ident) !== null); } @@ -939,11 +904,7 @@ protected function getFilesystemConfig($ident) return null; } - if (isset($this->filesystemConfig['connections'][$ident])) { - return $this->filesystemConfig['connections'][$ident]; - } - - return []; + return ($this->filesystemConfig['connections'][$ident] ?? []); } /** @@ -959,11 +920,7 @@ protected function isFilesystemPublic($ident) } $config = $this->getFilesystemConfig($ident); - if (isset($config['public']) && $config['public'] === false) { - return false; - } - - return true; + return !(isset($config['public']) && $config['public'] === false); } /** @@ -980,11 +937,8 @@ protected function getFilesystemAdminConfig($ident) } $elfConfig = $this->getAdminConnectorOptions(); - if (isset($elfConfig['roots'][$ident])) { - return $elfConfig['roots'][$ident]; - } - return []; + return ($elfConfig['roots'][$ident] ?? []); } /** @@ -1010,12 +964,10 @@ protected function elfinderConfig($key = null, $default = null) if ($key) { if (isset($this->elfinderConfig[$key])) { return $this->elfinderConfig[$key]; + } elseif (!is_string($default) && is_callable($default)) { + return $default(); } else { - if (!is_string($default) && is_callable($default)) { - return $default(); - } else { - return $default; - } + return $default; } } diff --git a/packages/admin/src/Charcoal/Admin/Action/Filesystem/LoadAction.php b/packages/admin/src/Charcoal/Admin/Action/Filesystem/LoadAction.php index dbaebc91f..8a9b78882 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Filesystem/LoadAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Filesystem/LoadAction.php @@ -72,10 +72,9 @@ class LoadAction extends AdminAction /** * Determine if user authentication is required. - * - * @return boolean */ - protected function authRequired() + #[\Override] + protected function authRequired(): bool { return true; } @@ -84,9 +83,9 @@ protected function authRequired() * Sets the action data. * * @param array $data The action data. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { $keys = $this->validDataFromRequest(); $data = array_intersect_key($data, array_flip($keys)); @@ -99,9 +98,9 @@ public function setData(array $data) * Sets the action data from a PSR Request object. * * @param RequestInterface $request A PSR-7 compatible Request instance. - * @return self */ - protected function setDataFromRequest(RequestInterface $request) + #[\Override] + protected function setDataFromRequest(RequestInterface $request): static { $keys = $this->validDataFromRequest(); $data = $request->getParams($keys); @@ -114,9 +113,8 @@ protected function setDataFromRequest(RequestInterface $request) * Add data to action, replacing existing items with the same data key. * * @param array $data The action data. - * @return self */ - public function mergeData(array $data) + public function mergeData(array $data): static { $this->params = array_replace($this->params, $data); @@ -128,7 +126,8 @@ public function mergeData(array $data) * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return [ 'disk', 'disposition', 'path', 'name' ]; } @@ -139,14 +138,14 @@ protected function validDataFromRequest() * @param array|null $keys Subset of keys to retrieve. * @return array|null */ - public function getParams(array $keys = null) + public function getParams(?array $keys = null) { $params = $this->params; if ($keys) { $subset = []; foreach ($keys as $key) { - if (array_key_exists($key, $params)) { + if (array_key_exists((string)$key, $params)) { $subset[$key] = $params[$key]; } } @@ -168,12 +167,10 @@ public function getParam($key, $default = null) $params = $this->params; if (is_array($params) && isset($params[$key])) { $result = $params[$key]; + } elseif (!is_string($default) && is_callable($default)) { + $result = $default(); } else { - if (!is_string($default) && is_callable($default)) { - $result = $default(); - } else { - $result = $default; - } + $result = $default; } return $result; @@ -189,7 +186,7 @@ public function run(RequestInterface $request, ResponseInterface $response) { unset($request); - $translator = $this->translator(); + $this->translator(); try { $disk = $this->getParam('disk', $this->filesystemConfig['default_connection']); @@ -225,7 +222,7 @@ public function run(RequestInterface $request, ResponseInterface $response) } try { - $filename = isset($name) ? $name : basename($path); + $filename = ($name ?? basename((string)$path)); $disposition = $this->generateHttpDisposition($disp, $filename); $resource = $handler->readStream(); $stream = new Stream($resource); @@ -276,7 +273,7 @@ public function run(RequestInterface $request, ResponseInterface $response) * @throws InvalidArgumentException If the parameters are invalid. * @return string A string suitable for use as a Content-Disposition field-value. */ - public function generateHttpDisposition($disposition, $filename, $filenameFallback = '') + public function generateHttpDisposition($disposition, $filename, $filenameFallback = ''): string { if (!in_array($disposition, [ self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE ])) { throw new InvalidArgumentException(sprintf( @@ -296,16 +293,16 @@ public function generateHttpDisposition($disposition, $filename, $filenameFallba // } // percent characters aren't safe in fallback. - if (strpos($filenameFallback, '%') !== false) { + if (str_contains($filenameFallback, '%')) { throw new InvalidArgumentException('The filename fallback cannot contain the "%" character.'); } // path separators aren't allowed in either. if ( - strpos($filename, '/') !== false || - strpos($filename, '\\') !== false || - strpos($filenameFallback, '/') !== false || - strpos($filenameFallback, '\\') !== false + str_contains($filename, '/') || + str_contains($filename, '\\') || + str_contains($filenameFallback, '/') || + str_contains($filenameFallback, '\\') ) { throw new InvalidArgumentException( 'The filename and the fallback cannot contain the "/" and "\\" characters.' @@ -344,7 +341,7 @@ protected function assertValidDisk($disk) } if (!is_string($disk)) { - $actualType = is_object($disk) ? get_class($disk) : gettype($disk); + $actualType = get_debug_type($disk); $message = $translator->translate( '{{ parameter }} must be a {{ expectedType }}, received {{ actualType }}', [ @@ -388,7 +385,7 @@ protected function assertValidPath($path) throw new InvalidArgumentException($message, 400); } elseif (!is_string($path)) { - $actualType = is_object($path) ? get_class($path) : gettype($path); + $actualType = get_debug_type($path); $message = $translator->translate( '{{ parameter }} must be a {{ expectedType }}, received {{ actualType }}', [ @@ -412,7 +409,7 @@ protected function assertValidPath($path) protected function assertValidName($name) { if (!is_string($name) && $name !== null) { - $actualType = is_object($name) ? get_class($name) : gettype($name); + $actualType = get_debug_type($name); $message = $this->translator()->translate( '{{ parameter }} must be a {{ expectedType }}, received {{ actualType }}', [ @@ -446,7 +443,7 @@ protected function assertValidDisposition($disposition) } if (!is_string($disposition) && $disposition !== null) { - $actualType = is_object($disposition) ? get_class($disposition) : gettype($disposition); + $actualType = get_debug_type($disposition); $message = $translator->translate( '{{ parameter }} must be a {{ expectedType }}, received {{ actualType }}', [ @@ -466,6 +463,7 @@ protected function assertValidDisposition($disposition) * @param Container $container A service locator. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Action/LoginAction.php b/packages/admin/src/Charcoal/Admin/Action/LoginAction.php index af3adbee4..3b3f9df99 100644 --- a/packages/admin/src/Charcoal/Admin/Action/LoginAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/LoginAction.php @@ -41,10 +41,9 @@ class LoginAction extends AdminAction * Authentication is required by default. * * Change to false in the login action controller; this is meant to be called before login. - * - * @return boolean */ - public function authRequired() + #[\Override] + public function authRequired(): bool { return false; } @@ -65,7 +64,7 @@ public function run(RequestInterface $request, ResponseInterface $response) '{{ errorMessage }}' => $failMessage ]); - $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null; + $ip = ($_SERVER['REMOTE_ADDR'] ?? null); $email = $request->getParam('email'); $password = $request->getParam('password'); @@ -125,8 +124,8 @@ public function run(RequestInterface $request, ResponseInterface $response) $this->addFeedback('success', $doneMessage); $this->setSuccess(true); - if (is_string($nextUrl) && !empty($nextUrl)) { - $this->setSuccessUrl((string)$nextUrl); + if (is_string($nextUrl) && ($nextUrl !== '' && $nextUrl !== '0')) { + $this->setSuccessUrl($nextUrl); } else { $this->setSuccessUrl((string)$this->adminUrl()); } diff --git a/packages/admin/src/Charcoal/Admin/Action/LogoutAction.php b/packages/admin/src/Charcoal/Admin/Action/LogoutAction.php index e521ed2b6..f054cbbbe 100644 --- a/packages/admin/src/Charcoal/Admin/Action/LogoutAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/LogoutAction.php @@ -62,7 +62,7 @@ public function run(RequestInterface $request, ResponseInterface $response) } /** Fail silently — Never confirm or deny the existence of an account. */ - $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null; + $ip = ($_SERVER['REMOTE_ADDR'] ?? null); if ($ip) { $logMessage = sprintf('[Admin] Logout attempt for unauthenticated user from %s', $ip); } else { @@ -78,9 +78,9 @@ public function run(RequestInterface $request, ResponseInterface $response) /** * @todo Provide feedback and redirection? - * @return array */ - public function results() + #[\Override] + public function results(): array { return [ 'success' => $this->success(), diff --git a/packages/admin/src/Charcoal/Admin/Action/Object/AbstractSaveAction.php b/packages/admin/src/Charcoal/Admin/Action/Object/AbstractSaveAction.php index 48a232e56..29bce6964 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Object/AbstractSaveAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Object/AbstractSaveAction.php @@ -43,11 +43,7 @@ public function setObj($obj) { $this->obj = $obj; - if ($obj instanceof ModelInterface) { - $this->objId = $obj->id(); - } else { - $this->objId = null; - } + $this->objId = $obj instanceof ModelInterface ? $obj->id() : null; return $this; } @@ -145,7 +141,7 @@ public function addFeedbackFromModelValidatorResult(ValidatorResult $result, Mod $propertyLabel = (string)$obj->property($prop)['label']; $resultMessage = $result->message(); - if (strpos($resultMessage, $propertyLabel) === false) { + if (!str_contains((string)$resultMessage, $propertyLabel)) { $resultMessage = strtr($this->translator()->translation('{{ errorMessage }}: {{ errorThrown }}'), [ '{{ errorMessage }}' => $propertyLabel, '{{ errorThrown }}' => $resultMessage, @@ -161,6 +157,7 @@ public function addFeedbackFromModelValidatorResult(ValidatorResult $result, Mod /** * @return array */ + #[\Override] public function results() { $results = [ diff --git a/packages/admin/src/Charcoal/Admin/Action/Object/DeleteAction.php b/packages/admin/src/Charcoal/Admin/Action/Object/DeleteAction.php index da13446d5..bb342f003 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Object/DeleteAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Object/DeleteAction.php @@ -58,7 +58,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $objId = $request->getParam('obj_id'); if (!$objType) { - $actualType = is_object($objType) ? get_class($objType) : gettype($objType); + $actualType = get_debug_type($objType); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_type"', '{{ expectedType }}' => 'string', @@ -70,7 +70,7 @@ public function run(RequestInterface $request, ResponseInterface $response) } if (!$objId) { - $actualType = is_object($objId) ? get_class($objId) : gettype($objId); + $actualType = get_debug_type($objId); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_id"', '{{ expectedType }}' => 'string or numeric', @@ -124,10 +124,8 @@ public function run(RequestInterface $request, ResponseInterface $response) } } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { return [ 'success' => $this->success(), diff --git a/packages/admin/src/Charcoal/Admin/Action/Object/ExportAction.php b/packages/admin/src/Charcoal/Admin/Action/Object/ExportAction.php index 89fcaba8a..a6bee833d 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Object/ExportAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Object/ExportAction.php @@ -53,7 +53,7 @@ public function run(RequestInterface $request, ResponseInterface $response) set_time_limit(0); $failMessage = $this->translator()->translation('Failed to export object(s)'); - $errorThrown = strtr($this->translator()->translation('{{ errorMessage }}: {{ errorThrown }}'), [ + strtr($this->translator()->translation('{{ errorMessage }}: {{ errorThrown }}'), [ '{{ errorMessage }}' => $failMessage ]); $reqMessage = $this->translator()->translation( @@ -67,7 +67,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $exportIdent = $request->getParam('ident'); if (!$objType) { - $actualType = is_object($objType) ? get_class($objType) : gettype($objType); + $actualType = get_debug_type($objType); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_type"', '{{ expectedType }}' => 'string', @@ -91,7 +91,7 @@ public function run(RequestInterface $request, ResponseInterface $response) if (isset($exportIdent)) { if (!is_string($exportIdent)) { - $actualType = is_object($exportIdent) ? get_class($exportIdent) : gettype($exportIdent); + $actualType = get_debug_type($exportIdent); $this->addFeedback('error', strtr($typeMessage, [ '{{ parameter }}' => 'Export "ident"', '{{ expectedType }}' => 'string', @@ -113,10 +113,8 @@ public function run(RequestInterface $request, ResponseInterface $response) return $response; } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { return [ 'success' => $this->success(), @@ -130,6 +128,7 @@ public function results() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Action/Object/LoadAction.php b/packages/admin/src/Charcoal/Admin/Action/Object/LoadAction.php index 92c7d42fb..05f2326f0 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Object/LoadAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Object/LoadAction.php @@ -43,17 +43,8 @@ class LoadAction extends AdminAction { /** * Store the collection loader for the current class. - * - * @var CollectionLoader */ - private $collectionLoader; - - /** - * Store the factory instance for the current class. - * - * @var \Charcoal\Factory\FactoryInterface - */ - private $modelFactory; + private ?\Charcoal\Loader\CollectionLoader $collectionLoader = null; /** * @var string @@ -70,7 +61,8 @@ class LoadAction extends AdminAction * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type', 'obj_id' @@ -107,7 +99,7 @@ public function run(RequestInterface $request, ResponseInterface $response) } if (!$objType) { - $actualType = is_object($objType) ? get_class($objType) : gettype($objType); + $actualType = get_debug_type($objType); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_type"', '{{ expectedType }}' => 'string', @@ -125,21 +117,13 @@ public function run(RequestInterface $request, ResponseInterface $response) $this->loadObjectCollection($objType); $count = count($this->objCollection); - switch ($count) { - case 0: - $doneMessage = $this->translator()->translation('No objects found.'); - break; - - case 1: - $doneMessage = $this->translator()->translation('One object found.'); - break; - - default: - $doneMessage = strtr($this->translator()->translation('{{ count }} objects found.'), [ - '{{ count }}' => $count - ]); - break; - } + $doneMessage = match ($count) { + 0 => $this->translator()->translation('No objects found.'), + 1 => $this->translator()->translation('One object found.'), + default => strtr($this->translator()->translation('{{ count }} objects found.'), [ + '{{ count }}' => $count + ]), + }; $this->addFeedback('success', $doneMessage); $this->setSuccess(true); @@ -157,7 +141,7 @@ public function run(RequestInterface $request, ResponseInterface $response) /** * @return array The object collection parsed as array */ - public function objCollection() + public function objCollection(): array { if (!$this->objCollection) { return []; @@ -170,14 +154,13 @@ public function objCollection() * Retrieve the model collection loader. * * @throws RuntimeException If the collection loader was not previously set. - * @return CollectionLoader */ - public function collectionLoader() + public function collectionLoader(): \Charcoal\Loader\CollectionLoader { - if (!isset($this->collectionLoader)) { + if (!$this->collectionLoader instanceof \Charcoal\Loader\CollectionLoader) { throw new RuntimeException(sprintf( 'Collection Loader is not defined for "%s"', - get_class($this) + static::class )); } @@ -195,14 +178,13 @@ public function objType() /** * @param string $objType The object type as string. * @throws InvalidArgumentException If the object type is not a string. - * @return self */ - public function setObjType($objType) + public function setObjType($objType): static { if (!is_string($objType)) { throw new InvalidArgumentException(sprintf( 'Object type must be a string, received %s', - is_object($objType) ? get_class($objType) : gettype($objType) + get_debug_type($objType) )); } @@ -211,10 +193,8 @@ public function setObjType($objType) return $this; } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { return [ 'success' => $this->success(), @@ -227,6 +207,7 @@ public function results() * @param Container $container DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -240,7 +221,7 @@ protected function setDependencies(Container $container) * @param string $objType The object type as string. * @return \Charcoal\Model\Collection */ - protected function loadObjectCollection($objType) + protected function loadObjectCollection($objType): \ArrayAccess|array { $proto = $this->modelFactory()->get($objType); $loader = $this->collectionLoader(); @@ -256,9 +237,8 @@ protected function loadObjectCollection($objType) * Set a model collection loader. * * @param CollectionLoader $loader The collection loader. - * @return self */ - protected function setCollectionLoader(CollectionLoader $loader) + protected function setCollectionLoader(CollectionLoader $loader): static { $this->collectionLoader = $loader; diff --git a/packages/admin/src/Charcoal/Admin/Action/Object/ReorderAction.php b/packages/admin/src/Charcoal/Admin/Action/Object/ReorderAction.php index 1b0a4b6c7..b9718e773 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Object/ReorderAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Object/ReorderAction.php @@ -45,7 +45,8 @@ class ReorderAction extends AdminAction implements ObjectContainerInterface * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type', 'obj_id' @@ -79,7 +80,7 @@ public function run(RequestInterface $request, ResponseInterface $response) try { if (!$objType) { - $actualType = is_object($objType) ? get_class($objType) : gettype($objType); + $actualType = get_debug_type($objType); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_type"', '{{ expectedType }}' => 'string', @@ -95,7 +96,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $this->setObjType($objType); if (!$objOrders || !is_array($objOrders)) { - $actualType = is_object($objOrders) ? get_class($objOrders) : gettype($objOrders); + $actualType = get_debug_type($objOrders); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_orders"', '{{ expectedType }}' => 'array of object IDs', @@ -107,7 +108,7 @@ public function run(RequestInterface $request, ResponseInterface $response) } if (!is_string($orderProperty)) { - $actualType = is_object($orderProperty) ? get_class($orderProperty) : gettype($orderProperty); + $actualType = get_debug_type($orderProperty); $this->addFeedback('error', strtr($typeMessage, [ '{{ parameter }}' => '"obj_property"', '{{ expectedType }}' => 'string', @@ -166,10 +167,8 @@ public function run(RequestInterface $request, ResponseInterface $response) } } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { return [ 'success' => $this->success(), @@ -181,6 +180,7 @@ public function results() * @param Container $container A DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Action/Object/RevertRevisionAction.php b/packages/admin/src/Charcoal/Admin/Action/Object/RevertRevisionAction.php index 3b320b310..92d2b7119 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Object/RevertRevisionAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Object/RevertRevisionAction.php @@ -50,7 +50,8 @@ class RevertRevisionAction extends AdminAction implements ObjectContainerInterfa * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type', @@ -66,12 +67,12 @@ protected function validDataFromRequest() * @throws InvalidArgumentException If the given revision is invalid. * @return ObjectContainerInterface Chainable */ - protected function setRevNum($revNum) + protected function setRevNum($revNum): static { if (!is_numeric($revNum)) { throw new InvalidArgumentException(sprintf( 'Revision must be an integer, received %s.', - (is_object($revNum) ? get_class($revNum) : gettype($revNum)) + (get_debug_type($revNum)) )); } diff --git a/packages/admin/src/Charcoal/Admin/Action/Object/SaveAction.php b/packages/admin/src/Charcoal/Admin/Action/Object/SaveAction.php index f87f55736..7203489ab 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Object/SaveAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Object/SaveAction.php @@ -51,9 +51,9 @@ class SaveAction extends AbstractSaveAction * This {@see self::$saveData subset} is merged onto the target model. * * @param RequestInterface $request A PSR-7 compatible Request instance. - * @return self */ - protected function setDataFromRequest(RequestInterface $request) + #[\Override] + protected function setDataFromRequest(RequestInterface $request): static { parent::setDataFromRequest($request); @@ -69,7 +69,8 @@ protected function setDataFromRequest(RequestInterface $request) * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type' @@ -80,9 +81,8 @@ protected function validDataFromRequest() * Filter the dataset used to create the target model. * * @param array $data The save data to filter. - * @return array */ - public function filterSaveData(array $data) + public function filterSaveData(array $data): array { unset( $data['widget_id'], @@ -102,7 +102,7 @@ public function filterSaveData(array $data) * @param array $data The save data. * @return SaveAction Chainable */ - public function setSaveData(array $data) + public function setSaveData(array $data): static { $this->saveData = $data; @@ -123,23 +123,22 @@ public function getSaveData() * @param ModelInterface $obj The object to validate. * @return boolean */ + #[\Override] public function validate(ModelInterface $obj) { $this->parsePrimaryKey($obj); - $result = parent::validate($obj); - return $result; + return parent::validate($obj); } /** * Prepare the primary key for the object. * * @param ModelInterface $obj The object to validate. - * @return void */ - public function parsePrimaryKey(ModelInterface $obj) + public function parsePrimaryKey(ModelInterface $obj): void { - if (($obj instanceof StorableInterface) && ($obj instanceof DescribablePropertyInterface)) { + if ($obj instanceof DescribablePropertyInterface) { $pk = $obj->key(); $id = $obj[$pk]; @@ -168,7 +167,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $objType = $request->getParam('obj_type'); if (!$objType) { - $actualType = is_object($objType) ? get_class($objType) : gettype($objType); + $actualType = get_debug_type($objType); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_type"', '{{ expectedType }}' => 'string', @@ -232,11 +231,7 @@ public function run(RequestInterface $request, ResponseInterface $response) } catch (PDOException $e) { $this->setObj(null); - if (isset($e->errorInfo[2])) { - $message = $e->errorInfo[2]; - } else { - $message = $e->getMessage(); - } + $message = ($e->errorInfo[2] ?? $e->getMessage()); $this->addFeedback('error', strtr($errorThrown, [ '{{ errorThrown }}' => $message diff --git a/packages/admin/src/Charcoal/Admin/Action/Object/UpdateAction.php b/packages/admin/src/Charcoal/Admin/Action/Object/UpdateAction.php index 1136dd539..283800deb 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Object/UpdateAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Object/UpdateAction.php @@ -45,9 +45,9 @@ class UpdateAction extends AbstractSaveAction * This {@see self::$updateData subset} is merged onto the target model. * * @param RequestInterface $request A PSR-7 compatible Request instance. - * @return self */ - protected function setDataFromRequest(RequestInterface $request) + #[\Override] + protected function setDataFromRequest(RequestInterface $request): static { parent::setDataFromRequest($request); @@ -63,7 +63,8 @@ protected function setDataFromRequest(RequestInterface $request) * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type', 'obj_id' @@ -74,9 +75,8 @@ protected function validDataFromRequest() * Filter the dataset used to update the target model. * * @param array $data The update data to filter. - * @return array */ - public function filterUpdateData(array $data) + public function filterUpdateData(array $data): array { unset( $data['widget_id'], @@ -98,7 +98,7 @@ public function filterUpdateData(array $data) * @param array $data The update data. * @return UpdateAction Chainable */ - public function setUpdateData(array $data) + public function setUpdateData(array $data): static { $this->updateData = $data; @@ -138,7 +138,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $objId = $request->getParam('obj_id'); if (!$objType) { - $actualType = is_object($objType) ? get_class($objType) : gettype($objType); + $actualType = get_debug_type($objType); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_type"', '{{ expectedType }}' => 'string', @@ -150,7 +150,7 @@ public function run(RequestInterface $request, ResponseInterface $response) } if (!$objId) { - $actualType = is_object($objId) ? get_class($objId) : gettype($objId); + $actualType = get_debug_type($objId); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_id"', '{{ expectedType }}' => 'ID', diff --git a/packages/admin/src/Charcoal/Admin/Action/Selectize/LoadAction.php b/packages/admin/src/Charcoal/Admin/Action/Selectize/LoadAction.php index 8ae9d176a..7c029e956 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Selectize/LoadAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Selectize/LoadAction.php @@ -36,7 +36,8 @@ class LoadAction extends BaseLoadAction * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'selectize_prop_ident', 'selectize_property' @@ -50,6 +51,7 @@ protected function validDataFromRequest() * @throws UnexpectedValueException If "obj_id" is passed as $request option. * @todo Implement obj_id support for load object action */ + #[\Override] public function run(RequestInterface $request, ResponseInterface $response) { unset($request); @@ -75,14 +77,14 @@ public function run(RequestInterface $request, ResponseInterface $response) $searchProperties = (array)$options['searchProperties']; } elseif ( !empty($choiceMap['label']) && - strpos($choiceMap['label'], '{{') === false + !str_contains((string)$choiceMap['label'], '{{') ) { $searchProperties = [ $choiceMap['label'] ]; } else { $searchProperties = []; } - if ($searchProperties) { + if ($searchProperties !== []) { $search = [ 'conjunction' => 'OR', 'conditions' => [], @@ -97,7 +99,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $filters = $property->filters(); if (is_array($filters)) { - array_push($filters, $search); + $filters[] = $search; } else { $filters = [ $search ]; } @@ -111,21 +113,13 @@ public function run(RequestInterface $request, ResponseInterface $response) $this->setSelectizeCollection($this->selectizeVal($choices)); $count = count($choices); - switch ($count) { - case 0: - $doneMessage = $this->translator()->translation('No objects found.'); - break; - - case 1: - $doneMessage = $this->translator()->translation('One object found.'); - break; - - default: - $doneMessage = strtr($this->translator()->translation('{{ count }} objects found.'), [ - '{{ count }}' => $count - ]); - break; - } + $doneMessage = match ($count) { + 0 => $this->translator()->translation('No objects found.'), + 1 => $this->translator()->translation('One object found.'), + default => strtr($this->translator()->translation('{{ count }} objects found.'), [ + '{{ count }}' => $count + ]), + }; $this->addFeedback('success', $doneMessage); $this->setSuccess(true); @@ -150,9 +144,8 @@ public function query() /** * @param string $query Query for LoadAction. - * @return self */ - public function setQuery($query) + public function setQuery($query): static { $this->query = $query; @@ -169,19 +162,16 @@ public function selectizeCollection() /** * @param array|mixed $selectizeCollection The collection to return. - * @return self */ - public function setSelectizeCollection($selectizeCollection) + public function setSelectizeCollection($selectizeCollection): static { $this->selectizeCollection = $selectizeCollection; return $this; } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { return [ 'success' => $this->success(), @@ -195,6 +185,7 @@ public function results() * @param Container $container DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Action/Selectize/SaveAction.php b/packages/admin/src/Charcoal/Admin/Action/Selectize/SaveAction.php index 6d6f4a7c5..04b08e5b2 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Selectize/SaveAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Selectize/SaveAction.php @@ -20,7 +20,8 @@ class SaveAction extends BaseSaveAction * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'selectize_obj_type', 'selectize_prop_ident', 'selectize_property' @@ -30,6 +31,7 @@ protected function validDataFromRequest() /** * @return array */ + #[\Override] public function results() { $results = parent::results(); @@ -46,6 +48,7 @@ public function results() * @param Container $container DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Action/Selectize/SelectizeRendererAwareTrait.php b/packages/admin/src/Charcoal/Admin/Action/Selectize/SelectizeRendererAwareTrait.php index 3c1d01851..cc1905081 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Selectize/SelectizeRendererAwareTrait.php +++ b/packages/admin/src/Charcoal/Admin/Action/Selectize/SelectizeRendererAwareTrait.php @@ -77,7 +77,7 @@ public function setSelectizeProperty($struct) protected function selectizeInput() { $prop = $this->selectizeProperty(); - $type = isset($prop['input_type']) ? $prop['input_type'] : SelectizeInput::class; + $type = ($prop['input_type'] ?? SelectizeInput::class); $input = $this->propertyInputFactory()->create($type); $input->setInputType($type); @@ -93,9 +93,8 @@ protected function selectizeInput() * Retrieves the output from SelectizeInput::selectizeVal. * * @param mixed $val The value(s) to parse as selectize choices. - * @return array */ - protected function selectizeVal($val) + protected function selectizeVal($val): array { if ($val === null) { return []; @@ -139,7 +138,7 @@ public function propertyInputFactory() if (!isset($this->propertyInputFactory)) { throw new RuntimeException(sprintf( 'Property Input Factory is not defined for [%s]', - get_class($this) + $this::class )); } @@ -170,7 +169,7 @@ public function propertyFactory() if (!isset($this->propertyFactory)) { throw new RuntimeException(sprintf( 'Property Control Factory is not defined for [%s]', - get_class($this) + $this::class )); } diff --git a/packages/admin/src/Charcoal/Admin/Action/Selectize/UpdateAction.php b/packages/admin/src/Charcoal/Admin/Action/Selectize/UpdateAction.php index e0b7430d9..9cf32a020 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Selectize/UpdateAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Selectize/UpdateAction.php @@ -20,7 +20,8 @@ class UpdateAction extends BaseUpdateAction * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'selectize_obj_type', 'selectize_prop_ident', 'selectize_property' @@ -30,6 +31,7 @@ protected function validDataFromRequest() /** * @return array */ + #[\Override] public function results() { $results = parent::results(); @@ -46,6 +48,7 @@ public function results() * @param Container $container DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Action/System/AbstractCacheAction.php b/packages/admin/src/Charcoal/Admin/Action/System/AbstractCacheAction.php index efbc5c979..247987653 100644 --- a/packages/admin/src/Charcoal/Admin/Action/System/AbstractCacheAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/System/AbstractCacheAction.php @@ -67,6 +67,7 @@ public function getTwigEngine(): ?TwigEngine /** * @return array */ + #[\Override] public function results() { return [ @@ -81,6 +82,7 @@ public function results() * @param Container $container A service locator. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -88,14 +90,14 @@ protected function setDependencies(Container $container) $this->setCachePool($container['cache']); $this->mustacheEngine = function () use ($container) { - if (class_exists('\Mustache_Engine')) { + if (class_exists('\Mustache\Engine')) { return $container['view/engine/mustache']; } return null; }; $this->twigEngine = function () use ($container) { - if (class_exists('\Twig\Environment')) { + if (class_exists(\Twig\Environment::class)) { return $container['view/engine/twig']; } diff --git a/packages/admin/src/Charcoal/Admin/Action/System/ClearCacheAction.php b/packages/admin/src/Charcoal/Admin/Action/System/ClearCacheAction.php index 2573ebab4..721e600d1 100644 --- a/packages/admin/src/Charcoal/Admin/Action/System/ClearCacheAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/System/ClearCacheAction.php @@ -24,7 +24,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $translator = $this->translator(); $cacheType = $request->getParam('cache_type'); - if (!is_string($cacheType) || empty($cacheType)) { + if (!is_string($cacheType) || ($cacheType === '' || $cacheType === '0')) { $this->addFeedback('error', $translator->translate('Cache type not defined.')); $this->setSuccess(false); return $response->withStatus(400); @@ -100,8 +100,7 @@ public function run(RequestInterface $request, ResponseInterface $response) private function clearGlobalCache() { $cache = $this->cachePool(); - $result = $cache->clear(); - return $result; + return $cache->clear(); } /** @@ -112,8 +111,7 @@ private function clearGlobalCache() private function clearPagesCache() { $cache = $this->cachePool(); - $result = $cache->deleteItems([ 'request', 'template' ]); - return $result; + return $cache->deleteItems([ 'request', 'template' ]); } /** @@ -124,21 +122,18 @@ private function clearPagesCache() private function clearObjectsCache() { $cache = $this->cachePool(); - $result = $cache->deleteItems([ 'object', 'metadata' ]); - return $result; + return $cache->deleteItems([ 'object', 'metadata' ]); } private function clearTwigCache(): bool { $engine = $this->getTwigEngine(); - if (!$engine) { + if (!$engine instanceof \Charcoal\View\Twig\TwigEngine) { return true; } $defaultCachePath = realpath($engine->cache()); - $cachePath = $defaultCachePath - ? $defaultCachePath - : realpath($this->appConfig['publicPath'] . DIRECTORY_SEPARATOR . $engine->cache()); + $cachePath = $defaultCachePath ?: realpath($this->appConfig['publicPath'] . DIRECTORY_SEPARATOR . $engine->cache()); if (!is_dir($cachePath)) { return false; } @@ -149,14 +144,12 @@ private function clearTwigCache(): bool private function clearMustacheCache(): bool { $engine = $this->getMustacheEngine(); - if (!$engine) { + if (!$engine instanceof \Charcoal\View\Mustache\MustacheEngine) { return true; } $defaultCachePath = realpath($engine->cache()); - $cachePath = $defaultCachePath - ? $defaultCachePath - : realpath($this->appConfig['publicPath'] . DIRECTORY_SEPARATOR . $engine->cache()); + $cachePath = $defaultCachePath ?: realpath($this->appConfig['publicPath'] . DIRECTORY_SEPARATOR . $engine->cache()); if (!is_dir($cachePath)) { return false; } diff --git a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/ActivateAction.php b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/ActivateAction.php index e196d5d54..0d0a7a909 100644 --- a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/ActivateAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/ActivateAction.php @@ -1,5 +1,7 @@ request('GET', $url, [ 'http_errors' => false ]); - } catch (Exception $e) { + } catch (Exception) { $this->setSuccess(false); return $response->withStatus(404); } @@ -84,7 +84,7 @@ public function run(RequestInterface $request, ResponseInterface $response) return $response->withStatus(404); } - if (strstr($headers['Content-Type'][0], 'text/html') !== false) { + if (str_contains($headers['Content-Type'][0], 'text/html')) { $outputFile = $outputDir . '/index.html'; $prefix = ''; } else { @@ -113,23 +113,20 @@ public function run(RequestInterface $request, ResponseInterface $response) } } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { - $ret = [ + return [ 'success' => $this->success(), 'feedbacks' => $this->feedbacks() ]; - - return $ret; } /** * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeactivateAction.php b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeactivateAction.php index c4c4a2644..a612ace58 100644 --- a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeactivateAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeactivateAction.php @@ -1,5 +1,7 @@ $this->success(), 'feedbacks' => $this->feedbacks() ]; - - return $ret; } /** * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeleteAction.php b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeleteAction.php index 66ac5cd1c..fc770f4aa 100644 --- a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeleteAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeleteAction.php @@ -59,23 +59,20 @@ public function run(RequestInterface $request, ResponseInterface $response) } } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { - $ret = [ + return [ 'success' => $this->success(), 'feedbacks' => $this->feedbacks() ]; - - return $ret; } /** * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeleteAllAction.php b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeleteAllAction.php index 4009cdce8..4e5496e98 100644 --- a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeleteAllAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/DeleteAllAction.php @@ -43,23 +43,20 @@ public function run(RequestInterface $request, ResponseInterface $response) return $response; } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { - $ret = [ + return [ 'success' => $this->success(), 'feedbacks' => $this->feedbacks() ]; - - return $ret; } /** * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -69,9 +66,8 @@ protected function setDependencies(Container $container) /** * @param string $dir Directory to delete. - * @return void */ - private function recursiveDelete($dir) + private function recursiveDelete(string $dir): void { $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS), diff --git a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/PreviewAction.php b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/PreviewAction.php index 00ea58008..ef5289d70 100644 --- a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/PreviewAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/PreviewAction.php @@ -20,10 +20,7 @@ class PreviewAction extends AdminAction */ private $basePath; - /** - * @var string - */ - private $fileContent = ''; + private string|bool $fileContent = ''; /** * @param RequestInterface $request A PSR-7 compatible Request instance. @@ -34,7 +31,7 @@ public function run(RequestInterface $request, ResponseInterface $response) { $url = $request->getParam('url'); $relativeUrl = str_replace($this->baseUrl(), '', $url); - $url = $this->baseUrl() . $relativeUrl; + $this->baseUrl(); $outputDir = $this->basePath . DIRECTORY_SEPARATOR . 'cache/static/' . $relativeUrl; if (!file_exists($outputDir)) { @@ -59,24 +56,21 @@ public function run(RequestInterface $request, ResponseInterface $response) return $response->withStatus(404); } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { - $ret = [ + return [ 'success' => $this->success(), 'feedbacks' => $this->feedbacks(), 'content' => $this->fileContent ]; - - return $ret; } /** * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/UpdateAction.php b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/UpdateAction.php index a9c6fa401..bee34396f 100644 --- a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/UpdateAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/UpdateAction.php @@ -44,23 +44,20 @@ public function run(RequestInterface $request, ResponseInterface $response) return $response; } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { - $ret = [ + return [ 'success' => $this->success(), 'feedbacks' => $this->feedbacks() ]; - - return $ret; } /** * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -74,7 +71,7 @@ protected function setDependencies(Container $container) * @param ResponseInterface $response PSR-7 response. * @return boolean */ - protected function cacheUrl($url, $outputDir, ResponseInterface $response) + protected function cacheUrl($url, string $outputDir, ResponseInterface $response) { unset($response); @@ -95,7 +92,7 @@ protected function cacheUrl($url, $outputDir, ResponseInterface $response) try { $guzzleClient = new GuzzleClient(); $static = $guzzleClient->request('GET', $url); - } catch (Exception $e) { + } catch (Exception) { $this->setSuccess(false); return false; } @@ -112,7 +109,7 @@ protected function cacheUrl($url, $outputDir, ResponseInterface $response) return false; } - if (strstr($headers['Content-Type'][0], 'text/html') !== false) { + if (str_contains($headers['Content-Type'][0], 'text/html')) { $outputFile = $outputDir . '/index.html'; $prefix = ''; } else { diff --git a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/UpdateAllAction.php b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/UpdateAllAction.php index 9e0c6202e..5cf172193 100644 --- a/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/UpdateAllAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/System/StaticWebsite/UpdateAllAction.php @@ -18,9 +18,9 @@ class UpdateAllAction extends UpdateAction /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + #[\Override] + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -35,17 +35,13 @@ public function run(RequestInterface $request, ResponseInterface $response) return $response; } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { - $ret = [ + return [ 'success' => $this->success(), 'feedbacks' => $this->feedbacks() ]; - - return $ret; } /** @@ -54,7 +50,7 @@ public function results() * @param integer $flags Glob flags. * @return array */ - protected function globRecursive($dir, $pattern, $flags = 0) + protected function globRecursive(string $dir, string $pattern, $flags = 0): array|false { $files = glob($dir . '/' . $pattern, $flags); foreach (glob($dir . '/*', (GLOB_ONLYDIR | GLOB_NOSORT)) as $dir) { diff --git a/packages/admin/src/Charcoal/Admin/Action/Tinymce/UploadImageAction.php b/packages/admin/src/Charcoal/Admin/Action/Tinymce/UploadImageAction.php index b41d04adf..88ad43638 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Tinymce/UploadImageAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Tinymce/UploadImageAction.php @@ -19,24 +19,18 @@ class UploadImageAction extends AdminAction /** * Whether uploaded files should be accessible from the web root. - * - * @var boolean */ - private $publicAccess = self::DEFAULT_PUBLIC_ACCESS; + private bool $publicAccess = self::DEFAULT_PUBLIC_ACCESS; /** * The relative path to the storage directory. - * - * @var string */ - private $uploadPath = self::DEFAULT_UPLOAD_PATH; + private string $uploadPath = self::DEFAULT_UPLOAD_PATH; /** * Whether existing destinations should be overwritten. - * - * @var boolean */ - private $overwrite = self::DEFAULT_OVERWRITE; + private bool $overwrite = self::DEFAULT_OVERWRITE; /** * The base path for the Charcoal installation. @@ -52,10 +46,7 @@ class UploadImageAction extends AdminAction */ private $publicPath; - /** - * @var string - */ - private $uploadedPath; + private ?string $uploadedPath = null; /** * Inject dependencies from a DI Container. @@ -63,6 +54,7 @@ class UploadImageAction extends AdminAction * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -78,19 +70,18 @@ protected function setDependencies(Container $container) * * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { $path = $request->getParam('upload_path'); - if (!!$path) { + if ((bool)$path) { $this->setUploadPath($path); } $this->uploadedPath = $this->fileUpload($_FILES['file']); - $this->setSuccess(!!$this->uploadedPath); + $this->setSuccess((bool)$this->uploadedPath); return $response; } @@ -100,9 +91,8 @@ public function run(RequestInterface $request, ResponseInterface $response) * * @param array $fileData The file data (from $_FILES, typically). * @throws \InvalidArgumentException If the FILES data argument is missing `name` or `tmp_name`. - * @return string */ - public function fileUpload(array $fileData) + public function fileUpload(array $fileData): string { if (!isset($fileData['name'])) { throw new \InvalidArgumentException( @@ -121,18 +111,16 @@ public function fileUpload(array $fileData) } else { $this->logger->notice(sprintf('File %s uploaded succesfully', $target)); $basePath = $this->basePath(); - $target = str_replace($basePath, '', $target); - return $target; + return str_replace($basePath, '', $target); } } /** * @param string $filename Optional. The filename to save. If unset, a default filename will be generated. * @throws \Exception If the target path is not writeable. - * @return string */ - public function uploadTarget($filename = null) + public function uploadTarget($filename = null): string { $basePath = $this->basePath(); @@ -143,7 +131,7 @@ public function uploadTarget($filename = null) // @todo: Feedback $this->logger->debug( 'Path does not exist. Attempting to create path ' . $dir . '.', - [get_called_class() . '::' . __FUNCTION__] + [static::class . '::' . __FUNCTION__] ); mkdir($dir, 0777, true); } @@ -156,7 +144,7 @@ public function uploadTarget($filename = null) $target = $dir . $filename; if ($this->fileExists($target)) { - if ($this->overwrite() === true) { + if ($this->overwrite()) { return $target; } else { $target = $dir . $this->generateUniqueFilename($filename); @@ -177,9 +165,8 @@ public function uploadTarget($filename = null) * * @param string $file The full file to check. * @param boolean $caseInsensitive Case-insensitive by default. - * @return boolean */ - public function fileExists($file, $caseInsensitive = true) + public function fileExists($file, $caseInsensitive = true): bool { if (!$this->isAbsolutePath($file)) { $file = $this->basePath() . DIRECTORY_SEPARATOR . $file; @@ -197,7 +184,7 @@ public function fileExists($file, $caseInsensitive = true) if ($files) { $pattern = preg_quote($file, '#'); foreach ($files as $f) { - if (preg_match("#${pattern}#i", $f)) { + if (preg_match("#{$pattern}#i", $f)) { return true; } } @@ -216,7 +203,7 @@ public function fileExists($file, $caseInsensitive = true) * @param string $file A file path. * @return boolean Returns TRUE if the given path is absolute. Otherwise, returns FALSE. */ - protected function isAbsolutePath($file) + protected function isAbsolutePath($file): bool { return strspn($file, '/\\', 0, 1) || (strlen($file) > 3 @@ -232,7 +219,7 @@ protected function isAbsolutePath($file) * @param string $filename The filename to sanitize. * @return string The sanitized filename. */ - public function sanitizeFilename($filename) + public function sanitizeFilename($filename): string { // Remove blacklisted caharacters $blacklist = ['/', '\\', '\0', '*', ':', '?', '"', '<', '>', '|', '#', '&', '!', '`', ' ']; @@ -249,22 +236,17 @@ public function sanitizeFilename($filename) * * @param string|array $filename The filename to alter. * @throws \InvalidArgumentException If the given filename is invalid. - * @return string */ - public function generateUniqueFilename($filename) + public function generateUniqueFilename($filename): string { if (!is_string($filename) && !is_array($filename)) { throw new \InvalidArgumentException(sprintf( 'The target must be a string or an array from [pathfino()], received %s', - (is_object($filename) ? get_class($filename) : gettype($filename)) + (get_debug_type($filename)) )); } - if (is_string($filename)) { - $info = pathinfo($filename); - } else { - $info = $filename; - } + $info = is_string($filename) ? pathinfo($filename) : $filename; $filename = $info['filename'] . '-' . uniqid(); @@ -275,10 +257,7 @@ public function generateUniqueFilename($filename) return $filename; } - /** - * @return string - */ - public function uploadPath() + public function uploadPath(): string { return $this->uploadPath; } @@ -290,9 +269,8 @@ public function uploadPath() * * @param string $path The destination directory, relative to project's root. * @throws \InvalidArgumentException If the path is not a string. - * @return self */ - public function setUploadPath($path) + public function setUploadPath($path): static { if (!is_string($path)) { throw new \InvalidArgumentException( @@ -310,21 +288,18 @@ public function setUploadPath($path) * Set whether uploaded files should be publicly available. * * @param boolean $public Whether uploaded files should be accessible (TRUE) or not (FALSE) from the web root. - * @return self */ - public function setPublicAccess($public) + public function setPublicAccess($public): static { - $this->publicAccess = !!$public; + $this->publicAccess = (bool)$public; return $this; } /** * Determine if uploaded files should be publicly available. - * - * @return boolean */ - public function publicAccess() + public function publicAccess(): bool { return $this->publicAccess; } @@ -333,21 +308,18 @@ public function publicAccess() * Set whether existing destinations should be overwritten. * * @param boolean $overwrite Whether existing destinations should be overwritten (TRUE) or not (FALSE). - * @return self */ - public function setOverwrite($overwrite) + public function setOverwrite($overwrite): static { - $this->overwrite = !!$overwrite; + $this->overwrite = (bool)$overwrite; return $this; } /** * Determine if existing destinations should be overwritten. - * - * @return boolean */ - public function overwrite() + public function overwrite(): bool { return $this->overwrite; } @@ -368,10 +340,9 @@ protected function basePath() /** * Default response stub. - * - * @return array */ - public function results() + #[\Override] + public function results(): array { return [ 'success' => $this->success(), diff --git a/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php b/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php index 8fcf6d9f9..0556402b5 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php @@ -115,7 +115,7 @@ public function run(RequestInterface $request, ResponseInterface $response) try { if (!$widgetType) { - $actualType = is_object($widgetType) ? get_class($widgetType) : gettype($widgetType); + $actualType = get_debug_type($widgetType); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"widget_type"', '{{ expectedType }}' => 'string', @@ -133,7 +133,7 @@ public function run(RequestInterface $request, ResponseInterface $response) if (isset($widgetOptions)) { if (!is_array($widgetOptions)) { - $actualType = is_object($widgetOptions) ? get_class($widgetOptions) : gettype($widgetOptions); + $actualType = get_debug_type($widgetOptions); $this->addFeedback('error', strtr($typeMessage, [ '{{ parameter }}' => '"widget_options"', '{{ expectedType }}' => 'array', @@ -190,7 +190,7 @@ public function run(RequestInterface $request, ResponseInterface $response) * @throws InvalidArgumentException If the widget ID argument is not a string. * @return LoadAction Chainable */ - public function setWidgetId($id) + public function setWidgetId($id): static { if (!is_string($id)) { throw new InvalidArgumentException( @@ -217,9 +217,8 @@ public function widgetId() * Set the widget's DATA. * * @param array|mixed $widgetData WidgetData for LoadAction. - * @return self */ - public function setWidgetData($widgetData) + public function setWidgetData($widgetData): static { $this->widgetData = $widgetData; @@ -243,7 +242,7 @@ public function widgetData() * @throws InvalidArgumentException If the widget type argument is not a string. * @return LoadAction Chainable */ - public function setWidgetType($type) + public function setWidgetType($type): static { if (!is_string($type)) { throw new InvalidArgumentException( @@ -273,7 +272,7 @@ public function widgetType() * @throws InvalidArgumentException If the widget HTML is not a string. * @return LoadAction Chainable */ - public function setWidgetHtml($html) + public function setWidgetHtml($html): static { if (!is_string($html)) { throw new InvalidArgumentException( @@ -296,10 +295,8 @@ public function widgetHtml() return $this->widgetHtml; } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { return [ 'success' => $this->success(), @@ -314,6 +311,7 @@ public function results() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setdependencies($container); @@ -331,7 +329,7 @@ protected function setDependencies(Container $container) */ protected function widgetView() { - if (!isset($this->widgetView)) { + if ($this->widgetView === null) { throw new RuntimeException('Widget Renderer is not defined'); } @@ -346,7 +344,7 @@ protected function widgetView() */ protected function widgetFactory() { - if (!isset($this->widgetFactory)) { + if ($this->widgetFactory === null) { throw new RuntimeException('Widget Factory is not defined'); } @@ -357,9 +355,8 @@ protected function widgetFactory() * Set the widget renderer. * * @param ViewInterface $view The view renderer to create widgets. - * @return void */ - private function setWidgetView(ViewInterface $view) + private function setWidgetView(ViewInterface $view): void { $this->widgetView = $view; } @@ -368,9 +365,8 @@ private function setWidgetView(ViewInterface $view) * Set the widget factory. * * @param FactoryInterface $factory The factory to create widgets. - * @return void */ - private function setWidgetFactory(FactoryInterface $factory) + private function setWidgetFactory(FactoryInterface $factory): void { $this->widgetFactory = $factory; } diff --git a/packages/admin/src/Charcoal/Admin/Action/Widget/Table/InlineAction.php b/packages/admin/src/Charcoal/Admin/Action/Widget/Table/InlineAction.php index 620910815..a52a7818c 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Widget/Table/InlineAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Widget/Table/InlineAction.php @@ -68,7 +68,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $reqMessage = $this->translator()->translation( '{{ parameter }} required, must be a {{ expectedType }}, received {{ actualType }}' ); - $typeMessage = $this->translator()->translation( + $this->translator()->translation( '{{ parameter }} must be a {{ expectedType }}, received {{ actualType }}' ); @@ -76,7 +76,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $objId = $request->getParam('obj_id'); if (!$objType) { - $actualType = is_object($objType) ? get_class($objType) : gettype($objType); + $actualType = get_debug_type($objType); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_type"', '{{ expectedType }}' => 'string', @@ -88,7 +88,7 @@ public function run(RequestInterface $request, ResponseInterface $response) } if (!$objId) { - $actualType = is_object($objId) ? get_class($objId) : gettype($objId); + $actualType = get_debug_type($objId); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_id"', '{{ expectedType }}' => 'string or numeric', @@ -149,10 +149,8 @@ public function run(RequestInterface $request, ResponseInterface $response) } } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { return [ 'success' => $this->success(), @@ -165,6 +163,7 @@ public function results() * @param Container $container DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -180,7 +179,7 @@ protected function setDependencies(Container $container) */ protected function widgetFactory() { - if (!isset($this->widgetFactory)) { + if ($this->widgetFactory === null) { throw new RuntimeException('Widget Factory is not defined'); } @@ -191,9 +190,8 @@ protected function widgetFactory() * Set the widget factory. * * @param FactoryInterface $factory The factory to create widgets. - * @return void */ - private function setWidgetFactory(FactoryInterface $factory) + private function setWidgetFactory(FactoryInterface $factory): void { $this->widgetFactory = $factory; } diff --git a/packages/admin/src/Charcoal/Admin/Action/Widget/Table/InlineMultiAction.php b/packages/admin/src/Charcoal/Admin/Action/Widget/Table/InlineMultiAction.php index 9f540d378..8f9b313a7 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Widget/Table/InlineMultiAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Widget/Table/InlineMultiAction.php @@ -48,10 +48,8 @@ class InlineMultiAction extends AdminAction /** * Store the widget factory. - * - * @var FactoryInterface */ - private $widgetFactory; + private ?\Charcoal\Factory\FactoryInterface $widgetFactory = null; /** * @param RequestInterface $request A PSR-7 compatible Request instance. @@ -68,7 +66,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $reqMessage = $this->translator()->translation( '{{ parameter }} required, must be a {{ expectedType }}, received {{ actualType }}' ); - $typeMessage = $this->translator()->translation( + $this->translator()->translation( '{{ parameter }} must be a {{ expectedType }}, received {{ actualType }}' ); @@ -76,7 +74,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $objIds = $request->getParam('obj_ids'); if (!$objType) { - $actualType = is_object($objType) ? get_class($objType) : gettype($objType); + $actualType = get_debug_type($objType); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_type"', '{{ expectedType }}' => 'string', @@ -88,7 +86,7 @@ public function run(RequestInterface $request, ResponseInterface $response) } if (!$objIds || !is_array($objIds)) { - $actualType = is_object($objIds) ? get_class($objIds) : gettype($objIds); + $actualType = get_debug_type($objIds); $this->addFeedback('error', strtr($reqMessage, [ '{{ parameter }}' => '"obj_ids"', '{{ expectedType }}' => 'array of object IDs', @@ -153,10 +151,8 @@ public function run(RequestInterface $request, ResponseInterface $response) } } - /** - * @return array - */ - public function results() + #[\Override] + public function results(): array { return [ 'success' => $this->success(), @@ -169,6 +165,7 @@ public function results() * @param Container $container DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -180,11 +177,10 @@ protected function setDependencies(Container $container) * Retrieve the widget factory. * * @throws RuntimeException If the widget factory was not previously set. - * @return FactoryInterface */ - protected function widgetFactory() + protected function widgetFactory(): \Charcoal\Factory\FactoryInterface { - if (!isset($this->widgetFactory)) { + if (!$this->widgetFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException('Widget Factory is not defined'); } @@ -195,9 +191,8 @@ protected function widgetFactory() * Set the widget factory. * * @param FactoryInterface $factory The factory to create widgets. - * @return void */ - private function setWidgetFactory(FactoryInterface $factory) + private function setWidgetFactory(FactoryInterface $factory): void { $this->widgetFactory = $factory; } diff --git a/packages/admin/src/Charcoal/Admin/AdminAction.php b/packages/admin/src/Charcoal/Admin/AdminAction.php index d97ee1eec..d101689ef 100644 --- a/packages/admin/src/Charcoal/Admin/AdminAction.php +++ b/packages/admin/src/Charcoal/Admin/AdminAction.php @@ -57,17 +57,13 @@ abstract class AdminAction extends AbstractAction implements /** * Store the result from the last validation by Google reCAPTCHA API. - * - * @var array|null */ - private $recaptchaLastResult; + private ?array $recaptchaLastResult = null; /** * Store the model factory. - * - * @var FactoryInterface $modelFactory */ - private $modelFactory; + private ?\Charcoal\Factory\FactoryInterface $modelFactory = null; /** * Action's init method is called automatically from `charcoal-app`'s Action Route. @@ -82,6 +78,7 @@ abstract class AdminAction extends AbstractAction implements * @return boolean * @see \Charcoal\App\Route\TemplateRoute::__invoke() */ + #[\Override] public function init(RequestInterface $request) { if (!session_id()) { @@ -165,12 +162,11 @@ public function siteName() */ public function results() { - $results = [ + return [ 'success' => $this->success(), 'next_url' => $this->redirectUrl(), 'feedbacks' => $this->feedbacks() ]; - return $results; } /** @@ -179,6 +175,7 @@ public function results() * @param Container $container DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -340,11 +337,11 @@ protected function validateCaptcha($token) * with a new Response object that represents a client error. * @return boolean Returns TRUE if the user response is valid, FALSE if it is invalid. */ - protected function validateCaptchaFromRequest(RequestInterface $request, ResponseInterface &$response = null) + protected function validateCaptchaFromRequest(RequestInterface $request, ?ResponseInterface &$response = null) { $token = $request->getParam('g-recaptcha-response', false); if (empty($token)) { - if ($response !== null) { + if ($response instanceof \Psr\Http\Message\ResponseInterface) { $this->addFeedback('error', $this->translator()->translate('Missing CAPTCHA response.')); $this->setSuccess(false); @@ -355,7 +352,7 @@ protected function validateCaptchaFromRequest(RequestInterface $request, Respons } $result = $this->validateCaptcha($token); - if ($result === false && $response !== null) { + if ($result === false && $response instanceof \Psr\Http\Message\ResponseInterface) { $this->addFeedback('error', $this->translator()->translate('Invalid or malformed CAPTCHA response.')); $this->setSuccess(false); diff --git a/packages/admin/src/Charcoal/Admin/AdminModule.php b/packages/admin/src/Charcoal/Admin/AdminModule.php index 3d32be4f8..07798bd0a 100644 --- a/packages/admin/src/Charcoal/Admin/AdminModule.php +++ b/packages/admin/src/Charcoal/Admin/AdminModule.php @@ -3,6 +3,7 @@ namespace Charcoal\Admin; // From PSR-7 +use Pimple\Container; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; // From 'charcoal-app' @@ -32,7 +33,8 @@ class AdminModule extends AbstractModule * * @return AdminModule Chainable */ - public function setUp() + #[\Override] + public function setUp(): static { // Hack: skip if the request does not start with '/admin' $container = $this->app()->getContainer(); @@ -47,15 +49,13 @@ public function setUp() $container->register(new AdminServiceProvider()); $module = $this; - $container['charcoal/admin/module'] = function () use ($module) { - return $module; - }; + $container['charcoal/admin/module'] = (fn(): static => $module); $adminConfig = $container['admin/config']; $this->setConfig($adminConfig); - $groupIdent = '/' . trim($adminConfig['base_path'], '/'); + $groupIdent = '/' . trim((string)$adminConfig['base_path'], '/'); // Add the route group $this->app()->group($groupIdent, 'charcoal/admin/module:setupRoutes') @@ -69,7 +69,8 @@ public function setUp() * * @return AdminModule Chainable */ - public function setupRoutes() + #[\Override] + public function setupRoutes(): static { if ($this->routeManager === null) { parent::setupRoutes(); @@ -102,7 +103,7 @@ public function setupHandlers( * @param object|HandlerInterface $handler An error handler instance. * @return HandlerInterface */ - $container->extend('notFoundHandler', function ($handler, $container) { + $container->extend('notFoundHandler', function ($handler, Container $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; if ($handler instanceof HandlerInterface) { @@ -125,7 +126,7 @@ public function setupHandlers( * @param object|HandlerInterface $handler An error handler instance. * @return HandlerInterface */ - $container->extend('notAllowedHandler', function ($handler, $container) { + $container->extend('notAllowedHandler', function ($handler, Container $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; if ($handler instanceof HandlerInterface) { @@ -148,7 +149,7 @@ public function setupHandlers( * @param object|HandlerInterface $handler An error handler instance. * @return HandlerInterface */ - $container->extend('phpErrorHandler', function ($handler, $container) { + $container->extend('phpErrorHandler', function ($handler, Container $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; if ($handler instanceof HandlerInterface) { @@ -171,7 +172,7 @@ public function setupHandlers( * @param object|HandlerInterface $handler An error handler instance. * @return HandlerInterface */ - $container->extend('errorHandler', function ($handler, $container) { + $container->extend('errorHandler', function ($handler, Container $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; if ($handler instanceof HandlerInterface) { @@ -196,7 +197,7 @@ public function setupHandlers( * @param object|HandlerInterface $handler An error handler instance. * @return HandlerInterface */ - $container->extend('maintenanceHandler', function ($handler, $container) { + $container->extend('maintenanceHandler', function ($handler, Container $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; if ($handler instanceof HandlerInterface) { @@ -226,11 +227,6 @@ private function isPathAdmin($path) if ($path === 'admin') { return true; } - - if (substr($path, 0, 6) === 'admin/') { - return true; - } - - return false; + return str_starts_with($path, 'admin/'); } } diff --git a/packages/admin/src/Charcoal/Admin/AdminScript.php b/packages/admin/src/Charcoal/Admin/AdminScript.php index 0d17d9304..22ccc2583 100644 --- a/packages/admin/src/Charcoal/Admin/AdminScript.php +++ b/packages/admin/src/Charcoal/Admin/AdminScript.php @@ -27,15 +27,14 @@ abstract class AdminScript extends AbstractScript /** * The model factory. - * - * @var FactoryInterface */ - private $modelFactory; + private ?\Charcoal\Factory\FactoryInterface $modelFactory = null; /** * @param Container $container Pimple DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -95,11 +94,10 @@ private function booleanInput(PropertyInterface $prop, $label) 1 => $prop->trueLabel(), 0 => $prop->falseLabel() ]; - $input = $climate->radio( + return $climate->radio( $label, $opts ); - return $input; } /** @@ -114,18 +112,15 @@ private function passwordInput(PropertyInterface $prop, $label) unset($prop); $climate = $this->climate(); - - $input = $climate->password($label); - return $input; + return $climate->password($label); } /** * Set the model factory. * * @param FactoryInterface $factory The factory used to create models. - * @return void */ - private function setModelFactory(FactoryInterface $factory) + private function setModelFactory(FactoryInterface $factory): void { $this->modelFactory = $factory; } diff --git a/packages/admin/src/Charcoal/Admin/AdminTemplate.php b/packages/admin/src/Charcoal/Admin/AdminTemplate.php index 88beb929e..d4497c116 100644 --- a/packages/admin/src/Charcoal/Admin/AdminTemplate.php +++ b/packages/admin/src/Charcoal/Admin/AdminTemplate.php @@ -78,20 +78,11 @@ class AdminTemplate extends AbstractTemplate implements */ protected $subtitle; - /** - * @var boolean - */ - private $showSecondaryMenu = true; + private bool $showSecondaryMenu = true; - /** - * @var boolean - */ - private $showMainMenu = true; + private bool $showMainMenu = true; - /** - * @var boolean - */ - private $showSystemMenu = true; + private bool $showSystemMenu = true; /** * @var boolean @@ -118,10 +109,7 @@ class AdminTemplate extends AbstractTemplate implements */ protected $secondaryMenu; - /** - * @var array - */ - private $adminDataForJs; + private ?array $adminDataForJs = null; /** * @var \Charcoal\Ui\Menu\MenuBuilder $menuBuilder @@ -133,15 +121,9 @@ class AdminTemplate extends AbstractTemplate implements */ private $menuItemBuilder; - /** - * @var FactoryInterface $modelFactory - */ - private $modelFactory; + private ?\Charcoal\Factory\FactoryInterface $modelFactory = null; - /** - * @var FactoryInterface $widgetFactory - */ - private $widgetFactory; + private ?\Charcoal\Factory\FactoryInterface $widgetFactory = null; /** * Template's init method is called automatically from `charcoal-app`'s Template Route. @@ -156,6 +138,7 @@ class AdminTemplate extends AbstractTemplate implements * @return boolean * @see \Charcoal\App\Route\TemplateRoute::__invoke() */ + #[\Override] public function init(RequestInterface $request) { if (!session_id()) { @@ -199,12 +182,11 @@ protected function authRedirect(RequestInterface $request) * Sets the template data from a PSR Request object. * * @param RequestInterface $request A PSR-7 compatible Request instance. - * @return self */ - protected function setDataFromRequest(RequestInterface $request) + protected function setDataFromRequest(RequestInterface $request): static { $keys = $this->validDataFromRequest(); - if (!empty($keys)) { + if ($keys !== []) { $this->setData($request->getParams($keys)); } @@ -216,7 +198,7 @@ protected function setDataFromRequest(RequestInterface $request) * * @return string[] */ - protected function validDataFromRequest() + protected function validDataFromRequest(): array { return [ // HTTP Handling @@ -230,7 +212,7 @@ protected function validDataFromRequest() * @param mixed $ident Template identifier. * @return AdminTemplate Chainable */ - public function setIdent($ident) + public function setIdent($ident): static { $this->ident = $ident; return $this; @@ -248,7 +230,7 @@ public function ident() * @param mixed $label Template label. * @return AdminTemplate Chainable */ - public function setLabel($label) + public function setLabel($label): static { $this->label = $this->translator()->translation($label); @@ -269,7 +251,7 @@ public function label() * @param mixed $title Template title. * @return AdminTemplate Chainable */ - public function setTitle($title) + public function setTitle($title): static { $this->title = $this->translator()->translation($title); @@ -296,7 +278,7 @@ public function title() * @param mixed $subtitle Template subtitle. * @return AdminTemplate Chainable */ - public function setSubtitle($subtitle) + public function setSubtitle($subtitle): static { $this->subtitle = $this->translator()->translation($subtitle); @@ -317,16 +299,13 @@ public function subtitle() * @param boolean $show The show main menu flag. * @return AdminTemplate Chainable */ - public function setShowMainMenu($show) + public function setShowMainMenu($show): static { - $this->showMainMenu = !!$show; + $this->showMainMenu = (bool)$show; return $this; } - /** - * @return boolean - */ - public function showMainMenu() + public function showMainMenu(): bool { return ($this->isAuthorized() && $this->showMainMenu); } @@ -359,16 +338,13 @@ public function mainMenu() * @param boolean $show The show footer menu flag. * @return AdminTemplate Chainable */ - public function setShowSystemMenu($show) + public function setShowSystemMenu($show): static { - $this->showSystemMenu = !!$show; + $this->showSystemMenu = (bool)$show; return $this; } - /** - * @return boolean - */ - public function showSystemMenu() + public function showSystemMenu(): bool { return ($this->isAuthorized() && $this->showSystemMenu && (count($this->systemMenu()) > 0)); } @@ -376,7 +352,7 @@ public function showSystemMenu() /** * @return array */ - public function systemMenu() + public function systemMenu(): \ArrayIterator { if ($this->systemMenu === null) { $this->systemMenu = $this->createSystemMenu(); @@ -389,16 +365,13 @@ public function systemMenu() * @param boolean $show The show secondary menu flag. * @return AdminTemplate Chainable */ - public function setShowSecondaryMenu($show) + public function setShowSecondaryMenu($show): static { - $this->showSecondaryMenu = !!$show; + $this->showSecondaryMenu = (bool)$show; return $this; } - /** - * @return boolean - */ - public function showSecondaryMenu() + public function showSecondaryMenu(): bool { return ($this->isAuthorized() && $this->showSecondaryMenu); } @@ -430,10 +403,7 @@ public function mainMenuLogo() return 'assets/admin/images/identicon.png'; } - /** - * @return string - */ - public function navContainerCssClasses() + public function navContainerCssClasses(): string { $classes = [ 'has-nav-logo' ]; @@ -496,7 +466,7 @@ public function documentTitle() $siteName = $this->siteName(); $pageTitle = strip_tags($this->title()); - if ($pageTitle) { + if ($pageTitle !== '' && $pageTitle !== '0') { if ($pageTitle === $siteName) { return sprintf('%1$s — Charcoal', $pageTitle); } else { @@ -509,10 +479,8 @@ public function documentTitle() /** * Retrieve the current language. - * - * @return string */ - public function lang() + public function lang(): string { return $this->translator()->getLocale(); } @@ -580,20 +548,15 @@ public function recaptchaInvisible() if ($hasSize && $recaptcha['size'] === 'invisible') { return true; } - - if (!$hasInvisible && !$hasSize) { - return true; - } - - return false; + return !$hasInvisible && !$hasSize; } /** * Alias of {@see self::recaptchaSiteKey()}. * - * @deprecated * @return string|null */ + #[\Deprecated] public function recaptchaKey() { return $this->recaptchaSiteKey(); @@ -623,7 +586,7 @@ public function recaptchaSiteKey() * * @return string[] */ - public function recaptchaParameters() + public function recaptchaParameters(): array { $apiConfig = $this->apiConfig('google.recaptcha'); $tplConfig = $this->get('recaptcha_options') ?: []; @@ -658,10 +621,8 @@ public function recaptchaParameters() /** * Generate a string representation of HTML attributes for the Google reCAPTCHA tag. - * - * @return string */ - public function recaptchaHtmlAttr() + public function recaptchaHtmlAttr(): string { $params = $this->recaptchaParameters(); @@ -681,6 +642,7 @@ public function recaptchaHtmlAttr() * @param Container $container DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -715,11 +677,11 @@ protected function setDependencies(Container $container) * @throws Exception If the factory is not set. * @return FactoryInterface The model factory. */ - protected function modelFactory() + protected function modelFactory(): \Charcoal\Factory\FactoryInterface { - if (!$this->modelFactory) { + if (!$this->modelFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new Exception( - sprintf('Model factory is not set for template "%s".', get_class($this)) + sprintf('Model factory is not set for template "%s".', static::class) ); } return $this->modelFactory; @@ -727,11 +689,10 @@ protected function modelFactory() /** * @throws Exception If the widget factory dependency was not previously set / injected. - * @return FactoryInterface */ - protected function widgetFactory() + protected function widgetFactory(): \Charcoal\Factory\FactoryInterface { - if ($this->widgetFactory === null) { + if (!$this->widgetFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new Exception( 'Widget factory was not set.' ); @@ -745,7 +706,7 @@ protected function widgetFactory() * @param string $name Name of the project. * @return AdminTemplate Chainable */ - protected function setSiteName($name) + protected function setSiteName($name): static { $this->siteName = $this->translator()->translation($name); return $this; @@ -756,9 +717,8 @@ protected function setSiteName($name) * * @param mixed $options The main menu widget ID or config. * @throws InvalidArgumentException If the admin config is missing, invalid, or malformed. - * @return array */ - protected function createMainMenu($options = null) + protected function createMainMenu($options = null): array { $mainMenuConfig = $this->adminConfig('main_menu'); @@ -791,7 +751,7 @@ protected function createMainMenu($options = null) $menuItems[] = $this->parseMainMenuItem($menuItem, $menuIdent, $mainMenuIdent); } - usort($menuItems, [ 'Charcoal\Admin\Support\Sorter', 'sortByPriority' ]); + usort($menuItems, \Charcoal\Admin\Support\Sorter::sortByPriority(...)); return $menuItems; } @@ -822,7 +782,7 @@ private function mainMenuIdent($options = null) } // Get main menu from the obj_type - $objType = filter_input(INPUT_GET, 'obj_type', FILTER_SANITIZE_STRING); + $objType = htmlspecialchars(trim(($_GET['obj_type'] ?? '')), ENT_QUOTES, 'UTF-8'); if ($objType) { $secondaryMenuItems = $this->adminConfig('secondary_menu'); foreach ($secondaryMenuItems as $main => $item) { @@ -834,7 +794,7 @@ private function mainMenuIdent($options = null) } // Choose main menu with a get parameter - $mainMenuFromRequest = filter_input(INPUT_GET, 'main_menu', FILTER_SANITIZE_STRING); + $mainMenuFromRequest = htmlspecialchars(trim(($_GET['main_menu'] ?? '')), ENT_QUOTES, 'UTF-8'); if ($mainMenuFromRequest) { $mainMenuIdent = $mainMenuFromRequest; } @@ -852,9 +812,8 @@ private function mainMenuIdent($options = null) * * @param string $objType The ObjType to search. * @param array|mixed $item The secondary menu item to search in. - * @return boolean */ - protected function isObjTypeInSecondaryMenuItem($objType, $item) + protected function isObjTypeInSecondaryMenuItem($objType, array $item): bool { if (isset($item['links'])) { foreach ($item['links'] as $obj => $i) { @@ -878,8 +837,9 @@ protected function isObjTypeInSecondaryMenuItem($objType, $item) /** * @throws InvalidArgumentException If the secondary menu widget is invalid. * @return \Charcoal\Admin\Widget\SecondaryMenuWidgetInterface[]| + * @return mixed[] */ - protected function createSecondaryMenu() + protected function createSecondaryMenu(): array { $secondaryMenuItems = $this->adminConfig('secondary_menu'); @@ -909,7 +869,7 @@ protected function createSecondaryMenu() } } - usort($menuItems, [ 'Charcoal\Admin\Support\Sorter', 'sortByPriority' ]); + usort($menuItems, \Charcoal\Admin\Support\Sorter::sortByPriority(...)); return $menuItems; } @@ -919,7 +879,7 @@ protected function createSecondaryMenu() * @throws InvalidArgumentException If the menu is missing, invalid, or malformed. * @return array|Generator */ - protected function createSystemMenu($options = null) + protected function createSystemMenu($options = null): array { $menuConfig = $this->adminConfig('system_menu'); @@ -964,7 +924,7 @@ protected function createSystemMenu($options = null) $menuItems[$menuIdent] = $menuItem; } - usort($menuItems, [ 'Charcoal\Admin\Support\Sorter', 'sortByPriority' ]); + usort($menuItems, \Charcoal\Admin\Support\Sorter::sortByPriority(...)); return $menuItems; } @@ -973,18 +933,16 @@ protected function createSystemMenu($options = null) * As a convenience, all admin templates have a model factory to easily create objects. * * @param FactoryInterface $factory The factory used to create models. - * @return void */ - private function setModelFactory(FactoryInterface $factory) + private function setModelFactory(FactoryInterface $factory): void { $this->modelFactory = $factory; } /** * @param FactoryInterface $factory The widget factory, to create the dashboard and secondary menu widgets. - * @return void */ - private function setWidgetFactory(FactoryInterface $factory) + private function setWidgetFactory(FactoryInterface $factory): void { $this->widgetFactory = $factory; } @@ -995,7 +953,7 @@ private function setWidgetFactory(FactoryInterface $factory) * @param string|null $currentIdent The current menu identifier. * @return array Finalized menu structure. */ - private function parseMainMenuItem(array $menuItem, $menuIdent = null, $currentIdent = null) + private function parseMainMenuItem(array $menuItem, $menuIdent = null, $currentIdent = null): array { $svgUri = $this->baseUrl() . 'assets/admin/images/svgs.svg#icon-'; @@ -1007,7 +965,7 @@ private function parseMainMenuItem(array $menuItem, $menuIdent = null, $currentI if (!empty($menuItem['url'])) { $url = $menuItem['url']; - if ($url && strpos($url, ':') === false && !in_array($url[0], [ '/', '#', '?' ])) { + if ($url && !str_contains((string)$url, ':') && !in_array($url[0], [ '/', '#', '?' ])) { $url = $this->adminUrl() . $url; } } else { @@ -1018,7 +976,7 @@ private function parseMainMenuItem(array $menuItem, $menuIdent = null, $currentI if (isset($menuItem['icon'])) { $icon = $menuItem['icon']; - if ($icon && strpos($icon, ':') === false && !in_array($icon[0], [ '/', '#', '?' ])) { + if ($icon && !str_contains((string)$icon, ':') && !in_array($icon[0], [ '/', '#', '?' ])) { $icon = $svgUri . $icon; } } else { @@ -1037,7 +995,7 @@ private function parseMainMenuItem(array $menuItem, $menuIdent = null, $currentI $menuItem['label'] = $this->translator()->translation($menuItem['label']); } - $menuItem['show_label'] = (isset($menuItem['show_label']) ? !!$menuItem['show_label'] : true); + $menuItem['show_label'] = (isset($menuItem['show_label']) ? (bool)$menuItem['show_label'] : true); $menuItem['selected'] = ($menuItem['ident'] === $currentIdent); @@ -1048,9 +1006,7 @@ private function parseMainMenuItem(array $menuItem, $menuIdent = null, $currentI $secondaryMenuWidget = current( array_filter( $this->secondaryMenu(), - function ($item) use ($menuIdent) { - return $item->ident() === $menuIdent; - } + fn($item): bool => $item->ident() === $menuIdent ) ); @@ -1070,7 +1026,7 @@ function ($item) use ($menuIdent) { * @param string|null $currentIdent The current menu identifier. * @return array Finalized menu structure. */ - private function parseSystemMenuItem(array $menuItem, $menuIdent = null, $currentIdent = null) + private function parseSystemMenuItem(array $menuItem, $menuIdent = null, $currentIdent = null): array { if (!isset($menuItem['ident'])) { $menuItem['ident'] = $menuIdent; @@ -1078,7 +1034,7 @@ private function parseSystemMenuItem(array $menuItem, $menuIdent = null, $curren if (!empty($menuItem['url'])) { $url = $menuItem['url']; - if ($url && strpos($url, ':') === false && !in_array($url[0], [ '/', '#', '?' ])) { + if ($url && !str_contains((string)$url, ':') && !in_array($url[0], [ '/', '#', '?' ])) { $url = $this->adminUrl() . $url; } } else { @@ -1125,10 +1081,8 @@ public function htmlAttr() /** * Generate an array containing a list of CSS classes to be used by the tag. - * - * @return array */ - public function htmlClasses() + public function htmlClasses(): array { $classes = [ 'has-no-js' @@ -1143,20 +1097,16 @@ public function htmlClasses() /** * Determine if main & secondary menu should appear as mobile in a desktop resolution. - * - * @return boolean */ - public function isFullscreenTemplate() + public function isFullscreenTemplate(): bool { return false; } /** * Retrieve the default data to the global Admin JavaScript application. - * - * @return array */ - final protected function getDefaultAdminDataForJs() + final protected function getDefaultAdminDataForJs(): array { return [ 'debug' => $this->debug(), @@ -1169,10 +1119,8 @@ final protected function getDefaultAdminDataForJs() /** * Retrieve all data options for the global Admin JavaScript application. - * - * @return array */ - final protected function getAdminDataForJs() + final protected function getAdminDataForJs(): array { if ($this->adminDataForJs === null) { $this->adminDataForJs = $this->getDefaultAdminDataForJs(); @@ -1185,9 +1133,8 @@ final protected function getAdminDataForJs() * Add extra data to the global Admin JavaScript application. * * @param array $data Additional options. - * @return self */ - final public function addAdminDataForJs(array $data) + final public function addAdminDataForJs(array $data): static { $this->adminDataForJs = array_merge($this->getAdminDataForJs(), $data); @@ -1196,14 +1143,10 @@ final public function addAdminDataForJs(array $data) /** * Retrieve the resolved data options for the global Admin JavaScript application. - * - * @return array */ - final public function adminDataForJs() + final public function adminDataForJs(): array { - return array_map(function ($datum) { - return is_callable($datum) ? $datum($this) : $datum; - }, $this->getAdminDataForJs()); + return array_map(fn($datum) => is_callable($datum) ? $datum($this) : $datum, $this->getAdminDataForJs()); } /** @@ -1216,7 +1159,7 @@ final public function adminDataForJsAsJson() $options = (JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); if ($this->debug()) { - $options = ($options | JSON_PRETTY_PRINT); + $options |= JSON_PRETTY_PRINT; } return json_encode($this->adminDataForJs(), $options); @@ -1227,7 +1170,7 @@ final public function adminDataForJsAsJson() * * @return string Returns a stringified JSON object, protected from Mustache rendering. */ - final public function escapedAdminDataForJsAsJson() + final public function escapedAdminDataForJsAsJson(): string { return '{{=<% %>=}}' . $this->adminDataForJsAsJson() . '<%={{ }}=%>'; } diff --git a/packages/admin/src/Charcoal/Admin/AdminWidget.php b/packages/admin/src/Charcoal/Admin/AdminWidget.php index 02d15bef2..d63806cef 100644 --- a/packages/admin/src/Charcoal/Admin/AdminWidget.php +++ b/packages/admin/src/Charcoal/Admin/AdminWidget.php @@ -50,20 +50,11 @@ class AdminWidget extends AbstractWidget implements */ public $widgetId; - /** - * @var string $type - */ - private $type; + private ?string $type = null; - /** - * @var string $template - */ - private $template; + private ?string $template = null; - /** - * @var string $ident - */ - private $ident = ''; + private ?string $ident = ''; /** * @var Translation|string|null $label @@ -75,15 +66,9 @@ class AdminWidget extends AbstractWidget implements */ private $lang; - /** - * @var boolean $showLabel - */ - private $showLabel; + private ?bool $showLabel = null; - /** - * @var boolean $showActions - */ - private $showActions; + private ?bool $showActions = null; /** * The widget's conditional logic. @@ -101,22 +86,15 @@ class AdminWidget extends AbstractWidget implements /** * Extra data sources to merge when setting data on an entity. - * - * @var array */ - private $dataSources; + private ?array $dataSources = null; /** * Associative array of source identifiers and options to apply when merging. - * - * @var array */ - private $dataSourceFilters = []; + private array $dataSourceFilters = []; - /** - * @var FactoryInterface $modelFactory - */ - private $modelFactory; + private ?\Charcoal\Factory\FactoryInterface $modelFactory = null; /** * Enable / Disable the widget. @@ -126,13 +104,10 @@ class AdminWidget extends AbstractWidget implements * @param mixed $active The active flag or condition. * @return self */ + #[\Override] public function setActive($active) { - if (is_callable($active) || is_string($active)) { - $condition = $active; - } else { - $condition = null; - } + $condition = is_callable($active) || is_string($active) ? $active : null; $this->activeCondition = $condition; @@ -142,6 +117,7 @@ public function setActive($active) /** * @return boolean */ + #[\Override] public function active() { if ($this->activeCondition !== null) { @@ -154,9 +130,8 @@ public function active() /** * @param string $template The UI item's template (identifier). * @throws InvalidArgumentException If the template identifier is not a string. - * @return self */ - public function setTemplate($template) + public function setTemplate($template): static { if ($template === null) { $this->template = null; @@ -177,7 +152,7 @@ public function setTemplate($template) /** * @return string */ - public function template() + public function template(): ?string { if ($this->template === null) { return $this->type(); @@ -188,9 +163,8 @@ public function template() /** * @param string $widgetId The widget identifier. - * @return self */ - public function setWidgetId($widgetId) + public function setWidgetId($widgetId): static { $this->widgetId = $widgetId; @@ -212,9 +186,8 @@ public function widgetId() /** * @param string $type The widget type. * @throws InvalidArgumentException If the argument is not a string. - * @return self */ - public function setType($type) + public function setType($type): static { if ($type === null) { $this->type = null; @@ -235,7 +208,7 @@ public function setType($type) /** * @return string */ - public function type() + public function type(): ?string { return $this->type; } @@ -245,7 +218,7 @@ public function type() * @throws InvalidArgumentException If the ident is not a string. * @return AdminWidget (Chainable) */ - public function setIdent($ident) + public function setIdent($ident): static { if ($ident === null) { $this->ident = null; @@ -266,7 +239,7 @@ public function setIdent($ident) /** * @return string */ - public function ident() + public function ident(): ?string { return $this->ident; } @@ -277,9 +250,8 @@ public function ident() * @param mixed $sources One or more data source identifiers to merge data from. * Pass NULL to reset the entity back to default sources. * Pass FALSE, an empty string or array to disable extra sources. - * @return self */ - public function setDataSources($sources) + public function setDataSources($sources): static { if ($sources === null) { $this->dataSources = null; @@ -327,19 +299,13 @@ public function dataSourceFilter($sourceIdent) $filters = array_merge($this->defaultDataSourceFilters(), $this->dataSourceFilters); - if (isset($filters[$sourceIdent])) { - return $filters[$sourceIdent]; - } - - return null; + return ($filters[$sourceIdent] ?? null); } /** * Retrieve the widget's data options for JavaScript components. - * - * @return array */ - public function widgetDataForJs() + public function widgetDataForJs(): array { return []; } @@ -354,7 +320,7 @@ final public function widgetDataForJsAsJson() $options = (JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); if ($this->debug()) { - $options = ($options | JSON_PRETTY_PRINT); + $options |= JSON_PRETTY_PRINT; } return json_encode($this->widgetDataForJs(), $options); @@ -365,16 +331,15 @@ final public function widgetDataForJsAsJson() * * @return string Returns a stringified JSON object, protected from Mustache rendering. */ - final public function escapedWidgetDataForJsAsJson() + final public function escapedWidgetDataForJsAsJson(): string { return '{{=<% %>=}}' . $this->widgetDataForJsAsJson() . '<%={{ }}=%>'; } /** * @param mixed $label The label. - * @return self */ - public function setLabel($label) + public function setLabel($label): static { $this->label = $this->translator()->translation($label); @@ -389,21 +354,17 @@ public function label() return $this->label; } - /** - * @return array - */ - public function actions() + public function actions(): array { return []; } /** * @param boolean $show The show actions flag. - * @return self */ - public function setShowActions($show) + public function setShowActions($show): static { - $this->showActions = !!$show; + $this->showActions = (bool)$show; return $this; } @@ -421,11 +382,10 @@ public function showActions() /** * @param boolean $show The show label flag. - * @return self */ - public function setShowLabel($show) + public function setShowLabel($show): static { - $this->showLabel = !!$show; + $this->showLabel = (bool)$show; return $this; } @@ -435,7 +395,7 @@ public function setShowLabel($show) public function showLabel() { if ($this->showLabel !== false) { - return !!strval($this->label()); + return (bool)strval($this->label()); } else { return false; } @@ -447,6 +407,7 @@ public function showLabel() * @param Container $container DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -483,7 +444,7 @@ protected function setModelFactory(FactoryInterface $factory) /** * @return FactoryInterface The model factory. */ - protected function modelFactory() + protected function modelFactory(): ?\Charcoal\Factory\FactoryInterface { return $this->modelFactory; } @@ -492,19 +453,18 @@ protected function modelFactory() * Parse the widget's conditional logic. * * @param callable|string $condition The callable or renderable condition. - * @return boolean */ - protected function resolveConditionalLogic($condition) + protected function resolveConditionalLogic($condition): bool { if (is_callable([ $this, $condition ])) { - return !!$this->{$condition}(); + return (bool)$this->{$condition}(); } elseif (is_callable($condition)) { - return !!$condition(); - } elseif ($this->view()) { - return !!$this->renderTemplate($condition); + return (bool)$condition(); + } elseif ($this->view() instanceof \Charcoal\View\ViewInterface) { + return (bool)$this->renderTemplate($condition); } - return !!$condition; + return (bool)$condition; } /** @@ -513,9 +473,8 @@ protected function resolveConditionalLogic($condition) * @param mixed $sourceIdent The data source identifier. * @param mixed $sourceFilter Optional filter to apply to the source's data. * @throws InvalidArgumentException If the data source is invalid. - * @return self */ - protected function addDataSources($sourceIdent, $sourceFilter = null) + protected function addDataSources($sourceIdent, $sourceFilter = null): static { $validSources = $this->acceptedDataSources(); @@ -552,7 +511,7 @@ protected function addDataSources($sourceIdent, $sourceFilter = null) * * @return string[] */ - protected function acceptedDataSources() + protected function acceptedDataSources(): array { return [ static::DATA_SOURCE_REQUEST, static::DATA_SOURCE_OBJECT, static::DATA_SOURCE_METADATA ]; } @@ -562,17 +521,15 @@ protected function acceptedDataSources() * * @return string[] */ - protected function defaultDataSources() + protected function defaultDataSources(): array { return []; } /** * Retrieve the default data source filters (when setting data on an entity). - * - * @return array */ - protected function defaultDataSourceFilters() + protected function defaultDataSourceFilters(): array { return []; } @@ -625,9 +582,8 @@ protected function resolveDataSourceFilter($toResolve) * Retrieve the available data sources (when setting data on an entity). * * @param array|mixed $dataset The entity data. - * @return self */ - protected function mergeDataSources($dataset = null) + protected function mergeDataSources($dataset = null): static { $sources = $this->dataSources(); foreach ($sources as $sourceIdent) { diff --git a/packages/admin/src/Charcoal/Admin/AssetsConfig.php b/packages/admin/src/Charcoal/Admin/AssetsConfig.php index 77e66aa65..dccf6e9c2 100644 --- a/packages/admin/src/Charcoal/Admin/AssetsConfig.php +++ b/packages/admin/src/Charcoal/Admin/AssetsConfig.php @@ -1,5 +1,7 @@ collections = $collections; diff --git a/packages/admin/src/Charcoal/Admin/Config.php b/packages/admin/src/Charcoal/Admin/Config.php index 0f750216a..d417a566d 100644 --- a/packages/admin/src/Charcoal/Admin/Config.php +++ b/packages/admin/src/Charcoal/Admin/Config.php @@ -18,20 +18,15 @@ class Config extends AbstractConfig /** * The base path for the admin module's route group. - * - * @var string $basePath */ - private $basePath = self::DEFAULT_BASE_PATH; + private string $basePath = self::DEFAULT_BASE_PATH; /** * @var array */ public $routes = []; - /** - * @var array - */ - private $handlers = []; + private array $handlers = []; /** * @var array @@ -50,6 +45,7 @@ class Config extends AbstractConfig * * @return array */ + #[\Override] public function defaults() { $baseDir = rtrim(realpath(__DIR__ . '/../../../'), '/'); @@ -63,9 +59,8 @@ public function defaults() * * @param string $path The admin module base path. * @throws InvalidArgumentException If the route group is invalid. - * @return self */ - public function setBasePath($path) + public function setBasePath($path): static { if (!is_string($path)) { throw new InvalidArgumentException( @@ -74,7 +69,7 @@ public function setBasePath($path) } // Can not be empty - if ($path == '') { + if ($path === '') { throw new InvalidArgumentException( 'Path can not be empty' ); @@ -86,10 +81,8 @@ public function setBasePath($path) /** * Retrieve the admin module's route group. - * - * @return string */ - public function basePath() + public function basePath(): string { return $this->basePath; } @@ -99,9 +92,8 @@ public function basePath() * * @see \Charcoal\App\AppConfig::setRoutes() For a similar implementation. * @param array $routes The route configuration structure to set. - * @return self */ - public function setRoutes(array $routes) + public function setRoutes(array $routes): static { $toIterate = RouteConfig::defaultRouteTypes(); foreach ($routes as $key => $val) { @@ -126,9 +118,8 @@ public function setRoutes(array $routes) * - "phpErrorHandler" * * @param array $handlers The handlers configuration structure to set. - * @return self */ - public function setHandlers(array $handlers) + public function setHandlers(array $handlers): static { $this->handlers = array_fill_keys(HandlerConfig::defaultHandlerTypes(), []); $this->handlers['defaults'] = []; @@ -143,10 +134,7 @@ public function setHandlers(array $handlers) return $this; } - /** - * @return array - */ - public function handlers() + public function handlers(): array { return $this->handlers; } @@ -156,9 +144,8 @@ public function handlers() * * @param array $view The global configset for the application's view service. * @throws InvalidArgumentException If the argument is not a configset. - * @return self */ - public function setView(array $view) + public function setView(array $view): static { $this->view = $view; return $this; diff --git a/packages/admin/src/Charcoal/Admin/Decorator/GridStackWidgetDecorator.php b/packages/admin/src/Charcoal/Admin/Decorator/GridStackWidgetDecorator.php index c4b3860d1..f60fa0484 100644 --- a/packages/admin/src/Charcoal/Admin/Decorator/GridStackWidgetDecorator.php +++ b/packages/admin/src/Charcoal/Admin/Decorator/GridStackWidgetDecorator.php @@ -21,18 +21,12 @@ class GridStackWidgetDecorator */ protected $gridStack = []; - /** - * @var WidgetInterface - */ - protected $widget; - /** * GridStackWidgetDecorator constructor. * @param WidgetInterface $widget The widget to decorate. */ - public function __construct(WidgetInterface $widget) + public function __construct(protected \Charcoal\App\Template\WidgetInterface $widget) { - $this->widget = $widget; } /** @@ -60,10 +54,8 @@ public function gridStack() /** * The default Grid Stack dataset. - * - * @return array */ - private function defaultGridStack() + private function defaultGridStack(): array { return [ 'width' => self::GS_WIDTH, diff --git a/packages/admin/src/Charcoal/Admin/Docs/Template/Object/DocTemplate.php b/packages/admin/src/Charcoal/Admin/Docs/Template/Object/DocTemplate.php index a3f8bdee5..9d701d449 100644 --- a/packages/admin/src/Charcoal/Admin/Docs/Template/Object/DocTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Docs/Template/Object/DocTemplate.php @@ -22,12 +22,15 @@ class DocTemplate extends AdminTemplate implements use DashboardContainerTrait; use ObjectContainerTrait; + public $headerMenu; + /** * Retrieve the list of parameters to extract from the HTTP request. * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type' @@ -59,9 +62,10 @@ public function headerMenu() * * @return \Charcoal\Translator\Translation */ + #[\Override] public function title() { - if (isset($this->title)) { + if ($this->title !== null) { return $this->title; } @@ -81,10 +85,10 @@ public function title() $metadata = $obj->metadata(); $objLabel = null; - if (!$objLabel && isset($metadata['admin']['forms'])) { + if (isset($metadata['admin']['forms'])) { $adminMetadata = $metadata['admin']; - $formIdent = filter_input(INPUT_GET, 'form_ident', FILTER_SANITIZE_STRING); + $formIdent = htmlspecialchars(trim(($_GET['form_ident'] ?? '')), ENT_QUOTES, 'UTF-8'); if (!$formIdent) { if (isset($adminMetadata['defaultForm'])) { $fomIdent = $adminMetadata['defaultForm']; @@ -113,11 +117,7 @@ public function title() } } - if ($this->isObjRenderable($obj)) { - $this->title = $obj->render((string)$objLabel, $obj); - } else { - $this->title = (string)$objLabel; - } + $this->title = $this->isObjRenderable($obj) ? $obj->render((string)$objLabel, $obj) : (string)$objLabel; return $this->title; } @@ -126,6 +126,7 @@ public function title() * @param Container $container DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -147,13 +148,11 @@ protected function createDashboardConfig() $dashboardIdent = $this->dashboardIdent(); if (empty($dashboardIdent)) { - $dashboardIdent = filter_input(INPUT_GET, 'dashboard_ident', FILTER_SANITIZE_STRING); + $dashboardIdent = htmlspecialchars(trim(($_GET['dashboard_ident'] ?? '')), ENT_QUOTES, 'UTF-8'); } - if (empty($dashboardIdent)) { - if (isset($adminMetadata['default_doc_dashboard'])) { - $dashboardIdent = $adminMetadata['default_doc_dashboard']; - } + if (empty($dashboardIdent) && isset($adminMetadata['default_doc_dashboard'])) { + $dashboardIdent = $adminMetadata['default_doc_dashboard']; } $overrideType = false; @@ -162,7 +161,7 @@ protected function createDashboardConfig() if (!isset($adminMetadata['default_edit_dashboard'])) { throw new Exception(sprintf( 'No default doc dashboard defined in admin metadata for %s', - get_class($this->obj()) + $this->obj()::class )); } $overrideType = true; @@ -199,11 +198,11 @@ protected function objAdminMetadata() $objMetadata = $obj->metadata(); - $adminMetadata = isset($objMetadata['admin']) ? $objMetadata['admin'] : null; + $adminMetadata = ($objMetadata['admin'] ?? null); if ($adminMetadata === null) { throw new Exception(sprintf( 'The object %s does not have an admin metadata.', - get_class($obj) + $obj::class )); } diff --git a/packages/admin/src/Charcoal/Admin/Docs/Widget/DocFormPropertyWidget.php b/packages/admin/src/Charcoal/Admin/Docs/Widget/DocFormPropertyWidget.php index 18fc3ab6e..30f2efcd7 100644 --- a/packages/admin/src/Charcoal/Admin/Docs/Widget/DocFormPropertyWidget.php +++ b/packages/admin/src/Charcoal/Admin/Docs/Widget/DocFormPropertyWidget.php @@ -19,12 +19,9 @@ class DocFormPropertyWidget extends FormPropertyWidget */ protected $displayOptions; - /** - * @return boolean - */ - public function hasExtraData() + public function hasExtraData(): bool { - return !!count($this->extraData()); + return (bool)count($this->extraData()); } /** @@ -34,7 +31,7 @@ public function collapsible() { $displayOps = $this->displayOptions(); - return isset($displayOps['collapsible']) ? $displayOps['collapsible'] : false; + return ($displayOps['collapsible'] ?? false); } /** @@ -44,7 +41,7 @@ public function collapsed() { $displayOps = $this->displayOptions(); - return isset($displayOps['collapsed']) ? $displayOps['collapsed'] : false; + return ($displayOps['collapsed'] ?? false); } /** @@ -54,7 +51,7 @@ public function parented() { $displayOps = $this->displayOptions(); - return isset($displayOps['parented']) ? $displayOps['parented'] : false; + return ($displayOps['parented'] ?? false); } /** @@ -64,34 +61,25 @@ public function typeDescription() { $type = $this->prop()->type(); - switch ($type) { - case 'boolean': - return $this->translator()->translation(' + return match ($type) { + 'boolean' => $this->translator()->translation(' The field is a TRUE | FALSE statement - '); - case 'image': - case 'audio': - case 'file': - return $this->translator()->translation(' + '), + 'image', 'audio', 'file' => $this->translator()->translation(' The field will ask to upload a file using the file manager - '); - case 'string': - case 'text': - return $this->translator()->translation(' + '), + 'string', 'text' => $this->translator()->translation(' The field is a simple text input - '); - case 'object': - return $this->translator()->translation(' + '), + 'object' => $this->translator()->translation(' The field is a relation to another object in the back-end (ex: a category object) - '); - case 'date-time': - return $this->translator()->translation(' + '), + 'date-time' => $this->translator()->translation(' The field requires a date and will prompt a date picker
as an easy way to provide it in a supported format - '); - default: - return ''; - } + '), + default => '', + }; } /** @@ -99,7 +87,7 @@ public function typeDescription() */ public function extraData() { - if (isset($this->extraData)) { + if ($this->extraData !== null) { return $this->extraData; } @@ -147,9 +135,8 @@ public function displayOptions() /** * @param array|mixed $displayOptions The display options array. * @throws \InvalidArgumentException If argument is not of type "array". - * @return self */ - public function setDisplayOptions($displayOptions) + public function setDisplayOptions($displayOptions): static { if (!is_array($displayOptions)) { throw new \InvalidArgumentException('display_options should be of type array'); diff --git a/packages/admin/src/Charcoal/Admin/Docs/Widget/FormGroup/DocFormGroup.php b/packages/admin/src/Charcoal/Admin/Docs/Widget/FormGroup/DocFormGroup.php index a21352a26..151d94264 100644 --- a/packages/admin/src/Charcoal/Admin/Docs/Widget/FormGroup/DocFormGroup.php +++ b/packages/admin/src/Charcoal/Admin/Docs/Widget/FormGroup/DocFormGroup.php @@ -1,5 +1,7 @@ description() || $this->notes() || count($this->groupProperties())) { - return false; - } - - return true; + return !($this->description() || $this->notes() || count($this->groupProperties())); } } diff --git a/packages/admin/src/Charcoal/Admin/Mustache/AssetsHelpers.php b/packages/admin/src/Charcoal/Admin/Mustache/AssetsHelpers.php index 21e8ef86a..ad33af132 100644 --- a/packages/admin/src/Charcoal/Admin/Mustache/AssetsHelpers.php +++ b/packages/admin/src/Charcoal/Admin/Mustache/AssetsHelpers.php @@ -7,7 +7,7 @@ use Assetic\Asset\AssetReference; use Assetic\Asset\StringAsset; use Assetic\AssetManager; -use Mustache_LambdaHelper as LambdaHelper; +use Mustache\LambdaHelper as LambdaHelper; // From charcoal-view use Charcoal\View\Mustache\HelpersInterface; @@ -19,27 +19,18 @@ class AssetsHelpers implements HelpersInterface /** * @var AssetManager|mixed $assets The assetic assets manager. */ - private $assets; + private ?\Assetic\AssetManager $assets = null; - /** - * @var string $action - */ - private $action; + private ?string $action = null; - /** - * @var string $collection - */ - private $collection; + private ?string $collection = null; - /** - * @var string $ident - */ - private $ident; + private ?string $ident = null; /** * @param array $data Class Dependencies. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { if (isset($data['assets']) && $data['assets'] instanceof AssetManager) { $this->assets = $data['assets']; @@ -48,8 +39,6 @@ public function __construct(array $data = null) /** * Get the collection of helpers as a plain array. - * - * @return array */ public function toArray(): array { @@ -80,17 +69,21 @@ protected function reset() * @param LambdaHelper|null $helper For rendering strings in the current context. * @return string */ - public function __invoke($text = null, LambdaHelper $helper = null) + public function __invoke($text = null, ?LambdaHelper $helper = null) { - if ($helper) { + if ($helper instanceof LambdaHelper) { $text = $helper->render($text); } + if ($this->action === null) { + return $text; + } + $return = $this->{$this->action}($this->collection, $text); $text = $return; $this->reset(); - if ($helper) { + if ($helper instanceof LambdaHelper) { return $helper->render($text); } @@ -105,7 +98,7 @@ public function __invoke($text = null, LambdaHelper $helper = null) * @param string $macro A domain, locale, or number. * @return boolean */ - public function __isset($macro) + public function __isset(string $macro) { return boolval($macro); } @@ -116,9 +109,8 @@ public function __isset($macro) * Required by Mustache. * * @param string $macro A domain, locale, or number. - * @return mixed */ - public function __get($macro) + public function __get(string $macro): mixed { if (!$this->action) { $macro = '__' . $macro; @@ -154,7 +146,7 @@ public function __get($macro) * @param string $text Asset string to inject. * @return string */ - protected function __inject($collection, $text) + protected function __inject($collection, $text): null { if (!$this->assets->has($collection)) { $this->assets->set($collection, new AssetCollection()); @@ -180,9 +172,8 @@ protected function __enqueue($collection) /** * @param string $collection The collection ident. - * @return string */ - protected function __output($collection) + protected function __output($collection): string { $dump = $this->assets->get($collection)->dump(); return '{{=<<<<% %>>>>=}}' . $dump . '<<<<%={{ }}=%>>>>'; diff --git a/packages/admin/src/Charcoal/Admin/Object/Notification.php b/packages/admin/src/Charcoal/Admin/Object/Notification.php index aa1da3ffb..a35ad7d44 100644 --- a/packages/admin/src/Charcoal/Admin/Object/Notification.php +++ b/packages/admin/src/Charcoal/Admin/Object/Notification.php @@ -1,5 +1,7 @@ users = []; @@ -58,14 +56,11 @@ public function setUsers($users) 'Users must be an array or a comma-separated string.' ); } - $this->users = array_map('trim', $users); + $this->users = array_map(trim(...), $users); return $this; } - /** - * @return array - */ - public function users() + public function users(): array { return $this->users; } @@ -75,7 +70,7 @@ public function users() * @throws InvalidArgumentException If the types are not an array or a comma-separated string. * @return Notification Chainable */ - public function setTargetTypes($targetTypes) + public function setTargetTypes($targetTypes): static { if ($targetTypes === null) { $this->targetTypes = null; @@ -89,14 +84,11 @@ public function setTargetTypes($targetTypes) 'Object types must be an array or a comma-separated string.' ); } - $this->targetTypes = array_map('trim', $targetTypes); + $this->targetTypes = array_map(trim(...), $targetTypes); return $this; } - /** - * @return array|null - */ - public function targetTypes() + public function targetTypes(): ?array { return $this->targetTypes; } @@ -106,7 +98,7 @@ public function targetTypes() * @throws InvalidArgumentException If the emails are not an array or a comma-separated string. * @return Notification Chainable */ - public function setExtraEmails($extraEmails) + public function setExtraEmails($extraEmails): static { if ($extraEmails === null) { $this->extraEmails = []; @@ -120,14 +112,11 @@ public function setExtraEmails($extraEmails) 'Extra emails must be an array or a comma-separated string.' ); } - $this->extraEmails = array_map('trim', $extraEmails); + $this->extraEmails = array_map(trim(...), $extraEmails); return $this; } - /** - * @return array|null - */ - public function extraEmails() + public function extraEmails(): array { return $this->extraEmails; } @@ -137,7 +126,7 @@ public function extraEmails() * @throws InvalidArgumentException If the frequency is not a valid mode. * @return Notification Chainable */ - public function setFrequency($frequency) + public function setFrequency($frequency): static { if ($frequency === null) { $this->frequency = null; @@ -162,7 +151,7 @@ public function setFrequency($frequency) /** * @return boolean */ - public function frequency() + public function frequency(): ?string { return $this->frequency; } @@ -171,16 +160,13 @@ public function frequency() * @param boolean $active The active flag. * @return Notification Chainable */ - public function setActive($active) + public function setActive($active): static { - $this->active = !!$active; + $this->active = (bool)$active; return $this; } - /** - * @return boolean - */ - public function active() + public function active(): bool { return $this->active; } diff --git a/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php b/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php index 2b03c9f7d..c685e86de 100644 --- a/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php +++ b/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php @@ -32,6 +32,7 @@ /** * Base Admin model property decorator */ +#[\AllowDynamicProperties] abstract class AbstractProperty implements AdminPropertyInterface, DescribableInterface, @@ -51,6 +52,8 @@ abstract class AbstractProperty implements */ private $property; + protected $inputName; + /** * @var array $propertyData */ @@ -371,9 +374,7 @@ public function parseEscapeOptions($escape) */ protected function wrapEscapeFunction(callable $callback) { - return function ($value) use ($callback) { - return call_user_func_array($callback, func_get_args()); - }; + return fn($value): mixed => call_user_func_array($callback, func_get_args()); } /** @@ -385,19 +386,17 @@ protected function wrapEscapeFunction(callable $callback) */ protected function assertValidEscapeFunction($escape) { - if (is_string($escape)) { - if (!function_exists($escape)) { - throw new InvalidArgumentException(sprintf( - 'Undefined escape function named "%s"', - $escape - )); - } + if (is_string($escape) && !function_exists($escape)) { + throw new InvalidArgumentException(sprintf( + 'Undefined escape function named "%s"', + $escape + )); } if (!is_callable($escape)) { throw new InvalidArgumentException(sprintf( 'Expected escape function name or function expression, received "%s"', - is_object($escape) ? get_class($escape) : gettype($escape) + get_debug_type($escape) )); } } @@ -420,7 +419,7 @@ public function getDefaultEscapeOptions() */ public function setMultiple($multiple) { - $this->multiple = !!$multiple; + $this->multiple = (bool)$multiple; return $this; } @@ -449,13 +448,11 @@ public function renderTranslatableTemplate($templateString) continue; } $translation = $templateString[$lang]; - $isBlank = empty($translation) && !is_numeric($translation); + $isBlank = ($translation === '' || $translation === '0') && !is_numeric($translation); if (!$isBlank) { $this->translator()->setLocale($lang); $translation = $this->renderTemplate($translation); - if ($translation !== null) { - $templateString[$lang] = $translation; - } + $templateString[$lang] = $translation; } } $this->translator()->setLocale($origLang); @@ -463,7 +460,7 @@ public function renderTranslatableTemplate($templateString) return $templateString; } elseif (is_string($templateString)) { - $isBlank = empty($templateString) && !is_numeric($templateString); + $isBlank = ($templateString === '' || $templateString === '0') && !is_numeric($templateString); if (!$isBlank) { return $this->renderTemplate($templateString); } @@ -495,7 +492,7 @@ protected function isObjRenderable($obj, $toString = false) return false; } - $key = get_class($obj); + $key = $obj::class; if (isset(static::$objRenderableCache[$key])) { return static::$objRenderableCache[$key]; @@ -542,7 +539,7 @@ protected function setDependencies(Container $container) * @param array $data Optional metadata to merge on the object. * @return PropertyMetadata */ - protected function createMetadata(array $data = null) + protected function createMetadata(?array $data = null) { $class = $this->metadataClass(); return new $class($data); @@ -576,7 +573,7 @@ protected function getter($key) * @param string $key The key to get the setter from. * @return string The setter method name, for a given key. */ - protected function setter($key) + protected function setter(string $key) { $setter = 'set_' . $key; return $this->camelize($setter); @@ -588,8 +585,8 @@ protected function setter($key) * @param string $str The snake_case string to camelize. * @return string The camelCase string. */ - private function camelize($str) + private function camelize($str): string { - return lcfirst(implode('', array_map('ucfirst', explode('_', $str)))); + return lcfirst(implode('', array_map(ucfirst(...), explode('_', $str)))); } } diff --git a/packages/admin/src/Charcoal/Admin/Property/AbstractPropertyDisplay.php b/packages/admin/src/Charcoal/Admin/Property/AbstractPropertyDisplay.php index 886255d5c..2b84786f3 100644 --- a/packages/admin/src/Charcoal/Admin/Property/AbstractPropertyDisplay.php +++ b/packages/admin/src/Charcoal/Admin/Property/AbstractPropertyDisplay.php @@ -56,6 +56,7 @@ abstract class AbstractPropertyDisplay extends AbstractProperty implements * @param PropertyInterface $property The property. * @return self */ + #[\Override] public function setProperty(PropertyInterface $property) { parent::setProperty($property); @@ -165,11 +166,7 @@ public function setDisplayName($displayName) */ public function displayName() { - if ($this->displayName) { - $name = $this->displayName; - } else { - $name = $this->propertyIdent(); - } + $name = $this->displayName ?: $this->propertyIdent(); if ($this->p()['l10n']) { $name .= '[' . $this->lang() . ']'; @@ -206,11 +203,7 @@ public function getDisplayOption($key, $default = null) { $options = $this->getDisplayOptions(); - if (isset($options[$key])) { - return $options[$key]; - } - - return $default; + return ($options[$key] ?? $default); } /** @@ -291,6 +284,7 @@ public function getDisplayEscapeOptions() * @throws InvalidArgumentException If the value to escape is not a string. * @return string */ + #[\Override] public function escapeVal($val, array $options = []) { if (!is_string($val)) { @@ -342,7 +336,7 @@ public function displayVal() if (!is_scalar($val)) { throw new UnexpectedValueException(sprintf( 'Property Display Value must be a string, received %s', - (is_object($val) ? get_class($val) : gettype($val)) + (get_debug_type($val)) )); } diff --git a/packages/admin/src/Charcoal/Admin/Property/AbstractPropertyInput.php b/packages/admin/src/Charcoal/Admin/Property/AbstractPropertyInput.php index cc220d2d8..a44274f81 100644 --- a/packages/admin/src/Charcoal/Admin/Property/AbstractPropertyInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/AbstractPropertyInput.php @@ -97,6 +97,7 @@ abstract class AbstractPropertyInput extends AbstractProperty implements * @param PropertyInterface $property The property. * @return self */ + #[\Override] public function setProperty(PropertyInterface $property) { parent::setProperty($property); @@ -212,11 +213,7 @@ public function setInputName($inputName) */ public function inputName() { - if ($this->inputName) { - $name = $this->inputName; - } else { - $name = $this->propertyIdent(); - } + $name = $this->inputName ?: $this->propertyIdent(); if ($this->p()['l10n']) { $name .= '[' . $this->lang() . ']'; @@ -253,11 +250,7 @@ public function getInputOption($key, $default = null) { $options = $this->getInputOptions(); - if (isset($options[$key])) { - return $options[$key]; - } - - return $default; + return ($options[$key] ?? $default); } /** @@ -342,6 +335,7 @@ public function getInputEscapeOptions() * @throws InvalidArgumentException If the value to escape is not a string. * @return string */ + #[\Override] public function escapeVal($val, array $options = []) { if (!is_string($val)) { @@ -379,8 +373,6 @@ public function escapeVal($val, array $options = []) /** * Overridable. * Makes it easier to pass InputVal options from children input types. - * - * @return array **/ public function getInputValOptions(): array { @@ -409,7 +401,7 @@ public function inputVal() if (!is_scalar($val)) { throw new UnexpectedValueException(sprintf( 'Property Input Value must be a string, received %s', - (is_object($val) ? get_class($val) : gettype($val)) + (get_debug_type($val)) )); } @@ -510,7 +502,7 @@ public function hasInputPrefix() public function inputPrefix() { if ($this->inputPrefix instanceof Translation) { - if (isset($this->inputPrefix->isRendered) && $this->inputPrefix->isRendered === false) { + if (property_exists($this->inputPrefix, 'isRendered') && $this->inputPrefix->isRendered !== null && $this->inputPrefix->isRendered === false) { $this->inputPrefix = $this->renderTranslatableTemplate($this->inputPrefix); } @@ -561,7 +553,7 @@ public function hasInputSuffix() public function inputSuffix() { if ($this->inputSuffix instanceof Translation) { - if (isset($this->inputSuffix->isRendered) && $this->inputSuffix->isRendered === false) { + if (property_exists($this->inputSuffix, 'isRendered') && $this->inputSuffix->isRendered !== null && $this->inputSuffix->isRendered === false) { $this->inputSuffix = $this->renderTranslatableTemplate($this->inputSuffix); } @@ -578,13 +570,7 @@ public function inputSuffix() */ public function hidden() { - if ($this->p()['l10n']) { - if ($this->lang() != $this->translator()->getLocale()) { - return true; - } - } - - return false; + return $this->p()['l10n'] && $this->lang() != $this->translator()->getLocale(); } /** @@ -593,7 +579,7 @@ public function hidden() */ public function setReadOnly($readOnly) { - $this->readOnly = !!$readOnly; + $this->readOnly = (bool)$readOnly; return $this; } @@ -611,7 +597,7 @@ public function readOnly() */ public function setRequired($required) { - $this->required = !!$required; + $this->required = (bool)$required; return $this; } @@ -629,7 +615,7 @@ public function required() */ public function setDisabled($disabled) { - $this->disabled = !!$disabled; + $this->disabled = (bool)$disabled; return $this; } @@ -689,7 +675,7 @@ public function placeholder() } if ($this->placeholder instanceof Translation) { - if (isset($this->placeholder->isRendered) && $this->placeholder->isRendered === false) { + if (property_exists($this->placeholder, 'isRendered') && $this->placeholder->isRendered !== null && $this->placeholder->isRendered === false) { $this->placeholder = $this->renderTranslatableTemplate($this->placeholder); } @@ -721,7 +707,7 @@ final public function controlDataForJsAsJson() $options = (JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); if ($this->debug()) { - $options = ($options | JSON_PRETTY_PRINT); + $options |= JSON_PRETTY_PRINT; } return json_encode($this->controlDataForJs(), $options); diff --git a/packages/admin/src/Charcoal/Admin/Property/AbstractSelectableInput.php b/packages/admin/src/Charcoal/Admin/Property/AbstractSelectableInput.php index 97ed1631b..dfd202bd2 100644 --- a/packages/admin/src/Charcoal/Admin/Property/AbstractSelectableInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/AbstractSelectableInput.php @@ -140,7 +140,7 @@ public function parsedVal() // Doing this in the parseVal method of abstract property // was causing multiple && l10n properties not to save. if (!is_array($val) && $this->p()['multiple']) { - $val = explode($this->p()->multipleSeparator(), $val); + $val = explode($this->p()->multipleSeparator(), (string)$val); } $this->parsedVal[$this->lang()] = $val; @@ -196,7 +196,7 @@ public function setEmptyChoice($choice) } else { throw new InvalidArgumentException(sprintf( 'Empty choice must be an array, received %s', - (is_object($choice) ? get_class($choice) : gettype($choice)) + (get_debug_type($choice)) )); } @@ -256,7 +256,7 @@ protected function renderChoiceObjMap($obj, $prop) return ''; } - if (strpos($prop, '{{') === false) { + if (!str_contains($prop, '{{')) { if (isset($obj[$prop])) { return $this->parseChoiceVal($obj[$prop]); } @@ -268,7 +268,7 @@ protected function renderChoiceObjMap($obj, $prop) return $obj->renderTemplate($prop); } else { $callback = function ($matches) use ($obj) { - $prop = trim($matches[1]); + $prop = trim((string)$matches[1]); if (isset($obj[$prop])) { return $this->parseChoiceVal($obj[$prop]); } @@ -341,7 +341,7 @@ public function choiceObjMap() public function inputNameFallback() { $name = $this->inputName(); - if (substr($name, -2, 2) === '[]') { + if (str_ends_with($name, '[]')) { return substr($name, 0, -2); } diff --git a/packages/admin/src/Charcoal/Admin/Property/AbstractTickableInput.php b/packages/admin/src/Charcoal/Admin/Property/AbstractTickableInput.php index 99c90a766..7a0bbca7c 100644 --- a/packages/admin/src/Charcoal/Admin/Property/AbstractTickableInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/AbstractTickableInput.php @@ -18,10 +18,8 @@ abstract class AbstractTickableInput extends AbstractSelectableInput /** * How radio controls should be displayed. - * - * @var string|null */ - private $inputLayout; + private ?string $inputLayout = null; /** * Prepare a single tickable option for output. @@ -30,6 +28,7 @@ abstract class AbstractTickableInput extends AbstractSelectableInput * @param array|object $choice The choice structure. * @return array|null */ + #[\Override] protected function parseChoice($ident, $choice) { $choice = parent::parseChoice($ident, $choice); @@ -63,7 +62,7 @@ public function setInputLayout($layout) if (!is_string($layout)) { throw new InvalidArgumentException(sprintf( 'Layout must be a string, received %s', - (is_object($layout) ? get_class($layout) : gettype($layout)) + (get_debug_type($layout)) )); } diff --git a/packages/admin/src/Charcoal/Admin/Property/Display/BooleanDisplay.php b/packages/admin/src/Charcoal/Admin/Property/Display/BooleanDisplay.php index 50b93c8df..ce09a3910 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Display/BooleanDisplay.php +++ b/packages/admin/src/Charcoal/Admin/Property/Display/BooleanDisplay.php @@ -1,5 +1,7 @@ '', @@ -91,6 +92,7 @@ protected function defaultEmptyChoice() * * @return string */ + #[\Override] public function displayVal() { $prop = $this->p(); diff --git a/packages/admin/src/Charcoal/Admin/Property/Display/ColorSwatchDisplay.php b/packages/admin/src/Charcoal/Admin/Property/Display/ColorSwatchDisplay.php index da3ae4cbf..2cd596706 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Display/ColorSwatchDisplay.php +++ b/packages/admin/src/Charcoal/Admin/Property/Display/ColorSwatchDisplay.php @@ -1,5 +1,7 @@ p(); $pad = str_repeat($this->indentation(), ($this->currentLevel() - 1)); @@ -51,7 +45,7 @@ public function displayVal() * @throws InvalidArgumentException If the indentation is not a string. * @return AbstractConfig Chainable */ - public function setIndentation($indent) + public function setIndentation($indent): static { if (!is_string($indent)) { throw new InvalidArgumentException( @@ -66,10 +60,8 @@ public function setIndentation($indent) /** * Retrieve the indentation string. - * - * @return integer */ - public function indentation() + public function indentation(): string { return $this->indentation; } @@ -81,9 +73,8 @@ public function indentation() * * @param integer $level The level of depth. * @throws InvalidArgumentException If the level is not an integer. - * @return self */ - public function setCurrentLevel($level) + public function setCurrentLevel($level): static { if (!is_int($level)) { throw new InvalidArgumentException( @@ -98,10 +89,8 @@ public function setCurrentLevel($level) /** * Retrieve the current level for output of the associated object. - * - * @return integer */ - public function currentLevel() + public function currentLevel(): int { return $this->currentLevel; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Display/ImageDisplay.php b/packages/admin/src/Charcoal/Admin/Property/Display/ImageDisplay.php index 0af14cadf..7317077f7 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Display/ImageDisplay.php +++ b/packages/admin/src/Charcoal/Admin/Property/Display/ImageDisplay.php @@ -28,6 +28,7 @@ class ImageDisplay extends AbstractPropertyDisplay * @see \Charcoal\Admin\Property\Display\LinkDisplay::hrefVal() * @return string */ + #[\Override] public function displayVal() { $val = parent::displayVal(); @@ -38,8 +39,8 @@ public function displayVal() $parts = parse_url($val); if (empty($parts['scheme']) && !in_array($val[0], [ '/', '#', '?' ])) { $path = isset($parts['path']) ? ltrim($parts['path'], '/') : ''; - $query = isset($parts['query']) ? $parts['query'] : ''; - $hash = isset($parts['fragment']) ? $parts['fragment'] : ''; + $query = ($parts['query'] ?? ''); + $hash = ($parts['fragment'] ?? ''); $val = $this->baseUrl->withPath($path)->withQuery($query)->withFragment($hash); } @@ -52,6 +53,7 @@ public function displayVal() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Property/Display/LinkDisplay.php b/packages/admin/src/Charcoal/Admin/Property/Display/LinkDisplay.php index 38d1a07a4..7898dc034 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Display/LinkDisplay.php +++ b/packages/admin/src/Charcoal/Admin/Property/Display/LinkDisplay.php @@ -29,6 +29,7 @@ class LinkDisplay extends AbstractPropertyDisplay /** * @return string */ + #[\Override] public function displayVal() { $prop = $this->property(); @@ -86,9 +87,8 @@ public function displayValList() * * @param string $url The link URL. * @param string $text The link text. - * @return string */ - protected function formatHtmlLink($url, $text = null) + protected function formatHtmlLink($url, $text = null): string { if ($text === null) { $text = $url; @@ -99,13 +99,11 @@ protected function formatHtmlLink($url, $text = null) $text = $format($text); } - $link = sprintf( + return sprintf( '%s', $this->getLocalUrl($url), $text ); - - return $link; } /** @@ -117,14 +115,12 @@ protected function formatHtmlLink($url, $text = null) protected function getLocalUrl($path) { $prop = $this->property(); - if ($prop instanceof FileProperty) { - if ($prop['publicAccess'] === false) { - $query = http_build_query([ - 'disk' => $prop['filesystem'], - 'path' => $path, - ]); - return $this->adminUrl('filesystem/download')->withQuery($query); - } + if ($prop instanceof FileProperty && $prop['publicAccess'] === false) { + $query = http_build_query([ + 'disk' => $prop['filesystem'], + 'path' => $path, + ]); + return $this->adminUrl('filesystem/download')->withQuery($query); } return $this->baseUrl($path); @@ -133,9 +129,8 @@ protected function getLocalUrl($path) /** * @param callable|string|null $format The link textt format. * @throws InvalidArgumentException If the format is not a valid callable. - * @return self */ - public function setLinkTextFormat($format) + public function setLinkTextFormat($format): static { if ($format !== null && !function_exists($format)) { throw new InvalidArgumentException( @@ -161,6 +156,7 @@ public function getLinkTextFormat() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Property/Display/MessageDisplay.php b/packages/admin/src/Charcoal/Admin/Property/Display/MessageDisplay.php index 2954d1480..3999a0c62 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Display/MessageDisplay.php +++ b/packages/admin/src/Charcoal/Admin/Property/Display/MessageDisplay.php @@ -44,9 +44,8 @@ class MessageDisplay extends AbstractPropertyDisplay implements /** * @param mixed $message The message to display. - * @return self */ - public function setMessage($message) + public function setMessage($message): static { $this->message = $this->translator()->translation($message); if ($this->message instanceof Translation) { @@ -56,12 +55,9 @@ public function setMessage($message) return $this; } - /** - * @return bool - */ - public function hasMessage() + public function hasMessage(): bool { - return !!$this->message; + return (bool)$this->message; } /** @@ -78,7 +74,7 @@ public function getMessage() public function displayMessage() { if ($this->message instanceof Translation) { - if (isset($this->message->isRendered) && $this->message->isRendered === false) { + if (property_exists($this->message, 'isRendered') && $this->message->isRendered !== null && $this->message->isRendered === false) { $this->message = $this->renderTranslatableTemplate($this->message); } diff --git a/packages/admin/src/Charcoal/Admin/Property/Display/ObjectDisplay.php b/packages/admin/src/Charcoal/Admin/Property/Display/ObjectDisplay.php index f8609270e..91aa8e0d6 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Display/ObjectDisplay.php +++ b/packages/admin/src/Charcoal/Admin/Property/Display/ObjectDisplay.php @@ -1,5 +1,7 @@ propertyVal() ? static::STATE_SUCCESS : static::STATE_DEFAULT; + return $this->propertyVal() ? static::STATE_SUCCESS : static::STATE_DEFAULT; } /** @@ -88,7 +89,7 @@ private function fallbackStatus() * @throws UnexpectedValueException When an unsupported operator is used. * @return boolean */ - private function testConditionWithOperator($condition) + private function testConditionWithOperator($condition): ?bool { $value = $condition; $operator = null; @@ -101,7 +102,7 @@ private function testConditionWithOperator($condition) throw new UnexpectedValueException(sprintf( 'The operator [%s] is not supported in [%s]', $operator, - get_class($this) + static::class )); } @@ -139,13 +140,12 @@ private function calculateState() if (is_array($state)) { foreach ($state as $stateIdent => $conditions) { - $result = is_string($conditions) ? - $result = $this->testConditionWithOperator($conditions) : false; + $result = is_string($conditions) && $result = $this->testConditionWithOperator($conditions); $result = !$result && is_array($conditions) ? - !!count(array_filter($conditions, [$this, 'testConditionWithOperator'])) : $result; + (bool)count(array_filter($conditions, $this->testConditionWithOperator(...))) : $result; - if (!!$result && in_array($stateIdent, static::SUPPORTED_STATES)) { + if ($result && in_array($stateIdent, static::SUPPORTED_STATES)) { return $stateIdent; } }; @@ -177,9 +177,8 @@ public function state() /** * @param array|callable $state State for StatusDisplay. - * @return self */ - public function setState($state) + public function setState($state): static { $this->state = $state; diff --git a/packages/admin/src/Charcoal/Admin/Property/Display/TextDisplay.php b/packages/admin/src/Charcoal/Admin/Property/Display/TextDisplay.php index 874ef842e..8cb2ae448 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Display/TextDisplay.php +++ b/packages/admin/src/Charcoal/Admin/Property/Display/TextDisplay.php @@ -1,5 +1,7 @@ objId = $objId; diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/AudioInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/AudioInput.php index df44ac2e0..06f9ef30c 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/AudioInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/AudioInput.php @@ -12,18 +12,15 @@ class AudioInput extends FileInput { /** * Retrieve list of default file type specifiers. - * - * @return string */ - public function getDefaultAccept() + #[\Override] + public function getDefaultAccept(): string { return 'audio/*'; } - /** - * @return string|null - */ - public function filePreview() + #[\Override] + public function filePreview(): string { $value = $this->inputVal(); if ($value) { diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/AudioWidgetInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/AudioWidgetInput.php index 7974d7e69..ac8dc5a03 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/AudioWidgetInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/AudioWidgetInput.php @@ -2,10 +2,11 @@ namespace Charcoal\Admin\Property\Input; +use Aws\signer\signerClient; use InvalidArgumentException; use UnexpectedValueException; // From Mustache -use Mustache_LambdaHelper as LambdaHelper; +use Mustache\LambdaHelper as LambdaHelper; // From 'charcoal-view' use Charcoal\View\ViewableInterface; // From 'charcoal-property' @@ -24,24 +25,18 @@ class AudioWidgetInput extends AudioInput /** * Whether text-to-speech is enabled. - * - * @var boolean */ - private $textEnabled = true; + private bool $textEnabled = true; /** * Whether audio recording is enabled. - * - * @var boolean */ - private $captureEnabled = true; + private bool $captureEnabled = true; /** * Whether file upload is enabled. - * - * @var boolean */ - private $uploadEnabled = true; + private bool $uploadEnabled = true; /** * URL for the "audio recorder" plugin. @@ -59,10 +54,8 @@ class AudioWidgetInput extends AudioInput /** * The text property for TTS. - * - * @var PropertyInterface */ - private $textProperty; + private ?\Charcoal\Property\PropertyInterface $textProperty = null; /** * The HTML input name attribute for TTS. @@ -87,125 +80,98 @@ class AudioWidgetInput extends AudioInput /** * Retrieve the control type for the HTML element ``. - * - * @return string */ - public function type() + #[\Override] + public function type(): string { return 'hidden'; } - /** - * @return boolean - */ - public function displayAudioWidget() + public function displayAudioWidget(): bool { return $this->textEnabled() || $this->captureEnabled() || $this->uploadEnabled(); } /** * @param boolean $textEnabled If TTS is enabled or not for this widget. - * @return self */ - public function setTextEnabled($textEnabled) + public function setTextEnabled($textEnabled): static { - $this->textEnabled = !!$textEnabled; + $this->textEnabled = (bool)$textEnabled; return $this; } - /** - * @return boolean - */ - public function textEnabled() + public function textEnabled(): bool { return $this->textEnabled; } /** * @param boolean $captureEnabled If recording is enabled or not for this widget. - * @return self */ - public function setCaptureEnabled($captureEnabled) + public function setCaptureEnabled($captureEnabled): static { - $this->captureEnabled = !!$captureEnabled; + $this->captureEnabled = (bool)$captureEnabled; return $this; } - /** - * @return boolean - */ - public function captureEnabled() + public function captureEnabled(): bool { return $this->captureEnabled; } /** - * @deprecated In favour of {@see self::setCaptureEnabled()} * * @param boolean $recordingEnabled If recording is enabled or not for this widget. - * @return self */ - public function setRecordingEnabled($recordingEnabled) + #[\Deprecated(message: 'In favour of {@see self::setCaptureEnabled()}')] + public function setRecordingEnabled($recordingEnabled): static { - $this->captureEnabled = !!$recordingEnabled; + $this->captureEnabled = (bool)$recordingEnabled; return $this; } - /** - * @deprecated In favour of {@see self::captureEnabled()} - * - * @return boolean - */ - public function recordingEnabled() + #[\Deprecated(message: 'In favour of {@see self::captureEnabled()}')] + public function recordingEnabled(): bool { return $this->captureEnabled; } /** * @param boolean $uploadEnabled If file upload is enabled or not for this widget. - * @return self */ - public function setUploadEnabled($uploadEnabled) + public function setUploadEnabled($uploadEnabled): static { - $this->uploadEnabled = !!$uploadEnabled; + $this->uploadEnabled = (bool)$uploadEnabled; return $this; } - /** - * @return boolean - */ - public function uploadEnabled() + public function uploadEnabled(): bool { return $this->uploadEnabled; } /** - * @deprecated In favour of {@see self::setUploadEnabled()} * * @param boolean $fileEnabled If file upload is enabled or not for this widget. - * @return self */ - public function setFileEnabled($fileEnabled) + #[\Deprecated(message: 'In favour of {@see self::setUploadEnabled()}')] + public function setFileEnabled($fileEnabled): static { - $this->uploadEnabled = !!$fileEnabled; + $this->uploadEnabled = (bool)$fileEnabled; return $this; } - /** - * @deprecated In favour of {@see self::uploadEnabled()} - * - * @return boolean - */ - public function fileEnabled() + #[\Deprecated(message: 'In favour of {@see self::uploadEnabled()}')] + public function fileEnabled(): bool { return $this->uploadEnabled; } /** * @param string $url The recording/exporting plugin URL. - * @return self */ - public function setRecorderPluginUrl($url) + public function setRecorderPluginUrl($url): static { $this->recorderPluginUrl = $url; return $this; @@ -238,7 +204,7 @@ public function prepareRecorderPluginUrl() { $uri = $this->getRecorderPluginUrlTemplate(); - return function ($noop, LambdaHelper $helper) use ($uri) { + return function ($noop, LambdaHelper $helper) use ($uri): null { $uri = $helper->render($uri); $this->setRecorderPluginUrl($uri); @@ -251,15 +217,12 @@ public function prepareRecorderPluginUrl() * * This method is overriden to change the `callback` value to reflect * the correct input control ID. - * - * @return string */ - protected function getRecorderPluginUrlTemplate() + protected function getRecorderPluginUrlTemplate(): string { $uri = 'assets/admin/scripts/vendors/recorderjs/recorder.js'; - $uri = '{{# withBaseUrl }}' . $uri . '{{/ withBaseUrl }}'; - return $uri; + return '{{# withBaseUrl }}' . $uri . '{{/ withBaseUrl }}'; } /** @@ -267,9 +230,8 @@ protected function getRecorderPluginUrlTemplate() * * @param string $activePane The active widget pane. * @throws InvalidArgumentException If the provided argument is not a string. - * @return self */ - public function setActivePane($activePane) + public function setActivePane($activePane): static { if ($activePane === null || $activePane === '') { $this->activePane = null; @@ -325,9 +287,8 @@ public function activePane() * Alias of {@see AbstractPropertyInput::setPropertyVal()}. * * @param mixed $val The audio property value. - * @return self */ - public function setAudioPropertyVal($val) + public function setAudioPropertyVal($val): static { $this->setPropertyVal($val); return $this; @@ -343,10 +304,7 @@ public function audioPropertyVal() return $this->propertyVal(); } - /** - * @return boolean - */ - public function hasAudioPropertyVal() + public function hasAudioPropertyVal(): bool { $prop = $this->audioProperty(); $val = $prop->inputVal($this->audioPropertyVal(), [ @@ -360,9 +318,8 @@ public function hasAudioPropertyVal() * Alias of {@see AbstractPropertyInput::setProperty()}. * * @param PropertyInterface $p The property for TTS. - * @return self */ - public function setAudioProperty(PropertyInterface $p) + public function setAudioProperty(PropertyInterface $p): static { $this->setProperty($p); return $this; @@ -392,9 +349,8 @@ public function audioPropertyIdent() * Alias of {@see AbstractPropertyInput::setInputName()}. * * @param string $inputName HTML input id attribute. - * @return self */ - public function setAudioInputName($inputName) + public function setAudioInputName($inputName): static { $this->setInputName($inputName); @@ -425,9 +381,8 @@ public function audioInputVal() * Set the property value for TTS. * * @param mixed $val The property value. - * @return self */ - public function setTextPropertyVal($val) + public function setTextPropertyVal($val): static { $this->textPropertyVal = $val; return $this; @@ -443,10 +398,7 @@ public function textPropertyVal() return $this->textPropertyVal; } - /** - * @return boolean - */ - public function hasTextPropertyVal() + public function hasTextPropertyVal(): bool { $prop = $this->textProperty(); $val = $prop->inputVal($this->textPropertyVal(), [ @@ -460,9 +412,8 @@ public function hasTextPropertyVal() * Set the property instance for TTS. * * @param PropertyInterface $p The property for TTS. - * @return self */ - public function setTextProperty(PropertyInterface $p) + public function setTextProperty(PropertyInterface $p): static { $this->textProperty = $p; return $this; @@ -473,7 +424,7 @@ public function setTextProperty(PropertyInterface $p) * * @return PropertyInterface */ - public function textProperty() + public function textProperty(): ?\Charcoal\Property\PropertyInterface { return $this->textProperty; } @@ -493,9 +444,8 @@ public function textPropertyIdent() * * @see AbstractPropertyInput::setInputName() * @param string $inputName HTML input name attribute. - * @return self */ - public function setTextInputName($inputName) + public function setTextInputName($inputName): static { $this->textInputName = $inputName; return $this; @@ -509,11 +459,7 @@ public function setTextInputName($inputName) */ public function textInputName() { - if ($this->textInputName) { - $name = $this->textInputName; - } else { - $name = $this->textPropertyIdent(); - } + $name = $this->textInputName ?: $this->textPropertyIdent(); if ($this->textProperty()['l10n']) { $name .= '[' . $this->lang() . ']'; @@ -529,7 +475,7 @@ public function textInputName() * @throws UnexpectedValueException If the value is invalid. * @return string */ - public function textInputVal() + public function textInputVal(): int|float|string|bool { $prop = $this->textProperty(); $val = $prop->inputVal($this->textPropertyVal(), [ @@ -543,7 +489,7 @@ public function textInputVal() if (!is_scalar($val)) { throw new UnexpectedValueException(sprintf( 'Property Input Value must be a string, received %s', - (is_object($val) ? get_class($val) : gettype($val)) + (get_debug_type($val)) )); } @@ -552,40 +498,32 @@ public function textInputVal() /** * Retrieve the input ID for the TTS property. - * - * @return string */ - public function textInputId() + public function textInputId(): string { return 'audio_text_' . $this->inputId(); } /** * Retrieve the input ID for the audio recorder property. - * - * @return string */ - public function captureInputId() + public function captureInputId(): string { return 'audio_capture_' . $this->inputId(); } /** * Retrieve the input ID for the audio file property. - * - * @return string */ - public function uploadInputId() + public function uploadInputId(): string { return 'audio_upload_' . $this->inputId(); } /** * Retrieve the input ID for the widget's hidden property. - * - * @return string */ - public function hiddenInputId() + public function hiddenInputId(): string { return 'audio_hidden_' . $this->inputId(); } @@ -595,7 +533,7 @@ public function hiddenInputId() * * @return callable|null */ - public function textPropertyContext() + public function textPropertyContext(): ?\Closure { if (!$this->textEnabled() || $this->currentContext) { return null; @@ -622,7 +560,7 @@ public function textPropertyContext() * * @return callable|null */ - public function capturePropertyContext() + public function capturePropertyContext(): ?\Closure { if (!$this->captureEnabled() || $this->currentContext) { return null; @@ -649,7 +587,7 @@ public function capturePropertyContext() * * @return callable|null */ - public function uploadPropertyContext() + public function uploadPropertyContext(): ?\Closure { if (!$this->uploadEnabled() || $this->currentContext) { return null; @@ -676,25 +614,22 @@ public function uploadPropertyContext() * * This method is overriden to change the `callback` value to reflect * the correct input control ID. - * - * @return string */ - protected function getFilePickerUrlTemplate() + #[\Override] + protected function getFilePickerUrlTemplate(): string { $uri = 'obj_type={{ objType }}&obj_id={{ objId }}&property={{ p.ident }}&callback={{ uploadInputId }}'; - $uri = '{{# withAdminUrl }}elfinder?' . $uri . '{{/ withAdminUrl }}'; - return $uri; + return '{{# withAdminUrl }}elfinder?' . $uri . '{{/ withAdminUrl }}'; } /** * Retrieve the control's data options for JavaScript components. - * - * @return array */ - public function controlDataForJs() + #[\Override] + public function controlDataForJs(): array { - $inputId = $this->inputId(); + $this->inputId(); $data = parent::controlDataForJs(); return array_replace($data, [ diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/CheckboxBtnGroupInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/CheckboxBtnGroupInput.php index 444ede0c4..5e4b69413 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/CheckboxBtnGroupInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/CheckboxBtnGroupInput.php @@ -1,5 +1,7 @@ `. - * - * @return string */ - public function type() + public function type(): string { return 'checkbox'; } /** * Always accept multiple values. - * - * @return boolean */ - public function multiple() + #[\Override] + public function multiple(): bool { return true; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/ColorPickerInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/ColorPickerInput.php index f268dc581..22bb2414c 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/ColorPickerInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/ColorPickerInput.php @@ -12,17 +12,13 @@ class ColorPickerInput extends AbstractPropertyInput { /** * Settings for {@link https://github.com/claviska/jquery-minicolors/ jQuery MiniColors}. - * - * @var array */ - private $pickerOptions; + private ?array $pickerOptions = null; /** * Retrieve the control type for the HTML element ``. - * - * @return string */ - public function type() + public function type(): string { return 'color'; } @@ -35,7 +31,7 @@ public function type() * @param array $settings The color picker options. * @return ColorpickerInput Chainable */ - public function setPickerOptions(array $settings) + public function setPickerOptions(array $settings): static { $this->pickerOptions = array_merge($this->defaultPickerOptions(), $settings); @@ -48,7 +44,7 @@ public function setPickerOptions(array $settings) * @param array $settings The color picker options. * @return ColorpickerInput Chainable */ - public function mergePickerOptions(array $settings) + public function mergePickerOptions(array $settings): static { $this->pickerOptions = array_merge($this->pickerOptions, $settings); @@ -63,7 +59,7 @@ public function mergePickerOptions(array $settings) * @throws InvalidArgumentException If the identifier is not a string. * @return ColorpickerInput Chainable */ - public function addPickerOption($key, $val) + public function addPickerOption($key, $val): static { if (!is_string($key)) { throw new InvalidArgumentException( @@ -83,10 +79,8 @@ public function addPickerOption($key, $val) /** * Retrieve the color picker's options. - * - * @return array */ - public function pickerOptions() + public function pickerOptions(): array { if ($this->pickerOptions === null) { $this->pickerOptions = $this->defaultPickerOptions(); @@ -97,10 +91,8 @@ public function pickerOptions() /** * Retrieve the default color picker options. - * - * @return array */ - public function defaultPickerOptions() + public function defaultPickerOptions(): array { return [ 'format' => 'hex', diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/DateTimePickerInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/DateTimePickerInput.php index 72650319a..0185af601 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/DateTimePickerInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/DateTimePickerInput.php @@ -19,17 +19,13 @@ class DateTimePickerInput extends AbstractPropertyInput /** * Settings for {@link https://eonasdan.github.io/bootstrap-datetimepicker/ Bootstrap Datepicker}. - * - * @var array */ - private $pickerOptions; + private ?array $pickerOptions = null; /** * Retrieve the control type for the HTML element ``. - * - * @return string */ - public function type() + public function type(): string { return 'datetime-local'; } @@ -37,9 +33,8 @@ public function type() /** * @param string $class The input group class attribute. * @throws InvalidArgumentException If the class is not a string. - * @return self */ - public function setInputGroupClass($class) + public function setInputGroupClass($class): static { if (!is_string($class)) { throw new InvalidArgumentException('CSS Class(es) must be a string'); @@ -64,7 +59,7 @@ public function inputGroupClass() * @param array $settings The color picker options. * @return ColorpickerInput Chainable */ - public function setPickerOptions(array $settings) + public function setPickerOptions(array $settings): static { $this->pickerOptions = array_merge($this->defaultPickerOptions(), $settings); @@ -77,7 +72,7 @@ public function setPickerOptions(array $settings) * @param array $settings The color picker options. * @return ColorpickerInput Chainable */ - public function mergePickerOptions(array $settings) + public function mergePickerOptions(array $settings): static { $this->pickerOptions = array_merge($this->pickerOptions, $settings); @@ -92,7 +87,7 @@ public function mergePickerOptions(array $settings) * @throws InvalidArgumentException If the identifier is not a string. * @return ColorpickerInput Chainable */ - public function addPickerOption($key, $val) + public function addPickerOption($key, $val): static { if (!is_string($key)) { throw new InvalidArgumentException( @@ -112,10 +107,8 @@ public function addPickerOption($key, $val) /** * Retrieve the color picker's options. - * - * @return array */ - public function pickerOptions() + public function pickerOptions(): array { if ($this->pickerOptions === null) { $this->pickerOptions = $this->defaultPickerOptions(); @@ -126,10 +119,8 @@ public function pickerOptions() /** * Retrieve the default color picker options. - * - * @return array */ - public function defaultPickerOptions() + public function defaultPickerOptions(): array { $date = null; @@ -139,7 +130,7 @@ public function defaultPickerOptions() return [ 'format' => self::DEFAULT_JS_FORMAT, - 'defaultDate' => $date ? $date->format(\DateTime::ISO8601) : null + 'defaultDate' => $date instanceof \DateTime ? $date->format(\DateTime::ISO8601) : null ]; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/DualSelectInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/DualSelectInput.php index 06847f268..a4a100c10 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/DualSelectInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/DualSelectInput.php @@ -23,10 +23,8 @@ class DualSelectInput extends AbstractSelectableInput /** * How the dual-select controls should be displayed. - * - * @var string|null */ - private $inputLayout; + private ?string $inputLayout = null; /** * Whether the lists can be filtered. @@ -44,10 +42,8 @@ class DualSelectInput extends AbstractSelectableInput /** * Settings for {@link http://crlcu.github.io/multiselect/ Multiselect}. - * - * @var array */ - private $dualSelectOptions; + private ?array $dualSelectOptions = null; /** * Retrieve the unselected options. @@ -123,11 +119,7 @@ public function searchable() $placeholder = $searchable['placeholder']; } - if (isset($placeholder)) { - $searchable[$ident]['placeholder'] = $this->translator()->translation($placeholder); - } else { - $searchable[$ident]['placeholder'] = $label; - } + $searchable[$ident]['placeholder'] = isset($placeholder) ? $this->translator()->translation($placeholder) : $label; } } else { $searchable = false; @@ -168,7 +160,7 @@ public function reorderable() * @throws OutOfBoundsException If the given layout is unsupported. * @return AbstractTickableInput Chainable */ - public function setInputLayout($layout) + public function setInputLayout($layout): static { if ($layout === null) { $this->inputLayout = null; @@ -179,7 +171,7 @@ public function setInputLayout($layout) if (!is_string($layout)) { throw new InvalidArgumentException(sprintf( 'Layout must be a string, received %s', - (is_object($layout) ? get_class($layout) : gettype($layout)) + (get_debug_type($layout)) )); } @@ -213,10 +205,8 @@ public function inputLayout() /** * Retrieve the input layouts; for templating. - * - * @return array */ - public function inputLayouts() + public function inputLayouts(): array { $supported = $this->supportedInputLayouts(); $layouts = []; @@ -229,10 +219,8 @@ public function inputLayouts() /** * Retrieve the supported input layouts. - * - * @return array */ - protected function supportedInputLayouts() + protected function supportedInputLayouts(): array { return [ self::COLS_INPUT_LAYOUT, @@ -258,7 +246,7 @@ protected function defaultInputLayout() * @param array $settings The dual-select options. * @return Selectinput Chainable */ - public function setDualSelectOptions(array $settings) + public function setDualSelectOptions(array $settings): static { $this->dualSelectOptions = array_merge($this->defaultDualSelectOptions(), $settings); @@ -271,7 +259,7 @@ public function setDualSelectOptions(array $settings) * @param array $settings The dual-select options. * @return Selectinput Chainable */ - public function mergeDualSelectOptions(array $settings) + public function mergeDualSelectOptions(array $settings): static { $this->dualSelectOptions = array_merge($this->dualSelectOptions, $settings); @@ -286,7 +274,7 @@ public function mergeDualSelectOptions(array $settings) * @throws InvalidArgumentException If the identifier is not a string. * @return Selectinput Chainable */ - public function addSelectOption($key, $val) + public function addSelectOption($key, $val): static { if (!is_string($key)) { throw new InvalidArgumentException( @@ -306,10 +294,8 @@ public function addSelectOption($key, $val) /** * Retrieve the dual-select's options. - * - * @return array */ - public function dualSelectOptions() + public function dualSelectOptions(): array { if ($this->dualSelectOptions === null) { $this->dualSelectOptions = $this->defaultDualSelectOptions(); @@ -320,10 +306,8 @@ public function dualSelectOptions() /** * Retrieve the default dual-select options. - * - * @return array */ - public function defaultDualSelectOptions() + public function defaultDualSelectOptions(): array { return []; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/EmailInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/EmailInput.php index 410ebe205..2fca5bc6a 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/EmailInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/EmailInput.php @@ -1,5 +1,7 @@ `. - * - * @return string */ - public function type() + #[\Override] + public function type(): string { return 'email'; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/FileInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/FileInput.php index b3e76b526..8f8ede750 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/FileInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/FileInput.php @@ -5,7 +5,7 @@ // From Pimple use Pimple\Container; // From Mustache -use Mustache_LambdaHelper as LambdaHelper; +use Mustache\LambdaHelper as LambdaHelper; // // From 'charcoal-admin' use Charcoal\Admin\Property\AbstractPropertyInput; @@ -30,24 +30,18 @@ class FileInput extends AbstractPropertyInput /** * Flag wether the "file preview" should be displayed. - * - * @var boolean */ - private $showFilePreview = true; + private bool $showFilePreview = true; /** * Flag wether the "file upload" input should be displayed. - * - * @var boolean */ - private $showFileUpload; + private ?bool $showFileUpload = null; /** * Flag wether the "file picker" popup button should be displaed. - * - * @var boolean */ - private $showFilePicker; + private ?bool $showFilePicker = null; /** * URL for the "file picker" popup. @@ -79,10 +73,8 @@ class FileInput extends AbstractPropertyInput /** * Retrieve the control type for the HTML element ``. - * - * @return string */ - public function type() + public function type(): string { return 'file'; } @@ -92,9 +84,8 @@ public function type() * * @link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file * @param string|string[] $types The accepted MIME types. - * @return self */ - public function setAccept($types) + public function setAccept($types): static { if (is_array($types)) { $types = implode(',', $types); @@ -108,10 +99,8 @@ public function setAccept($types) * Retrieve a comma-separated list of default file type specifiers. * * This method concatenates the file property's "acceptedMimetypes". - * - * @return string */ - public function getDefaultAccept() + public function getDefaultAccept(): string { $types = $this->property()['acceptedMimetypes']; return implode(',', $types); @@ -134,14 +123,14 @@ public function accept() /** * @return string|null */ - public function abridgedInputVal() + public function abridgedInputVal(): string|array|null { $val = (string)$this->inputVal(); - $val = preg_replace('!^' . preg_quote($this->p()['uploadPath'], '!') . '!', '', $val); + $val = preg_replace('!^' . preg_quote((string)$this->p()['uploadPath'], '!') . '!', '', $val); - if (strpos($val, '://') !== false) { - $host = parse_url($val, PHP_URL_HOST); - $path = ltrim(substr($val, (strpos($val, $host) + strlen($host) + 1)), '/'); + if (str_contains((string)$val, '://')) { + $host = parse_url((string)$val, PHP_URL_HOST); + $path = ltrim(substr((string)$val, (strpos((string)$val, (string)$host) + strlen($host) + 1)), '/'); if (mb_strlen($path) > 30) { $a = 12; $z = 12; @@ -153,10 +142,7 @@ public function abridgedInputVal() return $val; } - /** - * @return string|null - */ - public function filePreview() + public function filePreview(): string { $value = $this->inputVal(); if ($value) { @@ -181,8 +167,8 @@ public function placeholderVal() $parts = parse_url($val); if (empty($parts['scheme']) && !in_array($val[0], [ '/', '#', '?' ])) { $path = isset($parts['path']) ? ltrim($parts['path'], '/') : ''; - $query = isset($parts['query']) ? $parts['query'] : ''; - $hash = isset($parts['fragment']) ? $parts['fragment'] : ''; + $query = ($parts['query'] ?? ''); + $hash = ($parts['fragment'] ?? ''); $val = $this->baseUrl->withPath($path)->withQuery($query)->withFragment($hash); } @@ -204,8 +190,8 @@ public function previewVal() $parts = parse_url($val); if (empty($parts['scheme']) && !in_array($val[0], [ '/', '#', '?' ])) { $path = isset($parts['path']) ? ltrim($parts['path'], '/') : ''; - $query = isset($parts['query']) ? $parts['query'] : ''; - $hash = isset($parts['fragment']) ? $parts['fragment'] : ''; + $query = ($parts['query'] ?? ''); + $hash = ($parts['fragment'] ?? ''); $val = $this->baseUrl->withPath($path)->withQuery($query)->withFragment($hash); } @@ -216,17 +202,14 @@ public function previewVal() * @param boolean $show The show file preview flag. * @return FileInput Chainable */ - public function setShowFilePreview($show) + public function setShowFilePreview($show): static { - $this->showFilePreview = !!$show; + $this->showFilePreview = (bool)$show; return $this; } - /** - * @return boolean - */ - public function showFilePreview() + public function showFilePreview(): bool { return $this->showFilePreview; } @@ -235,9 +218,9 @@ public function showFilePreview() * @param boolean $show The show file upload flag. * @return FileInput Chainable */ - public function setShowFileUpload($show) + public function setShowFileUpload($show): static { - $this->showFileUpload = !!$show; + $this->showFileUpload = (bool)$show; return $this; } @@ -258,29 +241,23 @@ public function showFileUpload() * @param boolean $show The show file picker flag. * @return FileInput Chainable */ - public function setShowFilePicker($show) + public function setShowFilePicker($show): static { - $this->showFilePicker = !!$show; + $this->showFilePicker = (bool)$show; return $this; } - /** - * @return boolean - */ - public function showFilePicker() + public function showFilePicker(): bool { if ($this->showFilePicker === null) { - return !($this->showFileUpload === true); + return $this->showFileUpload !== true; } return $this->showFilePicker && $this->hasFilePicker(); } - /** - * @return boolean - */ - public function hasFilePicker() + public function hasFilePicker(): bool { return class_exists('\\elFinder'); } @@ -289,7 +266,7 @@ public function hasFilePicker() * @param string $url The file picker AJAX URL. * @return FileInput Chainable */ - public function setFilePickerUrl($url) + public function setFilePickerUrl($url): static { $this->filePickerUrl = $url; return $this; @@ -317,7 +294,7 @@ public function filePickerUrl() * * @return callable|null */ - public function prepareFilePickerUrl() + public function prepareFilePickerUrl(): ?\Closure { if (!$this->showFilePicker()) { return null; @@ -325,7 +302,7 @@ public function prepareFilePickerUrl() $uri = $this->getFilePickerUrlTemplate(); - return function ($noop, LambdaHelper $helper) use ($uri) { + return function ($noop, LambdaHelper $helper) use ($uri): null { $uri = $helper->render($uri); $this->setFilePickerUrl($uri); @@ -335,24 +312,20 @@ public function prepareFilePickerUrl() /** * Retrieve the elFinder connector URL template for rendering. - * - * @return string */ - protected function getFilePickerUrlTemplate() + protected function getFilePickerUrlTemplate(): string { $uri = 'obj_type={{ objType }}&obj_id={{ objId }}&property={{ p.ident }}&callback={{ inputId }}'; - $uri = '{{# withAdminUrl }}elfinder?' . $uri . '{{/ withAdminUrl }}'; - return $uri; + return '{{# withAdminUrl }}elfinder?' . $uri . '{{/ withAdminUrl }}'; } /** * Set the title for the file picker dialog. * * @param string|string[] $title The dialog title. - * @return self */ - public function setDialogTitle($title) + public function setDialogTitle($title): static { $this->dialogTitle = $this->translator()->translation($title); @@ -377,9 +350,8 @@ public function dialogTitle() * Set the label for the file picker button. * * @param string|string[] $label The button label. - * @return self */ - public function setChooseButtonLabel($label) + public function setChooseButtonLabel($label): static { $this->chooseButtonLabel = $this->translator()->translation($label); @@ -404,9 +376,8 @@ public function chooseButtonLabel() * Set the label for the file removal button. * * @param string|string[] $label The button label. - * @return self */ - public function setRemoveButtonLabel($label) + public function setRemoveButtonLabel($label): static { $this->removeButtonLabel = $this->translator()->translation($label); @@ -433,6 +404,7 @@ public function removeButtonLabel() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -445,7 +417,7 @@ protected function setDependencies(Container $container) * * @return \Charcoal\Translator\Translation|string|null */ - protected function defaultDialogTitle() + protected function defaultDialogTitle(): ?\Charcoal\Translator\Translation { return $this->translator()->translation('filesystem.library.media'); } @@ -455,7 +427,7 @@ protected function defaultDialogTitle() * * @return \Charcoal\Translator\Translation|string|null */ - protected function defaultChooseButtonLabel() + protected function defaultChooseButtonLabel(): ?\Charcoal\Translator\Translation { if ($this->property()['multiple']) { return $this->translator()->translation('Choose files…'); @@ -469,7 +441,7 @@ protected function defaultChooseButtonLabel() * * @return \Charcoal\Translator\Translation|string|null */ - protected function defaultRemoveButtonLabel() + protected function defaultRemoveButtonLabel(): ?\Charcoal\Translator\Translation { if ($this->property()['multiple']) { return $this->translator()->translation('Clear selected files'); @@ -480,10 +452,9 @@ protected function defaultRemoveButtonLabel() /** * Retrieve the control's data options for JavaScript components. - * - * @return array */ - public function controlDataForJs() + #[\Override] + public function controlDataForJs(): array { return [ 'input_name' => $this->inputName(), diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/HiddenInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/HiddenInput.php index d182cabf3..eb1b55000 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/HiddenInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/HiddenInput.php @@ -1,5 +1,7 @@ `. - * - * @return string */ - public function type() + #[\Override] + public function type(): string { return 'hidden'; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/ImageInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/ImageInput.php index d4b5f4ff1..20608e4f8 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/ImageInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/ImageInput.php @@ -15,18 +15,15 @@ class ImageInput extends FileInput /** * Retrieve list of default file type specifiers. - * - * @return string */ - public function getDefaultAccept() + #[\Override] + public function getDefaultAccept(): string { return 'image/*'; } - /** - * @return string|null - */ - public function filePreview() + #[\Override] + public function filePreview(): string { $value = $this->inputVal(); if ($value) { @@ -41,7 +38,8 @@ public function filePreview() * * @return \Charcoal\Translator\Translation|string|null */ - protected function defaultChooseButtonLabel() + #[\Override] + protected function defaultChooseButtonLabel(): ?\Charcoal\Translator\Translation { if ($this->property()['multiple']) { return $this->translator()->translation('Choose images…'); @@ -56,7 +54,7 @@ protected function defaultChooseButtonLabel() * @param string|string[] $classes A space-separated list of CSS classes. * @return ImageDisplay Chainable */ - public function setClassAttr($classes) + public function setClassAttr($classes): static { if (is_array($classes)) { $classes = implode(' ', $classes); diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/JsonEditorInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/JsonEditorInput.php index a87d41f68..72186408b 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/JsonEditorInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/JsonEditorInput.php @@ -27,7 +27,7 @@ class JsonEditorInput extends TextareaInput * @param array $settings The editor options. * @return Tinymce Chainable */ - public function setEditorOptions(array $settings) + public function setEditorOptions(array $settings): static { $this->editorOptions = array_merge($this->defaultEditorOptions(), $settings); @@ -40,7 +40,7 @@ public function setEditorOptions(array $settings) * @param array $settings The editor options. * @return Tinymce Chainable */ - public function mergeEditorOptions(array $settings) + public function mergeEditorOptions(array $settings): static { $this->editorOptions = array_merge($this->editorOptions, $settings); @@ -55,7 +55,7 @@ public function mergeEditorOptions(array $settings) * @throws InvalidArgumentException If the identifier is not a string. * @return Tinymce Chainable */ - public function addEditorOption($key, $val) + public function addEditorOption($key, $val): static { if (!is_string($key)) { throw new InvalidArgumentException( @@ -96,16 +96,10 @@ public function defaultEditorOptions() { $defaultData = $this->metadata()->defaultData(); - if (isset($defaultData['editor_options'])) { - return $defaultData['editor_options']; - } - - return []; + return ($defaultData['editor_options'] ?? []); } - /** - * @return array - */ + #[\Override] public function getInputValOptions(): array { return [ diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/MapWidgetInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/MapWidgetInput.php index b9f80d917..21888746a 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/MapWidgetInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/MapWidgetInput.php @@ -22,18 +22,15 @@ class MapWidgetInput extends AbstractPropertyInput /** * Settings for the map widget. - * - * @var array */ - private $mapOptions; + private ?array $mapOptions = null; /** * Sets the API key for the mapping service. * * @param string $key An API key. - * @return self */ - public function setApiKey($key) + public function setApiKey($key): static { $this->apiKey = $key; @@ -58,7 +55,7 @@ public function apiKey() * @param array $settings The map widget options. * @return MapWidgetInput Chainable */ - public function setMapOptions(array $settings) + public function setMapOptions(array $settings): static { if (isset($settings['api_key'])) { $this->setApiKey($settings['api_key']); @@ -79,7 +76,7 @@ public function setMapOptions(array $settings) * @param array $settings The map widget options. * @return MapWidgetInput Chainable */ - public function mergeMapOptions(array $settings) + public function mergeMapOptions(array $settings): static { if (isset($settings['api_key'])) { $this->setApiKey($settings['api_key']); @@ -98,7 +95,7 @@ public function mergeMapOptions(array $settings) * @throws InvalidArgumentException If the identifier is not a string. * @return MapWidgetInput Chainable */ - public function addMapOption($key, $val) + public function addMapOption($key, $val): static { if (!is_string($key)) { throw new InvalidArgumentException( @@ -122,10 +119,8 @@ public function addMapOption($key, $val) /** * Retrieve the map widget's options. - * - * @return array */ - public function mapOptions() + public function mapOptions(): array { if ($this->mapOptions === null) { $this->mapOptions = $this->defaultMapOptions(); @@ -135,10 +130,8 @@ public function mapOptions() /** * Retrieve the default map widget options. - * - * @return array */ - public function defaultMapOptions() + public function defaultMapOptions(): array { return [ 'api_key' => $this->apiKey() ]; } @@ -159,6 +152,7 @@ public function mapOptionsAsJson() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/NestedWidgetInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/NestedWidgetInput.php index 3f0411686..879eab382 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/NestedWidgetInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/NestedWidgetInput.php @@ -34,24 +34,18 @@ class NestedWidgetInput extends AbstractPropertyInput implements /** * Store the widget factory instance for the current class. - * - * @var FactoryInterface */ - private $widgetFactory; + private ?\Charcoal\Factory\FactoryInterface $widgetFactory = null; /** * Store the form group widget factory instance for the current class. - * - * @var FactoryInterface */ - private $formGroupFactory; + private ?\Charcoal\Factory\FactoryInterface $formGroupFactory = null; /** * The form group the input belongs to. - * - * @var FormGroupInterface */ - private $formGroup; + private ?\Charcoal\Ui\FormGroup\FormGroupInterface $formGroup = null; /** * Set the form input's parent group. @@ -59,7 +53,7 @@ class NestedWidgetInput extends AbstractPropertyInput implements * @param FormGroupInterface $formGroup The parent form group object. * @return FormInputInterface Chainable */ - public function setFormGroup(FormGroupInterface $formGroup) + public function setFormGroup(FormGroupInterface $formGroup): static { $this->formGroup = $formGroup; @@ -71,7 +65,7 @@ public function setFormGroup(FormGroupInterface $formGroup) * * @return FormGroupInterface */ - public function formGroup() + public function formGroup(): ?\Charcoal\Ui\FormGroup\FormGroupInterface { return $this->formGroup; } @@ -82,6 +76,7 @@ public function formGroup() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -94,9 +89,8 @@ protected function setDependencies(Container $container) * Set the widget factory. * * @param FactoryInterface $factory The factory to create widgets. - * @return self */ - protected function setWidgetFactory(FactoryInterface $factory) + protected function setWidgetFactory(FactoryInterface $factory): static { $this->widgetFactory = $factory; @@ -107,14 +101,13 @@ protected function setWidgetFactory(FactoryInterface $factory) * Retrieve the widget factory. * * @throws RuntimeException If the widget factory was not previously set. - * @return FactoryInterface */ - protected function widgetFactory() + protected function widgetFactory(): \Charcoal\Factory\FactoryInterface { - if ($this->widgetFactory === null) { + if (!$this->widgetFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException(sprintf( 'Widget Factory is not defined for "%s"', - get_class($this) + static::class )); } @@ -125,9 +118,8 @@ protected function widgetFactory() * Set the form group factory. * * @param FactoryInterface $factory The factory to create form groups. - * @return self */ - protected function setFormGroupFactory(FactoryInterface $factory) + protected function setFormGroupFactory(FactoryInterface $factory): static { $this->formGroupFactory = $factory; @@ -138,14 +130,13 @@ protected function setFormGroupFactory(FactoryInterface $factory) * Retrieve the form group factory. * * @throws RuntimeException If the form group factory was not previously set. - * @return FactoryInterface */ - protected function formGroupFactory() + protected function formGroupFactory(): \Charcoal\Factory\FactoryInterface { - if ($this->formGroupFactory === null) { + if (!$this->formGroupFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException(sprintf( 'Form Group Factory is not defined for "%s"', - get_class($this) + static::class )); } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/NumberInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/NumberInput.php index 4b43977da..b4bb9496b 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/NumberInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/NumberInput.php @@ -1,5 +1,7 @@ min = null; @@ -56,18 +52,12 @@ public function setMin($min) return $this; } - /** - * @return boolean - */ - public function hasMin() + public function hasMin(): bool { return !(empty($this->min) && !is_numeric($this->min)); } - /** - * @return integer|float|null - */ - public function min() + public function min(): int|float|null { return $this->min; } @@ -77,7 +67,7 @@ public function min() * @throws InvalidArgumentException If the argument is not a number. * @return Text Chainable */ - public function setMax($max) + public function setMax($max): static { if ($max === null || $max === '') { $this->max = null; @@ -94,18 +84,12 @@ public function setMax($max) return $this; } - /** - * @return boolean - */ - public function hasMax() + public function hasMax(): bool { return !(empty($this->max) && !is_numeric($this->max)); } - /** - * @return integer|float|null - */ - public function max() + public function max(): int|float|null { return $this->max; } @@ -115,7 +99,7 @@ public function max() * @throws InvalidArgumentException If the value is not a number. * @return Text Chainable */ - public function setStep($step) + public function setStep($step): static { if ($step === null || $step === '') { $this->step = null; @@ -137,18 +121,12 @@ public function setStep($step) return $this; } - /** - * @return boolean - */ - public function hasStep() + public function hasStep(): bool { return !(empty($this->step) && !is_numeric($this->step)); } - /** - * @return string|integer|float|null - */ - public function step() + public function step(): string|int|float|null { return $this->step; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/PasswordInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/PasswordInput.php index 19d206109..200db6481 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/PasswordInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/PasswordInput.php @@ -1,5 +1,7 @@ `. - * - * @return string */ - public function type() + #[\Override] + public function type(): string { return 'password'; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/PermalinkInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/PermalinkInput.php index 9c30149f5..91520639c 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/PermalinkInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/PermalinkInput.php @@ -42,6 +42,7 @@ class PermalinkInput extends TextInput * @param Container $container A service locator. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -55,9 +56,9 @@ protected function setDependencies(Container $container) * Used for the HTML "ID" attribute. * * @param string $inputId HTML input id attribute. - * @return self */ - public function setInputId($inputId) + #[\Override] + public function setInputId($inputId): static { parent::setInputId($inputId); $this->sampleId = $inputId; @@ -66,10 +67,8 @@ public function setInputId($inputId) /** * Get the permalink's absolute URI. - * - * @return string|null */ - public function viewLink() + public function viewLink(): string { $link = null; $locale = $this->lang(); @@ -88,9 +87,8 @@ public function viewLink() * Set the permalink's immutable base. * * @param mixed $route The base URI. - * @return self */ - protected function setBaseRoute($route) + protected function setBaseRoute($route): static { $this->baseRoute = $this->translator()->translation($route); return $this; @@ -98,10 +96,8 @@ protected function setBaseRoute($route) /** * Get the permalink's immutable base. - * - * @return string|null */ - public function baseRoute() + public function baseRoute(): string { if ($this->baseRoute === null) { $this->baseRoute = $this->baseUrl(); @@ -117,7 +113,7 @@ public function baseRoute() $translator->setLocale($origLocale); } - return rtrim((string)$link, '/') . '/'; + return rtrim($link, '/') . '/'; } /** @@ -128,7 +124,7 @@ public function baseRoute() public function editableRoute() { $link = $this->inputVal(); - if (empty($link)) { + if (in_array($link, [null, '', '0'], true)) { $link = $this->placeholder(); } @@ -139,9 +135,8 @@ public function editableRoute() * Set the base URI of the project. * * @param UriInterface $uri The base URI. - * @return self */ - protected function setBaseUrl(UriInterface $uri) + protected function setBaseUrl(UriInterface $uri): static { $this->baseUrl = $uri; return $this; @@ -155,10 +150,10 @@ protected function setBaseUrl(UriInterface $uri) */ public function baseUrl() { - if (!isset($this->baseUrl)) { + if ($this->baseUrl === null) { throw new RuntimeException(sprintf( 'The base URI is not defined for [%s]', - get_class($this) + static::class )); } @@ -195,9 +190,8 @@ public function samples() * Used for the HTML "ID" attribute. * * @param string $id HTML sample ID attribute. - * @return self */ - public function setSampleId($id) + public function setSampleId($id): static { $this->sampleId = $id; return $this; @@ -221,10 +215,8 @@ public function sampleId() /** * Generate a unique sample ID. - * - * @return string */ - protected function generateSampleId() + protected function generateSampleId(): string { return 'sample_' . uniqid(); } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/PhoneInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/PhoneInput.php index e9faf80d3..c9d623803 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/PhoneInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/PhoneInput.php @@ -1,5 +1,7 @@ `. - * - * @return string */ - public function type() + #[\Override] + public function type(): string { return 'tel'; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/RadioBtnGroupInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/RadioBtnGroupInput.php index 84311e0a9..c14504e2f 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/RadioBtnGroupInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/RadioBtnGroupInput.php @@ -1,5 +1,7 @@ `. - * - * @return string */ - public function type() + public function type(): string { return 'radio'; } /** * Never accept multiple values. - * - * @return boolean */ - public function multiple() + #[\Override] + public function multiple(): bool { return false; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/RangeInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/RangeInput.php index 709ca214d..571a0a4aa 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/RangeInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/RangeInput.php @@ -1,5 +1,7 @@ showRangeValue = (bool)$show; $this->setRangeValueLocation($show); @@ -39,10 +38,8 @@ public function setShowRangeValue($show) /** * Determine if the property's value should be displayed. - * - * @return boolean */ - public function showRangeValue() + public function showRangeValue(): bool { return $this->showRangeValue; } @@ -56,9 +53,8 @@ public function showRangeValue() * CSS selector, the query selector lookup will be done with the input's * ID prefix (e.g., "my_range_output" → `#input_5db6fc900736b_my_range_output`). * @throws InvalidArgumentException If the show flag is invalid. - * @return self */ - public function setRangeValueLocation($location) + public function setRangeValueLocation($location): static { switch ($location) { case false: @@ -79,7 +75,7 @@ public function setRangeValueLocation($location) throw new InvalidArgumentException(sprintf( 'Invalid range value location: %s ', - (is_object($location) ? get_class($location) : gettype($location)) + (get_debug_type($location)) )); } @@ -95,10 +91,9 @@ public function rangeValueLocation() /** * Retrieve the control's data options for JavaScript components. - * - * @return array */ - public function controlDataForJs() + #[\Override] + public function controlDataForJs(): array { return [ // Base Control diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlyInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlyInput.php index 74b8fa780..a46b9c108 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlyInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlyInput.php @@ -40,17 +40,13 @@ class ReadonlyInput extends AbstractPropertyInput /** * Whether the placeholder text should be shown when the value is empty. - * - * @var boolean */ - private $showPlaceholder = false; + private bool $showPlaceholder = false; /** * Store the factory instance for the current class. - * - * @var FactoryInterface */ - private $propertyDisplayFactory; + private ?\Charcoal\Factory\FactoryInterface $propertyDisplayFactory = null; /** * @return string @@ -113,6 +109,7 @@ public function displayVal() * @throws UnexpectedValueException If the value is invalid. * @return string */ + #[\Override] public function inputVal() { $property = $this->property(); @@ -139,7 +136,7 @@ public function inputVal() if (!is_scalar($val)) { throw new UnexpectedValueException(sprintf( 'Property Input Value must be a string, received %s', - (is_object($val) ? get_class($val) : gettype($val)) + (get_debug_type($val)) )); } @@ -149,6 +146,7 @@ public function inputVal() /** * @return boolean */ + #[\Override] public function hasPropertyVal() { if ($this->hasPropertyVal === null) { @@ -164,9 +162,9 @@ public function hasPropertyVal() * @param boolean $show Show (TRUE) or hide (FALSE) the notes. * @return UiItemInterface Chainable */ - public function setShowPlaceholder($show) + public function setShowPlaceholder($show): static { - $this->showPlaceholder = !!$show; + $this->showPlaceholder = (bool)$show; return $this; } @@ -201,7 +199,7 @@ public function maybeSerializeValue($input) return $output; } } - } catch (JsonException $e) { + } catch (JsonException) { // do nothing } } @@ -223,7 +221,7 @@ public function maybeUnserializeValue($input) if (!is_scalar($output) && !is_null($output)) { return $output; } - } catch (JsonException $e) { + } catch (JsonException) { // do nothing } } @@ -263,10 +261,9 @@ public function getRenderType() /** * Retrieve the default display options. - * - * @return array */ - public function getDefaultInputOptions() + #[\Override] + public function getDefaultInputOptions(): array { return [ 'maybe_input_is_serialized' => static::DEFAULT_MAYBE_INPUT_IS_SERIALIZED, @@ -279,6 +276,7 @@ public function getDefaultInputOptions() * @param Container $container Pimple DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -302,13 +300,12 @@ protected function setPropertyDisplayFactory(FactoryInterface $factory) * Retrieve the property display factory. * * @throws RuntimeException If the property display factory was not previously set. - * @return FactoryInterface */ - protected function getPropertyDisplayFactory() + protected function getPropertyDisplayFactory(): \Charcoal\Factory\FactoryInterface { - if (!isset($this->propertyDisplayFactory)) { + if (!$this->propertyDisplayFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException( - sprintf('Property Display Factory is not defined for "%s"', get_class($this)) + sprintf('Property Display Factory is not defined for "%s"', static::class) ); } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlySelectInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlySelectInput.php index cb7b57e45..0e613688b 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlySelectInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlySelectInput.php @@ -1,5 +1,7 @@ p()['allowNull'] && !$this->p()['multiple']) { @@ -52,6 +51,7 @@ public function choices() * @param array|object $choice The choice structure. * @return array|null */ + #[\Override] protected function parseChoice($ident, $choice) { $choice = parent::parseChoice($ident, $choice); @@ -85,7 +85,7 @@ protected function parseChoice($ident, $choice) * @param array $settings The select picker options. * @return Selectinput Chainable */ - public function setSelectOptions(array $settings) + public function setSelectOptions(array $settings): static { $this->selectOptions = array_merge($this->defaultSelectOptions(), $settings); @@ -98,7 +98,7 @@ public function setSelectOptions(array $settings) * @param array $settings The select picker options. * @return Selectinput Chainable */ - public function mergeSelectOptions(array $settings) + public function mergeSelectOptions(array $settings): static { $this->selectOptions = array_merge($this->selectOptions, $settings); @@ -113,7 +113,7 @@ public function mergeSelectOptions(array $settings) * @throws InvalidArgumentException If the identifier is not a string. * @return Selectinput Chainable */ - public function addSelectOption($key, $val) + public function addSelectOption($key, $val): static { if (!is_string($key)) { throw new InvalidArgumentException( @@ -133,10 +133,8 @@ public function addSelectOption($key, $val) /** * Retrieve the select picker's options. - * - * @return array */ - public function selectOptions() + public function selectOptions(): array { if ($this->selectOptions === null) { $this->selectOptions = $this->defaultSelectOptions(); @@ -147,10 +145,8 @@ public function selectOptions() /** * Retrieve the default select picker options. - * - * @return array */ - public function defaultSelectOptions() + public function defaultSelectOptions(): array { return [ 'style' => '', diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/Selectize/ListInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/Selectize/ListInput.php index e6f7887a4..d62ba53b2 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/Selectize/ListInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/Selectize/ListInput.php @@ -1,5 +1,7 @@ inputName) { - $name = $this->inputName; - } else { - $name = $this->propertyIdent(); - } + $name = $this->inputName ?: $this->propertyIdent(); if ($this->p()['l10n']) { $name .= '[' . $this->lang() . ']'; @@ -86,6 +79,7 @@ public function inputName() * @todo [^1]: With PHP7 we can simply do `yield from $choices;`. * @return \Generator */ + #[\Override] public function choices() { if ($this->p()['allowNull'] && !$this->p()['multiple']) { @@ -112,9 +106,8 @@ public function formWidget() /** * @param string $formWidget The form widget for object creation and modification. - * @return self */ - public function setFormWidget($formWidget) + public function setFormWidget($formWidget): static { $this->formWidget = $formWidget; @@ -125,11 +118,10 @@ public function setFormWidget($formWidget) * Show/hide the "Copy to Clipboard" button. * * @param boolean $flag Show (TRUE) or hide (FALSE) the copy button. - * @return self */ - public function setAllowClipboardCopy($flag) + public function setAllowClipboardCopy($flag): static { - $this->allowClipboardCopy = !!$flag; + $this->allowClipboardCopy = (bool)$flag; return $this; } @@ -152,7 +144,7 @@ public function allowClipboardCopy() * @param array $settings The selectize picker options. * @return TagsInput Chainable */ - public function setSelectizeOptions(array $settings) + public function setSelectizeOptions(array $settings): static { $this->selectizeOptions = array_merge( $this->defaultSelectizeOptions(), @@ -168,7 +160,7 @@ public function setSelectizeOptions(array $settings) * @param array $settings The selectize picker options. * @return TagsInput Chainable */ - public function mergeSelectizeOptions(array $settings) + public function mergeSelectizeOptions(array $settings): static { $this->selectizeOptions = array_merge( $this->selectizeOptions, @@ -186,7 +178,7 @@ public function mergeSelectizeOptions(array $settings) * @throws InvalidArgumentException If the identifier is not a string. * @return self Chainable */ - public function addSelectizeOption($key, $val) + public function addSelectizeOption($key, $val): static { if (!is_string($key)) { throw new InvalidArgumentException( @@ -260,10 +252,9 @@ public function selectizeOptionsAsJson() /** * Retrieve the default object-to-choice data map. - * - * @return array */ - public function defaultChoiceObjMap() + #[\Override] + public function defaultChoiceObjMap(): array { return [ 'value' => 'id', @@ -274,10 +265,9 @@ public function defaultChoiceObjMap() /** * Retrieve the control's data options for JavaScript components. - * - * @return array */ - public function controlDataForJs() + #[\Override] + public function controlDataForJs(): array { $prop = $this->property(); @@ -298,11 +288,9 @@ public function controlDataForJs() 'multiple_options' => $this->property()['multipleOptions'], ]; - if ($prop instanceof ObjectProperty) { - if ($prop['objType']) { - $data['pattern'] = $prop['pattern']; - $data['obj_type'] = $prop['objType']; - } + if ($prop instanceof ObjectProperty && $prop['objType']) { + $data['pattern'] = $prop['pattern']; + $data['obj_type'] = $prop['objType']; } return $data; @@ -314,6 +302,7 @@ public function controlDataForJs() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -326,14 +315,13 @@ protected function setDependencies(Container $container) * Retrieve the object model factory. * * @throws RuntimeException If the model factory was not previously set. - * @return FactoryInterface */ - protected function modelFactory() + protected function modelFactory(): \Charcoal\Factory\FactoryInterface { - if (!isset($this->modelFactory)) { + if (!$this->modelFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException(sprintf( 'Model Factory is not defined for "%s"', - get_class($this) + static::class )); } @@ -346,7 +334,7 @@ protected function modelFactory() * @param array $settings The selectize picker options. * @return array Returns the parsed options. */ - protected function parseSelectizeOptions(array $settings) + protected function parseSelectizeOptions(array $settings): array { return $settings; } @@ -355,9 +343,8 @@ protected function parseSelectizeOptions(array $settings) * Set an object model factory. * * @param FactoryInterface $factory The model factory, to create objects. - * @return self */ - private function setModelFactory(FactoryInterface $factory) + private function setModelFactory(FactoryInterface $factory): static { $this->modelFactory = $factory; @@ -368,9 +355,8 @@ private function setModelFactory(FactoryInterface $factory) * Set a model collection loader. * * @param CollectionLoader $loader The collection loader. - * @return self */ - private function setCollectionLoader(CollectionLoader $loader) + private function setCollectionLoader(CollectionLoader $loader): static { $this->collectionLoader = $loader; @@ -382,7 +368,7 @@ private function setCollectionLoader(CollectionLoader $loader) * * @return CollectionLoader */ - private function collectionLoader() + private function collectionLoader(): ?\Charcoal\Loader\CollectionLoader { return $this->collectionLoader; } @@ -392,9 +378,8 @@ private function collectionLoader() * * @param mixed $val The value to parse into selectize choices. * @param array $options Optional structure options. - * @return array */ - private function selectizeVal($val = null, array $options = []) + private function selectizeVal($val = null, array $options = []): array { /** @todo Find a use for this */ unset($options); diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/Selectize/Template/SpriteTemplate.php b/packages/admin/src/Charcoal/Admin/Property/Input/Selectize/Template/SpriteTemplate.php index 0dc45e5ee..0c1d11717 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/Selectize/Template/SpriteTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/Selectize/Template/SpriteTemplate.php @@ -30,6 +30,7 @@ class SpriteTemplate extends AbstractTemplate * @param Container $container A Pimple DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -47,9 +48,8 @@ public function showSpriteId() /** * @param boolean $flag Show the sprite id besides the icon. - * @return self */ - public function setShowSpriteId($flag) + public function setShowSpriteId($flag): static { $this->showSpriteId = $flag; diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/SelectizeInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/SelectizeInput.php index 06f60e543..e707c6db2 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/SelectizeInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/SelectizeInput.php @@ -48,24 +48,18 @@ class SelectizeInput extends SelectInput /** * Store the factory instance for the current class. - * - * @var FactoryInterface */ - private $modelFactory; + private ?\Charcoal\Factory\FactoryInterface $modelFactory = null; /** * Store the collection loader for the current class. - * - * @var CollectionLoader */ - private $collectionLoader; + private ?\Charcoal\Loader\CollectionLoader $collectionLoader = null; /** * Should the object be loaded in deferred mode. - * - * @var boolean */ - private $deferred; + private ?bool $deferred = null; /** * Whether to show a button to allow update items. @@ -104,10 +98,8 @@ class SelectizeInput extends SelectInput * The form data to use while creating objects through Selectize. * * Must be an array - * - * @var array|null */ - private $formData; + private ?array $formData = null; /** * Label for the create item dialog. @@ -130,20 +122,14 @@ class SelectizeInput extends SelectInput */ protected $isChoiceObjMapFinalized = false; - /** - * @var array - */ - private $selectizeTemplates; + private object|array|null $selectizeTemplates = null; /** * @var SelectizeRenderer */ private $selectizeRenderer; - /** - * @var array - */ - private $disabledFields = []; + private array $disabledFields = []; /** * @var string $remoteSource @@ -162,10 +148,8 @@ class SelectizeInput extends SelectInput /** * Check used to parse multi Optgroup map against the obj properties. - * - * @var boolean */ - private $isOptgroupObjMapFinalized = false; + private bool $isOptgroupObjMapFinalized = false; /** * This function takes an array and fill the model object with its value. @@ -179,9 +163,9 @@ class SelectizeInput extends SelectInput * on the metadata object, because the method `set_foobar()` does not exist. * * @param array $data The input data. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { // Push selectize options back at the end of the data container. if (isset($data['selectizeOptions'])) { @@ -199,14 +183,13 @@ public function setData(array $data) * Retrieve the object model factory. * * @throws RuntimeException If the model factory was not previously set. - * @return FactoryInterface */ - public function modelFactory() + public function modelFactory(): \Charcoal\Factory\FactoryInterface { - if (!isset($this->modelFactory)) { + if (!$this->modelFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException(sprintf( 'Model Factory is not defined for "%s"', - get_class($this) + static::class )); } @@ -217,9 +200,8 @@ public function modelFactory() * Set a model collection loader. * * @param CollectionLoader $loader The collection loader. - * @return self */ - private function setCollectionLoader(CollectionLoader $loader) + private function setCollectionLoader(CollectionLoader $loader): static { $this->collectionLoader = $loader; @@ -230,14 +212,13 @@ private function setCollectionLoader(CollectionLoader $loader) * Retrieve the model collection loader. * * @throws RuntimeException If the collection loader was not previously set. - * @return CollectionLoader */ - protected function collectionLoader() + protected function collectionLoader(): \Charcoal\Loader\CollectionLoader { - if (!isset($this->collectionLoader)) { + if (!$this->collectionLoader instanceof \Charcoal\Loader\CollectionLoader) { throw new RuntimeException(sprintf( 'Collection Loader is not defined for "%s"', - get_class($this) + static::class )); } @@ -246,10 +227,9 @@ protected function collectionLoader() /** * Retrieve the default empty option structure. - * - * @return array */ - protected function defaultEmptyChoice() + #[\Override] + protected function defaultEmptyChoice(): array { return [ 'value' => '', @@ -265,6 +245,7 @@ protected function defaultEmptyChoice() * @todo [^1]: With PHP7 we can simply do `yield from $choices;`. * @return \Generator|array */ + #[\Override] public function choices() { if ($this->p()['allowNull'] && !$this->p()['multiple']) { @@ -273,11 +254,7 @@ public function choices() } // When deferred, we want to fetch choices for current values only. - if ($this->deferred()) { - $choices = $this->selectizeVal($this->propertyVal()); - } else { - $choices = $this->selectizeVal($this->p()->choices()); - } + $choices = $this->deferred() ? $this->selectizeVal($this->propertyVal()) : $this->selectizeVal($this->p()->choices()); /* Pass along the Generator from the parent method [^1] */ /* Filter the all options down to those *not* selected */ @@ -291,22 +268,20 @@ public function choices() /** * Create an input group to nest extra inputs alongside selectize - * @return boolean */ - public function inputGroup() + public function inputGroup(): bool { - return !!($this->allowClipboardCopy() || $this->allowUpdate() || $this->allowCreate()); + return $this->allowClipboardCopy() || $this->allowUpdate() || $this->allowCreate(); } /** * Show/hide the "Copy to Clipboard" button. * * @param boolean $flag Show (TRUE) or hide (FALSE) the copy button. - * @return self */ - public function setAllowClipboardCopy($flag) + public function setAllowClipboardCopy($flag): static { - $this->allowClipboardCopy = !!$flag; + $this->allowClipboardCopy = (bool)$flag; return $this; } @@ -323,11 +298,10 @@ public function allowClipboardCopy() /** * @param boolean $allowUpdate Show (TRUE) or hide (FALSE) the update button. - * @return self */ - public function setAllowUpdate($allowUpdate) + public function setAllowUpdate($allowUpdate): static { - $this->allowUpdate = !!$allowUpdate; + $this->allowUpdate = (bool)$allowUpdate; return $this; } @@ -344,11 +318,10 @@ public function allowUpdate() /** * @param boolean $allowCreate Show (TRUE) or hide (FALSE) the create button. - * @return self */ - public function setAllowCreate($allowCreate) + public function setAllowCreate($allowCreate): static { - $this->allowCreate = !!$allowCreate; + $this->allowCreate = (bool)$allowCreate; return $this; } @@ -366,18 +339,17 @@ public function allowCreate() /** * @return boolean */ - public function deferred() + public function deferred(): ?bool { return $this->deferred; } /** * @param boolean $deferred Should the object be loaded in deferred mode. - * @return self */ - public function setDeferred($deferred) + public function setDeferred($deferred): static { - $this->deferred = ($this->property() instanceof ObjectProperty || $this->remoteSource()) ? $deferred : false; + $this->deferred = ($this->property() instanceof ObjectProperty || $this->remoteSource()) && $deferred; return $this; } @@ -392,9 +364,8 @@ public function formWidget() /** * @param string $formWidget The form widget for object creation and modification. - * @return self */ - public function setFormWidget($formWidget) + public function setFormWidget($formWidget): static { $this->formWidget = $formWidget; @@ -411,18 +382,14 @@ public function formIdent() /** * @param mixed $formIdent The form ident(s) for object creation and modification. - * @return self */ - public function setFormIdent($formIdent) + public function setFormIdent($formIdent): static { $this->formIdent = $formIdent; return $this; } - /** - * @return array|null - */ public function getFormData(): ?array { return $this->formData; @@ -430,7 +397,6 @@ public function getFormData(): ?array /** * @param array|null $formData FormData for SelectizeInput. - * @return self */ public function setFormData(?array $formData): self { @@ -451,9 +417,8 @@ public function formIdentAsJson() * Set the title for the create item dialog. * * @param string|string[] $title The dialog title. - * @return self */ - public function setDialogTitleCreate($title) + public function setDialogTitleCreate($title): static { $this->dialogTitleCreate = $this->translator()->translation($title); @@ -474,9 +439,8 @@ public function getDialogTitleCreate() * Set the title for the update item dialog. * * @param string|string[] $title The dialog title. - * @return self */ - public function setDialogTitleUpdate($title) + public function setDialogTitleUpdate($title): static { $this->dialogTitleUpdate = $this->translator()->translation($title); @@ -501,7 +465,7 @@ public function getDialogTitleUpdate() * @param array $settings The selectize picker options. * @return self Chainable */ - public function setSelectizeOptions(array $settings) + public function setSelectizeOptions(array $settings): static { $this->selectizeOptions = array_merge( $this->defaultSelectizeOptions(), @@ -517,7 +481,7 @@ public function setSelectizeOptions(array $settings) * @param array $settings The selectize picker options. * @return self Chainable */ - public function mergeSelectizeOptions(array $settings) + public function mergeSelectizeOptions(array $settings): static { $this->selectizeOptions = array_merge( $this->selectizeOptions, @@ -535,7 +499,7 @@ public function mergeSelectizeOptions(array $settings) * @throws InvalidArgumentException If the identifier is not a string. * @return self Chainable */ - public function addSelectizeOption($key, $val) + public function addSelectizeOption($key, $val): static { if (!is_string($key)) { throw new InvalidArgumentException( @@ -582,11 +546,7 @@ public function defaultSelectizeOptions() $options = $this->parseSelectizeOptions($options); } - if ($this->deferred()) { - $placeholder = $this->translator()->trans('Search…'); - } else { - $placeholder = $this->translator()->trans('Select…'); - } + $placeholder = $this->deferred() ? $this->translator()->trans('Search…') : $this->translator()->trans('Select…'); $options['placeholder'] = $placeholder; $prop = $this->property(); @@ -598,7 +558,7 @@ public function defaultSelectizeOptions() $optgroupProp = $model->p($this->optgroupProperty()); if ($optgroupProp instanceof ObjectProperty) { - $method = [ $this, 'mapObjToOptgroup' ]; + $method = $this->mapObjToOptgroup(...); $loader = $this->collectionLoader()->setModel($optgroupProp['objType']); @@ -621,7 +581,7 @@ public function defaultSelectizeOptions() $optgroups = array_values($optgroupProp->choices()); // Make sure label is converted to string. - array_walk($optgroups, function (&$item) { + array_walk($optgroups, function (array &$item): void { $item['label'] = (string)$item['label']; }); @@ -632,14 +592,10 @@ public function defaultSelectizeOptions() if ($prop instanceof SelectablePropertyInterface) { $choices = iterator_to_array($this->choices()); - if (isset($options['options'])) { - $options['options'] = array_merge($options['options'], $choices); - } else { - $options['options'] = $choices; - } + $options['options'] = isset($options['options']) ? array_merge($options['options'], $choices) : $choices; // L10n properties is not supported through selectize items array, - $items = !$prop['l10n'] ? $this->propertyVal() : null; + $items = $prop['l10n'] ? null : $this->propertyVal(); if ($items !== null && $prop instanceof AbstractProperty) { $items = $this->property()->inputVal($items); @@ -691,7 +647,7 @@ public function selectizeOptionsAsJson() * @param array $settings The selectize picker options. * @return array Returns the parsed options. */ - protected function parseSelectizeOptions(array $settings) + protected function parseSelectizeOptions(array $settings): array { // Translate labels $settings = $this->recursiveTranslation($settings); @@ -701,9 +657,8 @@ protected function parseSelectizeOptions(array $settings) /** * @param array $array The array of possible translation. - * @return array */ - private function recursiveTranslation(array $array) + private function recursiveTranslation(array $array): array { foreach ($array as &$item) { if (is_array($item)) { @@ -719,12 +674,9 @@ private function recursiveTranslation(array $array) return $array; } - /** - * @return boolean - */ - public function isObject() + public function isObject(): bool { - return !!($this->p() instanceof ObjectProperty); + return $this->p() instanceof ObjectProperty; } /** @@ -734,13 +686,10 @@ public function isObject() * * @return string */ + #[\Override] public function inputName() { - if ($this->inputName) { - $name = $this->inputName; - } else { - $name = $this->propertyIdent(); - } + $name = $this->inputName ?: $this->propertyIdent(); if ($this->p()['l10n']) { $name .= '[' . $this->lang() . ']'; @@ -756,7 +705,7 @@ public function inputName() /** * @return array */ - public function selectizeTemplates() + public function selectizeTemplates(): object|array|null { return $this->selectizeTemplates; } @@ -764,9 +713,8 @@ public function selectizeTemplates() /** * @param array|object|mixed $selectizeTemplates Selectize Templates array. * @throws \InvalidArgumentException If the supplied argument is not of type object. - * @return self */ - public function setSelectizeTemplates($selectizeTemplates) + public function setSelectizeTemplates($selectizeTemplates): static { if (!is_object($selectizeTemplates) && !is_array($selectizeTemplates)) { $selectizeTemplates = [ @@ -795,9 +743,8 @@ public function selectizeTemplatesAsJson() * @param mixed $val The value to parse into selectize choices. * @param array $options Optional structure options. * @throws InvalidArgumentException If the choice structure is missing a value. - * @return array */ - public function selectizeVal($val, array $options = []) + public function selectizeVal($val, array $options = []): array { /** @todo Find a use for this */ unset($options); @@ -822,10 +769,10 @@ public function selectizeVal($val, array $options = []) } $selectizeTemplates = $this->selectizeTemplates(); - $itemTemplate = isset($selectizeTemplates['item']) ? $selectizeTemplates['item'] : null; - $optionTemplate = isset($selectizeTemplates['option']) ? $selectizeTemplates['option'] : null; - $selectizeController = isset($selectizeTemplates['controller']) ? $selectizeTemplates['controller'] : null; - $selectizeData = isset($selectizeTemplates['data']) ? $selectizeTemplates['data'] : []; + $itemTemplate = ($selectizeTemplates['item'] ?? null); + $optionTemplate = ($selectizeTemplates['option'] ?? null); + $selectizeController = ($selectizeTemplates['controller'] ?? null); + $selectizeData = ($selectizeTemplates['data'] ?? []); if ($prop instanceof ObjectProperty) { foreach ($val as &$v) { @@ -945,6 +892,7 @@ public function sortObjects($objects) * * @return array Returns a data map to abide. */ + #[\Override] public function choiceObjMap() { $map = parent::choiceObjMap(); @@ -963,7 +911,7 @@ public function choiceObjMap() } foreach ($map as &$mapProp) { - $props = explode(':', $mapProp); + $props = explode(':', (string)$mapProp); foreach ($props as $p) { if (isset($objProperties[$p])) { $mapProp = $p; @@ -981,10 +929,9 @@ public function choiceObjMap() /** * Retrieve the default object-to-choice data map. - * - * @return array */ - public function defaultChoiceObjMap() + #[\Override] + public function defaultChoiceObjMap(): array { return [ 'value' => 'id', @@ -995,9 +942,8 @@ public function defaultChoiceObjMap() /** * @param array|\ArrayAccess|ModelInterface $obj The object to map to a optgroup. - * @return array */ - public function mapObjToOptgroup($obj) + public function mapObjToOptgroup($obj): array { $map = $this->optgroupObjMap(); @@ -1029,9 +975,8 @@ public function optgroupObjMap() /** * @param array|null $optgroupObjMap OptgroupObjMap for SelectizeInput. - * @return self */ - public function setOptgroupObjMap($optgroupObjMap) + public function setOptgroupObjMap($optgroupObjMap): static { $map = $optgroupObjMap ?: $this->defaultOptgroupObjMap(); @@ -1057,7 +1002,7 @@ public function setOptgroupObjMap($optgroupObjMap) } foreach ($map as &$mapProp) { - $props = explode(':', $mapProp); + $props = explode(':', (string)$mapProp); foreach ($props as $p) { if (isset($objProperties[$p])) { $mapProp = $p; @@ -1077,10 +1022,8 @@ public function setOptgroupObjMap($optgroupObjMap) /** * Retrieve the default object-to-optgroup data map. - * - * @return array */ - public function defaultOptgroupObjMap() + public function defaultOptgroupObjMap(): array { return [ 'value' => 'id', @@ -1091,10 +1034,9 @@ public function defaultOptgroupObjMap() /** * Retrieve the control's data options for JavaScript components. - * - * @return array */ - public function controlDataForJs() + #[\Override] + public function controlDataForJs(): array { $prop = $this->property(); @@ -1130,29 +1072,23 @@ public function controlDataForJs() 'multiple_options' => $this->property()['multipleOptions'], ]; - if ($prop instanceof ObjectProperty) { - if ($prop['objType']) { - $data['pattern'] = $prop['pattern']; - $data['obj_type'] = $prop['objType']; - } + if ($prop instanceof ObjectProperty && $prop['objType']) { + $data['pattern'] = $prop['pattern']; + $data['obj_type'] = $prop['objType']; } return $data; } - /** - * @return array - */ - public function disabledFields() + public function disabledFields(): array { return $this->disabledFields; } /** * @param array $disabledFields DisabledFields for SelectizeInput. - * @return self */ - public function setDisabledFields(array $disabledFields) + public function setDisabledFields(array $disabledFields): static { $this->disabledFields = $disabledFields; @@ -1169,9 +1105,8 @@ public function remoteSource() /** * @param string $remoteSource RemoteSource for SelectizeInput. - * @return self */ - public function setRemoteSource($remoteSource) + public function setRemoteSource($remoteSource): static { $this->remoteSource = $remoteSource; @@ -1192,9 +1127,8 @@ public function optgroupProperty() /** * @param string|null $optgroupProperty OptgroupProperty for SelectizeInput. - * @return self */ - public function setOptgroupProperty($optgroupProperty) + public function setOptgroupProperty($optgroupProperty): static { $this->optgroupProperty = $optgroupProperty; @@ -1207,6 +1141,7 @@ public function setOptgroupProperty($optgroupProperty) * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/StructureWidgetInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/StructureWidgetInput.php index 7561e3057..4bd467e07 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/StructureWidgetInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/StructureWidgetInput.php @@ -20,6 +20,7 @@ class StructureWidgetInput extends NestedWidgetInput * @throws DomainException If the widget is not a structure widget. * @return WidgetInterface */ + #[\Override] protected function createWidget() { $widget = parent::createWidget(); @@ -30,7 +31,7 @@ protected function createWidget() throw new DomainException(sprintf( 'Widget must an instance of %s, received %s', StructureFormGroup::class, - get_class($widget) + $widget::class )); } @@ -39,10 +40,9 @@ protected function createWidget() /** * Retrieve the default structure widget options. - * - * @return array */ - public function defaultWidgetData() + #[\Override] + public function defaultWidgetData(): array { return [ 'type' => StructureFormGroup::class diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/SwitchInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/SwitchInput.php index d89ea67df..927ef3a83 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/SwitchInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/SwitchInput.php @@ -1,5 +1,7 @@ `. - * - * @return string */ - public function type() + public function type(): string { return 'checkbox'; } - /** - * @return boolean - */ - public function checked() + public function checked(): bool { - return !!$this->inputVal(); + return (bool)$this->inputVal(); } - /** - * @return integer - */ - public function value() + public function value(): int { return $this->inputVal() ? 1 : 0; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/TabulatorInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/TabulatorInput.php index b767638a5..e2e69cf67 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/TabulatorInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/TabulatorInput.php @@ -27,6 +27,7 @@ class TabulatorInput extends AbstractPropertyInput * * @param array $options The input options. */ + #[\Override] public function setInputOptions(array $options): self { parent::setInputOptions($options); @@ -79,6 +80,7 @@ public function addInputOption(string $key, $val): self * * @return array */ + #[\Override] public function getDefaultInputOptions(): array { $translator = $this->translator(); @@ -175,9 +177,8 @@ public function getDefaultTabulatorOptions(): array /** * Retrieve the control's data options for JavaScript components. - * - * @return array */ + #[\Override] public function controlDataForJs(): array { $inputOptions = $this->getInputOptions(); diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/TextInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/TextInput.php index d314e9211..506ce455e 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/TextInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/TextInput.php @@ -10,10 +10,7 @@ */ class TextInput extends AbstractPropertyInput { - /** - * @var integer $size - */ - private $size = 0; + private int $size = 0; /** * The minimum number of characters allowed. @@ -21,10 +18,8 @@ class TextInput extends AbstractPropertyInput * Note: * - In Unicode code points. * - If zero or a negative value is specified, the length is ignored. - * - * @var integer */ - private $minLength = 0; + private int $minLength = 0; /** * The maximum number of characters allowed. @@ -33,22 +28,15 @@ class TextInput extends AbstractPropertyInput * - In UTF-16 code units. * - If it is not specified, the control allows an unlimited number of characters. * - If zero or a negative value is specified, the length is ignored. - * - * @var integer */ - private $maxLength = 0; + private int $maxLength = 0; - /** - * @var string $pattern - */ - private $pattern = ''; + private string $pattern = ''; /** * Retrieve the control type for the HTML element ``. - * - * @return string */ - public function type() + public function type(): string { return 'text'; } @@ -61,7 +49,8 @@ public function type() * @see AbstractPropertyInput::inputVal() * @return string */ - public function inputVal() + #[\Override] + public function inputVal(): ?string { return preg_replace('~[\n\r]~', '', parent::inputVal()); } @@ -71,7 +60,7 @@ public function inputVal() * @throws InvalidArgumentException If the argument is not a number. * @return Text Chainable */ - public function setMinLength($minLength) + public function setMinLength($minLength): static { if (!is_numeric($minLength)) { throw new InvalidArgumentException( @@ -83,10 +72,7 @@ public function setMinLength($minLength) return $this; } - /** - * @return integer - */ - public function minLength() + public function minLength(): int { return $this->minLength; } @@ -96,7 +82,7 @@ public function minLength() * @throws InvalidArgumentException If the argument is not a number. * @return Text Chainable */ - public function setMaxLength($maxLength) + public function setMaxLength($maxLength): static { if (!is_numeric($maxLength)) { throw new InvalidArgumentException( @@ -108,10 +94,7 @@ public function setMaxLength($maxLength) return $this; } - /** - * @return integer - */ - public function maxLength() + public function maxLength(): int { return $this->maxLength; } @@ -121,7 +104,7 @@ public function maxLength() * @throws InvalidArgumentException If the argument is not a number. * @return Text Chainable */ - public function setSize($size) + public function setSize($size): static { if (!is_numeric($size)) { throw new InvalidArgumentException( @@ -132,10 +115,7 @@ public function setSize($size) return $this; } - /** - * @return integer - */ - public function size() + public function size(): int { return $this->size; } @@ -145,7 +125,7 @@ public function size() * @throws InvalidArgumentException If the argument is not a string. * @return Text Chainable */ - public function setPattern($pattern) + public function setPattern($pattern): static { if (!is_string($pattern)) { throw new InvalidArgumentException( @@ -156,20 +136,16 @@ public function setPattern($pattern) return $this; } - /** - * @return string - */ - public function pattern() + public function pattern(): string { return $this->pattern; } /** * Retrieve the control's data options for JavaScript components. - * - * @return array */ - public function controlDataForJs() + #[\Override] + public function controlDataForJs(): array { return [ // Text Control diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/TextareaInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/TextareaInput.php index 03f0432d0..15a83a1a9 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/TextareaInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/TextareaInput.php @@ -1,5 +1,7 @@ cols; } @@ -60,7 +50,7 @@ public function cols() * @throws InvalidArgumentException If the argument is not a number. * @return Text Chainable */ - public function setRows($rows) + public function setRows($rows): static { if (!is_numeric($rows)) { throw new InvalidArgumentException( @@ -74,7 +64,7 @@ public function setRows($rows) /** * @return integer */ - public function rows() + public function rows(): ?int { return $this->rows; } @@ -84,7 +74,7 @@ public function rows() * @throws InvalidArgumentException If the argument is not a number. * @return Text Chainable */ - public function setMinLength($minLength) + public function setMinLength($minLength): static { if (!is_numeric($minLength)) { throw new InvalidArgumentException( @@ -95,10 +85,7 @@ public function setMinLength($minLength) return $this; } - /** - * @return integer - */ - public function minLength() + public function minLength(): int { return $this->minLength; } @@ -108,7 +95,7 @@ public function minLength() * @throws InvalidArgumentException If the argument is not a number. * @return Text Chainable */ - public function setMaxLength($maxLength) + public function setMaxLength($maxLength): static { if (!is_numeric($maxLength)) { throw new InvalidArgumentException( @@ -119,9 +106,7 @@ public function setMaxLength($maxLength) return $this; } - /** - * @return array - */ + #[\Override] public function getInputValOptions(): array { return [ @@ -129,10 +114,7 @@ public function getInputValOptions(): array ]; } - /** - * @return integer - */ - public function maxLength() + public function maxLength(): int { return $this->maxLength; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/Tinymce/BasicInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/Tinymce/BasicInput.php index 9875f5ebe..887f38960 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/Tinymce/BasicInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/Tinymce/BasicInput.php @@ -15,7 +15,7 @@ class BasicInput extends TinymceInput * * @param array $data Dependencies. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { parent::__construct($data); @@ -25,10 +25,8 @@ public function __construct(array $data = null) } } - /** - * @return string - */ - public function inputType() + #[\Override] + public function inputType(): string { return 'charcoal/admin/property/input/tinymce'; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/TinymceInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/TinymceInput.php index e0e6fb396..713cb7724 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/TinymceInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/TinymceInput.php @@ -4,7 +4,7 @@ use InvalidArgumentException; // From Mustache -use Mustache_LambdaHelper as LambdaHelper; +use Mustache\LambdaHelper as LambdaHelper; // From 'charcoal-admin' use Charcoal\Admin\Property\Input\TextareaInput; @@ -29,10 +29,8 @@ class TinymceInput extends TextareaInput /** * Flag wether the "file picker" popup button should be displaed. - * - * @var boolean */ - private $showFilePicker; + private ?bool $showFilePicker = null; /** * URL for the "file picker" popup. @@ -49,7 +47,7 @@ class TinymceInput extends TextareaInput * @param array $settings The editor options. * @return Tinymce Chainable */ - public function setEditorOptions(array $settings) + public function setEditorOptions(array $settings): static { $this->editorOptions = array_merge($this->defaultEditorOptions(), $settings); @@ -62,7 +60,7 @@ public function setEditorOptions(array $settings) * @param array $settings The editor options. * @return Tinymce Chainable */ - public function mergeEditorOptions(array $settings) + public function mergeEditorOptions(array $settings): static { $this->editorOptions = array_merge($this->editorOptions, $settings); @@ -77,7 +75,7 @@ public function mergeEditorOptions(array $settings) * @throws InvalidArgumentException If the identifier is not a string. * @return Tinymce Chainable */ - public function addEditorOption($key, $val) + public function addEditorOption($key, $val): static { if (!is_string($key)) { throw new InvalidArgumentException( @@ -118,11 +116,7 @@ public function defaultEditorOptions() { $defaultData = $this->metadata()->defaultData(); - if (isset($defaultData['editor_options'])) { - return $defaultData['editor_options']; - } - - return []; + return ($defaultData['editor_options'] ?? []); } /** @@ -139,9 +133,8 @@ public function editorOptionsAsJson() * Set the title for the file picker dialog. * * @param mixed $title The dialog title. - * @return self */ - public function setDialogTitle($title) + public function setDialogTitle($title): static { $this->dialogTitle = $this->translator()->translation($title); @@ -153,7 +146,7 @@ public function setDialogTitle($title) * * @return \Charcoal\Translator\Translation|string|null */ - protected function defaultDialogTitle() + protected function defaultDialogTitle(): ?\Charcoal\Translator\Translation { return $this->translator()->translation('filesystem.library.media'); } @@ -176,9 +169,9 @@ public function dialogTitle() * @param boolean $show The show file picker flag. * @return FileInput Chainable */ - public function setShowFilePicker($show) + public function setShowFilePicker($show): static { - $this->showFilePicker = !!$show; + $this->showFilePicker = (bool)$show; return $this; } @@ -195,10 +188,7 @@ public function showFilePicker() return $this->showFilePicker; } - /** - * @return boolean - */ - public function hasFilePicker() + public function hasFilePicker(): bool { return class_exists('\\elFinder'); } @@ -207,7 +197,7 @@ public function hasFilePicker() * @param string $url The file picker AJAX URL. * @return FileInput Chainable */ - public function setFilePickerUrl($url) + public function setFilePickerUrl($url): static { $this->filePickerUrl = $url; return $this; @@ -235,7 +225,7 @@ public function filePickerUrl() * * @return callable|null */ - public function prepareFilePickerUrl() + public function prepareFilePickerUrl(): ?\Closure { if (!$this->showFilePicker()) { return null; @@ -243,7 +233,7 @@ public function prepareFilePickerUrl() $uri = $this->getFilePickerUrlTemplate(); - return function ($noop, LambdaHelper $helper) use ($uri) { + return function ($noop, LambdaHelper $helper) use ($uri): null { $uri = $helper->render($uri); $this->setFilePickerUrl($uri); @@ -253,23 +243,19 @@ public function prepareFilePickerUrl() /** * Retrieve the elFinder connector URL template for rendering. - * - * @return string */ - protected function getFilePickerUrlTemplate() + protected function getFilePickerUrlTemplate(): string { $uri = 'obj_type={{ objType }}&obj_id={{ objId }}&property={{ p.ident }}&callback={{ inputId }}'; - $uri = '{{# withAdminUrl }}elfinder?' . $uri . '{{/ withAdminUrl }}'; - return $uri; + return '{{# withAdminUrl }}elfinder?' . $uri . '{{/ withAdminUrl }}'; } /** * Retrieve the control's data options for JavaScript components. - * - * @return array */ - public function controlDataForJs() + #[\Override] + public function controlDataForJs(): array { return [ 'editor_options' => $this->editorOptions(), diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/UrlInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/UrlInput.php index bb8ea6d70..a5ad5829a 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/UrlInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/UrlInput.php @@ -1,5 +1,7 @@ `. - * - * @return string */ - public function type() + #[\Override] + public function type(): string { return 'url'; } diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/VideoInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/VideoInput.php index 0b58728c6..f0a5645b0 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/VideoInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/VideoInput.php @@ -12,18 +12,15 @@ class VideoInput extends FileInput { /** * Retrieve list of default file type specifiers. - * - * @return string */ - public function getDefaultAccept() + #[\Override] + public function getDefaultAccept(): string { return 'video/*'; } - /** - * @return string|null - */ - public function filePreview() + #[\Override] + public function filePreview(): string { $value = $this->inputVal(); if ($value) { diff --git a/packages/admin/src/Charcoal/Admin/Property/PropertyDisplayInterface.php b/packages/admin/src/Charcoal/Admin/Property/PropertyDisplayInterface.php index 5c3fa340d..30acfadd7 100644 --- a/packages/admin/src/Charcoal/Admin/Property/PropertyDisplayInterface.php +++ b/packages/admin/src/Charcoal/Admin/Property/PropertyDisplayInterface.php @@ -1,5 +1,7 @@ 'now' ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** @@ -78,7 +76,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $this->startLock(); - $climate = $this->climate(); + $this->climate(); $frequency = $this->frequency(); @@ -101,6 +99,7 @@ public function run(RequestInterface $request, ResponseInterface $response) * @param Container $container Pimple DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -141,7 +140,7 @@ abstract protected function emailData(Notification $notification, array $objects * @param string $frequency The frequency type to load. * @return Charcoal\Model\CollectionInterface */ - private function loadNotifications($frequency) + private function loadNotifications($frequency): \ArrayAccess|array { $loader = new CollectionLoader([ 'logger' => $this->logger, @@ -152,35 +151,33 @@ private function loadNotifications($frequency) 'property' => 'frequency', 'val' => $frequency ]); - $notifications = $loader->load(); - return $notifications; + return $loader->load(); } /** * Handle a notification request * * @param Notification $notification The notification object to handle. - * @return void */ - private function handleNotification(Notification $notification) + private function handleNotification(Notification $notification): void { - if (empty($notification->targetTypes())) { + if (in_array($notification->targetTypes(), [null, []], true)) { return; } $objectsByTypes = []; $numTotal = 0; foreach ($notification->targetTypes() as $objType) { - $objType = trim($objType); + $objType = trim((string)$objType); $objects = $this->updatedObjects($objType); $num = count($objects); - if ($num == 0) { + if ($num === 0) { continue; } $obj = []; $obj['objects'] = $objects; $obj['num'] = $num; $obj['type'] = $objType; - $obj['typeLabel'] = isset($objects[0]['targetTypeLabel']) ? $objects[0]['targetTypeLabel'] : $objType; + $obj['typeLabel'] = ($objects[0]['targetTypeLabel'] ?? $objType); $objectsByTypes[$objType] = $obj; $numTotal += $num; @@ -192,11 +189,10 @@ private function handleNotification(Notification $notification) * @param Notification $notification The notification object. * @param array $objects The objects that were modified. * @param integer $numTotal Total number of modified objects. - * @return void */ - private function sendEmail(Notification $notification, array $objects, $numTotal) + private function sendEmail(Notification $notification, array $objects, int $numTotal): void { - if ($numTotal == 0) { + if ($numTotal === 0) { return; } @@ -237,7 +233,7 @@ private function sendEmail(Notification $notification, array $objects, $numTotal * @param string $objType The object (target) type to process. * @return CollectionInterface */ - private function updatedObjects($objType) + private function updatedObjects(string $objType): \ArrayAccess|array { $loader = new CollectionLoader([ 'logger' => $this->logger, @@ -266,7 +262,7 @@ private function updatedObjects($objType) $userFactory = $this->userFactory; $baseUrl = $this->baseUrl(); - $loader->setCallback(function (&$obj) use ($objFactory, $userFactory, $baseUrl) { + $loader->setCallback(function (array &$obj) use ($objFactory, $userFactory, $baseUrl): void { $diff = $obj->dataDiff(); $obj->updatedProperties = isset($diff[0]) ? array_keys($diff[0]) : []; $obj->dateStr = $obj['rev_ts']->format('Y-m-d H:i:s'); @@ -296,9 +292,8 @@ private function updatedObjects($objType) /** * @param FactoryInterface $factory The factory used to create queue items. - * @return void */ - private function setNotificationFactory(FactoryInterface $factory) + private function setNotificationFactory(FactoryInterface $factory): void { $this->notificationFactory = $factory; } @@ -306,16 +301,15 @@ private function setNotificationFactory(FactoryInterface $factory) /** * @return FactoryInterface */ - private function notificationFactory() + private function notificationFactory(): ?\Charcoal\Factory\FactoryInterface { return $this->notificationFactory; } /** * @param FactoryInterface $factory The factory used to create queue items. - * @return void */ - private function setRevisionFactory(FactoryInterface $factory) + private function setRevisionFactory(FactoryInterface $factory): void { $this->revisionFactory = $factory; } diff --git a/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessDailyScript.php b/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessDailyScript.php index ad5987bcc..495887fae 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessDailyScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessDailyScript.php @@ -1,5 +1,7 @@ setTime(0, 0, 0); @@ -35,9 +34,8 @@ protected function startDate() /** * Retrieve the "maximal" date that the revisions should have been made for this script. - * @return DateTime */ - protected function endDate() + protected function endDate(): \DateTime { $d = new DateTime('today'); $d->setTime(0, 0, 0); @@ -47,9 +45,8 @@ protected function endDate() /** * @param Notification $notification The notification object. * @param array $objects The objects that were modified. - * @return array */ - protected function emailData(Notification $notification, array $objects) + protected function emailData(Notification $notification, array $objects): array { unset($notification, $objects); diff --git a/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessHourlyScript.php b/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessHourlyScript.php index 97e6f4be6..17d7d1bfa 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessHourlyScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessHourlyScript.php @@ -14,19 +14,16 @@ class ProcessHourlyScript extends AbstractNotificationScript { /** * Get the frequency type of this script. - * - * @return string */ - protected function frequency() + protected function frequency(): string { return 'hourly'; } /** - * Retrieve the "minimal" date that the revisions should have been made for this script. - * @return DateTime - */ - protected function startDate() + * Retrieve the "minimal" date that the revisions should have been made for this script. + */ + protected function startDate(): \DateTime { $d = new DateTime('1 hour ago'); $d->setTime($d->format('H'), 0, 0); @@ -35,9 +32,8 @@ protected function startDate() /** * Retrieve the "maximal" date that the revisions should have been made for this script. - * @return DateTime */ - protected function endDate() + protected function endDate(): \DateTime { $d = new DateTime('now'); $d->setTime($d->format('H'), 0, 0); @@ -47,9 +43,8 @@ protected function endDate() /** * @param Notification $notification The notification object. * @param array $objects The objects that were modified. - * @return array */ - protected function emailData(Notification $notification, array $objects) + protected function emailData(Notification $notification, array $objects): array { unset($notification, $objects); diff --git a/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessMinuteScript.php b/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessMinuteScript.php index b250536ec..7063820ca 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessMinuteScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessMinuteScript.php @@ -14,19 +14,16 @@ class ProcessMinuteScript extends AbstractNotificationScript { /** * Get the frequency type of this script. - * - * @return string */ - protected function frequency() + protected function frequency(): string { return 'minute'; } /** * Retrieve the "minimal" date that the revisions should have been made for this script. - * @return DateTime */ - protected function startDate() + protected function startDate(): \DateTime { $d = new DateTime('1 minute ago'); $d->setTime(0, 0, 0); @@ -35,20 +32,17 @@ protected function startDate() /** * Retrieve the "maximal" date that the revisions should have been made for this script. - * @return DateTime */ - protected function endDate() + protected function endDate(): \DateTime { - $d = new DateTime($this->starDate() . ' +1 minute'); - return $d; + return new DateTime($this->starDate() . ' +1 minute'); } /** * @param Notification $notification The notification object. * @param array $objects The objects that were modified. - * @return array */ - protected function emailData(Notification $notification, array $objects) + protected function emailData(Notification $notification, array $objects): array { unset($notification, $objects); diff --git a/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessMonthlyScript.php b/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessMonthlyScript.php index 12ceaf6bd..62c4ee275 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessMonthlyScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessMonthlyScript.php @@ -1,5 +1,7 @@ setTime(0, 0, 0); @@ -35,9 +34,8 @@ protected function startDate() /** * Retrieve the "minimal" date that the revisions should have been made for this script. - * @return DateTime */ - protected function endDate() + protected function endDate(): \DateTime { $d = new DateTime('first day of this month'); $d->setTime(0, 0, 0); @@ -47,9 +45,8 @@ protected function endDate() /** * @param Notification $notification The notification object. * @param array $objects The objects that were modified. - * @return array */ - protected function emailData(Notification $notification, array $objects) + protected function emailData(Notification $notification, array $objects): array { unset($notification, $objects); diff --git a/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessWeeklyScript.php b/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessWeeklyScript.php index 47f95d6be..eafe5fa14 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessWeeklyScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Notification/ProcessWeeklyScript.php @@ -1,5 +1,7 @@ setTime(0, 0, 0); @@ -35,9 +34,8 @@ protected function startDate() /** * Retrieve the "maximal" date that the revisions should have been made for this script. - * @return DateTime */ - protected function endDate() + protected function endDate(): \DateTime { $d = new DateTime('last monday'); $d->setTime(0, 0, 0); @@ -47,9 +45,8 @@ protected function endDate() /** * @param Notification $notification The notification object. * @param array $objects The objects that were modified. - * @return array */ - protected function emailData(Notification $notification, array $objects) + protected function emailData(Notification $notification, array $objects): array { unset($notification, $objects); diff --git a/packages/admin/src/Charcoal/Admin/Script/Object/CreateScript.php b/packages/admin/src/Charcoal/Admin/Script/Object/CreateScript.php index 56e5a7a66..0a38cbc72 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Object/CreateScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Object/CreateScript.php @@ -13,10 +13,8 @@ */ class CreateScript extends AdminScript { - /** - * @return array - */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'obj-type' => [ @@ -30,17 +28,14 @@ public function defaultArguments() 'defaultValue' => '' ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); diff --git a/packages/admin/src/Charcoal/Admin/Script/Object/ProcessSchedulesScript.php b/packages/admin/src/Charcoal/Admin/Script/Object/ProcessSchedulesScript.php index e2740c42b..3402f9447 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Object/ProcessSchedulesScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Object/ProcessSchedulesScript.php @@ -26,15 +26,10 @@ class ProcessSchedulesScript extends AdminScript implements CronScriptInterface { use CronScriptTrait; - /** - * @var FactoryInterface $scheduleFactory - */ - private $scheduleFactory; + private ?\Charcoal\Factory\FactoryInterface $scheduleFactory = null; - /** - * @return array - */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'obj-type' => [ @@ -49,17 +44,14 @@ public function defaultArguments() 'defaultValue' => '' ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -72,17 +64,17 @@ public function run(RequestInterface $request, ResponseInterface $response) $scheduled = $this->loadSchedules($objType, $objId); - $callback = function ($obj) use ($climate) { + $callback = function ($obj): void { // No default callback }; - $successCallback = function ($obj) use ($climate) { + $successCallback = function ($obj) use ($climate): void { $climate->green()->out( sprintf('Object %s : %s schedule was successfully ran.', $obj->targetType(), $obj->targetId()) ); }; - $failureCallback = function ($obj) use ($climate) { + $failureCallback = function ($obj) use ($climate): void { $climate->red()->out( sprintf('Object %s : %s schedule could not be ran.', $obj->targetType(), $obj->targetId()) ); @@ -102,6 +94,7 @@ public function run(RequestInterface $request, ResponseInterface $response) * @param Container $container Pimple DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -112,16 +105,15 @@ protected function setDependencies(Container $container) /** * @return FactoryInterface */ - protected function scheduleFactory() + protected function scheduleFactory(): ?\Charcoal\Factory\FactoryInterface { return $this->scheduleFactory; } /** * @param FactoryInterface $factory The factory used to create queue items. - * @return void */ - private function setScheduleFactory(FactoryInterface $factory) + private function setScheduleFactory(FactoryInterface $factory): void { $this->scheduleFactory = $factory; } @@ -139,7 +131,7 @@ private function scheduleProto() * @param string $objId Optional object id to loader. * @return \Charcoal\Model\Collection|array */ - private function loadSchedules($objType = null, $objId = null) + private function loadSchedules($objType = null, $objId = null): \ArrayAccess|array { $loader = new CollectionLoader([ 'logger' => $this->logger, @@ -173,7 +165,6 @@ private function loadSchedules($objType = null, $objId = null) 'property' => 'scheduled_date', 'mode' => 'asc' ]); - $schedules = $loader->load(); - return $schedules; + return $loader->load(); } } diff --git a/packages/admin/src/Charcoal/Admin/Script/Object/Table/AlterPrimaryKeyScript.php b/packages/admin/src/Charcoal/Admin/Script/Object/Table/AlterPrimaryKeyScript.php index e80af22d9..69b27ed14 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Object/Table/AlterPrimaryKeyScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Object/Table/AlterPrimaryKeyScript.php @@ -78,6 +78,7 @@ class AlterPrimaryKeyScript extends AdminScript /** * @return void */ + #[\Override] protected function init() { parent::init(); @@ -93,9 +94,8 @@ protected function init() * * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -110,10 +110,8 @@ public function run(RequestInterface $request, ResponseInterface $response) /** * Execute the prime directive. - * - * @return self */ - public function start() + public function start(): static { $cli = $this->climate(); @@ -235,7 +233,7 @@ public function start() * @throws RuntimeException If the $oldKey does not exist. * @return IdProperty[] */ - protected function prepareProperties($oldKey, $newKey, &$oldProp = null, &$newProp = null) + protected function prepareProperties($oldKey, $newKey, &$oldProp = null, &$newProp = null): array { $model = $this->targetModel(); $source = $model->source(); @@ -282,11 +280,11 @@ protected function prepareProperties($oldKey, $newKey, &$oldProp = null, &$newPr ); } - if (preg_match('~\bINT\(?(?:$|\b)~i', $col['Type'])) { + if (preg_match('~\bINT\(?(?:$|\b)~i', (string)$col['Type'])) { $oldProp->setMode(IdProperty::MODE_AUTO_INCREMENT); - } elseif (preg_match('~(?:^|\b)(?:VAR)?CHAR\(13\)(?:$|\b)~i', $col['Type'])) { + } elseif (preg_match('~(?:^|\b)(?:VAR)?CHAR\(13\)(?:$|\b)~i', (string)$col['Type'])) { $oldProp->setMode(IdProperty::MODE_UNIQID); - } elseif (preg_match('~(?:^|\b)(?:VAR)?CHAR\(36\)(?:$|\b)~i', $col['Type'])) { + } elseif (preg_match('~(?:^|\b)(?:VAR)?CHAR\(36\)(?:$|\b)~i', (string)$col['Type'])) { $oldProp->setMode(IdProperty::MODE_UUID); } else { $oldProp->setMode(IdProperty::MODE_CUSTOM); @@ -299,7 +297,7 @@ protected function prepareProperties($oldKey, $newKey, &$oldProp = null, &$newPr throw new RuntimeException( sprintf( 'The model [%1$s] does not have the target field [%2$s]', - get_class($model), + $model::class, $oldKey ) ); @@ -316,41 +314,30 @@ protected function prepareProperties($oldKey, $newKey, &$oldProp = null, &$newPr * * @param string|IdProperty $mode The mode or property to resolve. * @throws UnexpectedValueException If the ID mode is invalid. - * @return string */ - protected function labelFromMode($mode) + protected function labelFromMode($mode): string { if ($mode instanceof IdProperty) { $mode = $mode->getMode(); } - - switch ($mode) { - case IdProperty::MODE_AUTO_INCREMENT: - return 'auto-increment'; - - case IdProperty::MODE_UNIQID: - return 'uniqid()'; - - case IdProperty::MODE_UUID: - return 'RFC-4122 UUID'; - - case IdProperty::MODE_CUSTOM: - return 'custom'; - } - - throw new UnexpectedValueException(sprintf( - 'The ID mode was not recognized: %s', - is_object($mode) ? get_class($mode) : gettype($mode) - )); + return match ($mode) { + IdProperty::MODE_AUTO_INCREMENT => 'auto-increment', + IdProperty::MODE_UNIQID => 'uniqid()', + IdProperty::MODE_UUID => 'RFC-4122 UUID', + IdProperty::MODE_CUSTOM => 'custom', + default => throw new UnexpectedValueException(sprintf( + 'The ID mode was not recognized: %s', + get_debug_type($mode) + )), + }; } /** * Retrieve a label for the property. * * @param IdProperty $prop The new ID property to analyse. - * @return string|null */ - protected function labelFromProp(IdProperty $prop) + protected function labelFromProp(IdProperty $prop): ?string { $mode = $prop->getMode(); switch ($mode) { @@ -362,7 +349,7 @@ protected function labelFromProp(IdProperty $prop) default: $label = $this->labelFromMode($mode); - if ($label) { + if ($label !== '' && $label !== '0') { return sprintf('auto-generated ID (%s)', $label); } else { return 'auto-generated ID'; @@ -377,11 +364,10 @@ protected function labelFromProp(IdProperty $prop) * * @param IdProperty $newProp The new ID property to analyse. * @param IdProperty $oldProp The previous ID property to analyse. - * @return self */ - protected function describeConversion(IdProperty $newProp, IdProperty $oldProp = null) + protected function describeConversion(IdProperty $newProp, ?IdProperty $oldProp = null): static { - if ($oldProp) { + if ($oldProp instanceof \Charcoal\Property\IdProperty) { $new = $this->labelFromProp($newProp); $old = $this->labelFromProp($oldProp); $desc = sprintf('Converting to %s from %s.', $new, $old); @@ -401,7 +387,7 @@ protected function describeConversion(IdProperty $newProp, IdProperty $oldProp = * @param IdProperty $prop The property to retrieve the field from. * @return PropertyField */ - protected function propertyField(IdProperty $prop) + protected function propertyField(IdProperty $prop): \Charcoal\Property\PropertyField|false { $fields = $prop->fields(); @@ -447,12 +433,7 @@ private function isPrimaryKeyDifferent() private function oldPrimaryKey() { if ($this->oldPrimaryKey === null) { - if ($this->isPrimaryKeyDifferent()) { - $oldKey = $this->climate()->arguments->get('old_key'); - } else { - $oldKey = $this->targetModel()->key(); - } - + $oldKey = $this->isPrimaryKeyDifferent() ? $this->climate()->arguments->get('old_key') : $this->targetModel()->key(); $this->oldPrimaryKey = $oldKey; } @@ -469,11 +450,7 @@ private function newPrimaryKey() if ($this->newPrimaryKey === null) { $model = $this->targetModel(); - if ($this->isPrimaryKeyDifferent()) { - $newKey = $model->key(); - } else { - $newKey = sprintf('%s_new', $model->key()); - } + $newKey = $this->isPrimaryKeyDifferent() ? $model->key() : sprintf('%s_new', $model->key()); $this->newPrimaryKey = $newKey; } @@ -486,9 +463,8 @@ private function newPrimaryKey() * * @param array|Traversable $rows The target model's existing rows. * @throws InvalidArgumentException If the given argument is not iterable. - * @return boolean */ - private function describeCount($rows = null) + private function describeCount($rows = null): bool { if ($rows === null) { $rows = $this->fetchTargetRows(); @@ -498,7 +474,7 @@ private function describeCount($rows = null) throw new InvalidArgumentException( sprintf( 'The rows must be iterable; received %s', - is_object($rows) ? get_class($rows) : gettype($rows) + get_debug_type($rows) ) ); } @@ -506,7 +482,7 @@ private function describeCount($rows = null) $cli = $this->climate(); $model = $this->targetModel(); - if (is_array($rows) || $rows instanceof Countable) { + if (is_countable($rows)) { $count = count($rows); } elseif ($rows instanceof PDOStatement) { $count = $rows->rowCount(); @@ -525,12 +501,10 @@ private function describeCount($rows = null) if (!$this->quiet()) { $cli->comment('The object table has 1 row.'); } - } else { - if (!$this->quiet()) { - $cli->comment( - sprintf('The object table has %s rows.', $count) - ); - } + } elseif (!$this->quiet()) { + $cli->comment( + sprintf('The object table has %s rows.', $count) + ); } return true; @@ -541,9 +515,8 @@ private function describeCount($rows = null) * * @param PropertyField $field The new ID field. * @param IdProperty $prop The new ID property. - * @return self */ - private function insertNewField(PropertyField $field, IdProperty $prop) + private function insertNewField(PropertyField $field, IdProperty $prop): static { unset($prop); @@ -588,9 +561,8 @@ private function insertNewField(PropertyField $field, IdProperty $prop) * * @param PropertyField $field The previous ID field. * @param IdProperty $prop The previous ID property. - * @return self */ - private function dropPrimaryKey(PropertyField $field, IdProperty $prop) + private function dropPrimaryKey(PropertyField $field, IdProperty $prop): static { $keepId = $this->climate()->arguments->defined('keep_id'); $model = $this->targetModel(); @@ -628,9 +600,8 @@ private function dropPrimaryKey(PropertyField $field, IdProperty $prop) * * @param PropertyField $field The new ID field. * @param IdProperty $prop The new ID property. - * @return self */ - private function applyPrimaryKey(PropertyField $field, IdProperty $prop) + private function applyPrimaryKey(PropertyField $field, IdProperty $prop): static { unset($prop); @@ -655,9 +626,8 @@ private function applyPrimaryKey(PropertyField $field, IdProperty $prop) * @param PropertyField $field The field to rename. * @param string $from The original field key. * @param string $to The new field key. - * @return self */ - private function renameColumn(PropertyField $field, $from, $to) + private function renameColumn(PropertyField $field, $from, $to): static { $model = $this->targetModel(); $source = $model->source(); @@ -681,9 +651,8 @@ private function renameColumn(PropertyField $field, $from, $to) * Remove the given field. * * @param PropertyField $field The field to remove. - * @return self */ - private function removeColumn(PropertyField $field) + private function removeColumn(PropertyField $field): static { $source = $this->targetModel()->source(); @@ -707,21 +676,20 @@ private function removeColumn(PropertyField $field) * @param IdProperty $oldProp The previous ID property. * @param PropertyField $oldField The previous ID field. * @throws InvalidArgumentException If the new property does not implement the proper mode. - * @return self */ protected function convertIdField( IdProperty $newProp, PropertyField $newField, IdProperty $oldProp, PropertyField $oldField - ) { + ): static { $cli = $this->climate(); $keepId = $cli->arguments->defined('keep_id'); $model = $this->targetModel(); $source = $model->source(); $table = $source->table(); - $dbh = $source->db(); + $source->db(); $newKey = $newProp->getIdent(); $oldKey = $oldProp->getIdent(); @@ -739,7 +707,7 @@ protected function convertIdField( switch ($mode) { case IdProperty::MODE_AUTO_INCREMENT: $pool = 0; - $ids = function () use (&$pool) { + $ids = function () use (&$pool): int { return ++$pool; }; break; @@ -750,7 +718,7 @@ protected function convertIdField( $generator = $this->idGenerator(); $pool = []; - $ids = function () use (&$pool, $model, $generator) { + $ids = function () use (&$pool, $generator) { $id = $generator(); while (in_array($id, $pool)) { $id = $generator(); @@ -764,7 +732,7 @@ protected function convertIdField( default: $pool = []; - $ids = function () use (&$pool, $newProp) { + $ids = function () use (&$pool, $newProp): ?string { $id = $newProp->autoGenerate(); while (in_array($id, $pool)) { $id = $newProp->autoGenerate(); @@ -830,14 +798,13 @@ protected function convertIdField( * @param IdProperty $oldProp The previous ID property. * @param PropertyField $oldField The previous ID field. * @throws InvalidArgumentException If the new property does not implement the proper mode. - * @return self */ protected function syncRelatedFields( IdProperty $newProp, PropertyField $newField, IdProperty $oldProp, PropertyField $oldField - ) { + ): static { unset($newProp, $oldProp, $oldField); $cli = $this->climate(); @@ -907,21 +874,18 @@ protected function syncRelatedFields( * * @return array */ + #[\Override] public function defaultArguments() { static $arguments; if ($arguments === null) { - $validateFieldName = function ($response) { - return is_string($response) && strlen($response) > 0; - }; + $validateFieldName = (fn($response): bool => is_string($response) && $response !== ''); - $validateCallback = function ($response) { - return is_string($response) && (strpos($callable, '::') > 1 || function_exists($response)); - }; + $validateCallback = (fn($response): bool => is_string($response) && (strpos($callable, '::') > 1 || function_exists($response))); - $validateModel = function ($response) { - if (strlen($response) === 0) { + $validateModel = function ($response): bool { + if ((string)$response === '') { return false; } @@ -936,8 +900,8 @@ public function defaultArguments() return true; }; - $validateModels = function ($response) { - if (strlen($response) === 0) { + $validateModels = function ($response): bool { + if ((string)$response === '') { return false; } @@ -1018,9 +982,8 @@ public function parentArguments() * * @param mixed $callable A function or method. * @throws InvalidArgumentException If the given argument is not a callable function. - * @return self */ - public function setIdGenerator($callable) + public function setIdGenerator($callable): static { $this->idGenerator = $this->parseIdGenerator($callable); @@ -1047,16 +1010,16 @@ public function parseIdGenerator($callable) $bail = false; if (is_array($callable) && count($callable) === 2) { - list($class, $func) = $callable; + [$class, $func] = $callable; $isMethod = ($class && $func); } elseif (is_string($callable) && strpos($callable, '::') > 1) { - list($class, $func) = explode('::', $callable); + [$class, $func] = explode('::', $callable); $isMethod = ($class && $func); } if ($isMethod) { $model = $this->targetModel(); - $isModel = is_a($model, $class); + $isModel = $model instanceof $class; $method = new ReflectionMethod($class, $func); if ($isModel && $method->isPublic()) { @@ -1073,7 +1036,7 @@ public function parseIdGenerator($callable) sprintf( 'The ID generator must be callable, received: %s', is_object($callable) - ? get_class($callable) + ? $callable::class : (is_string($callable) ? $callable : gettype($callable) @@ -1093,7 +1056,7 @@ public function parseIdGenerator($callable) */ public function idGenerator() { - if (!isset($this->idGenerator)) { + if ($this->idGenerator === null) { throw new RuntimeException('A function to generate a unique ID must be provided.'); } @@ -1105,9 +1068,8 @@ public function idGenerator() * * @param string|ModelInterface $model An object model. * @throws InvalidArgumentException If the given argument is not a model. - * @return self */ - public function setTargetModel($model) + public function setTargetModel($model): static { if (is_string($model)) { $model = $this->modelFactory()->get($model); @@ -1135,7 +1097,7 @@ public function setTargetModel($model) */ public function targetModel() { - if (!isset($this->targetModel)) { + if ($this->targetModel === null) { throw new RuntimeException('A model must be targeted.'); } @@ -1147,14 +1109,13 @@ public function targetModel() * * @param string|array $models One or more object models. * @throws InvalidArgumentException If the given argument is not a model. - * @return self */ - public function setRelatedModels($models) + public function setRelatedModels($models): static { $models = $this->parseAsArray($models); foreach ($models as $i => $model) { if (is_string($model)) { - list($model, $prop) = $this->resolveRelatedModel($model); + [$model, $prop] = $this->resolveRelatedModel($model); $models[$i] = $model; $this->relatedProperties[$model->objType()] = $prop; } elseif ($model instanceof ModelInterface) { @@ -1162,7 +1123,7 @@ public function setRelatedModels($models) throw new InvalidArgumentException( sprintf( 'The related model [%s] requires a target property', - get_class($model) + $model::class ) ); } @@ -1189,16 +1150,16 @@ public function setRelatedModels($models) * @throws InvalidArgumentException If the identifier is invalid. * @return array Returns an array containing a ModelInterface and a property identifier. */ - protected function resolveRelatedModel($pattern) + protected function resolveRelatedModel($pattern): array { - list($class, $prop) = array_pad($this->parseAsArray($pattern, ':'), 2, null); + [$class, $prop] = array_pad($this->parseAsArray($pattern, ':'), 2, null); $model = $this->modelFactory()->get($class); if (!$prop) { throw new InvalidArgumentException( sprintf( 'The related model [%s] requires a target property', - get_class($model) + $model::class ) ); } diff --git a/packages/admin/src/Charcoal/Admin/Script/Object/Table/AlterScript.php b/packages/admin/src/Charcoal/Admin/Script/Object/Table/AlterScript.php index 37df8a738..e510413b6 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Object/Table/AlterScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Object/Table/AlterScript.php @@ -13,10 +13,8 @@ */ class AlterScript extends AdminScript { - /** - * @return array - */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'obj-type' => [ @@ -25,17 +23,14 @@ public function defaultArguments() 'defaultValue' => '' ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -86,7 +81,7 @@ public function run(RequestInterface $request, ResponseInterface $response) return $response; } - $ret = $source->alterTable(); + $source->alterTable(); $climate->green()->out( "\n" . 'Success!' diff --git a/packages/admin/src/Charcoal/Admin/Script/Object/Table/CreateScript.php b/packages/admin/src/Charcoal/Admin/Script/Object/Table/CreateScript.php index 0cc9ecb37..b06cf7726 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Object/Table/CreateScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Object/Table/CreateScript.php @@ -13,10 +13,8 @@ */ class CreateScript extends AdminScript { - /** - * @return array - */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'obj-type' => [ @@ -25,17 +23,14 @@ public function defaultArguments() 'defaultValue' => '' ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -86,7 +81,7 @@ public function run(RequestInterface $request, ResponseInterface $response) return $response; } - $ret = $source->createTable(); + $source->createTable(); $climate->green()->out( "\n" . 'Success!' diff --git a/packages/admin/src/Charcoal/Admin/Script/ObjectsScript.php b/packages/admin/src/Charcoal/Admin/Script/ObjectsScript.php index 4591678ae..5b1d606d3 100644 --- a/packages/admin/src/Charcoal/Admin/Script/ObjectsScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/ObjectsScript.php @@ -28,10 +28,8 @@ class ObjectsScript extends AdminScript implements CollectionContainerInterface { use CollectionContainerTrait; - /** - * @return array - */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'obj-type' => [ @@ -54,17 +52,14 @@ public function defaultArguments() 'castTo' => 'int' ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -94,7 +89,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $collection = $this->collection(); $table = []; - $rows = $this->objectRows(); + $this->objectRows(); foreach ($collection as $c) { $obj = []; diff --git a/packages/admin/src/Charcoal/Admin/Script/Tools/CheckLinksScript.php b/packages/admin/src/Charcoal/Admin/Script/Tools/CheckLinksScript.php index f86325828..e9b05c170 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Tools/CheckLinksScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Tools/CheckLinksScript.php @@ -16,10 +16,7 @@ */ class CheckLinksScript extends AdminScript { - /** - * @var string - */ - private $startUrl; + private ?string $startUrl = null; /** * @var array @@ -36,10 +33,7 @@ class CheckLinksScript extends AdminScript */ private $processedUrls = []; - /** - * @var GuzzleClient - */ - private $guzzleClient; + private readonly \GuzzleHttp\Client $guzzleClient; /** * @var GoutteClient @@ -58,10 +52,8 @@ public function __construct($data = null) $this->goutteClient->setClient($this->guzzleClient); } - /** - * @return array - */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'url' => [ @@ -81,17 +73,14 @@ public function defaultArguments() 'defaultValue' => true ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request PSR-7 request. * @param ResponseInterface $response PSR-7 response. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -114,9 +103,8 @@ public function run(RequestInterface $request, ResponseInterface $response) /** * @param string $url The URL to check. - * @return void */ - private function checkUrl($url) + private function checkUrl($url): void { $rawUrl = $url; $this->processedUrls[] = $url; @@ -132,7 +120,7 @@ private function checkUrl($url) try { $response = $this->guzzleClient->request('GET', $url, [ 'http_errors' => false, - 'on_stats' => function (TransferStats $stats) { + 'on_stats' => function (TransferStats $stats): void { if ($stats->hasResponse()) { $code = $stats->getResponse()->getStatusCode(); $transferTime = (1000 * $stats->getTransferTime()); @@ -162,7 +150,7 @@ private function checkUrl($url) } } ]); - } catch (Exception $e) { + } catch (Exception) { // Do nothing $this->climate()->error('-- Error retrieving ' . $url); } @@ -174,13 +162,12 @@ private function checkUrl($url) /** * @param string $url The URL to retrieve links from. * @param integer $level The current level. - * @return void */ - private function retrieveLinks($url, $level) + private function retrieveLinks($url, int|float $level): void { $crawler = $this->goutteClient->request('GET', $url); - $crawler->filter('a')->each(function ($item) use ($level) { + $crawler->filter('a')->each(function ($item) use ($level): void { $href = $item->attr('href'); if (in_array($href, $this->processedUrls)) { return; @@ -202,19 +189,15 @@ private function isInternalLink($url) if (!isset($parsed['host'])) { return true; } - if ($parsed['host'] === $this->parsedStartUrl['host']) { - return true; - } - return false; + return $parsed['host'] === $this->parsedStartUrl['host']; } /** * @param string $url The URL to convert to absolute. - * @return string */ - private function absoluteLink($url) + private function absoluteLink($url): string { - if (strstr($url, 'http') === false) { + if (!str_contains($url, 'http')) { return $this->startUrl . ltrim($url, '/'); } else { return $url; @@ -223,16 +206,10 @@ private function absoluteLink($url) /** * @param string $url The URL to valdate. - * @return boolean */ - private function validateLink($url) + private function validateLink($url): bool { $parsed = parse_url($url); - if (isset($parsed['scheme'])) { - if (!in_array($parsed['scheme'], ['http', 'https'])) { - return false; - } - } - return true; + return !(isset($parsed['scheme']) && !in_array($parsed['scheme'], ['http', 'https'])); } } diff --git a/packages/admin/src/Charcoal/Admin/Script/Tools/CopyAssetsScript.php b/packages/admin/src/Charcoal/Admin/Script/Tools/CopyAssetsScript.php index 3b55aaa07..e8b3fca24 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Tools/CopyAssetsScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Tools/CopyAssetsScript.php @@ -15,15 +15,14 @@ */ class CopyAssetsScript extends AdminScript { + public $basePath; /** * @var string */ private $dir; - /** - * @return array - */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'dir' => [ @@ -32,17 +31,14 @@ public function defaultArguments() 'defaultValue' => 'www/assets/admin/' ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request PSR-7 request. * @param ResponseInterface $response PSR-7 response. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -91,6 +87,7 @@ public function run(RequestInterface $request, ResponseInterface $response) * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -109,7 +106,7 @@ protected function setDependencies(Container $container) * @param integer $permissions New folder creation permissions. * @return boolean Returns true on success, false on failure. */ - private function copy($source, $dest, $permissions = 0755) + private function copy(string $source, string $dest, $permissions = 0755) { // Check for symlinks if (is_link($source)) { @@ -130,7 +127,7 @@ private function copy($source, $dest, $permissions = 0755) $dir = dir($source); while (false !== $entry = $dir->read()) { // Skip pointers - if ($entry == '.' || $entry == '..') { + if ($entry === '.' || $entry === '..') { continue; } diff --git a/packages/admin/src/Charcoal/Admin/Script/Tools/OptimizeImagesScript.php b/packages/admin/src/Charcoal/Admin/Script/Tools/OptimizeImagesScript.php index c7147c730..8f1570250 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Tools/OptimizeImagesScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Tools/OptimizeImagesScript.php @@ -32,10 +32,8 @@ class OptimizeImagesScript extends AdminScript */ private $dir; - /** - * @return array - */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'jpg' => [ @@ -54,17 +52,14 @@ public function defaultArguments() 'defaultValue' => 'www/uploads/' ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request PSR-7 request. * @param ResponseInterface $response PSR-7 response. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -117,6 +112,7 @@ public function run(RequestInterface $request, ResponseInterface $response) * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -142,9 +138,8 @@ private function getOptipngCmd() /** * @param string $cmd The jpegoptim command. - * @return void */ - private function runJpegoptim($cmd) + private function runJpegoptim($cmd): void { $cmdName = sprintf( 'cd %s && \ @@ -172,9 +167,8 @@ private function runJpegoptim($cmd) /** * @param string $cmd The jpegoptim command. - * @return void */ - private function runOptipng($cmd) + private function runOptipng($cmd): void { $cmdName = sprintf( 'cd %s && \ @@ -197,11 +191,11 @@ private function runOptipng($cmd) * @param string $cmdName The binary name to search. * @return string */ - private function findCmd($cmdName) + private function findCmd(string $cmdName) { $cmd = exec('type -p ' . $cmdName); $cmd = str_replace($cmdName . ' is ', '', $cmd); - if (!$cmd) { + if ($cmd === '' || $cmd === '0') { $cmd = exec('where ' . $cmdName); } if (!$cmd) { diff --git a/packages/admin/src/Charcoal/Admin/Script/Tools/ResizeImagesScript.php b/packages/admin/src/Charcoal/Admin/Script/Tools/ResizeImagesScript.php index 1f2ecf868..3c03935d6 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Tools/ResizeImagesScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Tools/ResizeImagesScript.php @@ -32,10 +32,8 @@ class ResizeImagesScript extends AdminScript */ private $dir; - /** - * @return array - */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'width' => [ @@ -54,17 +52,14 @@ public function defaultArguments() 'defaultValue' => 'www/uploads/' ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request PSR-7 request. * @param ResponseInterface $response PSR-7 response. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -175,6 +170,7 @@ public function run(RequestInterface $request, ResponseInterface $response) * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -186,11 +182,11 @@ protected function setDependencies(Container $container) * @param string $cmdName The binary name to search. * @return string */ - private function findCmd($cmdName) + private function findCmd(string $cmdName) { $cmd = exec('type -p ' . $cmdName); $cmd = str_replace($cmdName . ' is ', '', $cmd); - if (!$cmd) { + if ($cmd === '' || $cmd === '0') { $cmd = exec('where ' . $cmdName); } if (!$cmd) { diff --git a/packages/admin/src/Charcoal/Admin/Script/Tools/StaticWebsite/CrawlScript.php b/packages/admin/src/Charcoal/Admin/Script/Tools/StaticWebsite/CrawlScript.php index 6a00bbfa3..09eecc502 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Tools/StaticWebsite/CrawlScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Tools/StaticWebsite/CrawlScript.php @@ -20,25 +20,16 @@ */ class CrawlScript extends AdminScript { - /** - * @var string - */ - private $startUrl; + private ?string $startUrl = null; - /** - * @var array - */ - private $parsedStartUrl; + private array|bool|null $parsedStartUrl = null; /** * @var string */ private $basePath; - /** - * @var string - */ - private $outputDir; + private ?string $outputDir = null; /** * @var integer @@ -50,10 +41,7 @@ class CrawlScript extends AdminScript */ private $processedUrls = []; - /** - * @var GuzzleClient - */ - private $guzzleClient; + private readonly \GuzzleHttp\Client $guzzleClient; /** * @var GoutteClient @@ -72,10 +60,8 @@ public function __construct($data = null) $this->goutteClient->setClient($this->guzzleClient); } - /** - * @return array - */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'url' => [ @@ -94,17 +80,14 @@ public function defaultArguments() 'defaultValue' => 2 ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request PSR-7 Request. * @param ResponseInterface $response PSR-7 Response. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -132,6 +115,7 @@ public function run(RequestInterface $request, ResponseInterface $response) * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -141,9 +125,8 @@ protected function setDependencies(Container $container) /** * @param string $url The URL to cache. The base (start) URL will be prefixed to relative URLs. - * @return void */ - private function cacheUrl($url) + private function cacheUrl(string|array $url): void { if (in_array($url, $this->processedUrls)) { return; @@ -169,7 +152,7 @@ private function cacheUrl($url) return; } - if (strstr($headers['Content-Type'][0], 'text/html') !== false) { + if (str_contains($headers['Content-Type'][0], 'text/html')) { $outputFile = $outputDir . '/index.html'; $prefix = ''; } else { @@ -191,12 +174,11 @@ private function cacheUrl($url) /** * @param string $url The URL to retrieve links from. * @param integer $level Current level. - * @return void */ - private function retrieveLinks($url, $level) + private function retrieveLinks(string|null|array $url, int|float $level): void { $crawler = $this->goutteClient->request('GET', $url); - $crawler->filter('a')->each(function ($item) use ($level) { + $crawler->filter('a')->each(function ($item) use ($level): void { $href = $item->attr('href'); $parsedHref = parse_url($href); if (isset($parsedHref['host']) && ($parsedHref['host'] !== $this->parsedStartUrl['host'])) { @@ -217,9 +199,8 @@ private function retrieveLinks($url, $level) /** * @param string $dir The directory to recursively delete. * @throws InvalidArgumentException If the argument is empty. - * @return mixed */ - private function recursiveDelete($dir) + private function recursiveDelete(string $dir): bool { if (!is_string($dir)) { throw new InvalidArgumentException( diff --git a/packages/admin/src/Charcoal/Admin/Script/Tools/StaticWebsite/UpdateScript.php b/packages/admin/src/Charcoal/Admin/Script/Tools/StaticWebsite/UpdateScript.php index b7c2b46dd..be1a7a6e8 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Tools/StaticWebsite/UpdateScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Tools/StaticWebsite/UpdateScript.php @@ -24,15 +24,10 @@ class UpdateScript extends AdminScript */ private $basePath; - /** - * @var \GuzzleHttp\Client - */ - private $guzzleClient; + private ?\GuzzleHttp\Client $guzzleClient = null; - /** - * @return array - */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'url' => [ @@ -46,17 +41,14 @@ public function defaultArguments() 'noValue' => true ], ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request PSR-7 Request. * @param ResponseInterface $response PSR-7 Response. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); $this->guzzleClient = new GuzzleClient(); @@ -96,6 +88,7 @@ public function run(RequestInterface $request, ResponseInterface $response) * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -106,9 +99,8 @@ protected function setDependencies(Container $container) /** * @param string $url The URL to cache. The base (start) URL will be prefixed to relative URLs. * @param string $outputDir The output directory. - * @return void */ - private function cacheUrl($url, $outputDir) + private function cacheUrl(string $url, string $outputDir): void { $relativeUrl = str_replace($this->baseUrl(), '', $url); $url = $this->baseUrl() . $relativeUrl; @@ -130,7 +122,7 @@ private function cacheUrl($url, $outputDir) return; } - if (strstr($headers['Content-Type'][0], 'text/html') !== false) { + if (str_contains($headers['Content-Type'][0], 'text/html')) { $outputFile = $outputDir . '/index.html'; $prefix = ''; } else { @@ -154,7 +146,7 @@ private function cacheUrl($url, $outputDir) * @param integer $flags Glob flags. * @return array */ - private function globRecursive($dir, $pattern, $flags = 0) + private function globRecursive(string $dir, string $pattern, $flags = 0): array|false { $files = glob($dir . '/' . $pattern, $flags); foreach (glob($dir . '/*', (GLOB_ONLYDIR | GLOB_NOSORT)) as $dir) { diff --git a/packages/admin/src/Charcoal/Admin/Script/Translation/TranslateScript.php b/packages/admin/src/Charcoal/Admin/Script/Translation/TranslateScript.php index 3d43c86fb..45611e49c 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Translation/TranslateScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Translation/TranslateScript.php @@ -37,10 +37,9 @@ class TranslateScript extends AdminScript * Valid arguments: * - path : path/to/files * - type : mustache | php - * - * @return array */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'path' => [ @@ -59,17 +58,14 @@ public function defaultArguments() 'defaultValue' => '' ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { // Unused unset($request); @@ -85,6 +81,7 @@ public function run(RequestInterface $request, ResponseInterface $response) switch ($type) { case 'mustache': + default: $regex = '/{{\s*#\s*_t\s*}}((.|\n|\r|\n\r)*?){{\s*\/\s*_t\s*}}/i'; $file = '*.mustache'; $index = 1; @@ -94,11 +91,6 @@ public function run(RequestInterface $request, ResponseInterface $response) $index = 'text'; $file = '*.php'; break; - default: - $regex = '/{{\s*#\s*_t\s*}}((.|\n|\r|\n\r)*?){{\s*\/\s*_t\s*}}/i'; - $file = '*.mustache'; - $index = 1; - break; } // Remove vendor/charcoal/app @@ -123,7 +115,7 @@ public function run(RequestInterface $request, ResponseInterface $response) } // Loop files to get original text. - foreach ($glob as $k => $f) { + foreach ($glob as $f) { $text = file_get_contents($f); if (preg_match($regex, $text)) { preg_match_all($regex, $text, $array); @@ -156,7 +148,7 @@ public function run(RequestInterface $request, ResponseInterface $response) * @return array * @see http://in.php.net/manual/en/function.glob.php#106595 */ - public function globRecursive($pattern, $flags = 0) + public function globRecursive($pattern, $flags = 0): array|false { $max = $this->maxRecursiveLevel(); $i = 1; @@ -174,9 +166,8 @@ public function globRecursive($pattern, $flags = 0) /** * BASE URL * Realpath - * @return string */ - public function base() + public function base(): string { return realpath($this->app()->config()->get('base_path') . DIRECTORY_SEPARATOR . '../../../') . '/'; } @@ -185,7 +176,7 @@ public function base() * ARGUMENTS * @return TranslateScript Chainable */ - public function getPath() + public function getPath(): static { $path = $this->argOrInput('path'); $this->path = $path; @@ -206,7 +197,7 @@ public function path() /** * @return TranslateScript Chainable */ - public function getFileType() + public function getFileType(): static { $type = $this->argOrInput('type'); $this->fileType = $type; @@ -240,10 +231,8 @@ public function file() /** * Returns associative array * 'original text' => [ 'translation' => 'translation text', 'context' => 'filename' ] - * - * @return array */ - public function fromCSV() + public function fromCSV(): array { $output = $this->file(); $base = $this->base(); @@ -255,10 +244,10 @@ public function fromCSV() $results = []; $row = 0; - while (($data = fgetcsv($file, 0, ',')) !== false) { + while (($data = fgetcsv($file, 0, ',', escape: '\\')) !== false) { $row++; // Skip column names - if ($row == 1) { + if ($row === 1) { continue; } /** @@ -267,7 +256,7 @@ public function fromCSV() * data[2] = CONTEXT */ $translation = $this->translateCSV($data); - if (!empty($translation)) { + if ($translation !== []) { $results[$translation[0]] = $translation[1]; } } @@ -279,7 +268,7 @@ public function fromCSV() * @param array $translations The translations to save in CSV. * @return TranslateScript Chainable */ - public function toCSV(array $translations) + public function toCSV(array $translations): static { $base = $this->base(); $output = $this->file(); @@ -298,11 +287,11 @@ public function toCSV(array $translations) // Wtf happened? return $this; } - fputcsv($file, $columns, $separator, $enclosure); + fputcsv($file, $columns, $separator, $enclosure, escape: '\\'); foreach ($translations as $orig => $translation) { $data = [ $orig, $translation['translation'], $translation['context'] ]; - fputcsv($file, $data, $separator, $enclosure); + fputcsv($file, $data, $separator, $enclosure, escape: '\\'); } fclose($file); @@ -312,34 +301,31 @@ public function toCSV(array $translations) /** * @param array $data The translation data. - * @return array * @todo multiple langs * data[0] = ORIGINAL * data[1] = TRANSLATION * data[2] = CONTEXT */ - public function translateCSV(array $data) + public function translateCSV(array $data): array { if (count($data) < 3) { return []; } - $output = [ + return [ $data[0], [ 'translation' => $data[1], 'context' => $data[2] ] ]; - - return $output; } /** * @todo make this optional * @return string lang ident */ - public function origLanguage() + public function origLanguage(): string { return 'fr'; } @@ -348,10 +334,11 @@ public function origLanguage() * Get opposite languages from DATABASE * * @return [type] [description] + * @return mixed[] */ - public function oppositeLanguages() + public function oppositeLanguages(): array { - $cfg = $this->app()->config(); + $this->app()->config(); $locales = $this->locales(); $languages = $locales['languages']; @@ -379,11 +366,11 @@ public function locales() } $cfg = $this->app()->config(); - $locales = isset($cfg['locales']) ? $cfg['locales'] : []; - $languages = isset($locales['languages']) ? $locales['languages'] : []; - $file = isset($locales['file']) ? $locales['file'] : $this->argOrInput('output'); + $locales = ($cfg['locales'] ?? []); + $languages = ($locales['languages'] ?? []); + $file = ($locales['file'] ?? $this->argOrInput('output')); // Default to FR - $default = isset($locales['default_language']) ? $locales['default_language'] : 'fr'; + $default = ($locales['default_language'] ?? 'fr'); $this->locales = [ 'languages' => $languages, @@ -396,10 +383,8 @@ public function locales() /** * Columns of CSV file * This is already built to take multiple languages - * - * @return array */ - public function columns() + public function columns(): array { $orig = $this->origLanguage(); $opposites = $this->oppositeLanguages(); @@ -416,26 +401,17 @@ public function columns() return $columns; } - /** - * @return string - */ - public function enclosure() + public function enclosure(): string { return '"'; } - /** - * @return string - */ - public function separator() + public function separator(): string { return ','; } - /** - * @return integer - */ - public function maxRecursiveLevel() + public function maxRecursiveLevel(): int { return 4; } diff --git a/packages/admin/src/Charcoal/Admin/Script/User/AclRole/CreateScript.php b/packages/admin/src/Charcoal/Admin/Script/User/AclRole/CreateScript.php index ce397f0ee..08261ab64 100644 --- a/packages/admin/src/Charcoal/Admin/Script/User/AclRole/CreateScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/User/AclRole/CreateScript.php @@ -18,9 +18,8 @@ class CreateScript extends AdminScript /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -72,10 +71,7 @@ public function run(RequestInterface $request, ResponseInterface $response) return $response; } - /** - * @return boolean - */ - public function authRequired() + public function authRequired(): bool { return false; } diff --git a/packages/admin/src/Charcoal/Admin/Script/User/CreateScript.php b/packages/admin/src/Charcoal/Admin/Script/User/CreateScript.php index 67872af55..e732e054c 100644 --- a/packages/admin/src/Charcoal/Admin/Script/User/CreateScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/User/CreateScript.php @@ -40,6 +40,7 @@ public function __construct($data = null) * @param Container $container Pimple DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -52,10 +53,9 @@ protected function setDependencies(Container $container) * Retrieve the available default arguments of this action. * * @link http://climate.thephpleague.com/arguments/ For descriptions of the options for CLImate. - * - * @return array */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'email' => [ @@ -81,17 +81,14 @@ public function defaultArguments() ] ]; - $arguments = array_merge(parent::defaultArguments(), $arguments); - - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -107,9 +104,8 @@ public function run(RequestInterface $request, ResponseInterface $response) /** * Create a new user in the database - * @return void */ - private function createUser() + private function createUser(): void { $authenticator = $this->authenticator(); @@ -148,11 +144,7 @@ private function createUser() $prompt = $prompts[$prop->ident()]; - if ($prompt['property']) { - $v = $prompt['property']; - } else { - $v = $this->promptProperty($prop, $prompt['label']); - } + $v = $prompt['property'] ?: $this->promptProperty($prop, $prompt['label']); if (isset($prompt['validation'])) { call_user_func($prompt['validation'], $v); } @@ -175,10 +167,7 @@ private function createUser() } } - /** - * @return array - */ - private function userPrompts() + private function userPrompts(): array { $translator = $this->translator(); $climate = $this->climate(); @@ -187,12 +176,12 @@ private function userPrompts() 'email' => [ 'label' => $translator->translate('Please enter email: '), 'property' => $climate->arguments->get('email'), - 'validation' => [ $this, 'validateEmail' ], + 'validation' => $this->validateEmail(...), ], 'password' => [ 'label' => $translator->translate('Please enter password: '), 'property' => $climate->arguments->get('password'), - 'validation' => [ $this, 'validatePassword' ], + 'validation' => $this->validatePassword(...), ], 'roles' => [ 'label' => $translator->translate('Please enter role(s) [ex: admin], comma separated: '), @@ -227,9 +216,8 @@ private function promptProperty($prop, $label) * @param string $email The email, from input. * @throws Exception If the email is empty or invalid (validated with php's filters) * or already exists in the database. - * @return void */ - private function validateEmail($email) + private function validateEmail($email): void { if (!$email) { throw new Exception( @@ -256,9 +244,8 @@ private function validateEmail($email) /** * @param string $password The password, from input. * @throws Exception If the password is empty or too small. - * @return void */ - private function validatePassword($password) + private function validatePassword($password): void { if (!$password) { throw new Exception( diff --git a/packages/admin/src/Charcoal/Admin/Script/User/ResetPasswordScript.php b/packages/admin/src/Charcoal/Admin/Script/User/ResetPasswordScript.php index 3b59f2e4d..e6c25cf94 100644 --- a/packages/admin/src/Charcoal/Admin/Script/User/ResetPasswordScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/User/ResetPasswordScript.php @@ -37,6 +37,7 @@ public function __construct($data = null) * @param Container $container Pimple DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -49,10 +50,9 @@ protected function setDependencies(Container $container) * Retrieve the available default arguments of this action. * * @link http://climate.thephpleague.com/arguments/ For descriptions of the options for CLImate. - * - * @return array */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'email' => [ @@ -74,17 +74,14 @@ public function defaultArguments() ] ]; - $arguments = array_merge(parent::defaultArguments(), $arguments); - - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -114,7 +111,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $authenticator->changeUserPassword($user, $password); if ($climate->arguments->get('sendEmail')) { - $this->sendResetPasswordEmail($email, $password); + $this->sendResetPasswordEmail(); } $climate->red()->out( @@ -125,12 +122,10 @@ public function run(RequestInterface $request, ResponseInterface $response) } /** - * @param string $email The user email. - * @param string $password The new, plain-text password. * @return void * @todo Implement reset password email dispatch. */ - private function sendResetPasswordEmail($email, $password) + private function sendResetPasswordEmail() { } } diff --git a/packages/admin/src/Charcoal/Admin/Service/AssetsBuilder.php b/packages/admin/src/Charcoal/Admin/Service/AssetsBuilder.php index f6b7aacab..64edad4c8 100644 --- a/packages/admin/src/Charcoal/Admin/Service/AssetsBuilder.php +++ b/packages/admin/src/Charcoal/Admin/Service/AssetsBuilder.php @@ -19,23 +19,13 @@ */ final class AssetsBuilder { - /** - * @var AssetManager|null - */ - private $assetManager = null; - - /** - * @var string|null - */ - private $basePath = null; + private ?\Assetic\AssetManager $assetManager = null; /** * @param string|null $basePath The assets base path. - * @return void */ - public function __construct($basePath = null) + public function __construct(private $basePath = null) { - $this->basePath = $basePath; } /** @@ -44,7 +34,7 @@ public function __construct($basePath = null) * @param AssetsConfig $config The assets management config. * @return AssetManager */ - public function __invoke(AssetsConfig $config) + public function __invoke(AssetsConfig $config): ?\Assetic\AssetManager { return $this->build($config); } @@ -53,7 +43,7 @@ public function __invoke(AssetsConfig $config) * @param AssetsConfig $config The assets management config. * @return AssetManager */ - public function build(AssetsConfig $config) + public function build(AssetsConfig $config): ?\Assetic\AssetManager { $this->assetManager = new AssetManager(); $this->parseCollections($config->collections()); @@ -63,14 +53,13 @@ public function build(AssetsConfig $config) /** * @param array $collections Assets collections. - * @return void */ - private function parseCollections(array $collections) + private function parseCollections(array $collections): void { foreach ($collections as $collectionIdent => $actions) { $files = ($actions['files'] ?? []); // Parse scoped files. Solves merging issues. - array_walk($actions, function ($scope) use (&$files) { + array_walk($actions, function (array $scope) use (&$files): void { if (isset($scope['files']) && !empty($scope['files'])) { $files = array_merge($files, $scope['files']); } @@ -88,7 +77,7 @@ private function parseCollections(array $collections) * @param string[] $files Files to convert to Collection assets. * @return AssetInterface[] */ - private function extractFiles(array $files = []) + private function extractFiles(array $files = []): array { $collection = []; @@ -107,7 +96,7 @@ private function extractFiles(array $files = []) } // Files with asterisks should be treated as glob. - if (strpos($file, '*') !== false) { + if (str_contains($file, '*')) { $collection[] = new GlobAsset($file); continue; } @@ -128,7 +117,7 @@ private function extractFiles(array $files = []) * @param string $file A file path. * @return boolean Returns TRUE if the given path is absolute. Otherwise, returns FALSE. */ - private function isAbsolutePath($file) + private function isAbsolutePath($file): bool { $file = (string)$file; diff --git a/packages/admin/src/Charcoal/Admin/Service/Exporter.php b/packages/admin/src/Charcoal/Admin/Service/Exporter.php index f9411be72..cfc1c753c 100644 --- a/packages/admin/src/Charcoal/Admin/Service/Exporter.php +++ b/packages/admin/src/Charcoal/Admin/Service/Exporter.php @@ -28,6 +28,8 @@ class Exporter { use TranslatorAwareTrait; + public $logger; + /** * Output file name * @var string $filename @@ -43,16 +45,14 @@ class Exporter /** * Options * Booleans - * @var boolean $convertBrToNewlines */ - private $convertBrToNewlines; + private ?bool $convertBrToNewlines = null; /** * Options * Booleans - * @var boolean $stripTags */ - private $stripTags; + private ?bool $stripTags = null; /** * Export ident for metadata @@ -62,21 +62,18 @@ class Exporter /** * Output properties - * @var array $properties */ - private $properties = []; + private array $properties = []; /** * CollectionConfig - * @var array $collectionConfig */ - private $collectionConfig; + private ?array $collectionConfig = null; /** * Model factory - * @var FactoryInterface $modelFactory */ - private $modelFactory; + private \Charcoal\Factory\FactoryInterface $modelFactory; /** * Property factory used @@ -134,7 +131,7 @@ public function __construct(array $data) * Init function * @return Exporter Chainable. */ - public function process() + public function process(): static { $this->prepareOptions(); $this->export(); @@ -143,9 +140,8 @@ public function process() /** * Export to CSV - * @return void */ - public function export() + public function export(): void { $headers = $this->fileHeaders(); $rows = $this->rows(); @@ -177,7 +173,7 @@ public function collection() if (!$this->collectionConfig()) { throw new RuntimeException(sprintf( 'Collection Config required for "%s"', - get_class($this) + static::class )); } @@ -230,7 +226,7 @@ private function proto() */ private function metadata() { - $proto = $this->proto(); + $this->proto(); return $this->proto()->metadata(); } @@ -241,7 +237,7 @@ private function metadata() * @throws InvalidArgumentException If no properties are defined. * @return Exporter Chainable. */ - private function prepareOptions() + private function prepareOptions(): static { $metadata = $this->metadata(); @@ -252,7 +248,7 @@ private function prepareOptions() throw new InvalidArgumentException(sprintf( 'No export ident defined for "%s" in %s', $this->objType(), - get_class($this) + static::class )); } @@ -265,7 +261,7 @@ private function prepareOptions() 'No export data defined for "%s" at "%s" in %s', $this->objType(), $this->exportIdent(), - get_class($this) + static::class )); } @@ -275,7 +271,7 @@ private function prepareOptions() throw new InvalidArgumentException(sprintf( 'No export data defined for "%s" in %s', $this->objType(), - get_class($this) + static::class )); } } @@ -284,7 +280,7 @@ private function prepareOptions() throw new InvalidArgumentException(sprintf( 'No properties defined to export "%s" in %s', $this->objType(), - get_class($this) + static::class )); } @@ -326,7 +322,7 @@ private function prepareOptions() /** * @return array File headers. */ - private function fileHeaders() + private function fileHeaders(): array { $metadata = $this->metadata(); $properties = $this->properties(); @@ -339,11 +335,7 @@ private function fileHeaders() continue; } - if (isset($prop['label'])) { - $label = $this->translator()->translation($prop['label']); - } else { - $label = ucfirst($p); - } + $label = isset($prop['label']) ? $this->translator()->translation($prop['label']) : ucfirst((string)$p); $out[] = $label; } @@ -394,7 +386,7 @@ private function rows() * @param string $filename Output filename. * @return Exporter (chainable). */ - private function setFilename($filename) + private function setFilename($filename): static { $this->filename = $filename; return $this; @@ -404,7 +396,7 @@ private function setFilename($filename) * @param string $objType Object to be exported. * @return Exporter (chainable). */ - private function setObjType($objType) + private function setObjType($objType): static { $this->objType = $objType; return $this; @@ -415,9 +407,9 @@ private function setObjType($objType) * @param boolean $bool Convert br to newline. * @return Exporter (chainable) */ - private function setConvertBrToNewlines($bool) + private function setConvertBrToNewlines($bool): static { - $this->convertBrToNewlines = !!$bool; + $this->convertBrToNewlines = (bool)$bool; return $this; } @@ -426,9 +418,9 @@ private function setConvertBrToNewlines($bool) * @param boolean $bool Strip tags. * @return Exporter (chainable) */ - private function setStripTags($bool) + private function setStripTags($bool): static { - $this->stripTags = !!$bool; + $this->stripTags = (bool)$bool; return $this; } @@ -439,7 +431,7 @@ private function setStripTags($bool) * @param string $ident Config ident. * @return Exporter (chainable) */ - public function setExportIdent($ident) + public function setExportIdent($ident): static { $this->exportIdent = $ident; return $this; @@ -451,14 +443,14 @@ public function setExportIdent($ident) * @throws InvalidArgumentException If the array is not a list of strings. * @return Exporter Chainable. */ - private function setProperties(array $properties) + private function setProperties(array $properties): static { $p = reset($properties); if (!is_string($p)) { throw new InvalidArgumentException(sprintf( 'Invalid properties to export "%s" in %s', $this->objType(), - get_class($this) + static::class )); } @@ -471,7 +463,7 @@ private function setProperties(array $properties) * @param array $cfg Collection config. * @return Exporter Chainable. */ - private function setCollectionConfig(array $cfg) + private function setCollectionConfig(array $cfg): static { $this->collectionConfig = $cfg; return $this; @@ -482,7 +474,7 @@ private function setCollectionConfig(array $cfg) * @param FactoryInterface $factory Model factory. * @return Exporter (chainable) */ - private function setModelFactory(FactoryInterface $factory) + private function setModelFactory(FactoryInterface $factory): static { $this->modelFactory = $factory; return $this; @@ -492,7 +484,7 @@ private function setModelFactory(FactoryInterface $factory) * @param FactoryInterface $factory The property factory, to create properties. * @return TableWidget Chainable */ - private function setPropertyFactory(FactoryInterface $factory) + private function setPropertyFactory(FactoryInterface $factory): static { $this->propertyFactory = $factory; return $this; @@ -521,7 +513,7 @@ private function objType() /** * @return boolean Convert to newlines. */ - private function convertBrToNewlines() + private function convertBrToNewlines(): ?bool { return $this->convertBrToNewlines; } @@ -529,7 +521,7 @@ private function convertBrToNewlines() /** * @return boolean Striptags. */ - private function stripTags() + private function stripTags(): ?bool { return $this->stripTags; } @@ -545,7 +537,7 @@ private function exportIdent() /** * @return array Properties. */ - private function properties() + private function properties(): array { return $this->properties; } @@ -553,7 +545,7 @@ private function properties() /** * @return array CollectionConfig. */ - private function collectionConfig() + private function collectionConfig(): ?array { return $this->collectionConfig; } @@ -561,7 +553,7 @@ private function collectionConfig() /** * @return ModelFactory Model factory. */ - private function modelFactory() + private function modelFactory(): \Charcoal\Factory\FactoryInterface { return $this->modelFactory; } @@ -588,11 +580,10 @@ private function propertyFactory() * @param string $text Text. * @return string Text with newlines. */ - private function brToNewline($text) + private function brToNewline($text): string { $breaks = [ '
', '
', '
' ]; - $text = str_ireplace($breaks, "\r\n", $text); - return $text; + return str_ireplace($breaks, "\r\n", $text); } /** diff --git a/packages/admin/src/Charcoal/Admin/Service/SelectizeRenderer.php b/packages/admin/src/Charcoal/Admin/Service/SelectizeRenderer.php index 43e369d42..ffc2568c3 100644 --- a/packages/admin/src/Charcoal/Admin/Service/SelectizeRenderer.php +++ b/packages/admin/src/Charcoal/Admin/Service/SelectizeRenderer.php @@ -64,15 +64,14 @@ public function __construct(array $data) * @param ModelInterface|array|null $context The context as Model or array. * @param string|null $controllerIdent The ControllerIdent string to override Object context. * @throws \InvalidArgumentException If the callable id not callable. - * @return string */ - public function renderTemplate($templateIdent, $context, $controllerIdent = null) + public function renderTemplate(string $templateIdent, $context, $controllerIdent = null): string { $template = null; if ($controllerIdent && is_string($controllerIdent)) { $controllerIdent = explode('::', $controllerIdent); - $controllerCallable = isset($controllerIdent[1]) ? $controllerIdent[1] : null; + $controllerCallable = ($controllerIdent[1] ?? null); $controllerIdent = $controllerIdent[0]; $template = $this->templateFactory->create($controllerIdent); @@ -84,7 +83,7 @@ public function renderTemplate($templateIdent, $context, $controllerIdent = null '%s::%s supplied in %s::%s is not a callable method.', $controllerIdent, $controllerCallable, - __CLASS__, + self::class, __FUNCTION__ )); } @@ -103,8 +102,8 @@ public function renderTemplate($templateIdent, $context, $controllerIdent = null } else { throw new \InvalidArgumentException(sprintf( '%s supplied in %s::%s is not callable.', - get_class($template), - __CLASS__, + $template::class, + self::class, __FUNCTION__ )); } diff --git a/packages/admin/src/Charcoal/Admin/ServiceProvider/AclServiceProvider.php b/packages/admin/src/Charcoal/Admin/ServiceProvider/AclServiceProvider.php index 7e3aebc59..c15a395a5 100644 --- a/packages/admin/src/Charcoal/Admin/ServiceProvider/AclServiceProvider.php +++ b/packages/admin/src/Charcoal/Admin/ServiceProvider/AclServiceProvider.php @@ -31,9 +31,8 @@ class AclServiceProvider implements ServiceProviderInterface { /** * @param Container $container Pimple DI Container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { /** * Use an AclManager to load default permissions from config and database. @@ -41,7 +40,7 @@ public function register(Container $container) * @param Container $container Pimple DI container * @return Acl */ - $container['admin/acl'] = function (Container $container) { + $container['admin/acl'] = function (Container $container): \Laminas\Permissions\Acl\Acl { $adminConfig = $container['admin/config']; @@ -75,8 +74,6 @@ public function register(Container $container) * @todo Do this right! * @return Acl */ - $container['authorizer/acl'] = function () { - return $container['admin/acl']; - }; + $container['authorizer/acl'] = (fn(): \Closure => $container['admin/acl']); } } diff --git a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php index fb236ce02..e780712fd 100644 --- a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php +++ b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php @@ -16,7 +16,7 @@ // From Slim use Slim\Http\Uri; // From Mustache -use Mustache_LambdaHelper as LambdaHelper; +use Mustache\LambdaHelper as LambdaHelper; // From 'charcoal-config' use Charcoal\Config\ConfigInterface; use Charcoal\Config\GenericConfig as Config; @@ -66,9 +66,8 @@ class AdminServiceProvider implements ServiceProviderInterface * It should not get services. * * @param Container $container The Pimple DI container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { // Ensure dependencies are set $container->register(new EmailServiceProvider()); @@ -102,7 +101,7 @@ protected function registerAdminServices(Container $container) * @param Container $container The Pimple DI Container. * @return AdminConfig */ - $container['admin/config'] = function (Container $container) { + $container['admin/config'] = function (Container $container): \Charcoal\Admin\Config { $appConfig = $container['config']; $extraConfigs = []; @@ -124,12 +123,10 @@ protected function registerAdminServices(Container $container) array_push($extraConfigs, ...$appAdminConfigs); } - if (!empty($extraConfigs)) { - foreach ($extraConfigs as $path) { - $configPath = $appConfig['base_path'] . DIRECTORY_SEPARATOR . ltrim($path, '/'); + foreach ($extraConfigs as $path) { + $configPath = $appConfig['base_path'] . DIRECTORY_SEPARATOR . ltrim($path, '/'); - $appConfig->addFile($configPath); - } + $appConfig->addFile($configPath); } $adminConfig = $appConfig['admin']; @@ -157,7 +154,7 @@ protected function registerAdminServices(Container $container) $adminUrl = clone $container['base-url']; if ($adminConfig['base_path']) { $basePath = rtrim($adminUrl->getBasePath(), '/'); - $adminPath = ltrim($adminConfig['base_path'], '/'); + $adminPath = ltrim((string)$adminConfig['base_path'], '/'); $adminUrl = $adminUrl->withBasePath($basePath . '/' . $adminPath); } } @@ -181,11 +178,9 @@ protected function registerAdminServices(Container $container) * @param Container $container A container instance. * @return ViewInterface */ - $container->extend('view', function (GenericView $view, Container $container): ViewInterface { - return new GenericView([ - 'engine' => $container['view/engine/mustache'] - ]); - }); + $container->extend('view', fn(GenericView $view, Container $container): ViewInterface => new GenericView([ + 'engine' => $container['view/engine/mustache'] + ])); /** * Extend view/config. @@ -216,11 +211,10 @@ protected function registerMetadataExtensions(Container $container) /** * @return MetadataConfig */ - $container['metadata/config'] = function (Container $container) { + $container['metadata/config'] = function (Container $container): \Charcoal\Model\Service\MetadataConfig { $settings = $container['admin/config']['metadata']; - $metaConfig = new MetadataConfig($settings); - return $metaConfig; + return new MetadataConfig($settings); }; } else { /** @@ -232,9 +226,9 @@ protected function registerMetadataExtensions(Container $container) * @param Container $container The Pimple DI container. * @return MetadataConfig */ - $container->extend('metadata/config', function (MetadataConfig $metaConfig, Container $container) { + $container->extend('metadata/config', function (MetadataConfig $metaConfig, Container $container): \Charcoal\Model\Service\MetadataConfig { $settings = $container['admin/config']['metadata']; - if (is_array($settings) && !empty($settings)) { + if (is_array($settings) && $settings !== []) { $metaConfig->merge($settings); } @@ -276,16 +270,16 @@ protected function registerMetadataExtensions(Container $container) * @param Container $container The Pimple DI container. * @return MetadataConfig */ - $container->extend('metadata/config', function (MetadataConfig $metaConfig, Container $container) { + $container->extend('metadata/config', function (MetadataConfig $metaConfig, Container $container): \Charcoal\Model\Service\MetadataConfig { $adminConfig = $container['admin/config']; - $adminDir = '/' . trim($adminConfig['base_path'], '/'); + $adminDir = '/' . trim((string)$adminConfig['base_path'], '/'); $metaPaths = $metaConfig->paths(); $parsedPaths = []; foreach ($metaPaths as $basePath) { $adminPath = rtrim($basePath, '/') . $adminDir; - - array_push($parsedPaths, $adminPath, $basePath); + $parsedPaths[] = $adminPath; + $parsedPaths[] = $basePath; } $metaConfig->setPaths($parsedPaths); @@ -306,15 +300,13 @@ protected function registerAuthExtensions(Container $container) * @param Container $container The Pimple DI Container. * @return Authenticator */ - $container['admin/authenticator'] = function (Container $container) { - return new Authenticator([ - 'logger' => $container['logger'], - 'user_type' => User::class, - 'user_factory' => $container['model/factory'], - 'token_type' => AuthToken::class, - 'token_factory' => $container['model/factory'] - ]); - }; + $container['admin/authenticator'] = (fn(Container $container): \Charcoal\User\Authenticator => new Authenticator([ + 'logger' => $container['logger'], + 'user_type' => User::class, + 'user_factory' => $container['model/factory'], + 'token_type' => AuthToken::class, + 'token_factory' => $container['model/factory'] + ])); /** * Replace default Authenticator ('charcoal-ui') with the Admin Authenticator. @@ -323,21 +315,17 @@ protected function registerAuthExtensions(Container $container) * @param Container $container The Pimple DI Container. * @return Authenticator */ - $container['authenticator'] = function (Container $container) { - return $container['admin/authenticator']; - }; + $container['authenticator'] = (fn(Container $container): mixed => $container['admin/authenticator']); /** * @param Container $container The Pimple DI container. * @return Authorizer */ - $container['admin/authorizer'] = function (Container $container) { - return new Authorizer([ - 'logger' => $container['logger'], - 'acl' => $container['admin/acl'], - 'resource' => 'admin' - ]); - }; + $container['admin/authorizer'] = (fn(Container $container): \Charcoal\User\Authorizer => new Authorizer([ + 'logger' => $container['logger'], + 'acl' => $container['admin/acl'], + 'resource' => 'admin' + ])); /** * Replace default Authorizer ('charcoal-ui') with the Admin Authorizer. @@ -346,9 +334,7 @@ protected function registerAuthExtensions(Container $container) * @param Container $container The Pimple DI Container. * @return Authorizer */ - $container['authorizer'] = function (Container $container) { - return $container['admin/authorizer']; - }; + $container['authorizer'] = (fn(Container $container): mixed => $container['admin/authorizer']); } /** @@ -360,9 +346,7 @@ protected function registerAuthExtensions(Container $container) protected function registerViewExtensions(Container $container) { if (!isset($container['view/mustache/helpers'])) { - $container['view/mustache/helpers'] = function () { - return []; - }; + $container['view/mustache/helpers'] = (fn(): array => []); } /** @@ -370,7 +354,7 @@ protected function registerViewExtensions(Container $container) * * @return array */ - $container->extend('view/mustache/helpers', function (array $helpers, Container $container) { + $container->extend('view/mustache/helpers', function (array $helpers, Container $container): array { $adminUrl = $container['admin/base-url']; $urls = [ @@ -387,8 +371,8 @@ protected function registerViewExtensions(Container $container) * @param string $uri A URI path to wrap. * @return UriInterface|null */ - 'withAdminUrl' => function ($uri, LambdaHelper $helper = null) use ($adminUrl) { - if ($helper) { + 'withAdminUrl' => function ($uri, ?LambdaHelper $helper = null) use ($adminUrl) { + if ($helper instanceof LambdaHelper) { $uri = $helper->render($uri); } @@ -397,16 +381,13 @@ protected function registerViewExtensions(Container $container) $uri = $adminUrl->withPath(''); } else { $parts = parse_url($uri); - if (!isset($parts['scheme'])) { - if (!in_array($uri[0], ['/', '#', '?'])) { - $path = isset($parts['path']) ? ltrim($parts['path'], '/') : ''; - $query = isset($parts['query']) ? $parts['query'] : ''; - $hash = isset($parts['fragment']) ? $parts['fragment'] : ''; - - return $adminUrl->withPath($path) - ->withQuery($query) - ->withFragment($hash); - } + if (!isset($parts['scheme']) && !in_array($uri[0], ['/', '#', '?'])) { + $path = isset($parts['path']) ? ltrim($parts['path'], '/') : ''; + $query = ($parts['query'] ?? ''); + $hash = ($parts['fragment'] ?? ''); + return $adminUrl->withPath($path) + ->withQuery($query) + ->withFragment($hash); } } @@ -432,7 +413,7 @@ protected function registerElfinderServices(Container $container) * @param AdminConfig $adminConfig The admin configset. * @return AdminConfig */ - $container->extend('admin/config', function (AdminConfig $adminConfig) { + $container->extend('admin/config', function (AdminConfig $adminConfig): \Charcoal\Admin\Config { $adminConfig['elfinder'] = new Config($adminConfig['elfinder']); return $adminConfig; @@ -444,9 +425,7 @@ protected function registerElfinderServices(Container $container) * @param Container $container The Pimple DI Container. * @return ConfigInterface */ - $container['elfinder/config'] = function (Container $container) { - return $container['admin/config']['elfinder']; - }; + $container['elfinder/config'] = (fn(Container $container): mixed => $container['admin/config']['elfinder']); } /** @@ -463,14 +442,12 @@ protected function registerSelectizeServices(Container $container) * @param Container $container The Pimple DI container. * @return SelectizeRenderer */ - $container['selectize/renderer'] = function (Container $container) { - return new SelectizeRenderer([ - 'logger' => $container['logger'], - 'translator' => $container['translator'], - 'template_factory' => $container['template/factory'], - 'view' => $container['view'] - ]); - }; + $container['selectize/renderer'] = (fn(Container $container): \Charcoal\Admin\Service\SelectizeRenderer => new SelectizeRenderer([ + 'logger' => $container['logger'], + 'translator' => $container['translator'], + 'template_factory' => $container['template/factory'], + 'view' => $container['view'] + ])); } /** @@ -479,7 +456,7 @@ protected function registerSelectizeServices(Container $container) */ protected function registerAssetsManager(Container $container) { - $container['assets/config'] = function (Container $container) { + $container['assets/config'] = function (Container $container): \Charcoal\Admin\AssetsConfig { $config = $container['admin/config']->get('assets'); return new AssetsConfig($config); @@ -498,54 +475,48 @@ protected function registerFactoryServices(Container $container) * @param Container $container The Pimple DI container. * @return FactoryInterface */ - $container['property/input/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => PropertyInputInterface::class, - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'] - ]], - 'resolver_options' => [ - 'suffix' => 'Input' - ] - ]); - }; + $container['property/input/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => PropertyInputInterface::class, + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'] + ]], + 'resolver_options' => [ + 'suffix' => 'Input' + ] + ])); /** * @param Container $container The Pimple DI container. * @return FactoryInterface */ - $container['property/display/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => PropertyDisplayInterface::class, - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'] - ]], - 'resolver_options' => [ - 'suffix' => 'Display' - ] - ]); - }; + $container['property/display/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => PropertyDisplayInterface::class, + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'] + ]], + 'resolver_options' => [ + 'suffix' => 'Display' + ] + ])); /** * @param Container $container A Pimple DI container. * @return FactoryInterface */ - $container['secondary-menu/group/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => SecondaryMenuGroupInterface::class, - 'default_class' => GenericSecondaryMenuGroup::class, - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'], - 'view' => $container['view'], - 'layout_builder' => $container['layout/builder'] - ]], - 'resolver_options' => [ - 'suffix' => 'SecondaryMenuGroup' - ] - ]); - }; + $container['secondary-menu/group/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => SecondaryMenuGroupInterface::class, + 'default_class' => GenericSecondaryMenuGroup::class, + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'], + 'view' => $container['view'], + 'layout_builder' => $container['layout/builder'] + ]], + 'resolver_options' => [ + 'suffix' => 'SecondaryMenuGroup' + ] + ])); } } diff --git a/packages/admin/src/Charcoal/Admin/ServiceProvider/AssetsManagerServiceProvider.php b/packages/admin/src/Charcoal/Admin/ServiceProvider/AssetsManagerServiceProvider.php index a57520303..3132925d8 100644 --- a/packages/admin/src/Charcoal/Admin/ServiceProvider/AssetsManagerServiceProvider.php +++ b/packages/admin/src/Charcoal/Admin/ServiceProvider/AssetsManagerServiceProvider.php @@ -21,9 +21,8 @@ class AssetsManagerServiceProvider implements ServiceProviderInterface * It should not get services. * * @param Container $container A container instance. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { $this->registerAssetsManager($container); $this->registerMustacheHelpersServices($container); @@ -36,9 +35,7 @@ public function register(Container $container) protected function registerMustacheHelpersServices(Container $container) { if (!isset($container['view/mustache/helpers'])) { - $container['view/mustache/helpers'] = function () { - return []; - }; + $container['view/mustache/helpers'] = (fn(): array => []); } /** @@ -47,11 +44,9 @@ protected function registerMustacheHelpersServices(Container $container) * @param Container $container Pimple DI container. * @return AssetsHelpers */ - $container['view/mustache/helpers/assets-manager'] = function (Container $container) { - return new AssetsHelpers([ - 'assets' => $container['assets'] - ]); - }; + $container['view/mustache/helpers/assets-manager'] = (fn(Container $container): \Charcoal\Admin\Mustache\AssetsHelpers => new AssetsHelpers([ + 'assets' => $container['assets'] + ])); /** * Extend global helpers for the Mustache Engine. @@ -60,12 +55,10 @@ protected function registerMustacheHelpersServices(Container $container) * @param Container $container A container instance. * @return array */ - $container->extend('view/mustache/helpers', function (array $helpers, Container $container) { - return array_merge( - $helpers, - $container['view/mustache/helpers/assets-manager']->toArray() - ); - }); + $container->extend('view/mustache/helpers', fn(array $helpers, Container $container): array => array_merge( + $helpers, + $container['view/mustache/helpers/assets-manager']->toArray() + )); } /** @@ -76,13 +69,13 @@ protected function registerMustacheHelpersServices(Container $container) */ protected function registerAssetsManager(Container $container) { - $container['assets/config'] = function (Container $container) { + $container['assets/config'] = function (Container $container): \Charcoal\Admin\AssetsConfig { $config = $container['view/config']->get('assets'); return new AssetsConfig($config); }; - $container['assets/builder'] = function (Container $container) { + $container['assets/builder'] = function (Container $container): \Charcoal\Admin\Service\AssetsBuilder { $appConfig = $container['config']; return new AssetsBuilder($appConfig['base_path']); diff --git a/packages/admin/src/Charcoal/Admin/Support/AdminTrait.php b/packages/admin/src/Charcoal/Admin/Support/AdminTrait.php index 33227c31e..d46b7c273 100644 --- a/packages/admin/src/Charcoal/Admin/Support/AdminTrait.php +++ b/packages/admin/src/Charcoal/Admin/Support/AdminTrait.php @@ -49,12 +49,10 @@ protected function adminConfig($key = null, $default = null) if ($key) { if (isset($this->adminConfig[$key])) { return $this->adminConfig[$key]; + } elseif (!is_string($default) && is_callable($default)) { + return $default(); } else { - if (!is_string($default) && is_callable($default)) { - return $default(); - } else { - return $default; - } + return $default; } } @@ -84,12 +82,10 @@ protected function appConfig($key = null, $default = null) if ($key) { if (isset($this->appConfig[$key])) { return $this->appConfig[$key]; + } elseif (!is_string($default) && is_callable($default)) { + return $default(); } else { - if (!is_string($default) && is_callable($default)) { - return $default(); - } else { - return $default; - } + return $default; } } diff --git a/packages/admin/src/Charcoal/Admin/Support/BaseUrlTrait.php b/packages/admin/src/Charcoal/Admin/Support/BaseUrlTrait.php index b66c8c610..01ea85ac9 100644 --- a/packages/admin/src/Charcoal/Admin/Support/BaseUrlTrait.php +++ b/packages/admin/src/Charcoal/Admin/Support/BaseUrlTrait.php @@ -50,7 +50,7 @@ public function baseUrl($targetPath = null) if (!isset($this->baseUrl)) { throw new RuntimeException(sprintf( 'The base URI is not defined for [%s]', - get_class($this) + $this::class )); } @@ -86,7 +86,7 @@ public function adminUrl($targetPath = null) if (!isset($this->adminUrl)) { throw new RuntimeException(sprintf( 'The Admin URI is not defined for [%s]', - get_class($this) + $this::class )); } @@ -101,17 +101,10 @@ public function adminUrl($targetPath = null) * Determine if the given URI is relative. * * @param string $uri A URI path to test. - * @return boolean */ - protected function isRelativeUri($uri) + protected function isRelativeUri($uri): bool { - if ($uri && !parse_url($uri, PHP_URL_SCHEME)) { - if (!in_array($uri[0], [ '/', '#', '?' ])) { - return true; - } - } - - return false; + return $uri && !parse_url($uri, PHP_URL_SCHEME) && !in_array($uri[0], [ '/', '#', '?' ]); } /** @@ -126,14 +119,12 @@ protected function createAbsoluteUrl(UriInterface $basePath, $targetPath) $targetPath = strval($targetPath); if ($targetPath === '') { return $basePath->withPath(''); - } else { - if ($this->isRelativeUri($targetPath)) { - $parts = parse_url($targetPath); - $path = isset($parts['path']) ? ltrim($parts['path'], '/') : ''; - $query = isset($parts['query']) ? $parts['query'] : ''; - $hash = isset($parts['fragment']) ? $parts['fragment'] : ''; - $targetPath = $basePath->withPath($path)->withQuery($query)->withFragment($hash); - } + } elseif ($this->isRelativeUri($targetPath)) { + $parts = parse_url($targetPath); + $path = isset($parts['path']) ? ltrim($parts['path'], '/') : ''; + $query = ($parts['query'] ?? ''); + $hash = ($parts['fragment'] ?? ''); + $targetPath = $basePath->withPath($path)->withQuery($query)->withFragment($hash); } return $targetPath; diff --git a/packages/admin/src/Charcoal/Admin/Support/HttpAwareTrait.php b/packages/admin/src/Charcoal/Admin/Support/HttpAwareTrait.php index 090f313af..24e2a324b 100644 --- a/packages/admin/src/Charcoal/Admin/Support/HttpAwareTrait.php +++ b/packages/admin/src/Charcoal/Admin/Support/HttpAwareTrait.php @@ -38,7 +38,7 @@ public function httpRequest() if ($this->httpRequest === null) { throw new RuntimeException(sprintf( 'PSR-7 HTTP Request is not defined for "%s"', - get_class($this) + $this::class )); } @@ -47,10 +47,8 @@ public function httpRequest() /** * Determine if a HTTP request object is set. - * - * @return boolean */ - public function hasHttpRequest() + public function hasHttpRequest(): bool { return $this->httpRequest instanceof RequestInterface; } @@ -77,7 +75,7 @@ public function httpResponse() if ($this->httpResponse === null) { throw new RuntimeException(sprintf( 'PSR-7 HTTP Response is not defined for "%s"', - get_class($this) + $this::class )); } @@ -86,10 +84,8 @@ public function httpResponse() /** * Determine if a HTTP response object is set. - * - * @return boolean */ - public function hasHttpResponse() + public function hasHttpResponse(): bool { return $this->httpResponse instanceof ResponseInterface; } @@ -124,10 +120,8 @@ protected function updateHttpResponseStatus($code, $reasonPhrase = '') /** * Is this response successful? - * - * @return boolean */ - protected function isHttpResponseSuccessful() + protected function isHttpResponseSuccessful(): bool { $response = $this->httpResponse(); diff --git a/packages/admin/src/Charcoal/Admin/Support/SecurityTrait.php b/packages/admin/src/Charcoal/Admin/Support/SecurityTrait.php index 86712e71e..23dbb0209 100644 --- a/packages/admin/src/Charcoal/Admin/Support/SecurityTrait.php +++ b/packages/admin/src/Charcoal/Admin/Support/SecurityTrait.php @@ -15,10 +15,8 @@ trait SecurityTrait * * For example, the "Login" / "Reset Password" templates * should return `false`. - * - * @return boolean */ - protected function authRequired() + protected function authRequired(): bool { return true; } diff --git a/packages/admin/src/Charcoal/Admin/Support/Sorter.php b/packages/admin/src/Charcoal/Admin/Support/Sorter.php index c8c172b0d..5e3ab906c 100644 --- a/packages/admin/src/Charcoal/Admin/Support/Sorter.php +++ b/packages/admin/src/Charcoal/Admin/Support/Sorter.php @@ -1,5 +1,7 @@ $b); } } diff --git a/packages/admin/src/Charcoal/Admin/Template/Account/LostPasswordTemplate.php b/packages/admin/src/Charcoal/Admin/Template/Account/LostPasswordTemplate.php index 9cef74fe5..1eb08d053 100644 --- a/packages/admin/src/Charcoal/Admin/Template/Account/LostPasswordTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/Account/LostPasswordTemplate.php @@ -21,9 +21,9 @@ class LostPasswordTemplate extends AdminTemplate * Determine if the password token is valid. * * @param RequestInterface $request The PSR-7 HTTP request. - * @return boolean */ - public function init(RequestInterface $request) + #[\Override] + public function init(RequestInterface $request): bool { $translator = $this->translator(); @@ -52,10 +52,8 @@ public function init(RequestInterface $request) return true; } - /** - * @return boolean - */ - public function authRequired() + #[\Override] + public function authRequired(): bool { return false; } @@ -73,6 +71,7 @@ public function urlLostPasswordAction() * * @return \Charcoal\Translator\Translation|string|null */ + #[\Override] public function title() { if ($this->title === null) { @@ -87,7 +86,8 @@ public function title() * * @return string[] */ - public function recaptchaParameters() + #[\Override] + public function recaptchaParameters(): array { $params = parent::recaptchaParameters(); $params['tabindex'] = 2; @@ -103,13 +103,11 @@ public function recaptchaParameters() // Templating // ========================================================================= - /** * Determine if main & secondary menu should appear as mobile in a desktop resolution. - * - * @return boolean */ - public function isFullscreenTemplate() + #[\Override] + public function isFullscreenTemplate(): bool { return true; } diff --git a/packages/admin/src/Charcoal/Admin/Template/Account/ResetPasswordTemplate.php b/packages/admin/src/Charcoal/Admin/Template/Account/ResetPasswordTemplate.php index d46c70b53..ddd5d47c9 100644 --- a/packages/admin/src/Charcoal/Admin/Template/Account/ResetPasswordTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/Account/ResetPasswordTemplate.php @@ -30,18 +30,14 @@ class ResetPasswordTemplate extends AdminTemplate * Determine if the password token is valid. * * @param RequestInterface $request The PSR-7 HTTP request. - * @return boolean */ - public function init(RequestInterface $request) + #[\Override] + public function init(RequestInterface $request): bool { // Undocumented Slim 3 feature: The route attributes are stored in routeInfo[2]. $routeInfo = $request->getAttribute('routeInfo'); - if (isset($routeInfo[2]['token'])) { - $this->lostPasswordToken = $routeInfo[2]['token']; - } else { - $this->lostPasswordToken = $request->getParam('token'); - } + $this->lostPasswordToken = ($routeInfo[2]['token'] ?? $request->getParam('token')); if ($this->lostPasswordToken && $this->validateToken($this->lostPasswordToken)) { return true; @@ -60,10 +56,8 @@ public function lostPasswordToken() return $this->lostPasswordToken; } - /** - * @return boolean - */ - public function authRequired() + #[\Override] + public function authRequired(): bool { return false; } @@ -86,9 +80,8 @@ public function urlResetPasswordAction() * * @see \Charcoal\Admin\Action\Account\ResetPasswordAction::validateToken() * @param string $token The token to validate. - * @return boolean */ - private function validateToken($token) + private function validateToken($token): bool { $obj = $this->modelFactory()->create(LostPasswordToken::class); $sql = strtr('SELECT * FROM `%table` WHERE `token` = :token AND `expiry` > NOW()', [ @@ -98,7 +91,7 @@ private function validateToken($token) 'token' => $token ]); - return !!$obj->token(); + return (bool)$obj->token(); } /** @@ -106,6 +99,7 @@ private function validateToken($token) * * @return \Charcoal\Translator\Translation|string|null */ + #[\Override] public function title() { if ($this->title === null) { @@ -120,7 +114,8 @@ public function title() * * @return string[] */ - public function recaptchaParameters() + #[\Override] + public function recaptchaParameters(): array { $params = parent::recaptchaParameters(); $params['tabindex'] = 5; @@ -136,13 +131,11 @@ public function recaptchaParameters() // Templating // ========================================================================= - /** * Determine if main & secondary menu should appear as mobile in a desktop resolution. - * - * @return boolean */ - public function isFullscreenTemplate() + #[\Override] + public function isFullscreenTemplate(): bool { return true; } diff --git a/packages/admin/src/Charcoal/Admin/Template/AuthTemplateTrait.php b/packages/admin/src/Charcoal/Admin/Template/AuthTemplateTrait.php index ab2c8b3fe..023686dda 100644 --- a/packages/admin/src/Charcoal/Admin/Template/AuthTemplateTrait.php +++ b/packages/admin/src/Charcoal/Admin/Template/AuthTemplateTrait.php @@ -65,7 +65,7 @@ public function urlResetPassword() * TRUE to use the default label, * or FALSE to disable the link. */ - public function returnToSiteLabel() + public function returnToSiteLabel(): false|string { $label = $this->adminConfig('login.visit_site'); if ($label === false) { diff --git a/packages/admin/src/Charcoal/Admin/Template/ElfinderTemplate.php b/packages/admin/src/Charcoal/Admin/Template/ElfinderTemplate.php index f578f0f48..8162f5c5f 100644 --- a/packages/admin/src/Charcoal/Admin/Template/ElfinderTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/ElfinderTemplate.php @@ -10,7 +10,7 @@ // From Pimple use Pimple\Container; // From Mustache -use Mustache_LambdaHelper as LambdaHelper; +use Mustache\LambdaHelper as LambdaHelper; // From 'charcoal-factory' use Charcoal\Factory\FactoryInterface; // From 'charcoal-translator' @@ -44,45 +44,35 @@ class ElfinderTemplate extends AdminTemplate /** * The related object type. - * - * @var string */ - private $objType; + private string|bool|null $objType = null; /** * The related object ID. - * - * @var string */ - private $objId; + private string|bool|null $objId = null; /** * The related property identifier. - * - * @var string */ - private $propertyIdent; + private string|bool|null $propertyIdent = null; /** * Whether to output JS/CSS assets for initializing elFinder. - * - * @var boolean */ - private $showAssets = true; + private bool $showAssets = true; /** * Custom localization messages. * * @var array|null */ - private $localizations; + private \ArrayIterator|array|null $localizations = null; /** * The related JS callback ID. - * - * @var string */ - private $callbackIdent = ''; + private string|bool $callbackIdent = ''; /** * URL for the elFinder connector. @@ -95,31 +85,31 @@ class ElfinderTemplate extends AdminTemplate * Sets the template data from a PSR Request object. * * @param RequestInterface $request A PSR-7 compatible Request instance. - * @return self */ - protected function setDataFromRequest(RequestInterface $request) + #[\Override] + protected function setDataFromRequest(RequestInterface $request): static { $keys = $this->validDataFromRequest(); $data = $request->getParams($keys); if (isset($data['obj_type'])) { - $this->objType = filter_var($data['obj_type'], FILTER_SANITIZE_STRING); + $this->objType = htmlspecialchars(trim($data['obj_type']), ENT_QUOTES, 'UTF-8'); } if (isset($data['obj_id'])) { - $this->objId = filter_var($data['obj_id'], FILTER_SANITIZE_STRING); + $this->objId = htmlspecialchars(trim($data['obj_id']), ENT_QUOTES, 'UTF-8'); } if (isset($data['property'])) { - $this->propertyIdent = filter_var($data['property'], FILTER_SANITIZE_STRING); + $this->propertyIdent = htmlspecialchars(trim($data['property']), ENT_QUOTES, 'UTF-8'); } if (isset($data['assets'])) { - $this->showAssets = !!$data['assets']; + $this->showAssets = (bool)$data['assets']; } if (isset($data['callback'])) { - $this->callbackIdent = filter_var($data['callback'], FILTER_SANITIZE_STRING); + $this->callbackIdent = htmlspecialchars(trim($data['callback']), ENT_QUOTES, 'UTF-8'); } if (isset($this->elfinderConfig['translations'])) { @@ -137,7 +127,8 @@ protected function setDataFromRequest(RequestInterface $request) * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ // Current object @@ -152,6 +143,7 @@ protected function validDataFromRequest() * * @return Translation */ + #[\Override] public function title() { if ($this->title === null) { @@ -165,9 +157,8 @@ public function title() * Set the custom localization messages. * * @param array $localizations An associative array of localizations. - * @return self */ - public function setLocalizations(array $localizations) + public function setLocalizations(array $localizations): static { $this->localizations = new ArrayIterator(); @@ -184,14 +175,13 @@ public function setLocalizations(array $localizations) * @param string $ident The message ID. * @param mixed $translations The message translations. * @throws InvalidArgumentException If the message ID is not a string or the translations are invalid. - * @return self */ - public function addLocalization($ident, $translations) + public function addLocalization($ident, $translations): static { if (!is_string($ident)) { throw new InvalidArgumentException(sprintf( 'Translation key must be a string, received %s', - (is_object($ident) ? get_class($ident) : gettype($ident)) + (get_debug_type($ident)) )); } @@ -205,14 +195,13 @@ public function addLocalization($ident, $translations) * * @param string $ident The message ID to remove. * @throws InvalidArgumentException If the message ID is not a string. - * @return self */ - public function removeLocalization($ident) + public function removeLocalization($ident): static { if (!is_string($ident)) { throw new InvalidArgumentException(sprintf( 'Translation key must be a string, received %s', - (is_object($ident) ? get_class($ident) : gettype($ident)) + (get_debug_type($ident)) )); } @@ -223,22 +212,18 @@ public function removeLocalization($ident) /** * Count the number of localizations. - * - * @return integer */ - public function numLocalizations() + public function numLocalizations(): int { return count($this->localizations()); } /** * Determine if there are any localizations. - * - * @return boolean */ - public function hasLocalizations() + public function hasLocalizations(): bool { - return !!$this->numLocalizations(); + return (bool)$this->numLocalizations(); } /** @@ -246,7 +231,7 @@ public function hasLocalizations() * * @return array */ - public function localizations() + public function localizations(): \ArrayIterator|array|null { if ($this->localizations === null) { $this->setLocalizations($this->defaultLocalizations()); @@ -267,15 +252,11 @@ public function localization($ident) if (!is_string($ident)) { throw new InvalidArgumentException(sprintf( 'Translation key must be a string, received %s', - (is_object($ident) ? get_class($ident) : gettype($ident)) + (get_debug_type($ident)) )); } - if (isset($this->localizations[$ident])) { - return $this->localizations[$ident]; - } - - return $ident; + return ($this->localizations[$ident] ?? $ident); } /** @@ -283,7 +264,7 @@ public function localization($ident) * * @return array> */ - public function elfinderLocalizations() + public function elfinderLocalizations(): array { $i18n = []; @@ -310,7 +291,7 @@ public function elfinderLocalizationsAsJson() $options = (JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); if ($this->debug()) { - $options = ($options | JSON_PRETTY_PRINT); + $options |= JSON_PRETTY_PRINT; } return json_encode($this->elfinderLocalizations(), $options); @@ -321,7 +302,7 @@ public function elfinderLocalizationsAsJson() * * @return string Returns a stringified JSON object, protected from Mustache rendering. */ - final public function escapedElfinderLocalizationsAsJson() + final public function escapedElfinderLocalizationsAsJson(): string { return '{{=<% %>=}}' . $this->elfinderLocalizationsAsJson() . '<%={{ }}=%>'; } @@ -342,10 +323,7 @@ public function elfinderAssetsUrl() return $this->baseUrl(static::ELFINDER_ASSETS_REL_PATH); } - /** - * @return string - */ - public function elfinderAssets() + public function elfinderAssets(): bool { return $this->showAssets; } @@ -355,16 +333,15 @@ public function elfinderAssets() * * @return string|null */ - public function elfinderCallback() + public function elfinderCallback(): string|bool { return $this->callbackIdent; } /** * @param string $url The elFinder connector AJAX URL. - * @return self */ - public function setElfinderConnectorUrl($url) + public function setElfinderConnectorUrl($url): static { $this->elfinderConnectorUrl = $url; return $this; @@ -392,7 +369,7 @@ public function prepareElfinderConnectorUrl() { $uri = $this->getElfinderConnectorUrlTemplate(); - return function ($noop, LambdaHelper $helper) use ($uri) { + return function ($noop, LambdaHelper $helper) use ($uri): null { $uri = $helper->render($uri); $this->setElfinderConnectorUrl($uri); @@ -402,15 +379,12 @@ public function prepareElfinderConnectorUrl() /** * Retrieve the elFinder connector URL template for rendering. - * - * @return string */ - protected function getElfinderConnectorUrlTemplate() + protected function getElfinderConnectorUrlTemplate(): string { $uri = 'obj_type={{ objType }}&obj_id={{ objId }}&property={{ propertyIdent }}'; - $uri = '{{# withAdminUrl }}elfinder-connector?' . $uri . '{{/ withAdminUrl }}'; - return $uri; + return '{{# withAdminUrl }}elfinder-connector?' . $uri . '{{/ withAdminUrl }}'; } /** @@ -418,7 +392,7 @@ protected function getElfinderConnectorUrlTemplate() * * @return string|null */ - public function objType() + public function objType(): string|bool|null { return $this->objType; } @@ -428,7 +402,7 @@ public function objType() * * @return string|null */ - public function objId() + public function objId(): string|bool|null { return $this->objId; } @@ -438,7 +412,7 @@ public function objId() * * @return string|null */ - public function propertyIdent() + public function propertyIdent(): string|bool|null { return $this->propertyIdent; } @@ -476,24 +450,20 @@ public function formProperty() */ public function elfinderClientConfig() { - if (empty($this->elfinderConfig['client'])) { - $settings = []; - } else { - $settings = $this->elfinderConfig['client']; - } + $settings = empty($this->elfinderConfig['client']) ? [] : $this->elfinderConfig['client']; $settings['lang'] = $this->translator()->getLocale(); $property = $this->formProperty(); if ($property) { - $mimeTypes = filter_input(INPUT_GET, 'filetype', FILTER_SANITIZE_STRING); + $mimeTypes = htmlspecialchars(trim(($_GET['filetype'] ?? '')), ENT_QUOTES, 'UTF-8'); if ($mimeTypes) { if ($mimeTypes === 'file') { $mimeTypes = []; } elseif (!is_array($mimeTypes)) { $mimeTypes = explode(',', $mimeTypes); - $mimeTypes = array_filter($mimeTypes, 'strlen'); + $mimeTypes = array_filter($mimeTypes, strlen(...)); } $settings['onlyMimes'] = $mimeTypes; @@ -517,7 +487,7 @@ public function elfinderClientConfigAsJson() $options = (JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); if ($this->debug()) { - $options = ($options | JSON_PRETTY_PRINT); + $options |= JSON_PRETTY_PRINT; } return json_encode($this->elfinderClientConfig(), $options); @@ -528,7 +498,7 @@ public function elfinderClientConfigAsJson() * * @return string Returns a stringified JSON object, protected from Mustache rendering. */ - final public function escapedElfinderClientConfigAsJson() + final public function escapedElfinderClientConfigAsJson(): string { return '{{=<% %>=}}' . $this->elfinderClientConfigAsJson() . '<%={{ }}=%>'; } @@ -539,6 +509,7 @@ final public function escapedElfinderClientConfigAsJson() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -551,7 +522,7 @@ protected function setDependencies(Container $container) * * @return array */ - protected function defaultLocalizations() + protected function defaultLocalizations(): array { $t = $this->translator(); @@ -569,13 +540,11 @@ protected function defaultLocalizations() // Templating // ========================================================================= - /** * Determine if main & secondary menu should appear as mobile in a desktop resolution. - * - * @return boolean */ - public function isFullscreenTemplate() + #[\Override] + public function isFullscreenTemplate(): bool { return false; } diff --git a/packages/admin/src/Charcoal/Admin/Template/HandlerTemplate.php b/packages/admin/src/Charcoal/Admin/Template/HandlerTemplate.php index 235eea173..b87e87717 100644 --- a/packages/admin/src/Charcoal/Admin/Template/HandlerTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/HandlerTemplate.php @@ -14,10 +14,8 @@ class HandlerTemplate extends AdminTemplate { use HandlerAwareTrait; - /** - * @return string - */ - public function ident() + #[\Override] + public function ident(): string { return 'error'; } @@ -27,6 +25,7 @@ public function ident() * * @return string|null */ + #[\Override] public function title() { return $this->appHandler()->getSummary(); @@ -34,10 +33,9 @@ public function title() /** * Error handler response is available to all users, no login required. - * - * @return boolean */ - protected function authRequired() + #[\Override] + protected function authRequired(): bool { return false; } diff --git a/packages/admin/src/Charcoal/Admin/Template/HelpTemplate.php b/packages/admin/src/Charcoal/Admin/Template/HelpTemplate.php index f1d62f01a..1e49057ac 100644 --- a/packages/admin/src/Charcoal/Admin/Template/HelpTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/HelpTemplate.php @@ -1,5 +1,7 @@ title === null) { diff --git a/packages/admin/src/Charcoal/Admin/Template/HomeTemplate.php b/packages/admin/src/Charcoal/Admin/Template/HomeTemplate.php index 6737361a1..ea9fe663a 100644 --- a/packages/admin/src/Charcoal/Admin/Template/HomeTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/HomeTemplate.php @@ -1,5 +1,7 @@ translator(); @@ -51,11 +51,10 @@ public function init(RequestInterface $request) /** * @todo Implement using PSR Request object - * @return boolean */ - private function isHttps() + private function isHttps(): bool { - if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) === 'on') { + if (isset($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) === 'on') { return true; } elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { return true; @@ -86,10 +85,9 @@ public function rememberMeEnabled() /** * Authentication is obviously never required for the login page. - * - * @return boolean */ - protected function authRequired() + #[\Override] + protected function authRequired(): bool { return false; } @@ -107,6 +105,7 @@ public function urlLoginAction() * * @return \Charcoal\Translator\Translation|string|null */ + #[\Override] public function title() { if ($this->title === null) { @@ -121,7 +120,8 @@ public function title() * * @return string[] */ - public function recaptchaParameters() + #[\Override] + public function recaptchaParameters(): array { $params = parent::recaptchaParameters(); $params['tabindex'] = 4; @@ -137,13 +137,11 @@ public function recaptchaParameters() // Templating // ========================================================================= - /** * Determine if main & secondary menu should appear as mobile in a desktop resolution. - * - * @return boolean */ - public function isFullscreenTemplate() + #[\Override] + public function isFullscreenTemplate(): bool { return true; } diff --git a/packages/admin/src/Charcoal/Admin/Template/LogoutTemplate.php b/packages/admin/src/Charcoal/Admin/Template/LogoutTemplate.php index 66a8f2da7..dc2801fbd 100644 --- a/packages/admin/src/Charcoal/Admin/Template/LogoutTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/LogoutTemplate.php @@ -1,5 +1,7 @@ authenticator(); @@ -34,10 +37,9 @@ public function init(RequestInterface $request) /** * Authentication is obviously never required for the login page. - * - * @return boolean */ - protected function authRequired() + #[\Override] + protected function authRequired(): bool { return false; } @@ -62,6 +64,7 @@ public function avatarImage() * * @return \Charcoal\Translator\Translation|string|null */ + #[\Override] public function title() { if ($this->title === null) { @@ -75,13 +78,11 @@ public function title() // Templating // ========================================================================= - /** * Determine if main & secondary menu should appear as mobile in a desktop resolution. - * - * @return boolean */ - public function isFullscreenTemplate() + #[\Override] + public function isFullscreenTemplate(): bool { return true; } diff --git a/packages/admin/src/Charcoal/Admin/Template/Object/CollectionTemplate.php b/packages/admin/src/Charcoal/Admin/Template/Object/CollectionTemplate.php index d7e213814..ab379e63a 100644 --- a/packages/admin/src/Charcoal/Admin/Template/Object/CollectionTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/Object/CollectionTemplate.php @@ -42,9 +42,9 @@ class CollectionTemplate extends AdminTemplate implements /** * @param RequestInterface $request PSR-7 request. - * @return boolean */ - public function init(RequestInterface $request) + #[\Override] + public function init(RequestInterface $request): bool { parent::init($request); $this->createObjTable(); @@ -57,7 +57,8 @@ public function init(RequestInterface $request) * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type' @@ -105,11 +106,7 @@ protected function createSearchWidget() $widgetData = []; } - if (isset($widgetData['type'])) { - $widgetType = $widgetData['type']; - } else { - $widgetType = SearchWidget::class; - } + $widgetType = ($widgetData['type'] ?? SearchWidget::class); $widget = $this->widgetFactory()->create($widgetType); $widget->setObjType($this->objType()); @@ -127,9 +124,10 @@ protected function createSearchWidget() * * @return \Charcoal\Translator\Translation */ + #[\Override] public function title() { - if (isset($this->title)) { + if ($this->title !== null) { return $this->title; } @@ -151,10 +149,10 @@ public function title() $metadata = $model->metadata(); $objLabel = null; - if (!$objLabel && isset($metadata['admin']['lists'])) { + if (isset($metadata['admin']['lists'])) { $adminMetadata = $metadata['admin']; - $listIdent = filter_input(INPUT_GET, 'collection_ident', FILTER_SANITIZE_STRING); + $listIdent = htmlspecialchars(trim(($_GET['collection_ident'] ?? '')), ENT_QUOTES, 'UTF-8'); if (!$listIdent) { $listIdent = $this->collectionIdent(); } @@ -190,11 +188,7 @@ public function title() } } - if ($hasView) { - $this->title = $model->render((string)$objLabel, $model); - } else { - $this->title = (string)$objLabel; - } + $this->title = $hasView ? $model->render((string)$objLabel, $model) : (string)$objLabel; return $this->title; } @@ -203,6 +197,7 @@ public function title() * @param Container $container DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -234,15 +229,10 @@ protected function createDashboardConfig() ); } - $dashboardConfig = $adminMetadata['dashboards'][$dashboardIdent]; - - return $dashboardConfig; + return $adminMetadata['dashboards'][$dashboardIdent]; } - /** - * @return void - */ - private function createObjTable() + private function createObjTable(): void { $obj = $this->proto(); if (!$obj) { @@ -289,7 +279,7 @@ private function metadataListIdent() */ private function metadataDashboardIdent() { - $dashboardIdent = filter_input(INPUT_GET, 'dashboard_ident', FILTER_SANITIZE_STRING); + $dashboardIdent = htmlspecialchars(trim(($_GET['dashboard_ident'] ?? '')), ENT_QUOTES, 'UTF-8'); if ($dashboardIdent) { return $dashboardIdent; } @@ -304,7 +294,7 @@ private function metadataDashboardIdent() // You've reached error. throw new Exception(sprintf( 'No default collection dashboard defined in admin metadata for %s.', - get_class($this->proto()) + $this->proto()::class )); } @@ -315,7 +305,6 @@ private function metadataDashboardIdent() protected function objAdminMetadata() { $objMetadata = $this->proto()->metadata(); - $adminMetadata = isset($objMetadata['admin']) ? $objMetadata['admin'] : []; - return $adminMetadata; + return ($objMetadata['admin'] ?? []); } } diff --git a/packages/admin/src/Charcoal/Admin/Template/Object/CreateTemplate.php b/packages/admin/src/Charcoal/Admin/Template/Object/CreateTemplate.php index 4fa387bcf..79a26df09 100644 --- a/packages/admin/src/Charcoal/Admin/Template/Object/CreateTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/Object/CreateTemplate.php @@ -28,13 +28,14 @@ class CreateTemplate extends AdminTemplate implements * @param RequestInterface $request PSR-7 HTTP Server Request. * @return boolean */ + #[\Override] public function init(RequestInterface $request) { $ret = parent::init($request); if ($this->obj()->id()) { $path = str_replace('object/create', 'object/edit', $request->getUri()->getPath()); - header('Location: ' . (string)$request->getUri()->withPath($path)); + header('Location: ' . $request->getUri()->withPath($path)); die(); } return $ret; @@ -45,7 +46,8 @@ public function init(RequestInterface $request) * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type', @@ -58,6 +60,7 @@ protected function validDataFromRequest() * * @return \Charcoal\Translator\Translation */ + #[\Override] public function title() { if ($this->title === null) { @@ -79,10 +82,10 @@ public function title() $objType = $this->objType(); $metadata = $obj->metadata(); - if (!$title && isset($metadata['admin']['forms'])) { + if (isset($metadata['admin']['forms'])) { $adminMetadata = $metadata['admin']; - $formIdent = filter_input(INPUT_GET, 'form_ident', FILTER_SANITIZE_STRING); + $formIdent = htmlspecialchars(trim(($_GET['form_ident'] ?? '')), ENT_QUOTES, 'UTF-8'); if (!$formIdent) { if (isset($adminMetadata['defaultForm'])) { $fomIdent = $adminMetadata['defaultForm']; @@ -140,6 +143,7 @@ public function title() * * @return Translation|string|null */ + #[\Override] public function subtitle() { if ($this->subtitle === null) { @@ -150,11 +154,7 @@ public function subtitle() $config = []; } - if (isset($config['subtitle'])) { - $title = $this->translator()->translation($config['subtitle']); - } else { - $title = ''; - } + $title = isset($config['subtitle']) ? $this->translator()->translation($config['subtitle']) : ''; $this->subtitle = $title; } @@ -166,6 +166,7 @@ public function subtitle() * @param Container $container DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -194,7 +195,7 @@ protected function createDashboardConfig() } else { throw new Exception(sprintf( 'Can not show object creation dashboard: No default create dashboard defined in admin metadata for %s', - get_class($this->obj()) + $this->obj()::class )); } } @@ -205,9 +206,7 @@ protected function createDashboardConfig() ); } - $dashboardConfig = $adminMetadata['dashboards'][$dashboardIdent]; - - return $dashboardConfig; + return $adminMetadata['dashboards'][$dashboardIdent]; } @@ -221,11 +220,11 @@ protected function objAdminMetadata() $objMetadata = $obj->metadata(); - $adminMetadata = isset($objMetadata['admin']) ? $objMetadata['admin'] : null; + $adminMetadata = ($objMetadata['admin'] ?? null); if ($adminMetadata === null) { throw new Exception(sprintf( 'The object %s does not have an admin metadata.', - get_class($obj) + $obj::class )); } diff --git a/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php b/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php index 9aedc36f5..1e81215ac 100644 --- a/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php @@ -27,13 +27,14 @@ class EditTemplate extends AdminTemplate implements * @param RequestInterface $request PSR-7 HTTP Server Request. * @return boolean */ + #[\Override] public function init(RequestInterface $request) { $ret = parent::init($request); if (!$this->obj()->id()) { $path = str_replace('object/edit', 'object/create', $request->getUri()->getPath()); - header('Location: ' . (string)$request->getUri()->withPath($path)); + header('Location: ' . $request->getUri()->withPath($path)); die(); } return $ret; @@ -44,7 +45,8 @@ public function init(RequestInterface $request) * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type', @@ -57,6 +59,7 @@ protected function validDataFromRequest() * * @return \Charcoal\Translator\Translation */ + #[\Override] public function title() { if ($this->title === null) { @@ -79,10 +82,10 @@ public function title() $objType = $this->objType(); $metadata = $obj->metadata(); - if (!$title && isset($metadata['admin']['forms'])) { + if (isset($metadata['admin']['forms'])) { $adminMetadata = $metadata['admin']; - $formIdent = filter_input(INPUT_GET, 'form_ident', FILTER_SANITIZE_STRING); + $formIdent = htmlspecialchars(trim(($_GET['form_ident'] ?? '')), ENT_QUOTES, 'UTF-8'); if (!$formIdent) { if (isset($adminMetadata['defaultForm'])) { $fomIdent = $adminMetadata['defaultForm']; @@ -128,6 +131,7 @@ public function title() * * @return Translation|string|null */ + #[\Override] public function subtitle() { if ($this->subtitle === null) { @@ -138,11 +142,7 @@ public function subtitle() $config = []; } - if (isset($config['subtitle'])) { - $title = $this->translator()->translation($config['subtitle']); - } else { - $title = ''; - } + $title = isset($config['subtitle']) ? $this->translator()->translation($config['subtitle']) : ''; $this->subtitle = $this->renderTitle($title); } @@ -154,6 +154,7 @@ public function subtitle() * @param Container $container DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -175,7 +176,7 @@ protected function createDashboardConfig() $dashboardIdent = $this->dashboardIdent(); if (empty($dashboardIdent)) { - $dashboardIdent = filter_input(INPUT_GET, 'dashboard_ident', FILTER_SANITIZE_STRING); + $dashboardIdent = htmlspecialchars(trim(($_GET['dashboard_ident'] ?? '')), ENT_QUOTES, 'UTF-8'); } if (empty($dashboardIdent)) { @@ -186,7 +187,7 @@ protected function createDashboardConfig() } else { throw new Exception(sprintf( 'No default edit dashboard defined in admin metadata for %s', - get_class($this->obj()) + $this->obj()::class )); } } @@ -197,9 +198,7 @@ protected function createDashboardConfig() ); } - $dashboardConfig = $adminMetadata['dashboards'][$dashboardIdent]; - - return $dashboardConfig; + return $adminMetadata['dashboards'][$dashboardIdent]; } /** @@ -228,11 +227,11 @@ protected function objAdminMetadata() $objMetadata = $obj->metadata(); - $adminMetadata = isset($objMetadata['admin']) ? $objMetadata['admin'] : null; + $adminMetadata = ($objMetadata['admin'] ?? null); if ($adminMetadata === null) { throw new Exception(sprintf( 'The object %s does not have an admin metadata.', - get_class($obj) + $obj::class )); } diff --git a/packages/admin/src/Charcoal/Admin/Template/System/ClearCacheTemplate.php b/packages/admin/src/Charcoal/Admin/Template/System/ClearCacheTemplate.php index f1f497b92..8bc64aadf 100644 --- a/packages/admin/src/Charcoal/Admin/Template/System/ClearCacheTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/System/ClearCacheTemplate.php @@ -38,10 +38,8 @@ class ClearCacheTemplate extends AdminTemplate /** * Summary of cache. - * - * @var array */ - private $cacheInfo; + private ?array $cacheInfo = null; /** * Cache service config. @@ -59,10 +57,8 @@ class ClearCacheTemplate extends AdminTemplate /** * Regular expression pattern to match a Stash / APC cache key. - * - * @var string */ - private $apcCacheKeyPattern; + private ?string $apcCacheKeyPattern = null; /** * Mustache View Engine. @@ -83,6 +79,7 @@ class ClearCacheTemplate extends AdminTemplate * * @return \Charcoal\Translator\Translation|string|null */ + #[\Override] public function title() { if ($this->title === null) { @@ -97,10 +94,11 @@ public function title() * * @return \Charcoal\Admin\Widget\SecondaryMenuWidgetInterface|null */ + #[\Override] public function secondaryMenu() { if ($this->secondaryMenu === null) { - $this->secondaryMenu = $this->createSecondaryMenu('system'); + $this->secondaryMenu = $this->createSecondaryMenu(); } return $this->secondaryMenu; @@ -108,14 +106,13 @@ public function secondaryMenu() /** * @param boolean $force Whether to reload cache information. - * @return array */ - public function cacheInfo($force = false) + public function cacheInfo($force = false): array { if ($this->cacheInfo === null || $force === true) { $flip = array_flip($this->availableCacheDrivers); - $driver = get_class($this->cache->getDriver()); - $cacheType = isset($flip['\\' . $driver]) ? $flip['\\' . $driver] : $driver; + $driver = $this->cache->getDriver()::class; + $cacheType = ($flip['\\' . $driver] ?? $driver); $globalItems = $this->globalCacheItems(); $this->cacheInfo = [ @@ -137,7 +134,7 @@ public function cacheInfo($force = false) /** * @return string */ - private function getCacheNamespace() + private function getCacheNamespace(): bool|string { return $this->cache->getNamespace(); } @@ -150,18 +147,12 @@ private function getApcNamespace() return $this->cacheConfig['prefix']; } - /** - * @return string - */ - private function getGlobalCacheKey() + private function getGlobalCacheKey(): string { return '/::' . $this->getCacheNamespace() . '::/'; } - /** - * @return array - */ - private function globalCacheInfo() + private function globalCacheInfo(): array { if ($this->isApc()) { $cacheKey = $this->getGlobalCacheKey(); @@ -190,10 +181,7 @@ private function globalCacheItems() } } - /** - * @return string - */ - private function getPagesCacheKey() + private function getPagesCacheKey(): string { return '/::' . $this->getCacheNamespace() . '::request::|::' . $this->getCacheNamespace() . '::template::/'; } @@ -224,10 +212,7 @@ public function getTwigEngine(): ?TwigEngine return null; } - /** - * @return array - */ - private function pagesCacheInfo() + private function pagesCacheInfo(): array { if ($this->isApc()) { $cacheKey = $this->getPagesCacheKey(); @@ -243,31 +228,12 @@ private function pagesCacheInfo() } } - /** - * @return array - */ - private function pagesCacheItems() - { - if ($this->isApc()) { - $cacheKey = $this->getPagesCacheKey(); - return $this->apcCacheItems($cacheKey); - } else { - return []; - } - } - - /** - * @return string - */ - private function getObjectsCacheKey() + private function getObjectsCacheKey(): string { return '/::' . $this->getCacheNamespace() . '::object::|::' . $this->getCacheNamespace() . '::metadata::/'; } - /** - * @return array - */ - private function objectsCacheInfo() + private function objectsCacheInfo(): array { if ($this->isApc()) { $cacheKey = $this->getObjectsCacheKey(); @@ -289,7 +255,7 @@ private function objectsCacheInfo() private function twigCacheInfo(): array { $engine = $this->getTwigEngine(); - if (!$engine) { + if (!$engine instanceof \Charcoal\View\Twig\TwigEngine) { return [ 'num_entries' => 0, 'total_size' => 0, @@ -298,9 +264,7 @@ private function twigCacheInfo(): array } $defaultCachePath = realpath($engine->cache()); - $cachePath = $defaultCachePath - ? $defaultCachePath - : realpath($this->appConfig['publicPath'] . DIRECTORY_SEPARATOR . $engine->cache()); + $cachePath = $defaultCachePath ?: realpath($this->appConfig['publicPath'] . DIRECTORY_SEPARATOR . $engine->cache()); if (!is_dir($cachePath)) { return [ @@ -323,7 +287,7 @@ private function twigCacheInfo(): array private function mustacheCacheInfo(): array { $engine = $this->getMustacheEngine(); - if (!$engine) { + if (!$engine instanceof \Charcoal\View\Mustache\MustacheEngine) { return [ 'num_entries' => 0, 'total_size' => 0, @@ -332,9 +296,7 @@ private function mustacheCacheInfo(): array } $defaultCachePath = realpath($engine->cache()); - $cachePath = $defaultCachePath - ? $defaultCachePath - : realpath($this->appConfig['publicPath'] . DIRECTORY_SEPARATOR . $engine->cache()); + $cachePath = $defaultCachePath ?: realpath($this->appConfig['publicPath'] . DIRECTORY_SEPARATOR . $engine->cache()); if (!is_dir($cachePath)) { return [ 'no_cache_folder' => true, @@ -362,24 +324,10 @@ private function dirSize(string $directory): int return $size; } - /** - * @return array - */ - private function objectsCacheItems() - { - if ($this->isApc()) { - $cacheKey = $this->getObjectsCacheKey(); - return $this->apcCacheItems($cacheKey); - } else { - return []; - } - } - /** * @param string $key The cache key to look at. - * @return array */ - private function apcCacheInfo($key) + private function apcCacheInfo(string $key): array { $iter = $this->createApcIterator($key); @@ -393,8 +341,8 @@ private function apcCacheInfo($key) $hitsTotal += $item['num_hits']; $ttlTotal += $item['ttl']; } - $sizeAvg = $numEntries ? ($sizeTotal / $numEntries) : 0; - $hitsAvg = $numEntries ? ($hitsTotal / $numEntries) : 0; + $sizeAvg = $numEntries !== 0 ? ($sizeTotal / $numEntries) : 0; + $hitsAvg = $numEntries !== 0 ? ($hitsTotal / $numEntries) : 0; return [ 'num_entries' => $numEntries, 'total_size' => $this->formatBytes($sizeTotal), @@ -408,7 +356,7 @@ private function apcCacheInfo($key) * @param string $key The cache key to look at. * @return array|\Generator */ - private function apcCacheItems($key) + private function apcCacheItems(string $key) { $iter = $this->createApcIterator($key); @@ -431,9 +379,8 @@ private function apcCacheItems($key) /** * @param string $key The cache item key to load. * @throws RuntimeException If the APC Iterator class is missing. - * @return \APCIterator|\APCUIterator|null */ - private function createApcIterator($key) + private function createApcIterator(string $key): \APCUIterator|\APCIterator { if (class_exists('\\APCUIterator', false)) { return new \APCUIterator($key); @@ -446,48 +393,40 @@ private function createApcIterator($key) /** * Determine if Charcoal has cache statistics. - * - * @return boolean */ - public function hasStats() + public function hasStats(): bool { return $this->isApc(); } /** * Determine if Charcoal is using the APC driver. - * - * @return boolean */ - public function isApc() + public function isApc(): bool { - return is_a($this->cache->getDriver(), Apc::class); + return $this->cache->getDriver() instanceof \Stash\Driver\Apc; } /** * Determine if Charcoal is using the Memcache driver. - * - * @return boolean */ - public function isMemcache() + public function isMemcache(): bool { - return is_a($this->cache->getDriver(), Memcache::class); + return $this->cache->getDriver() instanceof \Stash\Driver\Memcache; } /** * Determine if Charcoal is using the Ephemeral driver. - * - * @return boolean */ - public function isMemory() + public function isMemory(): bool { - return is_a($this->cache->getDriver(), Ephemeral::class); + return $this->cache->getDriver() instanceof \Stash\Driver\Ephemeral; } public function hasTwigCache(): bool { $engine = $this->getTwigEngine(); - if ($engine) { + if ($engine instanceof \Charcoal\View\Twig\TwigEngine) { return (bool)$engine->config()['useCache']; } @@ -513,10 +452,8 @@ public function hasViewCache(): bool * - `stashNS`: Stash Segment * - `poolNS`: Optional. Application Key * - `appKey`: Data Segment - * - * @return string */ - private function getApcCacheKeyPattern() + private function getApcCacheKeyPattern(): string { if ($this->apcCacheKeyPattern === null) { $pattern = '/^(?[a-f0-9]{32})::(?:(?'; @@ -556,7 +493,7 @@ private function formatApcCacheKey($key) * @param integer $bytes The number of bytes to format. * @return string */ - private function formatBytes($bytes) + private function formatBytes($bytes): int|string { if ($bytes === 0) { return 0; @@ -566,7 +503,7 @@ private function formatBytes($bytes) $base = log($bytes, 1024); $floor = floor($base); $unit = $units[$floor]; - $size = round(pow(1024, ($base - $floor)), 2); + $size = round((1024 ** ($base - $floor)), 2); $locale = localeconv(); $size = number_format($size, 2, $locale['decimal_point'], $locale['thousands_sep']); @@ -585,9 +522,9 @@ private function formatBytes($bytes) * @param DateTimeInterface|null $date2 The datetime to compare against. * @return string */ - private function formatTimeDiff(DateTimeInterface $date1, DateTimeInterface $date2 = null) + private function formatTimeDiff(DateTimeInterface $date1, ?DateTimeInterface $date2 = null) { - $isNow = $date2 === null; + $isNow = !$date2 instanceof \DateTimeInterface; if ($isNow) { $date2 = new DateTime('now', $date1->getTimezone()); } @@ -626,15 +563,14 @@ private function formatTimeDiff(DateTimeInterface $date1, DateTimeInterface $dat break; } - $time = $translator->transChoice($unit, $count, [ '{{ count }}' => $count ]); - - return $time; + return $translator->transChoice($unit, $count, [ '{{ count }}' => $count ]); } /** * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -644,14 +580,14 @@ protected function setDependencies(Container $container) $this->cacheConfig = $container['cache/config']; $this->mustacheEngine = function () use ($container) { - if (class_exists('\Mustache_Engine')) { + if (class_exists('\Mustache\Engine')) { return $container['view/engine/mustache']; } return null; }; $this->twigEngine = function () use ($container) { - if (class_exists('\Twig\Environment')) { + if (class_exists(\Twig\Environment::class)) { return $container['view/engine/twig']; } diff --git a/packages/admin/src/Charcoal/Admin/Template/System/Object/InfoTemplate.php b/packages/admin/src/Charcoal/Admin/Template/System/Object/InfoTemplate.php index a4a0f9988..334d10bcf 100644 --- a/packages/admin/src/Charcoal/Admin/Template/System/Object/InfoTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/System/Object/InfoTemplate.php @@ -26,23 +26,21 @@ class InfoTemplate extends AdminTemplate implements use DashboardContainerTrait; use ObjectContainerTrait; - /** - * @var array - */ - private $metadataFiles; + public $metadataLoader; + public $collectionLoader; + + private ?array $metadataFiles = null; /** * @return \Charcoal\Admin\Translation|\Charcoal\Translator\Translation|string|null */ + #[\Override] public function title() { return $this->objType(); } - /** - * @return array - */ - public function objProperties() + public function objProperties(): array { $ret = []; $properties = $this->obj()->metadata()->properties(); @@ -72,10 +70,10 @@ public function objProperties() $ret[] = $property; } - usort($ret, function ($a, $b) { - $ret = strcmp($a['metadataSource'], $b['metadataSource']); + usort($ret, function (array $a, array $b): int { + $ret = strcmp((string)$a['metadataSource'], (string)$b['metadataSource']); if ($ret === 0) { - return strcmp($a['ident'], $b['ident']); + return strcmp((string)$a['ident'], (string)$b['ident']); } else { return $ret; } @@ -83,29 +81,19 @@ public function objProperties() return $ret; } - /** - * @return string - */ - public function className() + public function className(): string { - return get_class($this->obj()); + return $this->obj()::class; } - /** - * @return array - */ - public function classHierarchy() + public function classHierarchy(): array { $ret = []; $ret = array_merge($ret, array_keys(class_parents($this->obj()))); - $ret = array_reverse($ret); - return $ret; + return array_reverse($ret); } - /** - * @return array - */ - public function classTraits() + public function classTraits(): array { $traits = []; $hierarchy = $this->classHierarchy(); @@ -117,31 +105,23 @@ public function classTraits() return $traits; } - /** - * @return array - */ - public function classInterfaces() + public function classInterfaces(): array { - $reflection = new ReflectionClass(get_class($this->obj())); + $reflection = new ReflectionClass($this->obj()::class); $interfaces = array_keys($reflection->getInterfaces()); sort($interfaces); return $interfaces; } - /** - * @return array - */ - public function metadataFiles() + public function metadataFiles(): array { if ($this->metadataFiles === null) { $files = []; $reflector = new ReflectionObject($this->metadataLoader); $method = $reflector->getMethod('hierarchy'); - $method->setAccessible(true); $hierarchy = $method->invoke($this->metadataLoader, $this->objType()); $method2 = $reflector->getMethod('loadMetadataFromSource'); - $method2->setAccessible(true); foreach ($hierarchy as $source) { $ret = $method2->invoke($this->metadataLoader, $source); if (!empty($ret)) { @@ -177,7 +157,7 @@ public function sourceTable() */ public function sourceEntries() { - $this->collectionLoader->setModel(get_class($this->obj())); + $this->collectionLoader->setModel($this->obj()::class); return $this->collectionLoader->loadCount(); } @@ -186,7 +166,8 @@ public function sourceEntries() * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type', 'obj_id' @@ -197,6 +178,7 @@ protected function validDataFromRequest() * @param Container $container DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -210,10 +192,7 @@ protected function setDependencies(Container $container) $this->collectionLoader = $container['model/collection/loader']; } - /** - * @return array - */ - protected function createDashboardConfig() + protected function createDashboardConfig(): array { return []; } @@ -234,9 +213,8 @@ private function getFirstFile($propertyIdent) /** * @param string $propertyIdent The property ident to retrieve. - * @return array */ - private function getAllFiles($propertyIdent) + private function getAllFiles($propertyIdent): array { $ret = []; $files = $this->metadataFiles(); diff --git a/packages/admin/src/Charcoal/Admin/Template/System/StaticWebsiteTemplate.php b/packages/admin/src/Charcoal/Admin/Template/System/StaticWebsiteTemplate.php index 9dadc2108..fb60a3459 100644 --- a/packages/admin/src/Charcoal/Admin/Template/System/StaticWebsiteTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/System/StaticWebsiteTemplate.php @@ -21,6 +21,7 @@ class StaticWebsiteTemplate extends AdminTemplate * * @return \Charcoal\Translator\Translation|string|null */ + #[\Override] public function title() { if ($this->title === null) { @@ -35,19 +36,17 @@ public function title() * * @return \Charcoal\Admin\Widget\SecondaryMenuWidgetInterface|null */ + #[\Override] public function secondaryMenu() { if ($this->secondaryMenu === null) { - $this->secondaryMenu = $this->createSecondaryMenu('system'); + $this->secondaryMenu = $this->createSecondaryMenu(); } return $this->secondaryMenu; } - /** - * @return boolean - */ - public function isStaticWebsiteEnabled() + public function isStaticWebsiteEnabled(): bool { return file_exists($this->basePath . DIRECTORY_SEPARATOR . '/www/static'); } @@ -65,7 +64,7 @@ public function staticWebsiteFiles() 'size' => $this->formatBytes(filesize($file)), 'mtime' => date(DATE_ATOM, filemtime($file)), 'generated' => date('Y-m-d H:i:s', filemtime($file)), - 'type' => pathinfo($file, PATHINFO_EXTENSION) + 'type' => pathinfo((string)$file, PATHINFO_EXTENSION) ]; } } @@ -74,6 +73,7 @@ public function staticWebsiteFiles() * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -84,9 +84,8 @@ protected function setDependencies(Container $container) * Human-readable bytes format. * * @param integer $size The number of bytes to format. - * @return boolean */ - private function formatBytes($size) + private function formatBytes(int|bool $size): int|string { if ($size === 0) { return 0; @@ -95,7 +94,7 @@ private function formatBytes($size) $suffixes = [ 'bytes', 'k', 'M', 'G', 'T' ]; $floor = floor($base); - return round(pow(1024, ($base - $floor)), 2) . ' ' . $suffixes[$floor]; + return round((1024 ** ($base - $floor)), 2) . ' ' . $suffixes[$floor]; } /** @@ -104,7 +103,7 @@ private function formatBytes($size) * @param integer $flags Glob flags. * @return array */ - private function globRecursive($dir, $pattern, $flags = 0) + private function globRecursive(string $dir, string $pattern, $flags = 0): array|false { $files = glob($dir . '/' . $pattern, $flags); foreach (glob($dir . '/*', (GLOB_ONLYDIR | GLOB_NOSORT)) as $dir) { diff --git a/packages/admin/src/Charcoal/Admin/Template/System/UserPermissionsTemplate.php b/packages/admin/src/Charcoal/Admin/Template/System/UserPermissionsTemplate.php index 633ae4243..745d61a8c 100644 --- a/packages/admin/src/Charcoal/Admin/Template/System/UserPermissionsTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/System/UserPermissionsTemplate.php @@ -26,9 +26,9 @@ class UserPermissionsTemplate extends AdminTemplate implements /** * @param RequestInterface $request PSR-7 request. - * @return boolean */ - public function init(RequestInterface $request) + #[\Override] + public function init(RequestInterface $request): bool { parent::init($request); @@ -42,17 +42,15 @@ public function init(RequestInterface $request) * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type' ], parent::validDataFromRequest()); } - /** - * @return void - */ - private function createObjTable() + private function createObjTable(): void { $obj = $this->modelFactory()->create('charcoal/admin/user/permission'); if ($obj->source()->tableExists() === false) { @@ -70,15 +68,13 @@ private function createObjTable() /** * @return \Charcoal\Translator\Translation */ - public function title() + #[\Override] + public function title(): ?\Charcoal\Translator\Translation { return $this->translator()->translation('Administrator Permissions'); } - /** - * @return mixed - */ - public function createDashboardConfig() + public function createDashboardConfig(): array { return [ 'layout' => [ @@ -99,6 +95,7 @@ public function createDashboardConfig() * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Template/System/UserRolesTemplate.php b/packages/admin/src/Charcoal/Admin/Template/System/UserRolesTemplate.php index cf457c235..adadb1a71 100644 --- a/packages/admin/src/Charcoal/Admin/Template/System/UserRolesTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/System/UserRolesTemplate.php @@ -25,7 +25,8 @@ class UserRolesTemplate extends AdminTemplate implements * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type' @@ -35,15 +36,13 @@ protected function validDataFromRequest() /** * @return \Charcoal\Translator\Translation */ - public function title() + #[\Override] + public function title(): ?\Charcoal\Translator\Translation { return $this->translator()->translation('Administrator Roles'); } - /** - * @return mixed - */ - public function createDashboardConfig() + public function createDashboardConfig(): array { return [ 'layout' => [ @@ -64,6 +63,7 @@ public function createDashboardConfig() * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Template/System/UsersTemplate.php b/packages/admin/src/Charcoal/Admin/Template/System/UsersTemplate.php index 5e83f09d1..6395fd450 100644 --- a/packages/admin/src/Charcoal/Admin/Template/System/UsersTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/System/UsersTemplate.php @@ -27,7 +27,8 @@ class UsersTemplate extends AdminTemplate implements * * @return string[] */ - protected function validDataFromRequest() + #[\Override] + protected function validDataFromRequest(): array { return array_merge([ 'obj_type' @@ -39,15 +40,13 @@ protected function validDataFromRequest() * * @return \Charcoal\Translator\Translation|string|null */ - public function title() + #[\Override] + public function title(): ?\Charcoal\Translator\Translation { return $this->translator()->translation('Administrators'); } - /** - * @return mixed - */ - public function createDashboardConfig() + public function createDashboardConfig(): array { return [ 'layout' => [ @@ -68,6 +67,7 @@ public function createDashboardConfig() * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Ui/ActionContainerTrait.php b/packages/admin/src/Charcoal/Admin/Ui/ActionContainerTrait.php index b0fa09721..e3016c63e 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/ActionContainerTrait.php +++ b/packages/admin/src/Charcoal/Admin/Ui/ActionContainerTrait.php @@ -38,7 +38,7 @@ trait ActionContainerTrait * to determine if any renderables should be processed. * @return array Returns a collection of parsed actions. */ - protected function parseActions(array $actions, $renderer = false) + protected function parseActions(array $actions, $renderer = false): array { $this->actionsPriority = $this->defaultActionPriority(); @@ -63,7 +63,7 @@ protected function parseActions(array $actions, $renderer = false) } } - usort($parsedActions, [ 'Charcoal\Admin\Support\Sorter', 'sortByPriority' ]); + usort($parsedActions, \Charcoal\Admin\Support\Sorter::sortByPriority(...)); while (($first = reset($parsedActions)) && $first['isSeparator']) { array_shift($parsedActions); @@ -82,7 +82,7 @@ protected function parseActions(array $actions, $renderer = false) * @param array ...$params Variable list of actions to merge. * @return array Returns a collection of merged actions. */ - protected function mergeActions(array ...$params) + protected function mergeActions(array ...$params): array { $unique = []; foreach ($params as $actions) { @@ -96,15 +96,11 @@ protected function mergeActions(array ...$params) $action['ident'] = $ident; $hasActions = (isset($action['actions']) && is_array($action['actions'])); - if ($hasActions) { - $action['actions'] = $this->mergeActions($action['actions']); - } else { - $action['actions'] = []; - } + $action['actions'] = $hasActions ? $this->mergeActions($action['actions']) : []; if (isset($unique[$ident])) { if (static::compareActions($action, $unique[$ident])) { - if ($hasActions && !!$unique[$ident]['actions']) { + if ($hasActions && (bool)$unique[$ident]['actions']) { $action['actions'] = $this->mergeActions( $unique[$ident]['actions'], $action['actions'] @@ -113,7 +109,7 @@ protected function mergeActions(array ...$params) } $unique[$ident] = array_replace($unique[$ident], $action); } else { - if ($hasActions && !!$unique[$ident]['actions']) { + if ($hasActions && (bool)$unique[$ident]['actions']) { $unique[$ident]['actions'] = $this->mergeActions( $unique[$ident]['actions'], $action['actions'] @@ -138,13 +134,9 @@ protected function mergeActions(array ...$params) * @param mixed $action The action structure. * @return string Resolved action identifier. */ - protected function parseActionIdent($ident, $action) + protected function parseActionIdent($ident, array $action) { - if (isset($action['ident'])) { - return $action['ident']; - } - - return $ident; + return ($action['ident'] ?? $ident); } /** @@ -176,11 +168,9 @@ protected function parseActionItem($action, $ident, $renderer = false) $action['ident'] = $ident; } - if (isset($action['buttonType'])) { - if (!in_array($action['buttonType'], $buttonTypes)) { - $action['actionType'] = $action['buttonType']; - $action['buttonType'] = 'button'; - } + if (isset($action['buttonType']) && !in_array($action['buttonType'], $buttonTypes)) { + $action['actionType'] = $action['buttonType']; + $action['buttonType'] = 'button'; } if (!isset($action['actionType'])) { @@ -232,21 +222,17 @@ protected function parseActionItem($action, $ident, $renderer = false) } if (isset($action['dataAttributes']) && is_array($action['dataAttributes'])) { - $action['dataAttributes'] = array_filter($action['dataAttributes'], function ($attribute) { - return !empty($attribute['key']) && - is_string($attribute['key']) && - !empty($attribute['value']) && - is_string($attribute['value']); - }); + $action['dataAttributes'] = array_filter($action['dataAttributes'], fn(array $attribute): bool => !empty($attribute['key']) && + is_string($attribute['key']) && + !empty($attribute['value']) && + is_string($attribute['value'])); } else { $action['dataAttributes'] = []; } if (isset($action['actions']) && is_array($action['actions'])) { $action['actions'] = $this->parseActions($action['actions']); - $action['hasActions'] = !!array_filter($action['actions'], function ($action) { - return $action['active']; - }); + $action['hasActions'] = (bool)array_filter($action['actions'], fn(array $action): mixed => $action['active']); } else { $action['actions'] = []; $action['hasActions'] = false; @@ -267,41 +253,25 @@ protected function parseActionItem($action, $ident, $renderer = false) * Resolve the action's type. * * @param mixed $action The action structure. - * @return string */ - protected function resolveActionType($action) + protected function resolveActionType(array $action): string { - switch ($action['ident']) { - case 'create': - case 'save': - case 'submit': - case 'update': - case 'edit': - return 'primary'; - - case 'reset': - return 'warning'; - - case 'delete': - return 'danger'; - - default: - return 'dark'; - } + return match ($action['ident']) { + 'create', 'save', 'submit', 'update', 'edit' => 'primary', + 'reset' => 'warning', + 'delete' => 'danger', + default => 'dark', + }; } /** * Fetch a viewable instance to process an action's renderables. - * - * @return ViewableInterface|null */ - protected function getActionRenderer() + protected function getActionRenderer(): ?\Charcoal\View\ViewableInterface { $obj = null; - if ($this instanceof FormSidebarInterface) { - if ($this->form()) { - $obj = $this->form()->obj(); - } + if ($this instanceof FormSidebarInterface && $this->form()) { + $obj = $this->form()->obj(); } if ($this instanceof ObjectContainerInterface) { @@ -309,7 +279,7 @@ protected function getActionRenderer() } if ($this instanceof CollectionContainerInterface) { - $obj = isset($this->currentObj) ? $this->currentObj : $this->proto(); + $obj = ($this->currentObj ?? $this->proto()); } if (($obj instanceof ViewableInterface) && ($obj->view() instanceof ViewInterface)) { @@ -328,7 +298,7 @@ protected function getActionRenderer() * @throws RuntimeException If a renderer is unavailable. * @return array Resolved action structure. */ - protected function parseActionRenderables($action, $renderer) + protected function parseActionRenderables(array $action, $renderer): array { if ($renderer === false) { return $action; @@ -379,13 +349,13 @@ protected function parseActionCondition($condition, $action = null, $renderer = $result = null; if ($renderer && is_callable([ $renderer, $condition ])) { - $result = !!$renderer->{$condition}(); + $result = (bool)$renderer->{$condition}(); } elseif (is_callable([ $this, $condition ])) { - $result = !!$this->{$condition}(); + $result = (bool)$this->{$condition}(); } elseif (is_callable($condition)) { - $result = !!$condition(); + $result = (bool)$condition(); } elseif ($renderer) { - $result = !!$renderer->renderTemplate($condition); + $result = (bool)$renderer->renderTemplate($condition); } if ($result !== null) { @@ -418,24 +388,24 @@ protected function parseActionUrl($url, $action = null, $renderer = null) $url = trim($url); - if (empty($url) && !is_numeric($url)) { + if (($url === '' || $url === '0') && !is_numeric($url)) { return '#'; } if ($renderer === null) { /** @todo Shame! Force `{{ id }}` to use "obj_id" GET parameter… */ - $objId = filter_input(INPUT_GET, 'obj_id', FILTER_SANITIZE_STRING); + $objId = htmlspecialchars(trim(($_GET['obj_id'] ?? '')), ENT_QUOTES, 'UTF-8'); if ($objId) { $url = preg_replace('~\{\{\s*(obj_)?id\s*\}\}~', $objId, $url); } /** @todo Shame! Force `{{ type }}` to use "obj_type" GET parameter… */ - $objType = filter_input(INPUT_GET, 'obj_type', FILTER_SANITIZE_STRING); + $objType = htmlspecialchars(trim(($_GET['obj_type'] ?? '')), ENT_QUOTES, 'UTF-8'); if ($objType) { - $url = preg_replace('~\{\{\s*(obj_)?type\s*\}\}~', $objType, $url); + $url = preg_replace('~\{\{\s*(obj_)?type\s*\}\}~', $objType, (string)$url); } - if ($url && strpos($url, ':') === false && !in_array($url[0], [ '/', '#', '?' ])) { + if ($url && !str_contains($url, ':') && !in_array($url[0], [ '/', '#', '?' ])) { $url = $this->adminUrl() . $url; } @@ -443,7 +413,7 @@ protected function parseActionUrl($url, $action = null, $renderer = null) } elseif ($renderer instanceof ViewableInterface) { $url = $renderer->renderTemplate($url); - if ($url && strpos($url, ':') === false && !in_array($url[0], [ '/', '#', '?' ])) { + if ($url && !str_contains($url, ':') && !in_array($url[0], [ '/', '#', '?' ])) { $url = $this->adminUrl() . $url; } } @@ -479,10 +449,8 @@ protected function parseActionCssClasses($classes, $action = null, $renderer = n /** * Retrieve the default action structure. - * - * @return array */ - protected function defaultActionStruct() + protected function defaultActionStruct(): array { return [ 'ident' => null, @@ -533,10 +501,10 @@ protected function defaultActionPriority() * @param array $b Second action object to sort. * @return boolean Returns TRUE if $a has priority. Otherwise, FALSE for $b. */ - protected function compareActions(array $a, array $b) + protected function compareActions(array $a, array $b): bool { - $a = isset($a['priority']) ? $a['priority'] : 0; - $b = isset($b['priority']) ? $b['priority'] : 0; + $a = ($a['priority'] ?? 0); + $b = ($b['priority'] ?? 0); $c = isset($action['isSubmittable']) && $action['isSubmittable']; return ($c || ($a === 0) || ($a >= $b)); diff --git a/packages/admin/src/Charcoal/Admin/Ui/CollectionContainerInterface.php b/packages/admin/src/Charcoal/Admin/Ui/CollectionContainerInterface.php index b5a47967f..c6a4ad298 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/CollectionContainerInterface.php +++ b/packages/admin/src/Charcoal/Admin/Ui/CollectionContainerInterface.php @@ -1,5 +1,7 @@ modelFactory === null) { throw new Exception(sprintf( 'Model Factory is not defined for "%s"', - get_class($this) + $this::class )); } @@ -198,9 +197,8 @@ protected function modelFactory() /** * @param FactoryInterface $factory The property display factory. - * @return CollectionContainerInterface Chainable */ - private function setPropertyDisplayFactory(FactoryInterface $factory) + private function setPropertyDisplayFactory(FactoryInterface $factory): CollectionContainerInterface { $this->propertyDisplayFactory = $factory; @@ -209,14 +207,13 @@ private function setPropertyDisplayFactory(FactoryInterface $factory) /** * @throws Exception If the property display factory was not previously injected / set. - * @return FactoryInterface */ - private function propertyDisplayFactory() + private function propertyDisplayFactory(): FactoryInterface { if ($this->propertyDisplayFactory === null) { throw new Exception(sprintf( 'Property display factory is not defined for "%s"', - get_class($this) + $this::class )); } @@ -225,9 +222,8 @@ private function propertyDisplayFactory() /** * @param CollectionLoader $loader The collection loader. - * @return CollectionContainerInterface Chainable */ - public function setCollectionLoader(CollectionLoader $loader) + public function setCollectionLoader(CollectionLoader $loader): CollectionContainerInterface { $this->collectionLoader = $loader; @@ -237,10 +233,8 @@ public function setCollectionLoader(CollectionLoader $loader) /** * Safe Collection Loader getter. * Create the loader if it was not set / injected. - * - * @return CollectionLoader */ - protected function collectionLoader() + protected function collectionLoader(): CollectionLoader { if ($this->collectionLoader === null) { $this->collectionLoader = $this->createCollectionLoader(); @@ -251,10 +245,8 @@ protected function collectionLoader() /** * Create a collection loader. - * - * @return CollectionLoader */ - protected function createCollectionLoader() + protected function createCollectionLoader(): \Charcoal\Loader\CollectionLoader { return new CollectionLoader([ 'logger' => $this->logger, @@ -269,16 +261,15 @@ protected function createCollectionLoader() * * @param CollectionLoader $loader The collection loader to prepare. * @param array|null $data Optional collection data. - * @return void */ - protected function configureCollectionLoader(CollectionLoader $loader, array $data = null) + protected function configureCollectionLoader(CollectionLoader $loader, ?array $data = null): void { - $objType = $this->getObjTypeOrFail(); + $this->getObjTypeOrFail(); $loader->setModel($this->proto()); $config = $this->collectionConfig(); - if (is_array($config) && !empty($config)) { + if (is_array($config) && $config !== []) { unset($config['properties']); $loader->setData($config); } @@ -293,9 +284,8 @@ protected function configureCollectionLoader(CollectionLoader $loader, array $da /** * @param string $objType The collection's object type. * @throws InvalidArgumentException If provided argument is not of type 'string'. - * @return CollectionContainerInterface Chainable */ - public function setObjType($objType) + public function setObjType($objType): CollectionContainerInterface { if (!is_string($objType)) { throw new InvalidArgumentException( @@ -307,10 +297,7 @@ public function setObjType($objType) return $this; } - /** - * @return string - */ - public function objType() + public function objType(): string { return $this->objType; } @@ -319,16 +306,15 @@ public function objType() * Retrieve the current object type or throw an exception. * * @throws UnexpectedValueException If the collection object type is invalid or missing. - * @return string */ - public function getObjTypeOrFail() + public function getObjTypeOrFail(): string { $objType = $this->objType(); if (!$objType) { throw new UnexpectedValueException(sprintf( '%1$s cannot create collection. Object type is not defined.', - get_class($this) + $this::class )); } @@ -340,9 +326,8 @@ public function getObjTypeOrFail() * * @param string $collectionIdent The collection identifier. * @throws InvalidArgumentException If the identifier argument is not a string. - * @return CollectionContainerInterface Chainable */ - public function setCollectionIdent($collectionIdent) + public function setCollectionIdent($collectionIdent): CollectionContainerInterface { if (!is_string($collectionIdent)) { throw new InvalidArgumentException( @@ -358,10 +343,8 @@ public function setCollectionIdent($collectionIdent) * Retrieve a key for the collection structure to use. * * If the collection key is undefined, resolve a fallback. - * - * @return string */ - public function collectionIdentFallback() + public function collectionIdentFallback(): string { $metadata = $this->proto()->metadata(); @@ -376,20 +359,16 @@ public function collectionIdentFallback() /** * Retrieve the key for the collection structure to use. - * - * @return string|null */ - public function collectionIdent() + public function collectionIdent(): ?string { return $this->collectionIdent; } /** * Return the current collection metadata. - * - * @return array */ - public function collectionMetadata() + public function collectionMetadata(): array { $proto = $this->proto(); $collectionIdent = $this->collectionIdent(); @@ -417,10 +396,8 @@ public function collectionMetadata() /** * Retrieve the collection configset. - * - * @return array|null */ - public function collectionConfig() + public function collectionConfig(): ?array { if ($this->collectionConfig === null) { $this->collectionConfig = $this->createCollectionConfig(); @@ -433,9 +410,8 @@ public function collectionConfig() * Replace the collection's configset with the given parameters. * * @param mixed $config New collection config values. - * @return CollectionContainerInterface Chainable */ - public function setCollectionConfig($config) + public function setCollectionConfig($config): CollectionContainerInterface { if (empty($config) || !is_array($config)) { $config = []; @@ -453,9 +429,8 @@ public function setCollectionConfig($config) * Merge given parameters into the collection's configset. * * @param array $config New collection config values. - * @return self */ - public function mergeCollectionConfig(array $config) + public function mergeCollectionConfig(array $config): static { if ($this->collectionConfig === null) { $this->setCollectionConfig($config); @@ -475,23 +450,18 @@ public function mergeCollectionConfig(array $config) * Stub: Parse given parameters into the collection's config set. * * @param array $config New collection config values. - * @return array */ - protected function parseCollectionConfig(array $config) + protected function parseCollectionConfig(array $config): array { - return array_filter($config, function ($val) { - return !empty($val) || is_numeric($val); - }); + return array_filter($config, fn($val): bool => !empty($val) || is_numeric($val)); } /** * Retrieve the default collection configuration. * * The default configset is determined by the collection ident and object type, if assigned. - * - * @return array|null */ - protected function defaultCollectionConfig() + protected function defaultCollectionConfig(): ?array { if ($this->defaultCollectionConfig === null) { $this->defaultCollectionConfig = $this->collectionMetadata(); @@ -502,28 +472,20 @@ protected function defaultCollectionConfig() /** * Stub: reimplement in classes using this trait. - * - * @return mixed */ - protected function createCollectionConfig() + protected function createCollectionConfig(): mixed { return $this->collectionMetadata(); } - /** - * @return boolean - */ - public function hasPagination() + public function hasPagination(): bool { return ($this->pagination() instanceof Pagination); } - /** - * @return PaginationInterface - */ - public function pagination() + public function pagination(): PaginationInterface { - if ($this->pagination === null || !($this->pagination instanceof PaginationInterface)) { + if (!($this->pagination instanceof PaginationInterface)) { $this->pagination = $this->createPagination(); $collectionConfig = $this->collectionConfig(); if (isset($collectionConfig['pagination'])) { @@ -538,43 +500,32 @@ public function pagination() * Prevents the mutation of pagination. * * @param mixed $pagination Unused parameter. - * @return self */ - public function setPagination($pagination) + public function setPagination($pagination): static { unset($pagination); return $this; } - /** - * @return PaginationInterface - */ - protected function createPagination() + protected function createPagination(): PaginationInterface { - $pagination = new Pagination(); - return $pagination; + return new Pagination(); } - /** - * @return integer - */ - public function page() + public function page(): int { return $this->pagination()->page(); } - /** - * @return integer - */ - public function numPerPage() + public function numPerPage(): int { return $this->pagination()->numPerPage(); } /** - * @return integer + * @throws Exception */ - public function numPages() + public function numPages(): int|float { if ($this->numPerPage() === 0) { return 0; @@ -583,10 +534,7 @@ public function numPages() return ceil($this->numTotal() / $this->numPerPage()); } - /** - * @return boolean - */ - public function hasFilters() + public function hasFilters(): bool { return count($this->filters()) > 0; } @@ -594,7 +542,7 @@ public function hasFilters() /** * @return FilterInterface[] */ - public function filters() + public function filters(): array { if ($this->filters === null) { $this->filters = []; @@ -619,27 +567,19 @@ public function filters() * Prevents the mutation of filters. * * @param mixed $filters Unused parameter. - * @return self */ - public function setFilters($filters) + public function setFilters($filters): static { unset($filters); return $this; } - /** - * @return FilterInterface - */ - protected function createFilter() + protected function createFilter(): FilterInterface { - $filter = new Filter(); - return $filter; + return new Filter(); } - /** - * @return boolean - */ - public function hasOrders() + public function hasOrders(): bool { return count($this->orders()) > 0; } @@ -647,7 +587,7 @@ public function hasOrders() /** * @return OrderInterface[] */ - public function orders() + public function orders(): array { if ($this->orders === null) { $this->orders = []; @@ -672,37 +612,28 @@ public function orders() * Prevents the mutation of orders. * * @param mixed $orders Unused parameter. - * @return self */ - public function setOrders($orders) + public function setOrders($orders): static { unset($orders); return $this; } - /** - * @return OrderInterface - */ - protected function createOrder() + protected function createOrder(): OrderInterface { - $order = new Order(); - return $order; + return new Order(); } /** * @param mixed $collection The collection. - * @return CollectionContainerInterface Chainable */ - public function setCollection($collection) + public function setCollection($collection): CollectionContainerInterface { $this->collection = $collection; return $this; } - /** - * @return Collection - */ - public function collection() + public function collection(): Collection { if ($this->collection === null) { $this->collection = $this->createCollection(); @@ -712,26 +643,20 @@ public function collection() } /** + * @param array|null $data Optional collection data. + * @return \ArrayAccess|array|ModelInterface[] * @todo Integrate $data; merge with $collectionConfig - * @param array $data Optional collection data. - * @throws Exception If the object type of the colletion has not been set. - * @return ModelInterface[] */ - public function createCollection(array $data = null) + public function createCollection(?array $data = null): \ArrayAccess|array { - $objType = $this->getObjTypeOrFail(); + $this->getObjTypeOrFail(); $loader = $this->collectionLoader(); $this->configureCollectionLoader($loader, $data); - - $collection = $loader->load(); - return $collection; + return $loader->load(); } - /** - * @return array - */ - public function objects() + public function objects(): array { return $this->collection()->values(); } @@ -740,10 +665,8 @@ public function objects() * Sort the objects before they are displayed as rows. * * This method is useful for classes using this trait. - * - * @return array */ - public function sortObjects() + public function sortObjects(): array { return $this->objects(); } @@ -752,9 +675,8 @@ public function sortObjects() * Prevents the mutation of properties. * * @param mixed $properties Unused parameter. - * @return self */ - public function setProperties($properties) + public function setProperties($properties): static { unset($properties); return $this; @@ -764,10 +686,8 @@ public function setProperties($properties) * Prepares and returns the properties. * * This method should be overriden in the class implementing this trait. - * - * @return array */ - public function properties() + public function properties(): array { return []; } @@ -776,10 +696,8 @@ public function properties() * Sort the properties before they are displayed as columns. * * This method is useful for classes using this trait. - * - * @return array */ - public function sortProperties() + public function sortProperties(): array { return $this->properties(); } @@ -788,19 +706,16 @@ public function sortProperties() * Retrieve the property customizations for the collection. * * This method should be overriden in the class implementing this trait. - * - * @return array */ - public function propertiesOptions() + public function propertiesOptions(): array { return []; } /** * Supplies properties for objects in table template specific to object configuration. - * @return \Generator */ - public function objectRows() + public function objectRows(): \Generator { // Get properties as defined in object's list metadata $properties = $this->sortProperties(); @@ -811,10 +726,8 @@ public function objectRows() // Go through each object to generate an array of properties listed in object's list metadata foreach ($objects as $object) { - if (isset($object['requiredAclPermissions']) && !empty($object['requiredAclPermissions'])) { - if ($this->hasPermissions($object['requiredAclPermissions']) === false) { - continue; - } + if (isset($object['requiredAclPermissions']) && !empty($object['requiredAclPermissions']) && $this->hasPermissions($object['requiredAclPermissions']) === false) { + continue; } $objectProperties = []; @@ -855,9 +768,8 @@ public function objectRows() * * @param ModelInterface $object The current row's object. * @param PropertyInterface $property The current property. - * @return void */ - protected function setupDisplayPropertyValue(ModelInterface $object, PropertyInterface $property) + protected function setupDisplayPropertyValue(ModelInterface $object, PropertyInterface $property): void { $displayType = $property['displayType']; @@ -891,13 +803,12 @@ protected function setupDisplayPropertyValue(ModelInterface $object, PropertyInt * @param ModelInterface $object The current row's object. * @param PropertyInterface $property The current property. * @param string $propertyValue The property $key's display value. - * @return array */ protected function parsePropertyCell( ModelInterface $object, PropertyInterface $property, - $propertyValue - ) { + string $propertyValue + ): array { unset($object); return [ @@ -913,9 +824,8 @@ protected function parsePropertyCell( * * @param ModelInterface $object The current row's object. * @param array $objectProperties The $object's display properties. - * @return array */ - protected function parseObjectRow(ModelInterface $object, array $objectProperties) + protected function parseObjectRow(ModelInterface $object, array $objectProperties): array { return [ 'object' => $object, @@ -925,27 +835,20 @@ protected function parseObjectRow(ModelInterface $object, array $objectPropertie ]; } - /** - * @return boolean - */ - public function hasObjects() + public function hasObjects(): bool { return ($this->numObjects() > 0); } - /** - * @return integer - */ - public function numObjects() + public function numObjects(): int { return count($this->objects()); } /** * @throws Exception If obj type was not set. - * @return integer */ - public function numTotal() + public function numTotal(): int { if ($this->numTotal === null) { $objType = $this->getObjTypeOrFail(); @@ -967,10 +870,8 @@ public function numTotal() /** * Retrieve the object's labels. - * - * @return array|null */ - public function objLabels() + public function objLabels(): ?array { if ($this->objLabels === null) { $objLabels = []; @@ -978,7 +879,7 @@ public function objLabels() $objMetadata = $proto->metadata(); if (isset($objMetadata['labels']) && !empty($objMetadata['labels'])) { $objLabels = $objMetadata['labels']; - array_walk($objLabels, function (&$value) { + array_walk($objLabels, function (&$value): void { $value = $this->translator()->translation($value); }); $this->objLabels = $objLabels; @@ -990,17 +891,16 @@ public function objLabels() /** * @param boolean $reload If true, reload will be forced. - * @throws InvalidArgumentException If the object type is not defined / can not create prototype. - * @return ModelInterface + * @throws InvalidArgumentException|Exception If the object type is not defined / can not create prototype. */ - public function proto($reload = false) + public function proto($reload = false): ModelInterface { if ($this->proto === null || $reload) { $objType = $this->objType(); if ($objType === null) { throw new InvalidArgumentException(sprintf( '%s Can not create an object prototype: object type is null.', - get_class($this) + $this::class )); } $this->proto = $this->modelFactory()->create($objType); @@ -1011,10 +911,9 @@ public function proto($reload = false) /** * Retrieve the current object in a collection or its prototype. - * - * @return ModelInterface + * @throws Exception */ - protected function getCurrentObjOrProto() + protected function getCurrentObjOrProto(): ModelInterface { return $this->currentObj ?: $this->proto(); } @@ -1022,13 +921,12 @@ protected function getCurrentObjOrProto() /** * Determine if the model implements {@see \Charcoal\View\ViewableInterface}. * - * @see \Charcoal\Admin\Ui\ObjectContainerTrait::isObjRenderable() - * * @param string|object $obj Object type or instance to test. * @param boolean $toString Whether to test for `__toString()`. - * @return boolean + * @throws Exception + * @see \Charcoal\Admin\Ui\ObjectContainerTrait::isObjRenderable() */ - protected function isObjRenderable($obj, $toString = false) + protected function isObjRenderable($obj, $toString = false): bool { if (is_string($obj)) { if (!method_exists($this, 'modelFactory')) { @@ -1042,7 +940,7 @@ protected function isObjRenderable($obj, $toString = false) return false; } - $key = get_class($obj); + $key = $obj::class; if (isset(static::$objRenderableCache[$key])) { return static::$objRenderableCache[$key]; diff --git a/packages/admin/src/Charcoal/Admin/Ui/DashboardContainerInterface.php b/packages/admin/src/Charcoal/Admin/Ui/DashboardContainerInterface.php index eb5353d44..143e4f6f4 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/DashboardContainerInterface.php +++ b/packages/admin/src/Charcoal/Admin/Ui/DashboardContainerInterface.php @@ -1,5 +1,7 @@ defaultDashboardType(); } - $dashboard = $this->dashboardBuilder->build($dashboardConfig); - - return $dashboard; + return $this->dashboardBuilder->build($dashboardConfig); } /** * Retrieve the default dashboard type class name. - * - * @return string */ - public function defaultDashboardType() + public function defaultDashboardType(): string { return DashboardWidget::class; } diff --git a/packages/admin/src/Charcoal/Admin/Ui/FeedbackContainerTrait.php b/packages/admin/src/Charcoal/Admin/Ui/FeedbackContainerTrait.php index 8eec4f6ae..469c928a6 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/FeedbackContainerTrait.php +++ b/packages/admin/src/Charcoal/Admin/Ui/FeedbackContainerTrait.php @@ -33,20 +33,16 @@ public function clearFeedback() /** * Determine if there's feedback. - * - * @return boolean */ - public function hasFeedbacks() + public function hasFeedbacks(): bool { return ($this->numFeedbacks() > 0); } /** * Count feedback. - * - * @return integer */ - public function numFeedbacks() + public function numFeedbacks(): int { return count($this->feedbacks()); } @@ -95,7 +91,7 @@ public function addFeedback($level, $message = null) $entry = $level; } elseif (is_string($level) && is_array($message)) { $entry = $message; - $entry['level'] = (string)$level; + $entry['level'] = $level; } else { $entry = [ 'level' => (string)$level, @@ -184,7 +180,7 @@ public function addFeedbackFromValidatorResult(ValidatorResult $result) * * @return string[] */ - public function getSupportedValidatorLevelsForFeedback() + public function getSupportedValidatorLevelsForFeedback(): array { return [ ValidatorInterface::ERROR, @@ -229,7 +225,7 @@ final protected function parseFeedback(array $entry) * @throws InvalidArgumentException If the feedback entry is invalid. * @return array A parsed feedback entry. */ - protected function parseFeedbackEntry(array $entry) + protected function parseFeedbackEntry(array $entry): array { $entry['message'] = (string)$entry['message']; @@ -247,7 +243,7 @@ protected function parseFeedbackEntry(array $entry) * * @return string A unique feedback entry ID. */ - protected function generateFeedbackEntryId() + protected function generateFeedbackEntryId(): string { return uniqid(); } @@ -258,7 +254,7 @@ protected function generateFeedbackEntryId() * @param string $level The feedback level. * @return boolean Whether the level is dismissable (TRUE) or not (FALSE). */ - protected function isFeedbackDismissable($level) + protected function isFeedbackDismissable($level): bool { return in_array($level, [ 'log', 'debug', 'info', 'notice' ]); } @@ -271,25 +267,13 @@ protected function isFeedbackDismissable($level) */ protected function resolveFeedbackType($level) { - switch ($level) { - case 'emergency': - case 'alert': - case 'critical': - case 'error': - return 'danger'; - - case 'debug': - return 'warning'; - - case 'notice': - case 'log': - return 'info'; - - case 'done': - return 'success'; - } - - return $level; + return match ($level) { + 'emergency', 'alert', 'critical', 'error' => 'danger', + 'debug' => 'warning', + 'notice', 'log' => 'info', + 'done' => 'success', + default => $level, + }; } /** @@ -300,24 +284,12 @@ protected function resolveFeedbackType($level) */ protected function resolveFeedbackLevel($level) { - switch ($level) { - case 'emergency': - case 'alert': - case 'critical': - case 'danger': - return 'error'; - - case 'debug': - return 'warning'; - - case 'notice': - case 'log': - return 'info'; - - case 'done': - return 'success'; - } - - return $level; + return match ($level) { + 'emergency', 'alert', 'critical', 'danger' => 'error', + 'debug' => 'warning', + 'notice', 'log' => 'info', + 'done' => 'success', + default => $level, + }; } } diff --git a/packages/admin/src/Charcoal/Admin/Ui/FormGroupInterface.php b/packages/admin/src/Charcoal/Admin/Ui/FormGroupInterface.php index 0b917e79a..d7a424a3f 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/FormGroupInterface.php +++ b/packages/admin/src/Charcoal/Admin/Ui/FormGroupInterface.php @@ -1,5 +1,7 @@ translator()->getLocale(); $locales = $this->translator()->locales(); $languages = []; - uasort($locales, [ 'Charcoal\Admin\Support\Sorter', 'sortByPriority' ]); + uasort($locales, \Charcoal\Admin\Support\Sorter::sortByPriority(...)); foreach ($locales as $locale => $localeStruct) { /** @@ -48,11 +47,7 @@ public function languages() $label = $this->translator()->translation($localeStruct['name']); } else { $trans = 'locale.' . $locale; - if ($trans === $this->translator()->trans($trans)) { - $label = strtoupper($locale); - } else { - $label = $this->translator()->translation($trans); - } + $label = $trans === $this->translator()->trans($trans) ? strtoupper((string)$locale) : $this->translator()->translation($trans); } $isCurrent = ($locale === $currentLocale); diff --git a/packages/admin/src/Charcoal/Admin/Ui/ImageAttributesTrait.php b/packages/admin/src/Charcoal/Admin/Ui/ImageAttributesTrait.php index e70410ff5..362acf3ee 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/ImageAttributesTrait.php +++ b/packages/admin/src/Charcoal/Admin/Ui/ImageAttributesTrait.php @@ -90,7 +90,7 @@ public function styleAttr() * * @return string */ - protected function defaultStyleAttr() + protected function defaultStyleAttr(): array { return [ 'height' => $this->height(), @@ -104,12 +104,11 @@ protected function defaultStyleAttr() * Parse the CSS styling declarations from the property's display features. * * @param string[] $styles An associative array of CSS styles. - * @return string */ - protected function parseStyleAttr(array $styles) + protected function parseStyleAttr(array $styles): string { $inline = array_map( - function ($val, $key) { + function (int|string $val, int|string $key) { if (is_bool($val)) { return ($val) ? $key : ''; } elseif (isset($val)) { @@ -278,10 +277,9 @@ public function maxHeight() * Determine if the value is a {@see @see http://en.wikipedia.org/wiki/Data_URI_scheme Data URI}. * * @param string $val A path or URI to analyze. - * @return boolean */ - protected function isDataUri($val) + protected function isDataUri($val): bool { - return (0 === strpos($val, 'data:')); + return (str_starts_with($val, 'data:')); } } diff --git a/packages/admin/src/Charcoal/Admin/Ui/LanguageSwitcherAwareInterface.php b/packages/admin/src/Charcoal/Admin/Ui/LanguageSwitcherAwareInterface.php index 17878deb2..7d6989268 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/LanguageSwitcherAwareInterface.php +++ b/packages/admin/src/Charcoal/Admin/Ui/LanguageSwitcherAwareInterface.php @@ -1,5 +1,7 @@ getWidget(); $this->setDynamicTemplate('widget_template', $widget->template()); @@ -183,12 +183,10 @@ public function widgetData($key = null, $default = null) if ($key) { if (isset($this->widgetData[$key])) { return $this->widgetData[$key]; + } elseif (!is_string($default) && is_callable($default)) { + return $default(); } else { - if (!is_string($default) && is_callable($default)) { - return $default(); - } else { - return $default; - } + return $default; } } @@ -197,10 +195,8 @@ public function widgetData($key = null, $default = null) /** * Retrieve the default nested widget options. - * - * @return array */ - public function defaultWidgetData() + public function defaultWidgetData(): array { return []; } @@ -246,7 +242,7 @@ public function setRenderableData(array $data) * @throws RuntimeException If the form doesn't have a model. * @return array|Traversable The rendered data. */ - protected function renderDataRecursive($data) + protected function renderDataRecursive($data): \Traversable|array { if (!is_array($data) && !($data instanceof Traversable)) { throw new InvalidArgumentException('The renderable data must be iterable.'); @@ -262,7 +258,7 @@ protected function renderDataRecursive($data) foreach ($data as $key => $val) { if (is_string($val)) { $data[$key] = $this->renderData($val); - } elseif (is_array($val) || ($val instanceof Traversable)) { + } elseif (is_iterable($val)) { $data[$key] = $this->renderDataRecursive($val); } else { continue; @@ -278,7 +274,7 @@ protected function renderDataRecursive($data) * @param string $data The data to render. * @return string The rendered data. */ - protected function renderData($data) + protected function renderData($data): string|array|null { $obj = $this->form()->obj(); @@ -300,14 +296,14 @@ protected function renderData($data) * @throws InvalidArgumentException If a route token is not a string. * @return string */ - private function parseDataToken($token) + private function parseDataToken($token): string|float|int { // Processes matches from a regular expression operation if (is_array($token) && isset($token[1])) { $token = $token[1]; } - $token = trim($token); + $token = trim((string)$token); $method = [ $this, $token ]; if (is_callable($method)) { @@ -324,8 +320,8 @@ private function parseDataToken($token) throw new InvalidArgumentException(sprintf( 'Data token "%1$s" must be a string with %2$s; received %3$s', $token, - get_called_class(), - (is_object($value) ? get_class($value) : gettype($value)) + static::class, + (get_debug_type($value)) )); } diff --git a/packages/admin/src/Charcoal/Admin/Ui/ObjectContainerInterface.php b/packages/admin/src/Charcoal/Admin/Ui/ObjectContainerInterface.php index 184e2ecf4..220a0dc09 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/ObjectContainerInterface.php +++ b/packages/admin/src/Charcoal/Admin/Ui/ObjectContainerInterface.php @@ -1,5 +1,7 @@ modelFactory === null) { throw new Exception(sprintf( 'Model factory not set for %s', - get_class($this) + $this::class )); } return $this->modelFactory; @@ -94,7 +93,7 @@ public function setObjType($objType) if (!is_string($objType)) { throw new InvalidArgumentException(sprintf( 'Object type must be a string, received %s.', - (is_object($objType) ? get_class($objType) : gettype($objType)) + (get_debug_type($objType)) )); } @@ -125,7 +124,7 @@ public function setObjId($objId) if (!is_scalar($objId)) { throw new InvalidArgumentException(sprintf( 'Object ID must be a string or numerical value, received %s.', - (is_object($objId) ? get_class($objId) : gettype($objId)) + (get_debug_type($objId)) )); } @@ -151,7 +150,7 @@ public function objId() * * @return string Escaped ID. */ - public function objIdWithSlashes() + public function objIdWithSlashes(): string { return addslashes($this->objId()); } @@ -198,10 +197,8 @@ public function proto() /** * Determine if the class has a concrete object. - * - * @return boolean */ - public function hasObj() + public function hasObj(): bool { return ($this->obj() && $this->obj()->id()); } @@ -216,11 +213,7 @@ public function obj() if ($this->obj === null) { $this->obj = $this->createOrLoadObj(); - if ($this->obj instanceof ModelInterface) { - $this->objId = $this->obj->id(); - } else { - $this->objId = null; - } + $this->objId = $this->obj instanceof ModelInterface ? $this->obj->id() : null; } return $this->obj; @@ -255,7 +248,7 @@ protected function cloneObj() if (empty($cloneId)) { throw new Exception(sprintf( '%1$s cannot clone object. Clone ID missing from request.', - get_class($this) + $this::class )); } @@ -285,7 +278,7 @@ protected function createObjFromBluePrint() if (empty($bpId)) { throw new Exception(sprintf( '%1$s cannot create object from blueprint. Blueprint ID missing from request.', - get_class($this) + $this::class )); } @@ -320,30 +313,28 @@ protected function createObj() if ($objBaseClass) { $message = sprintf( '[%1$s] can not create object: Object type [%2$s] does not match [%3$s]', - get_class($this), + $this::class, $objType, $objBaseClass ); } else { $message = sprintf( '[%1$s] can not create object: Invalid object type [%2$s]', - get_class($this), + $this::class, $objType ); } } else { $message = sprintf( '[%1$s] can not create object: Missing object type', - get_class($this) + $this::class ); } throw new Exception($message); } - $obj = $this->modelFactory()->create($objType); - - return $obj; + return $this->modelFactory()->create($objType); } /** @@ -377,16 +368,15 @@ protected function validateObjType() } return $this->validateObjBaseClass($this->proto()); - } catch (Exception $e) { + } catch (Exception) { return false; } } /** * @param mixed $obj Object to validate. - * @return boolean */ - protected function validateObjBaseClass($obj) + protected function validateObjBaseClass($obj): bool { $objBaseClass = $this->objBaseClass(); if (!$objBaseClass) { @@ -396,7 +386,7 @@ protected function validateObjBaseClass($obj) try { return ($obj instanceof $objBaseClass); - } catch (Exception $e) { + } catch (Exception) { return false; } } @@ -409,7 +399,7 @@ protected function validateObjBaseClass($obj) */ protected function getSingularLabelFromObj(ModelInterface $obj) { - $key = get_class($obj); + $key = $obj::class; if (isset(static::$labelCache[$key])) { return static::$labelCache[$key]; @@ -425,11 +415,7 @@ protected function getSingularLabelFromObj(ModelInterface $obj) $label = null; } - if (is_array($label)) { - $label = reset($label); - } else { - $label = (new ReflectionClass($obj))->getShortName(); - } + $label = is_array($label) ? reset($label) : (new ReflectionClass($obj))->getShortName(); static::$labelCache[$key] = $label; @@ -453,7 +439,7 @@ protected function isObjRenderable($obj, $toString = false) return false; } - $key = get_class($obj); + $key = $obj::class; if (isset(static::$objRenderableCache[$key])) { return static::$objRenderableCache[$key]; diff --git a/packages/admin/src/Charcoal/Admin/Ui/ObjectRevisionsInterface.php b/packages/admin/src/Charcoal/Admin/Ui/ObjectRevisionsInterface.php index 846efab13..25c7c1c1e 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/ObjectRevisionsInterface.php +++ b/packages/admin/src/Charcoal/Admin/Ui/ObjectRevisionsInterface.php @@ -1,5 +1,7 @@ latestRevision(); $propLabel = '%2$s'; - $callback = function (ObjectRevisionInterface &$revision) use ($lastRevision, $obj, $propLabel) { + $callback = function (ObjectRevisionInterface &$revision) use ($lastRevision, $obj, $propLabel): void { $dataDiff = $revision['dataDiff']; $revision->revTsDisplay = $revision['revTs']->format('Y-m-d H:i:s'); $revision->revUserDisplay = $revision->p('revUser')->displayVal($revision['revUser']); diff --git a/packages/admin/src/Charcoal/Admin/Ui/SecondaryMenu/GenericSecondaryMenuGroup.php b/packages/admin/src/Charcoal/Admin/Ui/SecondaryMenu/GenericSecondaryMenuGroup.php index 9768c560e..c79df642c 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/SecondaryMenu/GenericSecondaryMenuGroup.php +++ b/packages/admin/src/Charcoal/Admin/Ui/SecondaryMenu/GenericSecondaryMenuGroup.php @@ -1,5 +1,7 @@ hasPermissions($link['permissions']) === false) { - continue; - } + if (isset($link['permissions']) && $this->hasPermissions($link['permissions']) === false) { + continue; } yield $link; @@ -282,26 +280,22 @@ public function links() /** * Determine if the secondary menu has any links. - * - * @return boolean */ - public function hasLinks() + public function hasLinks(): bool { - return !!$this->numLinks(); + return (bool)$this->numLinks(); } /** * Count the number of secondary menu links. - * - * @return integer */ - public function numLinks() + public function numLinks(): int { if (!is_array($this->links) && !($this->links instanceof \Traversable)) { return 0; } - $links = array_filter($this->links, function ($link) { + $links = array_filter($this->links, function (array $link): bool { if (isset($link['active']) && !$link['active']) { return false; } @@ -310,14 +304,7 @@ public function numLinks() $link['permissions'] = $link['required_acl_permissions']; unset($link['required_acl_permissions']); } - - if (isset($link['permissions'])) { - if ($this->hasPermissions($link['permissions']) === false) { - return false; - } - } - - return true; + return !(isset($link['permissions']) && $this->hasPermissions($link['permissions']) === false); }); return count($links); @@ -332,7 +319,7 @@ public function numLinks() public function isSelected($flag = null) { if ($flag !== null) { - $this->isSelected = !!$flag; + $this->isSelected = (bool)$flag; $this->setCollapsed(!$flag); } @@ -342,20 +329,16 @@ public function isSelected($flag = null) /** * Determine if the secondary groups should be displayed as panels. - * - * @return boolean */ - public function displayAsPanel() + public function displayAsPanel(): bool { return in_array($this->displayType(), [ 'panel', 'collapsible' ]); } /** * Determine if the group is collapsible. - * - * @return boolean */ - public function collapsible() + public function collapsible(): bool { return ($this->displayType() === 'collapsible'); } @@ -368,7 +351,7 @@ public function collapsible() */ public function setCollapsed($flag) { - $this->collapsed = !!$flag; + $this->collapsed = (bool)$flag; return $this; } @@ -401,7 +384,7 @@ public function collapsed() */ public function setParented($flag) { - $this->parented = !!$flag; + $this->parented = (bool)$flag; return $this; } @@ -447,7 +430,7 @@ public function ident() */ public function setActive($active) { - $this->active = !!$active; + $this->active = (bool)$active; return $this; } diff --git a/packages/admin/src/Charcoal/Admin/Ui/StructureContainerInterface.php b/packages/admin/src/Charcoal/Admin/Ui/StructureContainerInterface.php index 184421c44..e068046ab 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/StructureContainerInterface.php +++ b/packages/admin/src/Charcoal/Admin/Ui/StructureContainerInterface.php @@ -1,5 +1,7 @@ supportedDisplayLayouts(); $displays = []; @@ -93,10 +91,8 @@ public function displays() /** * Retrieve the supported display layouts. - * - * @return array */ - protected function supportedDisplayLayouts() + protected function supportedDisplayLayouts(): array { return [ self::GROUP_STRUCT_DISPLAY, @@ -123,7 +119,7 @@ protected function defaultDisplay() */ public function setShowEmpty($show) { - $this->showEmpty = !!$show; + $this->showEmpty = (bool)$show; return $this; } diff --git a/packages/admin/src/Charcoal/Admin/User.php b/packages/admin/src/Charcoal/Admin/User.php index 4e518a153..f5a20c453 100644 --- a/packages/admin/src/Charcoal/Admin/User.php +++ b/packages/admin/src/Charcoal/Admin/User.php @@ -1,5 +1,7 @@ 'charcoal_admin_login', ]); - return $defaults; } } diff --git a/packages/admin/src/Charcoal/Admin/User/LostPasswordToken.php b/packages/admin/src/Charcoal/Admin/User/LostPasswordToken.php index a2cc68e79..2b65109ab 100644 --- a/packages/admin/src/Charcoal/Admin/User/LostPasswordToken.php +++ b/packages/admin/src/Charcoal/Admin/User/LostPasswordToken.php @@ -1,5 +1,7 @@ token = $token; return $this; @@ -63,9 +59,8 @@ public function token() /** * @param string $user The user. - * @return self */ - public function setUser($user) + public function setUser($user): static { $this->user = $user; return $this; @@ -82,9 +77,8 @@ public function user() /** * @param DateTimeInterface|string|null $expiry The date/time at object's creation. * @throws InvalidArgumentException If the date/time is invalid. - * @return self */ - public function setExpiry($expiry) + public function setExpiry($expiry): static { if ($expiry === null) { $this->expiry = null; @@ -95,7 +89,7 @@ public function setExpiry($expiry) try { $expiry = new DateTime($expiry); } catch (Exception $e) { - throw new InvalidArgumentException($e->getMessage()); + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); } } @@ -110,10 +104,7 @@ public function setExpiry($expiry) return $this; } - /** - * @return DateTimeInterface|null - */ - public function expiry() + public function expiry(): ?\DateTimeInterface { return $this->expiry; } @@ -122,6 +113,7 @@ public function expiry() * @param Container $container Pimple DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -132,9 +124,10 @@ protected function setDependencies(Container $container) * @see \Charcoal\Source\StorableTrait::preSave() For the "create" Event. * @return boolean */ + #[\Override] protected function preSave() { - if ($this->expiry === null) { + if (!$this->expiry instanceof \DateTimeInterface) { $this->setExpiry('now +' . $this->defaultExpiry); } diff --git a/packages/admin/src/Charcoal/Admin/User/Permission.php b/packages/admin/src/Charcoal/Admin/User/Permission.php index 665cac388..ae5c28817 100644 --- a/packages/admin/src/Charcoal/Admin/User/Permission.php +++ b/packages/admin/src/Charcoal/Admin/User/Permission.php @@ -1,5 +1,7 @@ numColumns = $numColumns; return $this; } - /** - * @return float|integer - */ - public function bsColRatio() + public function bsColRatio(): float|int { return abs(12 / ($this->numColumns() ?: 12)); } @@ -67,9 +63,8 @@ public function cardTemplate() /** * @param string $cardTemplate CardTemplate for CardCollectionWidget. - * @return self */ - public function setCardTemplate($cardTemplate) + public function setCardTemplate($cardTemplate): static { $this->cardTemplate = $cardTemplate; @@ -94,13 +89,13 @@ public function objectCardRow() * * @param ModelInterface $object The current row's object. * @param array $objectProperties The $object's display properties. - * @return array */ - protected function parseObjectRow(ModelInterface $object, array $objectProperties) + #[\Override] + protected function parseObjectRow(ModelInterface $object, array $objectProperties): array { $row = $this->parseCollectionObjectRow($object, $objectProperties); $objProps = $row['objectProperties']; - array_walk($objProps, function ($value) use (&$row) { + array_walk($objProps, function (array $value) use (&$row): void { $row['objectProperties'][$value['ident']] = $value['val']; if (!method_exists($row['object'], 'isChipSuccess')) { @@ -113,20 +108,17 @@ protected function parseObjectRow(ModelInterface $object, array $objectPropertie /** * Retrieve the widget's data options for JavaScript components. - * - * @return array */ - public function widgetDataForJs() + #[\Override] + public function widgetDataForJs(): array { - $data = array_merge_recursive( + return array_merge_recursive( parent::widgetDataForJs(), [ 'card_template' => $this->cardTemplate(), 'num_columns' => $this->numColumns() ] ); - - return $data; } /** @@ -161,9 +153,8 @@ public function showFooterChip() /** * @param boolean $showFooterChip ShowFooterChip for CardCollectionWidget. - * @return self */ - public function setShowFooterChip($showFooterChip) + public function setShowFooterChip($showFooterChip): static { $this->showFooterChip = $showFooterChip; @@ -182,19 +173,15 @@ public function chipTitle() return $this->chipTitle; } - /** - * @return string - */ - private function defaultChipTitle() + private function defaultChipTitle(): string { return $this->translator()->translate('Active'); } /** * @param Translation|string $chipTitle ChipTitle for CardCollectionWidget. - * @return self */ - public function setChipTitle($chipTitle) + public function setChipTitle($chipTitle): static { $this->chipTitle = $this->translator()->translation($chipTitle); diff --git a/packages/admin/src/Charcoal/Admin/Widget/CollectionMapWidget.php b/packages/admin/src/Charcoal/Admin/Widget/CollectionMapWidget.php index a8232e52f..750fc873a 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/CollectionMapWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/CollectionMapWidget.php @@ -66,7 +66,8 @@ class CollectionMapWidget extends AdminWidget implements CollectionContainerInte * @param array $data The widget data. * @return TableWidget Chainable */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -82,9 +83,8 @@ public function setData(array $data) * Sets the API key for the mapping service. * * @param string $key An API key. - * @return self */ - public function setApiKey($key) + public function setApiKey($key): static { $this->apiKey = $key; @@ -105,7 +105,7 @@ public function apiKey() * @param string $p The latitude property ident. * @return MapWidget Chainable */ - public function setLatProperty($p) + public function setLatProperty($p): static { $this->latProperty = $p; return $this; @@ -123,7 +123,7 @@ public function latProperty() * @param string $p The longitude property ident. * @return MapWidget Chainable */ - public function setLonProperty($p) + public function setLonProperty($p): static { $this->lonProperty = $p; return $this; @@ -141,7 +141,7 @@ public function lonProperty() * @param string $p The polygon property ident. * @return MapWidget Chainable */ - public function setPolygonProperty($p) + public function setPolygonProperty($p): static { $this->polygonProperty = $p; return $this; @@ -159,7 +159,7 @@ public function polygonProperty() * @param string $p The path property ident. * @return MapWidget Chainable */ - public function setPathProperty($p) + public function setPathProperty($p): static { $this->pathProperty = $p; return $this; @@ -177,7 +177,7 @@ public function pathProperty() * @param string $template The infobox template ident. * @return CollectionMapWidget Chainable */ - public function setInfoboxTemplate($template) + public function setInfoboxTemplate($template): static { $this->infoboxTemplate = $template; return $this; @@ -204,7 +204,7 @@ public function mapObjects() if (!$objType) { throw new UnexpectedValueException(sprintf( '%1$s cannot create collection map. Object type is not defined.', - get_class($this) + static::class )); } @@ -212,12 +212,12 @@ public function mapObjects() $loader->setModel($this->proto()); $collectionConfig = $this->collectionConfig(); - if (is_array($collectionConfig) && !empty($collectionConfig)) { + if (is_array($collectionConfig) && $collectionConfig !== []) { unset($collectionConfig['properties']); $loader->setData($collectionConfig); } - $callback = function (&$obj) { + $callback = function (&$obj): void { $obj->mapInfoboxTemplate = $this->infoboxTemplate(); if ($this->latProperty() && $this->latProperty()) { @@ -273,10 +273,7 @@ public function mapObjects() } } - /** - * @return boolean - */ - public function showInfobox() + public function showInfobox(): bool { return ($this->infoboxTemplate != ''); } @@ -294,10 +291,8 @@ public function dataFromRequest() /** * Retrieve the accepted metadata from the current request. - * - * @return array */ - public function acceptedRequestData() + public function acceptedRequestData(): array { return [ 'obj_type', @@ -315,7 +310,7 @@ public function dataFromObject() { $proto = $this->proto(); $objMetadata = $proto->metadata(); - $adminMetadata = (isset($objMetadata['admin']) ? $objMetadata['admin'] : null); + $adminMetadata = ($objMetadata['admin'] ?? null); if (empty($adminMetadata['lists'])) { return []; @@ -334,11 +329,7 @@ public function dataFromObject() return []; } - if (isset($adminMetadata['lists'][$collectionIdent])) { - $objListData = $adminMetadata['lists'][$collectionIdent]; - } else { - $objListData = []; - } + $objListData = ($adminMetadata['lists'][$collectionIdent] ?? []); $collectionConfig = []; @@ -368,7 +359,7 @@ public function dataFromObject() } } - if ($collectionConfig) { + if ($collectionConfig !== []) { $this->mergeCollectionConfig($collectionConfig); } @@ -381,6 +372,7 @@ public function dataFromObject() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -420,11 +412,7 @@ protected function getPropertyValue(ModelInterface $obj, $key) $data = $obj; foreach (explode('.', $key) as $segment) { $accessible = is_array($data) || $data instanceof ArrayAccess; - if ($data instanceof ArrayAccess) { - $exists = $data->offsetExists($segment); - } else { - $exists = array_key_exists($segment, $data); - } + $exists = $data instanceof ArrayAccess ? $data->offsetExists($segment) : array_key_exists($segment, $data); if ($accessible && $exists) { $data = $data[$segment]; @@ -446,6 +434,7 @@ protected function getPropertyValue(ModelInterface $obj, $key) * @param mixed $toResolve A callable used when merging data. * @return callable|null */ + #[\Override] protected function resolveDataSourceFilter($toResolve) { if (is_string($toResolve)) { diff --git a/packages/admin/src/Charcoal/Admin/Widget/DashboardWidget.php b/packages/admin/src/Charcoal/Admin/Widget/DashboardWidget.php index 0313fdb65..811b7efab 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/DashboardWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/DashboardWidget.php @@ -28,6 +28,7 @@ class DashboardWidget extends AdminWidget implements * @param Container $container The DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Widget/Dialog/ImportlistWidget.php b/packages/admin/src/Charcoal/Admin/Widget/Dialog/ImportlistWidget.php index b1c594c08..d0409a1b3 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/Dialog/ImportlistWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/Dialog/ImportlistWidget.php @@ -1,5 +1,7 @@ objId()) { return $this->translator()->translation('Update'); @@ -106,7 +105,8 @@ public function defaultBackToObjectLabel() * @param array $data The widget data. * @return ObjectForm Chainable */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -121,6 +121,7 @@ public function setData(array $data) /** * @return FormSidebarInterface[]|\Generator */ + #[\Override] public function sidebars() { $objId = $this->obj()->id(); @@ -134,7 +135,7 @@ public function sidebars() $metadata = $this->obj()->metadata(); $objType = (isset($metadata['labels']['singular_name']) ? $translator->translate($metadata['labels']['singular_name']) - : (new ReflectionClass($obj))->getShortName()); + : (new ReflectionClass($this->obj()))->getShortName()); $label = $translator->translate('Back to {{name}} id: {{id}}'); $label = strtr($label, [ @@ -169,9 +170,8 @@ public function sidebars() * * @param string $formIdent The form identifier. * @throws InvalidArgumentException If the identifier is not a string. - * @return self */ - public function setFormIdent($formIdent) + public function setFormIdent($formIdent): static { if (!is_string($formIdent)) { throw new InvalidArgumentException( @@ -209,7 +209,7 @@ public function formIdentFallback() * * @return array */ - public function displayOptions() + public function displayOptions(): ?array { if (!$this->displayOptions) { $this->setDisplayOptions([]); @@ -223,9 +223,8 @@ public function displayOptions() * * @param array $options Display configuration. * @throws \RuntimeException If the display options are not an associative array. - * @return self */ - public function setDisplayOptions(array $options) + public function setDisplayOptions(array $options): static { if (!is_array($options)) { throw new \RuntimeException('The display options must be an associative array.'); @@ -238,10 +237,8 @@ public function setDisplayOptions(array $options) /** * Retrieve the default display options for the widget. - * - * @return array */ - public function defaultDisplayOptions() + public function defaultDisplayOptions(): array { return [ 'parented' => false, @@ -265,7 +262,7 @@ public function formIdent() * @throws InvalidArgumentException If argument is not a string. * @return ActionInterface Chainable */ - public function setNextUrl($url) + public function setNextUrl($url): static { if (!is_string($url)) { throw new InvalidArgumentException( @@ -287,6 +284,7 @@ public function setNextUrl($url) * * @return string Relative URL */ + #[\Override] public function action() { $action = parent::action(); @@ -311,14 +309,15 @@ public function action() * @throws UnexpectedValueException If a property data is invalid. * @return DocFormPropertyWidget[]|Generator */ - public function formProperties(array $group = null) + #[\Override] + public function formProperties(?array $group = null) { $obj = $this->obj(); $props = $obj->metadata()->properties(); // We need to sort form properties by form group property order if a group exists - if (!empty($group)) { - $group = array_map([ $this, 'camelize' ], $group); + if ($group !== null && $group !== []) { + $group = array_map($this->camelize(...), $group); $group = array_flip($group); $props = array_intersect_key($props, $group); $props = array_merge($group, $props); @@ -344,7 +343,7 @@ public function formProperties(array $group = null) throw new UnexpectedValueException(sprintf( 'Invalid property data for "%1$s", received %2$s', $propertyIdent, - (is_object($propertyMetadata) ? get_class($propertyMetadata) : gettype($propertyMetadata)) + (get_debug_type($propertyMetadata)) )); } @@ -386,7 +385,7 @@ public function formProperty($propertyIdent) throw new UnexpectedValueException(sprintf( 'Invalid property data for "%1$s", received %2$s', $propertyIdent, - (is_object($propertyMetadata) ? get_class($propertyMetadata) : gettype($propertyMetadata)) + (get_debug_type($propertyMetadata)) )); } @@ -407,19 +406,14 @@ public function formProperty($propertyIdent) * @param array $data Data. * @return ObjectFormWidget Chainable. */ - public function setFormData(array $data) + #[\Override] + public function setFormData(array $data): static { $objData = $this->objData(); $merged = array_replace_recursive($objData, $data); // Remove null values - $merged = array_filter($merged, function ($val) { - if ($val === null) { - return false; - } - - return true; - }); + $merged = array_filter($merged, fn($val): bool => $val !== null); $this->formData = $merged; $this->obj()->setData($merged); @@ -432,6 +426,7 @@ public function setFormData(array $data) * * @return array */ + #[\Override] public function formData() { if (!$this->formData) { @@ -460,9 +455,8 @@ public function showHeader() /** * @param boolean $showHeader Is the Header to be shown. - * @return self */ - public function setShowHeader($showHeader) + public function setShowHeader($showHeader): static { $this->showHeader = $showHeader; @@ -479,19 +473,16 @@ public function showTitle() /** * @param boolean $showTitle Is the title to be shown. - * @return self */ - public function setShowTitle($showTitle) + public function setShowTitle($showTitle): static { $this->showTitle = $showTitle; return $this; } - /** - * @return string - */ - public function defaultGroupType() + #[\Override] + public function defaultGroupType(): string { return 'charcoal/admin/docs/widget/form-group/doc'; } @@ -501,17 +492,17 @@ public function defaultGroupType() * * @return string[] */ - protected function defaultDataSources() + #[\Override] + protected function defaultDataSources(): array { return [ static::DATA_SOURCE_REQUEST, static::DATA_SOURCE_OBJECT ]; } /** * Retrieve the default data source filters (when setting data on an entity). - * - * @return array */ - protected function defaultDataSourceFilters() + #[\Override] + protected function defaultDataSourceFilters(): array { return [ 'request' => null, @@ -528,6 +519,7 @@ protected function defaultDataSourceFilters() * @param mixed $toResolve A callable used when merging data. * @return callable|null */ + #[\Override] protected function resolveDataSourceFilter($toResolve) { if (is_string($toResolve)) { @@ -554,10 +546,9 @@ protected function resolveDataSourceFilter($toResolve) /** * Retrieve the accepted metadata from the current request. - * - * @return array */ - protected function acceptedRequestData() + #[\Override] + protected function acceptedRequestData(): array { return array_merge( [ 'obj_type', 'obj_id', 'template' ], @@ -574,7 +565,7 @@ protected function dataFromObject() { $obj = $this->obj(); $objMetadata = $obj->metadata(); - $adminMetadata = (isset($objMetadata['admin']) ? $objMetadata['admin'] : null); + $adminMetadata = ($objMetadata['admin'] ?? null); $formIdent = $this->formIdent(); if (!$formIdent) { @@ -585,11 +576,7 @@ protected function dataFromObject() $formIdent = $obj->render($formIdent); } - if (isset($adminMetadata['forms'][$formIdent])) { - $objFormData = $adminMetadata['forms'][$formIdent]; - } else { - $objFormData = []; - } + $objFormData = ($adminMetadata['forms'][$formIdent] ?? []); if (isset($objFormData['groups']) && isset($adminMetadata['form_groups'])) { $extraFormGroups = array_intersect( @@ -627,7 +614,8 @@ protected function dataFromObject() * @param array|null $data Optional. The form group data to set. * @return FormGroupInterface */ - protected function createFormGroup(array $data = null) + #[\Override] + protected function createFormGroup(?array $data = null) { $type = $this->defaultGroupType(); @@ -665,13 +653,13 @@ protected function createFormGroup(array $data = null) * @param FormGroupInterface $group The form group to update. * @param array|null $groupData Optional. The new group data to apply. * @param string|null $groupIdent Optional. The new group identifier. - * @return FormGroupInterface */ + #[\Override] protected function updateFormGroup( FormGroupInterface $group, - array $groupData = null, + ?array $groupData = null, $groupIdent = null - ) { + ): FormGroupInterface { $group->setForm($this); if ($groupIdent !== null) { diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/AclPermissions.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/AclPermissions.php index d0789e22a..7247c6d42 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/AclPermissions.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/AclPermissions.php @@ -30,20 +30,11 @@ class AclPermissions extends AdminWidget implements { use FormGroupTrait; - /** - * @var Acl $roleAcl - */ - private $roleAcl; + private ?\Laminas\Permissions\Acl\Acl $roleAcl = null; - /** - * @var array - */ - private $roleAllowed; + private ?array $roleAllowed = null; - /** - * @var array - */ - private $roleDenied; + private ?array $roleDenied = null; /** * Store the collection loader for the current class. @@ -71,15 +62,12 @@ class AclPermissions extends AdminWidget implements * * @return string */ - public function objId() + public function objId(): string|false|null { - return filter_input(INPUT_GET, 'obj_id', FILTER_SANITIZE_STRING); + return htmlspecialchars(trim(($_GET['obj_id'] ?? '')), ENT_QUOTES, 'UTF-8'); } - /** - * @return array - */ - public function permissionCategories() + public function permissionCategories(): array { $loader = $this->collectionLoader(); $loader->setModel(PermissionCategory::class); @@ -103,6 +91,7 @@ public function permissionCategories() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -120,10 +109,10 @@ protected function setDependencies(Container $container) */ protected function db() { - if (!isset($this->database)) { + if ($this->database === null) { throw new RuntimeException(sprintf( 'Database Connection is not defined for "%s"', - get_class($this) + static::class )); } @@ -138,10 +127,10 @@ protected function db() */ protected function adminAcl() { - if (!isset($this->aclManager)) { + if ($this->aclManager === null) { throw new RuntimeException(sprintf( 'ACL Manager is not defined for "%s"', - get_class($this) + static::class )); } @@ -156,10 +145,10 @@ protected function adminAcl() */ protected function collectionLoader() { - if (!isset($this->collectionLoader)) { + if ($this->collectionLoader === null) { throw new RuntimeException(sprintf( 'Collection Loader is not defined for "%s"', - get_class($this) + static::class )); } @@ -168,12 +157,9 @@ protected function collectionLoader() - /** - * @return Acl - */ - protected function roleAcl() + protected function roleAcl(): \Laminas\Permissions\Acl\Acl { - if (!$this->roleAcl) { + if (!$this->roleAcl instanceof \Laminas\Permissions\Acl\Acl) { $id = $this->objId(); $this->roleAcl = new Acl(); @@ -195,8 +181,8 @@ protected function roleAcl() $sth->execute(); $permissions = $sth->fetch(PDO::FETCH_ASSOC); - $this->roleAllowed = explode(',', trim($permissions['allowed'])); - $this->roleDenied = explode(',', trim($permissions['denied'])); + $this->roleAllowed = explode(',', trim((string)$permissions['allowed'])); + $this->roleDenied = explode(',', trim((string)$permissions['denied'])); foreach ($this->roleAllowed as $allowed) { $this->roleAcl->allow($id, 'admin', $allowed); @@ -211,12 +197,11 @@ protected function roleAcl() /** * @param string $category The category ident to load permissions from. - * @return array */ - private function loadCategoryPermissions($category) + private function loadCategoryPermissions($category): array { $adminAcl = $this->adminAcl(); - $roleAcl = $this->roleAcl(); + $this->roleAcl(); $loader = $this->collectionLoader(); $loader->setModel(Permission::class); diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/GenericFormGroup.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/GenericFormGroup.php index e1a20645f..2b175b894 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/GenericFormGroup.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/GenericFormGroup.php @@ -1,5 +1,7 @@ widgetId = $widgetId; @@ -116,7 +109,8 @@ public function setWidgetId($widgetId) /** * @return Translation|string|null */ - public function description() + #[\Override] + public function description(): string { return $this->renderTemplate((string)parent::description()); } @@ -124,7 +118,8 @@ public function description() /** * @return Translation|string|null */ - public function notes() + #[\Override] + public function notes(): string { return $this->renderTemplate((string)parent::notes()); } @@ -135,6 +130,7 @@ public function notes() * @param boolean|string $show Whether to show or hide notes. * @return FormGroupWidget Chainable */ + #[\Override] public function setShowNotes($show) { $this->showNotesAbove = ($show === 'above'); @@ -142,10 +138,7 @@ public function setShowNotes($show) return parent::setShowNotes($show); } - /** - * @return boolean - */ - public function showNotesAbove() + public function showNotesAbove(): bool { return $this->showNotesAbove && $this->showNotes(); } @@ -154,6 +147,7 @@ public function showNotesAbove() * @param Container $container The DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -168,9 +162,8 @@ protected function setDependencies(Container $container) * Set the widget factory. * * @param FactoryInterface $factory The factory to create widgets. - * @return self */ - protected function setWidgetFactory(FactoryInterface $factory) + protected function setWidgetFactory(FactoryInterface $factory): static { $this->widgetFactory = $factory; @@ -181,14 +174,13 @@ protected function setWidgetFactory(FactoryInterface $factory) * Retrieve the widget factory. * * @throws RuntimeException If the widget factory was not previously set. - * @return FactoryInterface */ - protected function widgetFactory() + protected function widgetFactory(): \Charcoal\Factory\FactoryInterface { - if ($this->widgetFactory === null) { + if (!$this->widgetFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException(sprintf( 'Widget Factory is not defined for "%s"', - get_class($this) + static::class )); } diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/ObjectRevisionsFormGroup.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/ObjectRevisionsFormGroup.php index ac241fa3a..a9f81723b 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/ObjectRevisionsFormGroup.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/ObjectRevisionsFormGroup.php @@ -40,9 +40,8 @@ class ObjectRevisionsFormGroup extends AbstractFormGroup implements /** * @param string $widgetId The widget identifier. - * @return self */ - public function setWidgetId($widgetId) + public function setWidgetId($widgetId): static { $this->widgetId = $widgetId; @@ -61,10 +60,8 @@ public function widgetId() return $this->widgetId; } - /** - * @return boolean - */ - public function active() + #[\Override] + public function active(): bool { return parent::active() && $this->objType() && $this->objId(); } @@ -105,6 +102,7 @@ public function objId() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/StructureFormGroup.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/StructureFormGroup.php index f92b5ff71..b1757bfab 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/StructureFormGroup.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/StructureFormGroup.php @@ -109,10 +109,8 @@ class StructureFormGroup extends FormGroupWidget implements /** * The form group the input belongs to. - * - * @var FormGroupInterface|null */ - private $formGroup; + private ?\Charcoal\Ui\FormGroup\FormGroupInterface $formGroup = null; /** * Whether the form is ready. @@ -136,19 +134,16 @@ class StructureFormGroup extends FormGroupWidget implements */ protected $rawData; - /** - * @return string - */ - public function type() + #[\Override] + public function type(): string { return 'charcoal/admin/widget/form-group/structure'; } /** * @param string $structId The structure entry identifier. - * @return self */ - public function setStructId($structId) + public function setStructId($structId): static { $this->structId = $structId; return $this; @@ -168,9 +163,9 @@ public function structId() /** * @param array $data Widget data. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { if ($this->rawData === null) { $this->rawData = $data; @@ -186,6 +181,7 @@ public function setData(array $data) * * @return boolean If TRUE or unset, check if there is a title. */ + #[\Override] public function showHeader() { if ($this->display() === self::SEAMLESS_STRUCT_DISPLAY) { @@ -200,6 +196,7 @@ public function showHeader() * * @return boolean If TRUE or unset, check if there are notes. */ + #[\Override] public function showFooter() { if ($this->display() === self::SEAMLESS_STRUCT_DISPLAY) { @@ -216,7 +213,8 @@ public function showFooter() * * @return string If unset, returns the UI item type. */ - public function template() + #[\Override] + public function template(): ?string { $this->setDynamicTemplate('structure_template', $this->displayTemplate()); @@ -225,10 +223,8 @@ public function template() /** * Retrieve the property's display layout template. - * - * @return string|null */ - public function displayTemplate() + public function displayTemplate(): string { $display = $this->display(); @@ -272,9 +268,8 @@ public function obj() * Set the form input's parent group. * * @param FormGroupInterface $formGroup The parent form group object. - * @return self */ - public function setFormGroup(FormGroupInterface $formGroup) + public function setFormGroup(FormGroupInterface $formGroup): static { $this->formGroup = $formGroup; @@ -283,20 +278,16 @@ public function setFormGroup(FormGroupInterface $formGroup) /** * Retrieve the input's parent group. - * - * @return FormGroupInterface|null */ - public function formGroup() + public function formGroup(): ?\Charcoal\Ui\FormGroup\FormGroupInterface { return $this->formGroup; } /** * Clear the group's parent group. - * - * @return self */ - public function clearFormGroup() + public function clearFormGroup(): static { $this->formGroup = null; @@ -312,9 +303,8 @@ public function clearFormGroup() * @param string|ModelStructureProperty $propertyIdent The property identifier—or instance—of a storage property. * @throws InvalidArgumentException If the property identifier is not a string. * @throws UnexpectedValueException If a property is invalid. - * @return self */ - public function setStorageProperty($propertyIdent) + public function setStorageProperty($propertyIdent): static { $property = null; if ($propertyIdent instanceof PropertyInterface) { @@ -331,11 +321,11 @@ public function setStorageProperty($propertyIdent) throw new UnexpectedValueException(sprintf( 'The "%1$s" property is not defined on [%2$s]', $propertyIdent, - get_class($obj) + $obj::class )); } - if ($property === null) { + if (!$property instanceof \Charcoal\Property\PropertyInterface) { $property = $obj->property($propertyIdent); } @@ -349,8 +339,8 @@ public function setStorageProperty($propertyIdent) throw new UnexpectedValueException(sprintf( '"%s" [%s] is not a model structure property on [%s].', $propertyIdent, - (is_object($property) ? get_class($property) : gettype($property)), - (is_object($obj) ? get_class($obj) : gettype($obj)) + (get_debug_type($property)), + (get_debug_type($obj)) )); } @@ -368,7 +358,7 @@ public function storageProperty() if ($this->storageProperty === null) { throw new RuntimeException(sprintf( 'Storage property owner is not defined for "%s"', - get_class($this) + static::class )); } @@ -406,11 +396,7 @@ protected function autoFormGroup() $property = $this->storageProperty(); $struct = $property->getStructureMetadata(); - if (isset($struct['admin']['auto_form_group'])) { - $this->autoFormGroup = $struct['admin']['auto_form_group']; - } else { - $this->autoFormGroup = true; - } + $this->autoFormGroup = ($struct['admin']['auto_form_group'] ?? true); } return $this->autoFormGroup; @@ -445,8 +431,6 @@ protected function finalizeStructure($reload = false) protected function findStructureFormGroup(): ?array { $struct = $this->storageProperty()->getStructureMetadata(); - - $formGroup = null; if (isset($struct['admin']['form_group'])) { if (\is_string($struct['admin']['form_group'])) { $groupName = $struct['admin']['form_group']; @@ -476,6 +460,7 @@ protected function findStructureFormGroup(): ?array * * @return array */ + #[\Override] protected function parsedFormProperties() { if ($this->parsedFormProperties === null) { @@ -485,30 +470,28 @@ protected function parsedFormProperties() $availableProperties = $this->structProperties(); $structProperties = []; - if (!empty($groupProperties)) { - foreach ($groupProperties as $propertyIdent => $propertyMetadata) { - if (is_string($propertyMetadata)) { - $propertyIdent = $propertyMetadata; - $propertyMetadata = null; - } - - $propertyIdent = $this->camelize($propertyIdent); - - if (!isset($availableProperties[$propertyIdent])) { - continue; - } - - if (is_array($propertyMetadata)) { - $propertyMetadata = array_merge($propertyMetadata, $availableProperties[$propertyIdent]); - } else { - $propertyMetadata = $availableProperties[$propertyIdent]; - } - - $structProperties[$propertyIdent] = $propertyMetadata; + foreach ($groupProperties as $propertyIdent => $propertyMetadata) { + if (is_string($propertyMetadata)) { + $propertyIdent = $propertyMetadata; + $propertyMetadata = null; } + + $propertyIdent = $this->camelize($propertyIdent); + + if (!isset($availableProperties[$propertyIdent])) { + continue; + } + + if (is_array($propertyMetadata)) { + $propertyMetadata = array_merge($propertyMetadata, $availableProperties[$propertyIdent]); + } else { + $propertyMetadata = $availableProperties[$propertyIdent]; + } + + $structProperties[$propertyIdent] = $propertyMetadata; } - if (empty($structProperties) && $this->autoFormGroup() === true) { + if ($structProperties === [] && $this->autoFormGroup() === true) { $structProperties = $availableProperties; } @@ -526,12 +509,11 @@ protected function parsedFormProperties() * @throws UnexpectedValueException If a property data is invalid. * @return \Charcoal\Admin\Widget\FormPropertyWidget[]|\Generator */ + #[\Override] public function formProperties() { - if ($this instanceof ConditionalizableInterface) { - if ($this->condition() !== null && !$this->resolvedCondition()) { - return []; - } + if ($this->condition() !== null && !$this->resolvedCondition()) { + return []; } $this->finalizeStructure(); @@ -592,7 +574,7 @@ public function formProperties() throw new UnexpectedValueException(sprintf( 'Invalid property data for "%1$s", received %2$s', $propertyIdent, - (is_object($propertyMetadata) ? get_class($propertyMetadata) : gettype($propertyMetadata)) + (get_debug_type($propertyMetadata)) )); } diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/TemplateOptionsFormGroup.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/TemplateOptionsFormGroup.php index a8584dddd..a4d254b33 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/TemplateOptionsFormGroup.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/TemplateOptionsFormGroup.php @@ -80,14 +80,12 @@ class TemplateOptionsFormGroup extends StructureFormGroup * * @var TemplateableInterface|string|null */ - private $controllerIdent; + private ?string $controllerIdent = null; /** * Store the metadata loader instance. - * - * @var MetadataLoader */ - private $metadataLoader; + private ?\Charcoal\Model\Service\MetadataLoader $metadataLoader = null; /** * Set the form object's template controller identifier. @@ -95,7 +93,7 @@ class TemplateOptionsFormGroup extends StructureFormGroup * @param mixed $ident The template controller identifier. * @return TemplateableInterface Chainable */ - public function setControllerIdent($ident) + public function setControllerIdent(string $ident): static { if (class_exists($ident)) { $this->controllerIdent = $ident; @@ -103,7 +101,7 @@ public function setControllerIdent($ident) return $this; } - if (substr($ident, -9) !== '-template') { + if (!str_ends_with($ident, '-template')) { $ident .= '-template'; } @@ -114,10 +112,8 @@ public function setControllerIdent($ident) /** * Retrieve the form object's template controller identifier. - * - * @return mixed */ - public function controllerIdent() + public function controllerIdent(): ?string { return $this->controllerIdent; } @@ -132,7 +128,7 @@ public function controllerIdent() * @throws UnexpectedValueException If a property data is invalid. * @return StructureFormGroup */ - public function setTemplateProperty($propertyIdent) + public function setTemplateProperty($propertyIdent): static { if ($propertyIdent === null) { $this->templateProperty = null; @@ -155,11 +151,11 @@ public function setTemplateProperty($propertyIdent) throw new UnexpectedValueException(sprintf( 'The "%1$s" property is not defined on [%2$s]', $propertyIdent, - get_class($this->obj()) + $this->obj()::class )); } - if ($property === null) { + if (!$property instanceof \Charcoal\Property\PropertyInterface) { $property = $obj->property($propertyIdent); } @@ -183,7 +179,7 @@ public function templateProperty() } else { throw new RuntimeException(sprintf( 'Storage property owner is not defined for "%s"', - get_class($this) + static::class )); } } @@ -197,6 +193,7 @@ public function templateProperty() * @throws RuntimeException If the storage property was not previously set. * @return PropertyInterface */ + #[\Override] public function storageProperty() { if ($this->storageProperty === null) { @@ -206,7 +203,7 @@ public function storageProperty() } else { throw new RuntimeException(sprintf( 'Storage property owner is not defined for "%s"', - get_class($this) + static::class )); } } @@ -220,6 +217,7 @@ public function storageProperty() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -231,9 +229,8 @@ protected function setDependencies(Container $container) * Set a metadata loader. * * @param MetadataLoader $loader The loader instance, used to load metadata. - * @return self */ - protected function setMetadataLoader(MetadataLoader $loader) + protected function setMetadataLoader(MetadataLoader $loader): static { $this->metadataLoader = $loader; @@ -244,14 +241,13 @@ protected function setMetadataLoader(MetadataLoader $loader) * Retrieve the metadata loader. * * @throws RuntimeException If the metadata loader was not previously set. - * @return MetadataLoader */ - protected function metadataLoader() + protected function metadataLoader(): \Charcoal\Model\Service\MetadataLoader { - if ($this->metadataLoader === null) { + if (!$this->metadataLoader instanceof \Charcoal\Model\Service\MetadataLoader) { throw new RuntimeException(sprintf( 'Metadata Loader is not defined for "%s"', - get_class($this) + static::class )); } @@ -266,8 +262,7 @@ protected function metadataLoader() */ protected function loadMetadata($metadataIdent) { - $metadata = $this->metadataLoader()->load($metadataIdent, $this->metadataClass()); - return $metadata; + return $this->metadataLoader()->load($metadataIdent, $this->metadataClass()); } /** @@ -283,10 +278,8 @@ protected function createMetadata() /** * Retrieve the class name of the metadata object. - * - * @return string */ - protected function metadataClass() + protected function metadataClass(): string { return StructureMetadata::class; } @@ -297,6 +290,7 @@ protected function metadataClass() * @param boolean $reload Rebuild the form group's structure. * @return void */ + #[\Override] protected function finalizeStructure($reload = false) { if ($reload || !$this->isStructureFinalized) { @@ -311,7 +305,7 @@ protected function finalizeStructure($reload = false) } $controllerInterfaces = (array)$this->controllerIdent(); - if (!empty($controllerInterfaces)) { + if ($controllerInterfaces !== []) { $metadataLoader = $this->metadataLoader(); $controllerStructKey = $controllerInterfaces; diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php index b4768d05e..3fdebeb2c 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php @@ -34,30 +34,22 @@ class FormGroupWidget extends AbstractUiItem implements /** * Whether notes shoudl be display before or after the form fields. - * - * @var boolean */ - private $showNotesAbove = false; + private bool $showNotesAbove = false; /** * @var array|null $parsedFormProperties */ protected $parsedFormProperties; - /** - * @var array $groupProperties - */ - private $groupProperties = []; + private array $groupProperties = []; - /** - * @var array $propertiesOptions - */ - private $propertiesOptions = []; + private array $propertiesOptions = []; /** * @param array|\ArrayAccess $data Dependencies. */ - public function __construct($data) + public function __construct(?array $data) { parent::__construct($data); @@ -70,7 +62,8 @@ public function __construct($data) * @param array $data Widget data. * @return FormGroupWidget Chainable */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { if (!empty($data['properties'])) { $this->setGroupProperties($data['properties']); @@ -92,10 +85,8 @@ public function setData(array $data) return $this; } - /** - * @return string - */ - public function type() + #[\Override] + public function type(): string { return 'charcoal/admin/widget/form-group-widget'; } @@ -104,7 +95,7 @@ public function type() * @param string $widgetId The widget identifier. * @return AdminWidget Chainable */ - public function setWidgetId($widgetId) + public function setWidgetId($widgetId): static { $this->widgetId = $widgetId; @@ -127,7 +118,7 @@ public function widgetId() * @param array $properties The group properties. * @return FormGroupWidget Chainable */ - public function setGroupProperties(array $properties) + public function setGroupProperties(array $properties): static { $this->groupProperties = $properties; $this->parsedFormProperties = null; @@ -135,10 +126,7 @@ public function setGroupProperties(array $properties) return $this; } - /** - * @return array - */ - public function groupProperties() + public function groupProperties(): array { return $this->groupProperties; } @@ -147,29 +135,24 @@ public function groupProperties() * @param array $properties The options to customize the group properties. * @return FormGroupWidget Chainable */ - public function setPropertiesOptions(array $properties) + public function setPropertiesOptions(array $properties): static { $this->propertiesOptions = $properties; return $this; } - /** - * @return array - */ - public function propertiesOptions() + public function propertiesOptions(): array { return $this->propertiesOptions; } /** * Determine if the form group has properties. - * - * @return boolean */ - public function hasFormProperties() + public function hasFormProperties(): bool { - return !!count($this->parsedFormProperties()); + return (bool)count($this->parsedFormProperties()); } /** @@ -182,7 +165,7 @@ public function formProperties() $form = $this->form(); $obj = ($form instanceof ObjectContainerInterface) ? $form->obj() : null; - $groupProperties = array_map([ $this, 'camelize' ], $this->groupProperties()); + $groupProperties = array_map($this->camelize(...), $this->groupProperties()); $formProperties = $this->parsedFormProperties(); $propOptions = $this->propertiesOptions(); @@ -233,9 +216,8 @@ public function formProperties() * Retrieve the available languages, formatted for the sidebar language-switcher. * * @see FormSidebarWidget::languages() - * @return array */ - public function languages() + public function languages(): array { $currentLocale = $this->translator()->getLocale(); $languages = []; @@ -249,7 +231,7 @@ public function languages() } else { $trans = 'locale.' . $locale; if ($trans === $this->translator()->translate($trans)) { - $label = strtoupper($locale); + $label = strtoupper((string)$locale); } else { $label = $this->translator()->translation($trans); } @@ -267,10 +249,8 @@ public function languages() /** * Retrieve the current language. - * - * @return string */ - public function lang() + public function lang(): string { return $this->translator()->getLocale(); } @@ -300,7 +280,8 @@ public function locale() /** * @return Translation|string|null */ - public function description() + #[\Override] + public function description(): string { return $this->renderTemplate((string)parent::description()); } @@ -308,7 +289,8 @@ public function description() /** * @return Translation|string|null */ - public function notes() + #[\Override] + public function notes(): string { return $this->renderTemplate((string)parent::notes()); } @@ -319,6 +301,7 @@ public function notes() * @param boolean|string $show Whether to show or hide notes. * @return FormGroupWidget Chainable */ + #[\Override] public function setShowNotes($show) { $this->showNotesAbove = ($show === 'above'); @@ -326,10 +309,7 @@ public function setShowNotes($show) return parent::setShowNotes($show); } - /** - * @return boolean - */ - public function showNotesAbove() + public function showNotesAbove(): bool { return $this->showNotesAbove && $this->showNotes(); } @@ -338,6 +318,7 @@ public function showNotesAbove() * @param Container $container The DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormPropertyWidget.php b/packages/admin/src/Charcoal/Admin/Widget/FormPropertyWidget.php index e690ff3f1..64cdd7b78 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormPropertyWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormPropertyWidget.php @@ -80,10 +80,8 @@ class FormPropertyWidget extends AdminWidget implements /** * The model property's metadata. - * - * @var array */ - private $propertyData = []; + private array $propertyData = []; /** * Store the property control instance. @@ -164,31 +162,23 @@ class FormPropertyWidget extends AdminWidget implements /** * Store the model property factory. - * - * @var FactoryInterface */ - private $propertyFactory; + private ?\Charcoal\Factory\FactoryInterface $propertyFactory = null; /** * Store the property form control factory. - * - * @var FactoryInterface */ - private $propertyInputFactory; + private ?\Charcoal\Factory\FactoryInterface $propertyInputFactory = null; /** * Store the property display factory. - * - * @var FactoryInterface */ - private $propertyDisplayFactory; + private ?\Charcoal\Factory\FactoryInterface $propertyDisplayFactory = null; /** * Track the state of data merging. - * - * @var boolean */ - private $isMergingWidgetData = false; + private bool $isMergingWidgetData = false; /** * The UI item's icon. @@ -204,11 +194,10 @@ class FormPropertyWidget extends AdminWidget implements * Retrieve the property factory. * * @throws RuntimeException If the property factory is missing. - * @return FactoryInterface */ - public function propertyFactory() + public function propertyFactory(): \Charcoal\Factory\FactoryInterface { - if ($this->propertyFactory === null) { + if (!$this->propertyFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException( 'Missing Property Factory' ); @@ -221,11 +210,10 @@ public function propertyFactory() * Retrieve the property control factory. * * @throws RuntimeException If the property control factory is missing. - * @return FactoryInterface */ - public function propertyInputFactory() + public function propertyInputFactory(): \Charcoal\Factory\FactoryInterface { - if ($this->propertyInputFactory === null) { + if (!$this->propertyInputFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException( 'Missing Property Input Factory' ); @@ -238,11 +226,10 @@ public function propertyInputFactory() * Retrieve the property display factory. * * @throws RuntimeException If the property display factory is missing. - * @return FactoryInterface */ - public function propertyDisplayFactory() + public function propertyDisplayFactory(): \Charcoal\Factory\FactoryInterface { - if ($this->propertyDisplayFactory === null) { + if (!$this->propertyDisplayFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException( 'Missing Property Display Factory' ); @@ -256,6 +243,7 @@ public function propertyDisplayFactory() * * @return string */ + #[\Override] public function widgetId() { $type = $this->outputType(); @@ -281,7 +269,8 @@ public function widgetId() * @throws InvalidArgumentException If the argument is not a string. * @return FormPropertyWidget Chainable */ - public function setType($type) + #[\Override] + public function setType($type): static { if (empty($type)) { $this->type = null; @@ -313,7 +302,7 @@ public function setType($type) * @throws InvalidArgumentException If the argument is not a string. * @return FormPropertyWidget Chainable */ - public function setOutputType($type) + public function setOutputType($type): static { if (empty($type)) { $this->outputType = static::DEFAULT_OUTPUT; @@ -368,10 +357,8 @@ public function outputType() /** * Retrieve the supported property output types. - * - * @return array */ - public function supportedOutputTypes() + public function supportedOutputTypes(): array { return [ static::PROPERTY_CONTROL, static::PROPERTY_DISPLAY ]; } @@ -382,7 +369,7 @@ public function supportedOutputTypes() * @param FormGroupInterface $formGroup The parent form group object. * @return FormPropertyWidget Chainable */ - public function setFormGroup(FormGroupInterface $formGroup) + public function setFormGroup(FormGroupInterface $formGroup): static { $this->formGroup = $formGroup; @@ -404,7 +391,7 @@ public function formGroup() * * @return FormPropertyWidget Chainable */ - public function clearFormGroup() + public function clearFormGroup(): static { $this->formGroup = null; @@ -417,7 +404,8 @@ public function clearFormGroup() * @param array|ArrayAccess $data Widget and property data. * @return FormPropertyWidget Chainable */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { $this->isMergingWidgetData = true; @@ -439,7 +427,7 @@ public function setData(array $data) * @param array $data Widget and property data. * @return FormPropertyWidget Chainable */ - public function merge(array $data) + public function merge(array $data): static { $this->isMergingWidgetData = true; @@ -459,7 +447,7 @@ public function merge(array $data) * @throws InvalidArgumentException If the argument is not a string. * @return FormPropertyWidget Chainable */ - public function setPropertyType($type) + public function setPropertyType($type): static { if (empty($type)) { $this->propertyType = null; @@ -494,7 +482,7 @@ public function propertyType() * @throws InvalidArgumentException If the property ident is not a string. * @return FormPropertyWidget Chainable */ - public function setPropertyIdent($propertyIdent) + public function setPropertyIdent($propertyIdent): static { if (!is_string($propertyIdent)) { throw new InvalidArgumentException( @@ -523,7 +511,7 @@ public function propertyIdent() * @param array $data The property configset. * @return FormPropertyWidget Chainable */ - public function setPropertyData(array $data) + public function setPropertyData(array $data): static { $this->propertyData = $data; @@ -544,7 +532,7 @@ public function setPropertyData(array $data) * @param array $data The property configset. * @return FormPropertyWidget Chainable */ - public function mergePropertyData(array $data) + public function mergePropertyData(array $data): static { $this->propertyData = array_replace($this->propertyData, $data); @@ -561,10 +549,8 @@ public function mergePropertyData(array $data) /** * Retrieve the property metadata. - * - * @return array */ - public function propertyData() + public function propertyData(): array { return $this->propertyData; } @@ -575,7 +561,7 @@ public function propertyData() * @param mixed $propertyVal The property value. * @return FormPropertyWidget Chainable */ - public function setPropertyVal($propertyVal) + public function setPropertyVal($propertyVal): static { $this->propertyVal = $propertyVal; @@ -598,9 +584,10 @@ public function propertyVal() * @param boolean $show Show (TRUE) or hide (FALSE) the label. * @return FormPropertyWidget Chainable */ - public function setShowLabel($show) + #[\Override] + public function setShowLabel($show): static { - $this->showLabel = !!$show; + $this->showLabel = (bool)$show; return $this; } @@ -610,20 +597,17 @@ public function setShowLabel($show) * * @return boolean If TRUE or unset, check if there is a label. */ + #[\Override] public function showLabel() { if ($this->showLabel === null) { $prop = $this->property(); $show = $prop['show_label']; - if ($show !== null) { - $this->showLabel = $show; - } else { - $this->showLabel = true; - } + $this->showLabel = ($show ?? true); } if ($this->showLabel !== false) { - return !!strval($this->property()['label']); + return (bool)strval($this->property()['label']); } else { return false; } @@ -635,9 +619,9 @@ public function showLabel() * @param boolean $show Show (TRUE) or hide (FALSE) the description. * @return FormPropertyWidget Chainable */ - public function setShowDescription($show) + public function setShowDescription($show): static { - $this->showDescription = !!$show; + $this->showDescription = (bool)$show; return $this; } @@ -652,15 +636,11 @@ public function showDescription() if ($this->showDescription === null) { $prop = $this->property(); $show = $prop['show_description']; - if ($show !== null) { - $this->showDescription = $show; - } else { - $this->showDescription = true; - } + $this->showDescription = ($show ?? true); } if ($this->showDescription !== false) { - return !!strval($this->property()['description']); + return (bool)strval($this->property()['description']); } else { return false; } @@ -672,9 +652,9 @@ public function showDescription() * @param boolean|string $show Show (TRUE) or hide (FALSE) the notes. * @return FormPropertyWidget Chainable */ - public function setShowNotes($show) + public function setShowNotes($show): static { - $this->showNotes = ($show === 'above' ? $show : !!$show); + $this->showNotes = ($show === 'above' ? $show : (bool)$show); return $this; } @@ -689,15 +669,11 @@ public function showNotes() if ($this->showNotes === null) { $prop = $this->property(); $show = $prop['show_notes']; - if ($show !== null) { - $this->showNotes = $show; - } else { - $this->showNotes = true; - } + $this->showNotes = ($show ?? true); } if ($this->showNotes !== false) { - return !!strval($this->property()['notes']); + return (bool)strval($this->property()['notes']); } else { return false; } @@ -720,13 +696,13 @@ public function showNotesAbove() $notes = $this->property()['notes']; - return !!$notes; + return (bool)$notes; } /** * @return Translation|string|null */ - public function description() + public function description(): string { return $this->renderTemplate((string)$this->property()['description']); } @@ -734,23 +710,17 @@ public function description() /** * @return Translation|string|null */ - public function notes() + public function notes(): string { return $this->renderTemplate((string)$this->property()['notes']); } - /** - * @return boolean - */ - public function hidden() + public function hidden(): bool { return ($this->inputType() === static::HIDDEN_FORM_CONTROL || $this->property()['hidden']); } - /** - * @return boolean - */ - public function editable() + public function editable(): bool { return ($this->inputType() !== static::READONLY_FORM_CONTROL && $this->outputType() === static::PROPERTY_CONTROL); } @@ -765,34 +735,22 @@ public function required() return $this->property()['required']; } - /** - * @return string - */ - public function inputId() + public function inputId(): string { return 'input_id'; } - /** - * @return string - */ - public function inputName() + public function inputName(): string { return 'input_name'; } - /** - * @return string - */ - public function displayId() + public function displayId(): string { return 'display_id'; } - /** - * @return string - */ - public function displayName() + public function displayName(): string { return 'display_name'; } @@ -804,7 +762,7 @@ public function displayName() * @throws InvalidArgumentException If the argument is not a string. * @return FormPropertyWidget Chainable */ - public function setInputType($type) + public function setInputType($type): static { if (empty($type)) { $this->inputType = null; @@ -843,7 +801,7 @@ public function inputType() * @throws InvalidArgumentException If the argument is not a string. * @return FormPropertyWidget Chainable */ - public function setDisplayType($type) + public function setDisplayType($type): static { if (empty($type)) { $this->displayType = null; @@ -881,7 +839,7 @@ public function displayType() * @param PropertyInterface $property The property. * @return FormPropertyWidget Chainable */ - public function setProperty(PropertyInterface $property) + public function setProperty(PropertyInterface $property): static { $this->property = $property; $this->propertyType = $property->type(); @@ -926,10 +884,8 @@ public function prop() /** * Determine if the form control's active language should be displayed. - * - * @return boolean */ - public function showActiveLanguage() + public function showActiveLanguage(): bool { $property = $this->property(); $locales = count($this->translator()->availableLocales()); @@ -945,18 +901,16 @@ public function showActiveLanguage() public function inputNameAsCssClass() { $name = str_replace([ ']', '[' ], [ '', '-' ], $this->propertyIdent()); - $name = $this->camelize($name); - return $name; + return $this->camelize($name); } /** * Set the CSS class name(s) for the `.form-field`. * * @param mixed $cssClass One or more CSS class names. - * @return self */ - public function setFormFieldCssClass($cssClass) + public function setFormFieldCssClass($cssClass): static { $cssClass = array_merge($this->defaultFormFieldCssClasses(), $this->parseCssClasses($cssClass)); $this->formFieldCssClass = array_unique($cssClass); @@ -967,11 +921,10 @@ public function setFormFieldCssClass($cssClass) * Add CSS class name(s) for the `.form-field`. * * @param mixed $cssClass One or more CSS class names. - * @return self */ - public function addFormFieldCssClass($cssClass) + public function addFormFieldCssClass($cssClass): static { - if (empty($this->formFieldCssClass)) { + if ($this->formFieldCssClass === []) { $this->formFieldCssClass = $this->defaultFormFieldCssClasses(); } @@ -982,12 +935,10 @@ public function addFormFieldCssClass($cssClass) /** * Retrieve the CSS class name(s) for the `.form-field`. - * - * @return string */ - public function formFieldCssClass() + public function formFieldCssClass(): string { - if (empty($this->formFieldCssClass)) { + if ($this->formFieldCssClass === []) { $this->formFieldCssClass = $this->defaultFormFieldCssClasses(); } @@ -998,9 +949,8 @@ public function formFieldCssClass() * Set the CSS class name(s) for the `.form-group`. * * @param mixed $cssClass One or more CSS class names. - * @return self */ - public function setFormGroupCssClass($cssClass) + public function setFormGroupCssClass($cssClass): static { $cssClass = array_merge($this->defaultFormGroupCssClasses(), $this->parseCssClasses($cssClass)); $this->formGroupCssClass = array_unique($cssClass); @@ -1011,11 +961,10 @@ public function setFormGroupCssClass($cssClass) * Add CSS class name(s) for the `.form-group`. * * @param mixed $cssClass One or more CSS class names. - * @return self */ - public function addFormGroupCssClass($cssClass) + public function addFormGroupCssClass($cssClass): static { - if (empty($this->formGroupCssClass)) { + if ($this->formGroupCssClass === []) { $this->formGroupCssClass = $this->defaultFormGroupCssClasses(); } @@ -1026,12 +975,10 @@ public function addFormGroupCssClass($cssClass) /** * Retrieve the CSS class name(s) for the `.form-group`. - * - * @return string */ - public function formGroupCssClass() + public function formGroupCssClass(): string { - if (empty($this->formGroupCssClass)) { + if ($this->formGroupCssClass === []) { $this->formGroupCssClass = $this->defaultFormGroupCssClasses(); } @@ -1044,7 +991,7 @@ public function formGroupCssClass() * @param string $mode The L10N display mode. * @return FormPropertyWidget Chainable */ - public function setL10nMode($mode) + public function setL10nMode($mode): static { $this->l10nMode = $mode; return $this; @@ -1062,10 +1009,8 @@ public function l10nMode() /** * Determine if the property should output for each language. - * - * @return boolean */ - public function loopL10n() + public function loopL10n(): bool { return ($this->l10nMode() === 'loop_inputs'); } @@ -1159,6 +1104,7 @@ public function output() * @param Container $container Service container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -1175,7 +1121,7 @@ protected function setDependencies(Container $container) * @param FactoryInterface $factory The factory to create property values. * @return FormPropertyWidget Chainable */ - protected function setPropertyFactory(FactoryInterface $factory) + protected function setPropertyFactory(FactoryInterface $factory): static { $this->propertyFactory = $factory; @@ -1188,7 +1134,7 @@ protected function setPropertyFactory(FactoryInterface $factory) * @param FactoryInterface $factory The factory to create form controls for property values. * @return FormPropertyWidget Chainable */ - protected function setPropertyInputFactory(FactoryInterface $factory) + protected function setPropertyInputFactory(FactoryInterface $factory): static { $this->propertyInputFactory = $factory; @@ -1201,7 +1147,7 @@ protected function setPropertyInputFactory(FactoryInterface $factory) * @param FactoryInterface $factory The factory to create displayable property values. * @return FormPropertyWidget Chainable */ - protected function setPropertyDisplayFactory(FactoryInterface $factory) + protected function setPropertyDisplayFactory(FactoryInterface $factory): static { $this->propertyDisplayFactory = $factory; @@ -1229,7 +1175,7 @@ protected function resolveOutputType($type) } else { throw new InvalidArgumentException(sprintf( 'Invalid form property output type, received %s', - is_object($type) ? get_class($type) : gettype($type) + get_debug_type($type) )); } } @@ -1255,7 +1201,7 @@ public function resolvedOutputType() * * @return string[] */ - protected function defaultFormFieldCssClasses() + protected function defaultFormFieldCssClasses(): array { $classes = [ 'form-field', 'form-field-' . $this->widgetId() ]; @@ -1287,7 +1233,7 @@ protected function defaultFormFieldCssClasses() * * @return string[] */ - protected function defaultFormGroupCssClasses() + protected function defaultFormGroupCssClasses(): array { return [ 'form-group' ]; } @@ -1299,7 +1245,7 @@ protected function defaultFormGroupCssClasses() * @throws InvalidArgumentException If a class name is not a string. * @return string[] */ - protected function parseCssClasses($classes) + protected function parseCssClasses($classes): array { if (is_string($classes)) { $classes = explode(' ', $classes); @@ -1309,7 +1255,7 @@ protected function parseCssClasses($classes) throw new InvalidArgumentException('CSS Class(es) must be a space-delimited string or an array'); } - return array_filter($classes, 'strlen'); + return array_filter($classes, strlen(...)); } /** @@ -1318,7 +1264,7 @@ protected function parseCssClasses($classes) * @param array $data The widget and property data. * @return array Returns the remaining dataset. */ - private function setCoreData(array $data) + private function setCoreData(array $data): array { if (isset($data['ident'])) { $this->setPropertyIdent($data['ident']); @@ -1370,7 +1316,7 @@ private function resolveInputType() /** Attempt input type resolution without instantiating the property, at first. */ $metadata = $this->propertyData(); - if ($metadata) { + if ($metadata !== []) { if (isset($metadata['hidden']) && $metadata['hidden']) { $type = static::HIDDEN_FORM_CONTROL; } @@ -1415,10 +1361,8 @@ private function resolveDisplayType() /** Attempt display type resolution without instantiating the property, at first. */ $metadata = $this->propertyData(); - if ($metadata) { - if (isset($metadata['display_type'])) { - $type = $metadata['display_type']; - } + if ($metadata && isset($metadata['display_type'])) { + $type = $metadata['display_type']; } if ($this->propertyType || $this->property) { @@ -1443,7 +1387,7 @@ private function createProperty() if ($ident && is_string($ident)) { $message = sprintf('Missing property type for property "%s"', $ident); } else { - $message = sprintf('Missing property type'); + $message = 'Missing property type'; } throw new UnexpectedValueException($message); } @@ -1534,7 +1478,7 @@ private function createDisplayProperty() * @param array $data The widget and property data. * @return array Returns the remaining dataset. */ - protected function filterInputPropertyData(array $data) + protected function filterInputPropertyData(array $data): array { unset( $data['formFieldCssClass'], @@ -1552,7 +1496,7 @@ protected function filterInputPropertyData(array $data) * @param array $data The widget and property data. * @return array Returns the remaining dataset. */ - protected function filterDisplayPropertyData(array $data) + protected function filterDisplayPropertyData(array $data): array { return $data; } @@ -1571,9 +1515,8 @@ public function icon() * Set the path to the item's icon associated with the object. * * @param string $icon A path to an image. - * @return self */ - public function setIcon($icon) + public function setIcon($icon): static { $this->icon = $icon; @@ -1582,15 +1525,13 @@ public function setIcon($icon) /** * Check for icon(s) - * - * @return boolean */ - public function hasIcon() + public function hasIcon(): bool { if (is_array($this->icon())) { - return !!count($this->icon()); + return (bool)count($this->icon()); } - return !!$this->icon(); + return (bool)$this->icon(); } } diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormSidebarWidget.php b/packages/admin/src/Charcoal/Admin/Widget/FormSidebarWidget.php index d2189706b..996130f4d 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormSidebarWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormSidebarWidget.php @@ -39,10 +39,8 @@ class FormSidebarWidget extends AdminWidget implements /** * Store a reference to the parent form widget. - * - * @var FormInterface */ - private $form; + private ?\Charcoal\Ui\Form\FormInterface $form = null; /** * Store the sidebar actions. @@ -74,17 +72,13 @@ class FormSidebarWidget extends AdminWidget implements /** * Customize the shown properties. - * - * @var array */ - private $propertiesOptions = []; + private array $propertiesOptions = []; /** * The title is displayed by default. - * - * @var boolean */ - private $showTitle = true; + private bool $showTitle = true; /** * The sidebar's title. @@ -95,10 +89,8 @@ class FormSidebarWidget extends AdminWidget implements /** * The subtitle is displayed by default. - * - * @var boolean */ - private $showSubtitle = true; + private bool $showSubtitle = true; /** * The sidebar's subtitle. @@ -151,23 +143,22 @@ class FormSidebarWidget extends AdminWidget implements /** * Whether the object is revisionable. - * - * @var boolean */ - private $isObjRevisionable; + private ?bool $isObjRevisionable = null; /** * The required Acl permissions for the whole sidebar. * * @var string[] */ - private $requiredGlobalAclPermissions = []; + private array $requiredGlobalAclPermissions = []; /** * @param array|ArrayInterface $data Class data. * @return FormSidebarWidget Chainable */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -199,7 +190,7 @@ public function setData(array $data) * @param FormInterface $form The related form widget. * @return FormSidebarWidget Chainable */ - public function setForm(FormInterface $form) + public function setForm(FormInterface $form): static { $this->form = $form; @@ -211,7 +202,7 @@ public function setForm(FormInterface $form) * * @return FormInterface */ - public function form() + public function form(): ?\Charcoal\Ui\Form\FormInterface { return $this->form; } @@ -222,7 +213,7 @@ public function form() * @param array $properties The form's object properties. * @return FormSidebarWidget Chainable */ - public function setSidebarProperties(array $properties) + public function setSidebarProperties(array $properties): static { $this->sidebarProperties = $properties; @@ -241,20 +232,16 @@ public function sidebarProperties() /** * Determine if the sidebar has any object properties. - * - * @return boolean */ - public function hasSidebarProperties() + public function hasSidebarProperties(): bool { return ($this->numSidebarProperties() > 0); } /** * Count the number of object properties in the sidebar. - * - * @return integer */ - public function numSidebarProperties() + public function numSidebarProperties(): int { return count($this->sidebarProperties()); } @@ -265,7 +252,7 @@ public function numSidebarProperties() * @param array $properties The options to customize the group properties. * @return FormSidebarWidget Chainable */ - public function setPropertiesOptions(array $properties) + public function setPropertiesOptions(array $properties): static { $this->propertiesOptions = $properties; @@ -274,10 +261,8 @@ public function setPropertiesOptions(array $properties) /** * Retrieve the map of object property customizations. - * - * @return array */ - public function propertiesOptions() + public function propertiesOptions(): array { return $this->propertiesOptions; } @@ -292,7 +277,7 @@ public function formProperties() $form = $this->form(); $obj = $form->obj(); - $availableProperties = $obj->properties(); + $obj->properties(); $sidebarProperties = $this->sidebarProperties(); $propertiesOptions = $this->propertiesOptions(); @@ -345,9 +330,7 @@ public function showSidebarActions() return false; } - $actions = array_filter($actions, function ($action) { - return $action['active'] === true; - }); + $actions = array_filter($actions, fn(array $action): bool => $action['active'] === true); $this->showSidebarActions = (count($actions) > 0); } @@ -380,7 +363,7 @@ public function sidebarActions() * @param array $actions One or more actions. * @return FormSidebarWidget Chainable. */ - protected function setSidebarActions(array $actions) + protected function setSidebarActions(array $actions): static { $this->parsedSidebarActions = false; @@ -399,22 +382,19 @@ protected function setSidebarActions(array $actions) * @param array $actions Actions to resolve. * @return array Sidebar actions. */ - protected function createSidebarActions(array $actions) + protected function createSidebarActions(array $actions): array { $this->actionsPriority = $this->defaultActionPriority(); - $sidebarActions = $this->parseAsSidebarActions($actions); - - return $sidebarActions; + return $this->parseAsSidebarActions($actions); } /** * Parse the given actions as object actions. * * @param array $actions Actions to resolve. - * @return array */ - protected function parseAsSidebarActions(array $actions) + protected function parseAsSidebarActions(array $actions): array { $sidebarActions = []; foreach ($actions as $ident => $action) { @@ -441,9 +421,7 @@ protected function parseAsSidebarActions(array $actions) if ($action['actions']) { $action['actions'] = $this->parseAsSidebarActions($action['actions']); - $action['hasActions'] = !!array_filter($action['actions'], function ($action) { - return $action['active']; - }); + $action['hasActions'] = (bool)array_filter($action['actions'], fn(array $action): mixed => $action['active']); } if (isset($sidebarActions[$ident])) { @@ -458,7 +436,7 @@ protected function parseAsSidebarActions(array $actions) } } - usort($sidebarActions, [ 'Charcoal\Admin\Support\Sorter', 'sortByPriority' ]); + usort($sidebarActions, \Charcoal\Admin\Support\Sorter::sortByPriority(...)); while (($first = reset($sidebarActions)) && $first['isSeparator']) { array_shift($sidebarActions); @@ -481,7 +459,7 @@ protected function defaultSidebarActions() if ($this->defaultSidebarActions === null) { $this->defaultSidebarActions = []; - if ($this->form()) { + if ($this->form() instanceof \Charcoal\Ui\Form\FormInterface) { $save = [ 'label' => $this->form()->submitLabel(), 'ident' => 'save', @@ -495,10 +473,7 @@ protected function defaultSidebarActions() return $this->defaultSidebarActions; } - /** - * @return string - */ - public function jsActionPrefix() + public function jsActionPrefix(): string { return 'js-sidebar'; } @@ -519,7 +494,7 @@ public function isObjDeletable() $this->isObjDeletable = false; } else { $obj = $this->form()->obj(); - $this->isObjDeletable = !!$obj->id(); + $this->isObjDeletable = (bool)$obj->id(); $method = [ $obj, 'isDeletable' ]; if (is_callable($method)) { @@ -539,7 +514,7 @@ public function isObjDeletable() * * @return boolean */ - public function isObjRevisionable() + public function isObjRevisionable(): ?bool { if ($this->isObjRevisionable === null) { // Overridden by permissions @@ -553,7 +528,7 @@ public function isObjRevisionable() } if ($obj instanceof RevisionableInterface && $obj['revisionEnabled']) { - $this->isObjRevisionable = !!count($obj->allRevisions()); + $this->isObjRevisionable = (bool)count($obj->allRevisions()); } } } @@ -634,7 +609,7 @@ public function isObjViewable() $this->isObjViewable = false; } else { $obj = $this->form()->obj(); - $this->isObjViewable = !!$obj->id(); + $this->isObjViewable = (bool)$obj->id(); $method = [ $obj, 'isViewable' ]; if (is_callable($method)) { @@ -652,9 +627,9 @@ public function isObjViewable() * @param boolean $show Show (TRUE) or hide (FALSE) the title. * @return UiItemInterface Chainable */ - public function setShowTitle($show) + public function setShowTitle($show): static { - $this->showTitle = !!$show; + $this->showTitle = (bool)$show; return $this; } @@ -669,7 +644,7 @@ public function showTitle() if ($this->showTitle === false) { return false; } else { - return !!$this->title(); + return (bool)$this->title(); } } @@ -677,7 +652,7 @@ public function showTitle() * @param mixed $title The sidebar title. * @return FormSidebarWidget Chainable */ - public function setTitle($title) + public function setTitle($title): static { $this->title = $this->translator()->translation($title); @@ -700,9 +675,9 @@ public function title() * @param boolean $show The show subtitle flag. * @return FormSidebarWidget Chainable */ - public function setShowSubtitle($show) + public function setShowSubtitle($show): static { - $this->showSubtitle = !!$show; + $this->showSubtitle = (bool)$show; return $this; } @@ -714,7 +689,7 @@ public function showSubtitle() if ($this->showSubtitle === false) { return false; } else { - return !!$this->subtitle(); + return (bool)$this->subtitle(); } } @@ -722,7 +697,7 @@ public function showSubtitle() * @param mixed $subtitle The sidebar widget subtitle. * @return FormSidebarWidget Chainable */ - public function setSubtitle($subtitle) + public function setSubtitle($subtitle): static { $this->subtitle = $this->translator()->translation($subtitle); @@ -761,31 +736,26 @@ public function showFooter() * Enable / Disable the sidebar's footer. * * @param mixed $show The show footer flag. - * @return FormSidebarWidget */ - public function setShowFooter($show) + public function setShowFooter($show): static { - $this->showFooter = !!$show; + $this->showFooter = (bool)$show; return $this; } /** * Determine if wrapper containing the subtitle and properties should be displayed. - * - * @return boolean */ - public function showPropertiesWrapper() + public function showPropertiesWrapper(): bool { return $this->showSubtitle() || $this->hasSidebarProperties(); } /** * Determine if wrapper containing the language switcher and actions should be displayed. - * - * @return boolean */ - public function showActionsWrapper() + public function showActionsWrapper(): bool { return $this->showLanguageSwitch() || $this->showSidebarActions(); } @@ -797,10 +767,8 @@ public function showActionsWrapper() protected function resolveShowLanguageSwitch() { $form = $this->form(); - if ($form) { - if ($form instanceof LanguageSwitcherAwareInterface) { - return $form->supportsLanguageSwitch(); - } + if ($form && $form instanceof LanguageSwitcherAwareInterface) { + return $form->supportsLanguageSwitch(); } return false; @@ -811,24 +779,24 @@ protected function resolveShowLanguageSwitch() * * @see AdminWidget::resolveConditionalLogic() * @param callable|string $condition The callable or renderable condition. - * @return boolean */ - protected function resolveConditionalLogic($condition) + #[\Override] + protected function resolveConditionalLogic($condition): bool { $renderer = $this->getActionRenderer(); if ($renderer && is_callable([ $renderer, $condition ])) { - return !!$renderer->{$condition}(); + return (bool)$renderer->{$condition}(); } elseif (is_callable([ $this, $condition ])) { - return !!$this->{$condition}(); + return (bool)$this->{$condition}(); } elseif (is_callable($condition)) { - return !!$condition(); - } elseif ($renderer) { - return !!$renderer->renderTemplate($condition); - } elseif ($this->view()) { - return !!$this->renderTemplate($condition); + return (bool)$condition(); + } elseif ($renderer instanceof \Charcoal\View\ViewableInterface) { + return (bool)$renderer->renderTemplate($condition); + } elseif ($this->view() instanceof \Charcoal\View\ViewInterface) { + return (bool)$this->renderTemplate($condition); } - return !!$condition; + return (bool)$condition; } // ACL Permissions @@ -851,26 +819,21 @@ protected function checkPermission($permissionName) } $authUser = $this->authenticator()->user(); - if (!$authUser || !$this->authorizer()->userAllowed($authUser, $permissions)) { - return false; - } - - return true; + return $authUser && $this->authorizer()->userAllowed($authUser, $permissions); } /** * @return string[] */ - public function requiredGlobalAclPermissions() + public function requiredGlobalAclPermissions(): array { return $this->requiredGlobalAclPermissions; } /** * @param array $permissions The GlobalAcl permissions required pby the form group. - * @return self */ - public function setRequiredGlobalAclPermissions(array $permissions) + public function setRequiredGlobalAclPermissions(array $permissions): static { $this->requiredGlobalAclPermissions = $permissions; @@ -892,6 +855,6 @@ protected function isAssoc(array $array) return false; } - return !!array_filter($array, 'is_string', ARRAY_FILTER_USE_KEY); + return (bool)array_filter($array, is_string(...), ARRAY_FILTER_USE_KEY); } } diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormWidget.php b/packages/admin/src/Charcoal/Admin/Widget/FormWidget.php index 233531116..1a8cc18e6 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormWidget.php @@ -99,16 +99,15 @@ class FormWidget extends AdminWidget implements /** * Store the factory instance for the current class. - * - * @var FactoryInterface */ - private $widgetFactory; + private ?\Charcoal\Factory\FactoryInterface $widgetFactory = null; /** * @param array $data The widget data. * @return FormWidget Chainable */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { $this->setDefaultFormGroupsTemplate(); $this->setDefaultFormTabsTemplate(); @@ -122,7 +121,7 @@ public function setData(array $data) * @param array $data Optional. The form property data to set. * @return FormPropertyWidget */ - public function createFormProperty(array $data = null) + public function createFormProperty(?array $data = null) { $p = $this->widgetFactory()->create($this->formPropertyClass()); if ($data !== null) { @@ -139,7 +138,7 @@ public function createFormProperty(array $data = null) * @throws InvalidArgumentException If the class name is not a string. * @return FormWidget Chainable */ - protected function setFormPropertyClass($className) + protected function setFormPropertyClass($className): static { if (!is_string($className)) { throw new InvalidArgumentException( @@ -167,7 +166,7 @@ public function formPropertyClass() * @throws InvalidArgumentException If the property is already registered. * @return \Charcoal\Admin\Widget\FormPropertyWidget|mixed */ - public function getOrCreateFormProperty($ident, array $data = null) + public function getOrCreateFormProperty($ident, ?array $data = null) { if ($this->updateFormProperty($ident, $data)) { return $this->formProperties[$ident]; @@ -203,7 +202,7 @@ public function getOrCreateFormProperty($ident, array $data = null) * @throws InvalidArgumentException If the property is already registered. * @return \Charcoal\Admin\Widget\FormPropertyWidget|mixed */ - public function getOrCreateHiddenProperty($ident, array $data = null) + public function getOrCreateHiddenProperty($ident, ?array $data = null) { if ($this->updateHiddenProperty($ident, $data)) { return $this->hiddenProperties[$ident]; @@ -233,7 +232,7 @@ public function getOrCreateHiddenProperty($ident, array $data = null) * @param array $data Property metadata. * @return \Charcoal\Admin\Widget\FormPropertyWidget|mixed */ - protected function buildFormProperty($ident, array $data = null) + protected function buildFormProperty($ident, ?array $data = null) { $formProperty = $this->createFormProperty(); $formProperty->setPropertyIdent($ident); @@ -264,7 +263,7 @@ protected function buildFormProperty($ident, array $data = null) * @param array $data Property metadata. * @return \Charcoal\Admin\Widget\FormPropertyWidget|null */ - protected function updateFormProperty($ident, array $data = null) + protected function updateFormProperty($ident, ?array $data = null) { if ($ident && isset($this->formProperties[$ident])) { $formProperty = $this->formProperties[$ident]; @@ -286,7 +285,7 @@ protected function updateFormProperty($ident, array $data = null) * @param array $data Property metadata. * @return \Charcoal\Admin\Widget\FormPropertyWidget|null */ - protected function updateHiddenProperty($ident, array $data = null) + protected function updateHiddenProperty($ident, ?array $data = null) { if ($ident && isset($this->hiddenProperties[$ident])) { $formProperty = $this->hiddenProperties[$ident]; @@ -306,27 +305,24 @@ protected function updateHiddenProperty($ident, array $data = null) /** * @param string $ident Property ident. - * @return boolean */ - protected function hasFormProperty($ident) + protected function hasFormProperty($ident): bool { return ($ident && isset($this->formProperties[$ident])); } /** * @param string $ident Property ident. - * @return boolean */ - protected function hasHiddenProperty($ident) + protected function hasHiddenProperty($ident): bool { return ($ident && isset($this->hiddenProperties[$ident])); } /** * @param array $sidebars The form sidebars. - * @return self */ - public function setSidebars(array $sidebars) + public function setSidebars(array $sidebars): static { $this->sidebars = []; foreach ($sidebars as $sidebarIdent => $sidebar) { @@ -340,9 +336,8 @@ public function setSidebars(array $sidebars) * @param string $sidebarIdent The sidebar identifier. * @param array|FormSidebarInterface $sidebar The sidebar data or object. * @throws InvalidArgumentException If the ident is not a string or the sidebar is not valid. - * @return self */ - public function addSidebar($sidebarIdent, $sidebar) + public function addSidebar($sidebarIdent, $sidebar): static { if (!is_string($sidebarIdent)) { throw new InvalidArgumentException( @@ -381,10 +376,8 @@ public function addSidebar($sidebarIdent, $sidebar) /** * Determines if any sidebars are defined. - * - * @return boolean */ - public function hasSidebars() + public function hasSidebars(): bool { return (bool)$this->sidebars; } @@ -397,17 +390,13 @@ public function hasSidebars() public function sidebars() { $sidebars = $this->sidebars; - uasort($sidebars, [ $this, 'sortSidebarsByPriority' ]); + uasort($sidebars, $this->sortSidebarsByPriority(...)); foreach ($sidebars as $sidebarIdent => $sidebar) { if (!$sidebar->active()) { continue; } - if ($sidebar->template()) { - $template = $sidebar->template(); - } else { - $template = 'charcoal/admin/widget/form.sidebar'; - } + $template = $sidebar->template() ?: 'charcoal/admin/widget/form.sidebar'; $this->setDynamicTemplate('widget_template', $template); yield $sidebarIdent => $sidebar; @@ -418,9 +407,8 @@ public function sidebars() * Replace property controls to the form. * * @param array $properties The form properties. - * @return self */ - public function setFormProperties(array $properties) + public function setFormProperties(array $properties): static { $this->formProperties = []; @@ -433,9 +421,8 @@ public function setFormProperties(array $properties) * Add property controls to the form. * * @param array $properties The form properties. - * @return self */ - public function addFormProperties(array $properties) + public function addFormProperties(array $properties): static { foreach ($properties as $propertyIdent => $property) { $this->addFormProperty($propertyIdent, $property); @@ -455,7 +442,7 @@ public function addFormProperties(array $properties) * @throws InvalidArgumentException If the identifier or the property is invalid. * @return FormInterface Chainable */ - public function addFormProperty($propertyIdent, $formProperty) + public function addFormProperty($propertyIdent, $formProperty): static { if (!is_string($propertyIdent)) { throw new InvalidArgumentException( @@ -480,7 +467,7 @@ public function addFormProperty($propertyIdent, $formProperty) throw new InvalidArgumentException(sprintf( 'Property must be an array or an instance of FormPropertyWidget, received %s', - is_object($formProperty) ? get_class($formProperty) : gettype($formProperty) + get_debug_type($formProperty) )); } @@ -510,7 +497,7 @@ public function formProperties() * * @return FormPropertyWidget[] */ - public function getFormProperties() + public function getFormProperties(): array { $formProperties = []; foreach ($this->formProperties as $formProperty) { @@ -530,7 +517,7 @@ public function getFormProperties() * @param array $properties The hidden form properties. * @return FormInterface Chainable */ - public function setHiddenProperties(array $properties) + public function setHiddenProperties(array $properties): static { $this->hiddenProperties = []; @@ -545,7 +532,7 @@ public function setHiddenProperties(array $properties) * @param array $properties The hidden form properties. * @return FormInterface Chainable */ - public function addHiddenProperties(array $properties) + public function addHiddenProperties(array $properties): static { foreach ($properties as $propertyIdent => $property) { $this->addHiddenProperty($propertyIdent, $property); @@ -562,7 +549,7 @@ public function addHiddenProperties(array $properties) * @throws InvalidArgumentException If the identifier or the property is invalid. * @return FormInterface Chainable */ - public function addHiddenProperty($propertyIdent, $formProperty) + public function addHiddenProperty($propertyIdent, $formProperty): static { if (!is_string($propertyIdent)) { throw new InvalidArgumentException( @@ -588,7 +575,7 @@ public function addHiddenProperty($propertyIdent, $formProperty) throw new InvalidArgumentException(sprintf( 'Form property must be an array or an instance of FormPropertyWidget, received %s', - is_object($formProperty) ? get_class($formProperty) : gettype($formProperty) + get_debug_type($formProperty) )); } @@ -610,8 +597,6 @@ public function hiddenProperties() /** * Whether a language switcher could be displayed. - * - * @return bool */ public function supportsLanguageSwitch(): bool { @@ -620,10 +605,8 @@ public function supportsLanguageSwitch(): bool /** * Determine if the form has any multilingual properties. - * - * @return boolean */ - public function hasL10nFormProperties() + public function hasL10nFormProperties(): bool { $locales = count($this->translator()->availableLocales()); if ($locales > 1) { @@ -653,9 +636,8 @@ public function submitLabel() /** * @param string|Translation $label The submit label for the form. - * @return self */ - public function setSubmitLabel($label) + public function setSubmitLabel($label): static { $this->submitLabel = $this->translator()->translate($label); @@ -664,18 +646,13 @@ public function setSubmitLabel($label) /** * Retrieve the default label for the form submission button. - * - * @return \Charcoal\Translator\Translation|null */ - public function defaultSubmitLabel() + public function defaultSubmitLabel(): ?\Charcoal\Translator\Translation { return $this->translator()->translation('Save'); } - /** - * @return string - */ - public function defaultGroupType() + public function defaultGroupType(): string { return 'charcoal/admin/widget/form-group/generic'; } @@ -686,7 +663,7 @@ public function defaultGroupType() * @param string $partial The partial template to render the form groups within. * @return FormWidget Chainable */ - public function setGroupsTemplate($partial) + public function setGroupsTemplate(?string $partial): static { $this->setDynamicTemplate('form_groups_template', $partial); $this->groupsTemplate = $partial; @@ -707,18 +684,12 @@ public function groupsTemplate() return $this->groupsTemplate; } - /** - * @return void - */ - public function setDefaultFormGroupsTemplate() + public function setDefaultFormGroupsTemplate(): void { $this->setGroupsTemplate($this->defaultFormGroupsTemplate()); } - /** - * @return string - */ - public function defaultFormGroupsTemplate() + public function defaultFormGroupsTemplate(): string { return 'charcoal/admin/template/form/groups-wrapper'; } @@ -729,7 +700,7 @@ public function defaultFormGroupsTemplate() * @param string $partial The partial template to render the form tabs within. * @return FormWidget Chainable */ - public function setTabsTemplate($partial) + public function setTabsTemplate(?string $partial): static { $this->setDynamicTemplate('form_tabs_template', $partial); $this->tabsTemplate = $partial; @@ -750,18 +721,12 @@ public function tabsTemplate() return $this->tabsTemplate; } - /** - * @return void - */ - public function setDefaultFormTabsTemplate() + public function setDefaultFormTabsTemplate(): void { $this->setTabsTemplate($this->defaultFormTabsTemplate()); } - /** - * @return string - */ - public function defaultFormTabsTemplate() + public function defaultFormTabsTemplate(): string { return 'charcoal/admin/template/form/nav-tabs'; } @@ -770,6 +735,7 @@ public function defaultFormTabsTemplate() * @param Container $container The DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -790,14 +756,13 @@ protected function setDependencies(Container $container) * Retrieve the widget factory. * * @throws RuntimeException If the widget factory was not previously set. - * @return FactoryInterface */ - protected function widgetFactory() + protected function widgetFactory(): \Charcoal\Factory\FactoryInterface { - if ($this->widgetFactory === null) { + if (!$this->widgetFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException(sprintf( 'Widget Factory is not defined for "%s"', - get_class($this) + static::class )); } @@ -827,10 +792,8 @@ protected function dataFromRequest() /** * Retrieve the accepted metadata from the current request. - * - * @return array */ - protected function acceptedRequestData() + protected function acceptedRequestData(): array { return [ 'form_ident', @@ -852,15 +815,10 @@ protected function acceptedRequestData() protected function sortItemsByPriority( PrioritizableInterface $a, PrioritizableInterface $b - ) { + ): int { $priorityA = $a->priority(); $priorityB = $b->priority(); - - if ($priorityA === $priorityB) { - return 0; - } - - return ($priorityA < $priorityB) ? (-1) : 1; + return ($priorityA <=> $priorityB); } /** @@ -873,14 +831,9 @@ protected function sortItemsByPriority( protected function sortSidebarsByPriority( FormSidebarInterface $a, FormSidebarInterface $b - ) { + ): int { $a = $a->priority(); $b = $b->priority(); - - if ($a === $b) { - return 0; - } - - return ($a < $b) ? (-1) : 1; + return ($a <=> $b); } } diff --git a/packages/admin/src/Charcoal/Admin/Widget/Graph/AbstractGraphWidget.php b/packages/admin/src/Charcoal/Admin/Widget/Graph/AbstractGraphWidget.php index faacc7cea..9b7b02416 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/Graph/AbstractGraphWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/Graph/AbstractGraphWidget.php @@ -164,10 +164,9 @@ public function categoriesJson() /** * Retrieve the widget's data options for JavaScript components. - * - * @return array */ - public function widgetDataForJs() + #[\Override] + public function widgetDataForJs(): array { return [ 'list_actions' => $this->graphActions(), @@ -278,9 +277,7 @@ protected function createGraphActions(array $actions) { $this->actionsPriority = $this->defaultActionPriority(); - $graphActions = $this->parseAsGraphActions($actions); - - return $graphActions; + return $this->parseAsGraphActions($actions); } /** @@ -300,13 +297,11 @@ protected function parseAsGraphActions(array $actions) $action['priority'] = $this->actionsPriority++; } - $action['empty'] = (isset($action['empty']) ? boolval($action['empty']) : false); + $action['empty'] = (isset($action['empty']) && boolval($action['empty'])); if (is_array($action['actions'])) { $action['actions'] = $this->parseAsGraphActions($action['actions']); - $action['hasActions'] = !!array_filter($action['actions'], function ($action) { - return $action['active']; - }); + $action['hasActions'] = (bool)array_filter($action['actions'], fn(array $action): mixed => $action['active']); } if (isset($graphActions[$ident])) { @@ -321,7 +316,7 @@ protected function parseAsGraphActions(array $actions) } } - usort($graphActions, [ 'Charcoal\Admin\Support\Sorter', 'sortByPriority' ]); + usort($graphActions, \Charcoal\Admin\Support\Sorter::sortByPriority(...)); while (($first = reset($graphActions)) && $first['isSeparator']) { array_shift($graphActions); diff --git a/packages/admin/src/Charcoal/Admin/Widget/Graph/AbstractTimeGraphWidget.php b/packages/admin/src/Charcoal/Admin/Widget/Graph/AbstractTimeGraphWidget.php index 6693057f3..26c86bad7 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/Graph/AbstractTimeGraphWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/Graph/AbstractTimeGraphWidget.php @@ -27,30 +27,16 @@ abstract class AbstractTimeGraphWidget extends AbstractGraphWidget implements Ti /** * The date grouping type can be "hour", "day" or "month". - * - * @var string $groupingType */ - private $groupingType; + private ?string $groupingType = null; - /** - * @var string $dateFirnat - */ - private $dateFormat; + private ?string $dateFormat = null; - /** - * @var string $sqlDateFormat - */ - private $sqlDateFormat; + private ?string $sqlDateFormat = null; - /** - * @var DateTimeInterface $startDate - */ - private $startDate; + private ?\DateTimeInterface $startDate = null; - /** - * @var DateTimeInterface $endDate - */ - private $endDate; + private ?\DateTimeInterface $endDate = null; /** * @var DateInterval $dateInterval @@ -150,7 +136,7 @@ public function setStartDate($ts) throw new InvalidArgumentException(sprintf( 'Invalid start date: %s', $e->getMessage() - ), $e); + ), $e, $e); } } if (!($ts instanceof DateTimeInterface)) { @@ -184,7 +170,7 @@ public function setEndDate($ts) throw new InvalidArgumentException(sprintf( 'Invalid end date: %s', $e->getMessage() - ), $e); + ), $e, $e); } } if (!($ts instanceof DateTimeInterface)) { diff --git a/packages/admin/src/Charcoal/Admin/Widget/Graph/GraphWidgetInterface.php b/packages/admin/src/Charcoal/Admin/Widget/Graph/GraphWidgetInterface.php index 143d3935f..7b96d5de1 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/Graph/GraphWidgetInterface.php +++ b/packages/admin/src/Charcoal/Admin/Widget/Graph/GraphWidgetInterface.php @@ -1,5 +1,7 @@ showAsCard = !!$show; + $this->showAsCard = (bool)$show; return $this; } @@ -71,9 +71,8 @@ public function getShowAsCard() * Set the input options. * * @param array $options Optional property input settings. - * @return self */ - public function setGraphOptions(array $options) + public function setGraphOptions(array $options): static { $this->graphOptions = array_merge($this->getDefaultGraphOptions(), $options); @@ -91,11 +90,7 @@ public function getGraphOption($key, $default = null) { $options = $this->getGraphOptions(); - if (isset($options[$key])) { - return $options[$key]; - } - - return $default; + return ($options[$key] ?? $default); } /** @@ -114,20 +109,17 @@ public function getGraphOptions() /** * Retrieve the default display options. - * - * @return array */ - public function getDefaultGraphOptions() + public function getDefaultGraphOptions(): array { return []; } /** * Retrieve the widget's data options for JavaScript components. - * - * @return array */ - public function widgetDataForJs() + #[\Override] + public function widgetDataForJs(): array { return [ 'graph_options' => $this->getGraphOptions(), diff --git a/packages/admin/src/Charcoal/Admin/Widget/GridStackDashboardWidget.php b/packages/admin/src/Charcoal/Admin/Widget/GridStackDashboardWidget.php index 76ad80e89..cf0fb78ed 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/GridStackDashboardWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/GridStackDashboardWidget.php @@ -41,6 +41,7 @@ class GridStackDashboardWidget extends AdminWidget implements * @param Container $container The DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -55,49 +56,46 @@ protected function setDependencies(Container $container) * @param callable $widgetCallback A callback applied to each widget. * @return UiItemInterface[]|\Generator */ - public function widgets(callable $widgetCallback = null) + public function widgets(?callable $widgetCallback = null) { $widgets = $this->widgets; $gridStack = $this->gridStack() ?: []; $parsedGridStack = []; - array_walk($gridStack, function ($item) use (&$parsedGridStack) { + array_walk($gridStack, function (array $item) use (&$parsedGridStack): void { $parsedGridStack[$item['id']] = $item; }); // Load gridStack from user preferences $user = $this->adminUser(); - $userGridStack = json_decode($user->preferences(), true)['grid_stack'] ?: []; + $userGridStack = json_decode((string)$user->preferences(), true)['grid_stack'] ?: []; $parsedUserGridStack = []; - array_walk($userGridStack, function ($item) use (&$parsedUserGridStack) { + array_walk($userGridStack, function (array $item) use (&$parsedUserGridStack): void { $parsedUserGridStack[$item['id']] = $item; }); - $widgetCallback = isset($widgetCallback) ? $widgetCallback : $this->widgetCallback; + $widgetCallback ??= $this->widgetCallback; foreach ($widgets as $widget) { if (isset($widget['permissions']) && $this instanceof AuthAwareInterface) { $widget->setActive($this->hasPermissions($widget['permissions'])); } - if (!!count($parsedUserGridStack)) { + if ((bool)count($parsedUserGridStack)) { if (isset($parsedUserGridStack[$widget->ident()])) { $widget->setData([ 'grid_stack' => $parsedUserGridStack[$widget->ident()] ]); } - } else { - if (isset($parsedGridStack[$widget->ident()])) { - $gridStack = array_replace_recursive( - $parsedGridStack[$widget->ident()], - $widget['grid_stack'] ?: [] - ); - - $widget->setData([ - 'grid_stack' => $gridStack - ]); - } + } elseif (isset($parsedGridStack[$widget->ident()])) { + $gridStack = array_replace_recursive( + $parsedGridStack[$widget->ident()], + $widget['grid_stack'] ?: [] + ); + $widget->setData([ + 'grid_stack' => $gridStack + ]); } $gridStackDeco = new GridStackWidgetDecorator($widget); @@ -126,9 +124,8 @@ public function gridStack() /** * @param mixed $gridStack GridStack for AdvancedDashboardWidget. - * @return self */ - public function setGridStack($gridStack) + public function setGridStack($gridStack): static { $this->gridStack = $gridStack; @@ -157,7 +154,7 @@ public function adminUser() * @param LayoutBuilder $builder The layout builder, to create customized layout object(s). * @return \Charcoal\Ui\Layout\DashboardInterface Chainable */ - public function setLayoutBuilder(LayoutBuilder $builder) + public function setLayoutBuilder(LayoutBuilder $builder): null { return null; } @@ -166,7 +163,7 @@ public function setLayoutBuilder(LayoutBuilder $builder) * @param LayoutInterface|array $layout The layout object or structure. * @return \Charcoal\Ui\Layout\DashboardInterface Chainable */ - public function setLayout($layout) + public function setLayout($layout): null { return null; } @@ -174,7 +171,7 @@ public function setLayout($layout) /** * @return LayoutInterface */ - public function layout() + public function layout(): null { return null; } diff --git a/packages/admin/src/Charcoal/Admin/Widget/HierarchicalTableWidget.php b/packages/admin/src/Charcoal/Admin/Widget/HierarchicalTableWidget.php index f8e6ba872..c5d0933c0 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/HierarchicalTableWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/HierarchicalTableWidget.php @@ -19,10 +19,9 @@ class HierarchicalTableWidget extends TableWidget { /** * Provide a template to fullfill UIItem interface. - * - * @return string */ - public function template() + #[\Override] + public function template(): string { return 'charcoal/admin/widget/table'; } @@ -36,10 +35,11 @@ public function template() * @param PropertyInterface $property The current property. * @return void */ + #[\Override] protected function setupDisplayPropertyValue( ModelInterface $object, PropertyInterface $property - ) { + ): void { parent::setupDisplayPropertyValue($object, $property); if ($this->display instanceof HierarchicalDisplay) { @@ -51,9 +51,9 @@ protected function setupDisplayPropertyValue( * Sort the objects before they are displayed as rows. * * @see \Charcoal\Admin\Ui\CollectionContainerTrait::sortObjects() - * @return array */ - public function sortObjects() + #[\Override] + public function sortObjects(): array { $collection = new HierarchicalCollection($this->objects(), false); $collection diff --git a/packages/admin/src/Charcoal/Admin/Widget/LayoutWidget.php b/packages/admin/src/Charcoal/Admin/Widget/LayoutWidget.php index ad496119b..198bda638 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/LayoutWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/LayoutWidget.php @@ -1,5 +1,7 @@ null, @@ -89,9 +77,8 @@ public function widgetDataForJs() * * @param string|null $key The latitude property ident. * @throws InvalidArgumentException If the property key is not a string. - * @return self */ - public function setLatProperty($key) + public function setLatProperty($key): static { if ($key === null) { $this->latProperty = $key; @@ -110,10 +97,8 @@ public function setLatProperty($key) /** * Retrieve the $obj property key for the latitude. - * - * @return string|null */ - public function latProperty() + public function latProperty(): ?string { return $this->latProperty; } @@ -123,9 +108,8 @@ public function latProperty() * * @param string|null $key The longitude property key. * @throws InvalidArgumentException If the property key is not a string. - * @return self */ - public function setLngProperty($key) + public function setLngProperty($key): static { if ($key === null) { $this->lngProperty = $key; @@ -145,11 +129,10 @@ public function setLngProperty($key) /** * Set the $obj property key for the longitude. * - * @deprecated In favour of {@see self::setLngProperty()}. * @param string $key The longitude property key. - * @return self */ - public function setLonProperty($key) + #[\Deprecated(message: 'In favour of {@see self::setLngProperty()}.')] + public function setLonProperty($key): static { $this->logger->warning( 'MapWidget "lon_property" is deprecated. Use "lng_property".', @@ -161,10 +144,8 @@ public function setLonProperty($key) /** * Retrieve the $obj property key for the longitude. - * - * @return string|null */ - public function lngProperty() + public function lngProperty(): ?string { return $this->lngProperty; } @@ -174,9 +155,8 @@ public function lngProperty() * * @param float $coord The latitude of a location. * @throws InvalidArgumentException If the longitude is not a number. - * @return self */ - public function setLat($coord) + public function setLat($coord): static { if ($coord === null) { $this->lat = $coord; @@ -217,9 +197,8 @@ public function lat() * * @param float $coord The longitude of a location. * @throws InvalidArgumentException If the longitude is not a number. - * @return self */ - public function setLng($coord) + public function setLng($coord): static { if ($coord === null) { $this->lng = $coord; @@ -258,9 +237,9 @@ public function lng() /** * Set the $obj property key for the longitude. * - * @deprecated In favour of {@see self::lng()}. * @return self */ + #[\Deprecated(message: 'In favour of {@see self::lng()}.')] public function lon() { $this->logger->warning( @@ -275,7 +254,7 @@ public function lon() * * @return float[]|null */ - public function latLng() + public function latLng(): ?array { $lat = $this->lat(); $lng = $this->lng(); @@ -292,7 +271,7 @@ public function latLng() * * @return float[]|null */ - public function coords() + public function coords(): ?array { $lat = $this->lat(); $lng = $this->lng(); @@ -314,7 +293,7 @@ public function hasObj() if ($this->obj === null) { try { $this->obj(); - } catch (InvalidArgumentException $e) { + } catch (InvalidArgumentException) { return false; } } @@ -331,8 +310,8 @@ public function hasObj() public function obj() { if ($this->obj === null) { - $objId = filter_input(INPUT_GET, 'obj_id', FILTER_SANITIZE_STRING); - $objType = filter_input(INPUT_GET, 'obj_type', FILTER_SANITIZE_STRING); + $objId = htmlspecialchars(trim(($_GET['obj_id'] ?? '')), ENT_QUOTES, 'UTF-8'); + $objType = htmlspecialchars(trim(($_GET['obj_type'] ?? '')), ENT_QUOTES, 'UTF-8'); if ($objId && $objType) { $obj = $this->modelFactory()->create($objType); $obj->load($objId); diff --git a/packages/admin/src/Charcoal/Admin/Widget/ObjectFormWidget.php b/packages/admin/src/Charcoal/Admin/Widget/ObjectFormWidget.php index a76dd8068..9ae33675a 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/ObjectFormWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/ObjectFormWidget.php @@ -29,6 +29,11 @@ class ObjectFormWidget extends FormWidget implements { use ObjectContainerTrait; + /** + * @var mixed + */ + public $nextUrl; + /** * @var string */ @@ -54,10 +59,7 @@ class ObjectFormWidget extends FormWidget implements */ protected $forcePageReload = false; - /** - * @return string - */ - public function widgetType() + public function widgetType(): string { return 'charcoal/admin/widget/object-form'; } @@ -67,7 +69,8 @@ public function widgetType() * * @return Translation|string|null */ - public function defaultSubmitLabel() + #[\Override] + public function defaultSubmitLabel(): ?\Charcoal\Translator\Translation { if ($this->objId()) { return $this->translator()->translation('Update'); @@ -80,7 +83,8 @@ public function defaultSubmitLabel() * @param array $data The widget data. * @return ObjectFormWidget Chainable */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -99,7 +103,7 @@ public function setData(array $data) * @throws InvalidArgumentException If the identifier is not a string. * @return ObjectForm Chainable */ - public function setFormIdent($formIdent) + public function setFormIdent($formIdent): static { if (!is_string($formIdent)) { throw new InvalidArgumentException( @@ -147,7 +151,7 @@ public function formIdent() * @throws InvalidArgumentException If argument is not a string. * @return ActionInterface Chainable */ - public function setNextUrl($url) + public function setNextUrl($url): static { if (!is_string($url)) { throw new InvalidArgumentException( @@ -174,9 +178,8 @@ public function allowReload() /** * @param boolean $allowReload AllowReload for ObjectFormWidget. - * @return self */ - public function setAllowReload($allowReload) + public function setAllowReload($allowReload): static { $this->allowReload = $allowReload; @@ -193,9 +196,8 @@ public function forcePageReload() /** * @param boolean $forcePageReload ForcePageReload for ObjectFormWidget. - * @return self */ - public function setForcePageReload($forcePageReload) + public function setForcePageReload($forcePageReload): static { $this->forcePageReload = $forcePageReload; @@ -207,6 +209,7 @@ public function setForcePageReload($forcePageReload) * * @return string Relative URL */ + #[\Override] public function action() { $action = parent::action(); @@ -230,14 +233,15 @@ public function action() * @throws UnexpectedValueException If a property data is invalid. * @return FormPropertyWidget[]|\Generator */ - public function formProperties(array $group = null) + #[\Override] + public function formProperties(?array $group = null) { $obj = $this->obj(); $props = $obj->metadata()->properties(); // We need to sort form properties by form group property order if a group exists - if (!empty($group)) { - $group = array_map([ $this, 'camelize' ], $group); + if ($group !== null && $group !== []) { + $group = array_map($this->camelize(...), $group); $group = array_flip($group); $props = array_intersect_key($props, $group); $props = array_merge($group, $props); @@ -253,7 +257,7 @@ public function formProperties(array $group = null) throw new UnexpectedValueException(sprintf( 'Invalid property data for "%1$s", received %2$s', $propertyIdent, - (is_object($propertyMetadata) ? get_class($propertyMetadata) : gettype($propertyMetadata)) + (get_debug_type($propertyMetadata)) )); } @@ -293,13 +297,11 @@ public function formProperty($propertyIdent) throw new UnexpectedValueException(sprintf( 'Invalid property data for "%1$s", received %2$s', $propertyIdent, - (is_object($propertyMetadata) ? get_class($propertyMetadata) : gettype($propertyMetadata)) + (get_debug_type($propertyMetadata)) )); } - $p = $this->getOrCreateFormProperty($propertyIdent, $propertyMetadata); - - return $p; + return $this->getOrCreateFormProperty($propertyIdent, $propertyMetadata); } /** @@ -311,19 +313,14 @@ public function formProperty($propertyIdent) * @param array $data Data. * @return ObjectFormWidget Chainable. */ - public function setFormData(array $data) + #[\Override] + public function setFormData(array $data): static { $objData = $this->objData(); $merged = array_replace_recursive($objData, $data); // Remove null values - $merged = array_filter($merged, function ($val) { - if ($val === null) { - return false; - } - - return true; - }); + $merged = array_filter($merged, fn($val): bool => $val !== null); $this->formData = $merged; $this->obj()->setData($merged); @@ -336,6 +333,7 @@ public function setFormData(array $data) * * @return array */ + #[\Override] public function formData() { if (!$this->formData) { @@ -356,10 +354,9 @@ public function objData() /** * Retrieve the widget's data options for JavaScript components. - * - * @return array */ - public function widgetDataForJs() + #[\Override] + public function widgetDataForJs(): array { return [ 'obj_id' => $this->objId(), @@ -378,9 +375,8 @@ public function widgetDataForJs() * Self recursive when a groups is an instance of FormInterface. * * @param array|null $groups Form groups to parse. - * @return array */ - protected function groupsConditionalLogic(array $groups = null) + protected function groupsConditionalLogic(?array $groups = null): array { if (!$groups) { $groups = iterator_to_array($this->groups()); @@ -391,7 +387,7 @@ protected function groupsConditionalLogic(array $groups = null) foreach ($groups as $group) { if ($group instanceof FormInterface) { $groupGroups = iterator_to_array($group->groups()); - if (!empty($groupGroups)) { + if ($groupGroups !== []) { $conditions = array_merge( $conditions, $this->groupsConditionalLogic($groupGroups) @@ -411,6 +407,7 @@ protected function groupsConditionalLogic(array $groups = null) * @param Container $container The DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -424,17 +421,17 @@ protected function setDependencies(Container $container) * * @return string[] */ - protected function defaultDataSources() + #[\Override] + protected function defaultDataSources(): array { return [static::DATA_SOURCE_REQUEST, static::DATA_SOURCE_OBJECT]; } /** * Retrieve the default data source filters (when setting data on an entity). - * - * @return array */ - protected function defaultDataSourceFilters() + #[\Override] + protected function defaultDataSourceFilters(): array { return [ 'request' => null, @@ -451,6 +448,7 @@ protected function defaultDataSourceFilters() * @param mixed $toResolve A callable used when merging data. * @return callable|null */ + #[\Override] protected function resolveDataSourceFilter($toResolve) { if (is_string($toResolve)) { @@ -477,10 +475,9 @@ protected function resolveDataSourceFilter($toResolve) /** * Retrieve the accepted metadata from the current request. - * - * @return array */ - protected function acceptedRequestData() + #[\Override] + protected function acceptedRequestData(): array { return array_merge([ 'obj_type', @@ -498,7 +495,7 @@ protected function dataFromObject() { $obj = $this->obj(); $objMetadata = $obj->metadata(); - $adminMetadata = (isset($objMetadata['admin']) ? $objMetadata['admin'] : null); + $adminMetadata = ($objMetadata['admin'] ?? null); $formIdent = $this->formIdent(); if (!$formIdent) { @@ -509,11 +506,7 @@ protected function dataFromObject() $formIdent = $obj->render($formIdent); } - if (isset($adminMetadata['forms'][$formIdent])) { - $objFormData = $adminMetadata['forms'][$formIdent]; - } else { - $objFormData = []; - } + $objFormData = ($adminMetadata['forms'][$formIdent] ?? []); $formGroups = []; @@ -525,7 +518,7 @@ protected function dataFromObject() $formGroups = array_merge($formGroups, $adminMetadata['formGroups']); } - if (isset($objFormData['groups']) && !empty($formGroups)) { + if (isset($objFormData['groups']) && $formGroups !== []) { $extraFormGroups = array_intersect( array_keys($formGroups), array_keys($objFormData['groups']) @@ -548,7 +541,7 @@ protected function dataFromObject() $formSidebars = array_merge($formSidebars, $adminMetadata['formSidebars']); } - if (isset($objFormData['sidebars']) && !empty($formSidebars)) { + if (isset($objFormData['sidebars']) && $formSidebars !== []) { $extraFormSidebars = array_intersect( array_keys($formSidebars), array_keys($objFormData['sidebars']) @@ -566,9 +559,8 @@ protected function dataFromObject() /** * Whether a language switcher could be displayed. - * - * @return bool */ + #[\Override] public function supportsLanguageSwitch(): bool { if ($this->validateObjType()) { @@ -593,10 +585,9 @@ public function supportsLanguageSwitch(): bool /** * Determine if the form has any multilingual properties. - * - * @return boolean */ - public function hasL10nFormProperties() + #[\Override] + public function hasL10nFormProperties(): bool { if ($this->validateObjType()) { $locales = count($this->translator()->availableLocales()); @@ -616,11 +607,8 @@ public function hasL10nFormProperties() /** * Determine if the group has any multilingual properties. - * - * @param FormGroupInterface $group - * @return bool */ - protected function hasL10nGroupProperties(FormGroupInterface $group) + protected function hasL10nGroupProperties(FormGroupInterface $group): bool { if ($group instanceof AdminFormGroupInterface) { foreach ($group->groupProperties() as $prop) { @@ -635,10 +623,6 @@ protected function hasL10nGroupProperties(FormGroupInterface $group) /** * Determine if the model property is multilingual. - * - * @param ModelInterface $model - * @param string $propertyIdent - * @return ?bool */ protected function isL10nModelProperty(ModelInterface $model, string $propertyIdent): ?bool { @@ -667,6 +651,7 @@ protected function isL10nModelProperty(ModelInterface $model, string $propertyId * @throws InvalidArgumentException If the identifier is not a string or the group is invalid. * @return FormGroupInterface */ + #[\Override] protected function parseFormGroup($groupIdent, $group) { $group = parent::parseFormGroup($groupIdent, $group); @@ -680,10 +665,8 @@ protected function parseFormGroup($groupIdent, $group) /** * Yield the form's property controls. - * - * @return array */ - public function parseFormProperties() + public function parseFormProperties(): array { $props = []; foreach ($this->formProperties as $k => $v) { @@ -699,13 +682,10 @@ public function parseFormProperties() * @param array|null $data Optional. The form group data to set. * @return FormGroupInterface */ - protected function createFormGroup(array $data = null) + #[\Override] + protected function createFormGroup(?array $data = null) { - if (isset($data['type'])) { - $type = $data['type']; - } else { - $type = $this->defaultGroupType(); - } + $type = ($data['type'] ?? $this->defaultGroupType()); $group = $this->formGroupFactory()->create($type); $group->setForm($this->formWidget()); @@ -734,13 +714,13 @@ protected function createFormGroup(array $data = null) * @param FormGroupInterface $group The form group to update. * @param array|null $groupData Optional. The new group data to apply. * @param string|null $groupIdent Optional. The new group identifier. - * @return FormGroupInterface */ + #[\Override] protected function updateFormGroup( FormGroupInterface $group, - array $groupData = null, + ?array $groupData = null, $groupIdent = null - ) { + ): FormGroupInterface { $group->setForm($this); if ($groupIdent !== null) { diff --git a/packages/admin/src/Charcoal/Admin/Widget/ObjectRevisionsWidget.php b/packages/admin/src/Charcoal/Admin/Widget/ObjectRevisionsWidget.php index cb482ded4..d5239e223 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/ObjectRevisionsWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/ObjectRevisionsWidget.php @@ -1,5 +1,7 @@ objType() && $this->objId(); } @@ -45,9 +45,8 @@ public function objType() /** * @param string $objType ObjType for ObjectRevisionsWidget. - * @return self */ - public function setObjType($objType) + public function setObjType($objType): static { $this->objType = $objType; @@ -64,9 +63,8 @@ public function objId() /** * @param string|integer $objId ObjId for ObjectRevisionsWidget. - * @return self */ - public function setObjId($objId) + public function setObjId($objId): static { $this->objId = $objId; @@ -78,7 +76,8 @@ public function setObjId($objId) * * @return string[] */ - protected function defaultDataSources() + #[\Override] + protected function defaultDataSources(): array { return [ static::DATA_SOURCE_REQUEST, @@ -88,15 +87,9 @@ protected function defaultDataSources() /** * Retrieve the accepted metadata from the current request. - * - * @return array */ - protected function acceptedRequestData() + protected function acceptedRequestData(): array { - return array_merge([ - 'obj_type', - 'obj_id', - 'template', - ]); + return ['obj_type', 'obj_id', 'template']; } } diff --git a/packages/admin/src/Charcoal/Admin/Widget/PaginationWidget.php b/packages/admin/src/Charcoal/Admin/Widget/PaginationWidget.php index b72ce6473..bb08a46a7 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/PaginationWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/PaginationWidget.php @@ -21,17 +21,13 @@ class PaginationWidget extends AdminWidget /** * The pager object. - * - * @var PaginationInterface */ - private $pager; + private ?\Charcoal\Source\Pagination $pager = null; /** * The total number of items. - * - * @var integer */ - private $numTotal; + private ?int $numTotal = null; /** * @var integer @@ -43,9 +39,9 @@ class PaginationWidget extends AdminWidget * * @return PaginationInterface */ - protected function pager() + protected function pager(): \Charcoal\Source\Pagination { - if ($this->pager === null) { + if (!$this->pager instanceof \Charcoal\Source\Pagination) { $this->pager = $this->createPagination(); } @@ -57,19 +53,17 @@ protected function pager() * * @return PaginationInterface */ - protected function createPagination() + protected function createPagination(): \Charcoal\Source\Pagination { - $pagination = new Pagination(); - return $pagination; + return new Pagination(); } /** * Set the page number. * * @param integer $page The current page. Pages should start at 1. - * @return self */ - public function setPage($page) + public function setPage($page): static { $this->pager()->setPage($page); @@ -88,20 +82,16 @@ public function page() /** * Retrieve the previous page number. - * - * @return integer */ - public function pagePrev() + public function pagePrev(): int { return max(1, ($this->page() - 1)); } /** * Retrieve the next page number. - * - * @return integer */ - public function pageNext() + public function pageNext(): int { return min($this->numPages(), ($this->page() + 1)); } @@ -111,9 +101,8 @@ public function pageNext() * * @param integer $count The number of results to return, per page. * Use 0 to request all results. - * @return self */ - public function setNumPerPage($count) + public function setNumPerPage($count): static { $this->pager()->setNumPerPage($count); @@ -135,7 +124,7 @@ public function numPerPage() * * @return integer */ - public function numTotal() + public function numTotal(): ?int { return $this->numTotal; } @@ -145,9 +134,8 @@ public function numTotal() * * @param integer $total The total number of items. * @throws InvalidArgumentException If the argument is not a number or lower than 0. - * @return self */ - public function setNumTotal($total) + public function setNumTotal($total): static { if (!is_numeric($total)) { throw new InvalidArgumentException( @@ -167,10 +155,7 @@ public function setNumTotal($total) return $this; } - /** - * @return array - */ - public function pages() + public function pages(): array { if ($this->quickJumpEnabled()) { return $this->buildQuickJumpForm(); @@ -189,12 +174,8 @@ public function pages() return $out; } - /** - * @return array - */ - private function buildQuickJumpForm() + private function buildQuickJumpForm(): array { - $out = []; $i = 1; $numPages = $this->numPages(); $maxPageCount = $this->maxPageCount(); @@ -253,16 +234,13 @@ private function buildQuickJumpForm() } } - $out = array_merge($left, $middle, $right); - - return $out; + return array_merge($left, $middle, $right); } /** * @param integer $page The page index. - * @return array */ - private function formatPage($page) + private function formatPage($page): array { return [ 'separator' => false, @@ -276,7 +254,7 @@ private function formatPage($page) * * @return integer */ - public function numPages() + public function numPages(): int|float { if ($this->numPerPage() == 0) { return 1; @@ -295,9 +273,8 @@ public function maxPageCount() /** * @param integer $maxPageCount The maximum number of page to display in pager at the same time. - * @return PaginationWidget */ - public function setMaxPageCount($maxPageCount) + public function setMaxPageCount($maxPageCount): static { $this->maxPageCount = $maxPageCount; @@ -307,40 +284,32 @@ public function setMaxPageCount($maxPageCount) /** * Determine if pagination can be displayed. - * - * @return boolean */ - public function showPagination() + public function showPagination(): bool { return ($this->numPages() > 1); } /** * Determine if the "previous page" link can be displayed. - * - * @return boolean */ - public function previousEnabled() + public function previousEnabled(): bool { return ($this->page() > 1); } /** * Determine if the "next page" link can be displayed. - * - * @return boolean */ - public function nextEnabled() + public function nextEnabled(): bool { return ($this->page() < $this->numPages()); } /** * His the quick jump input allowed? - * - * @return boolean */ - public function quickJumpEnabled() + public function quickJumpEnabled(): bool { return ($this->numPages() > $this->maxPageCount()); } diff --git a/packages/admin/src/Charcoal/Admin/Widget/QuickFormWidget.php b/packages/admin/src/Charcoal/Admin/Widget/QuickFormWidget.php index 8db61685b..c6cfaa9ed 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/QuickFormWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/QuickFormWidget.php @@ -1,5 +1,7 @@ obj()->metadata(); @@ -60,7 +63,7 @@ public function formIdentFallback() if (isset($this->formData()['form_ident'])) { $ident = $this->formData()['form_ident']; - if (is_string($ident) && !empty($ident)) { + if (is_string($ident) && ($ident !== '' && $ident !== '0')) { return $ident; } } @@ -70,10 +73,9 @@ public function formIdentFallback() /** * Retrieve the widget's data options for JavaScript components. - * - * @return array */ - public function widgetDataForJs() + #[\Override] + public function widgetDataForJs(): array { return array_merge_recursive( parent::widgetDataForJs(), @@ -89,6 +91,7 @@ public function widgetDataForJs() * * @return \Charcoal\Translator\Translation|string|null */ + #[\Override] public function submitLabel() { if (isset($this->formData()['submit_label'])) { @@ -101,37 +104,30 @@ public function submitLabel() /** * @see HasLanguageSwitcherTrait::showLanguageSwitch() - * @return boolean */ - protected function resolveShowLanguageSwitch() + protected function resolveShowLanguageSwitch(): bool { return $this->supportsLanguageSwitch(); } /** * Determine if content groups are to be displayed as languages tabbable panes. - * - * @return boolean */ - public function isDisplayModeLang() + public function isDisplayModeLang(): bool { return ($this->groupDisplayMode() === self::DISPLAY_MODE_LANG); } /** * Determine if content groups are to be displayed as tabbable panes. - * - * @return boolean */ - public function isTabbable() + #[\Override] + public function isTabbable(): bool { return in_array($this->groupDisplayMode(), $this->getTabbableDisplayModes()); } - /** - * @return array - */ - public function getTabbableDisplayModes() + public function getTabbableDisplayModes(): array { return [ self::DISPLAY_MODE_TAB, @@ -147,16 +143,14 @@ public function availableLanguagesAsJson() $options = (JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); if ($this->debug()) { - $options = ($options | JSON_PRETTY_PRINT); + $options |= JSON_PRETTY_PRINT; } return json_encode($this->languages(), $options); } - /** - * @return string - */ - public function defaultFormTabsTemplate() + #[\Override] + public function defaultFormTabsTemplate(): string { return 'charcoal/admin/template/form/nav-tabs'; } diff --git a/packages/admin/src/Charcoal/Admin/Widget/SearchWidget.php b/packages/admin/src/Charcoal/Admin/Widget/SearchWidget.php index dacdb82bc..d8b495792 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/SearchWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/SearchWidget.php @@ -26,9 +26,9 @@ class SearchWidget extends AdminWidget implements CollectionContainerInterface /** * @param array $data The search widget data. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { if (isset($data['obj_type'])) { $this->setObjType($data['obj_type']); @@ -51,10 +51,10 @@ public function dataFromObject() { $obj = $this->proto(); $metadata = $obj->metadata(); - $adminMetadata = isset($metadata['admin']) ? $metadata['admin'] : null; + $adminMetadata = ($metadata['admin'] ?? null); $collectionIdent = $this->collectionIdent(); if (!$collectionIdent) { - $collectionIdent = isset($adminMetadata['default_list']) ? $adminMetadata['default_list'] : ''; + $collectionIdent = ($adminMetadata['default_list'] ?? ''); } if (isset($adminMetadata['lists'][$collectionIdent])) { @@ -80,7 +80,7 @@ public function properties() $collectionIdent = $this->collectionIdent(); if ($collectionIdent) { $metadata = $model->metadata(); - $adminMetadata = isset($metadata['admin']) ? $metadata['admin'] : null; + $adminMetadata = ($metadata['admin'] ?? null); if (isset($adminMetadata['lists'][$collectionIdent]['properties'])) { // Flipping to have property ident as key @@ -119,10 +119,9 @@ public function propertiesIdents() /** * Retrieve the widget's data options for JavaScript components. - * - * @return array */ - public function widgetDataForJs() + #[\Override] + public function widgetDataForJs(): array { return [ 'obj_type' => $this->objType(), diff --git a/packages/admin/src/Charcoal/Admin/Widget/SecondaryMenuWidget.php b/packages/admin/src/Charcoal/Admin/Widget/SecondaryMenuWidget.php index 96dc4bc25..3364d4576 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/SecondaryMenuWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/SecondaryMenuWidget.php @@ -27,6 +27,8 @@ class SecondaryMenuWidget extends AdminWidget implements use ActionContainerTrait; use HttpAwareTrait; + public $isCurrent; + /** * Default sorting priority for an action. * @@ -71,31 +73,23 @@ class SecondaryMenuWidget extends AdminWidget implements /** * Whether the group is collapsed or not. - * - * @var boolean */ - private $collapsed = false; + private bool $collapsed = false; /** * Whether the group has siblings or not. - * - * @var boolean */ - private $parented = false; + private bool $parented = false; /** * The title is displayed by default. - * - * @var boolean */ - private $showTitle = true; + private bool $showTitle = true; /** * The description is displayed by default. - * - * @var boolean */ - private $showDescription = true; + private bool $showDescription = true; /** * The currently highlighted item. @@ -148,9 +142,9 @@ class SecondaryMenuWidget extends AdminWidget implements /** * @param array $data Class data. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { if (isset($data['actions'])) { @@ -242,9 +236,8 @@ public function adminRoute() /** * @param string $ident The ident for the current item to highlight. - * @return self */ - public function setCurrentItem($ident) + public function setCurrentItem($ident): static { $this->currentItem = $ident; return $this; @@ -262,9 +255,8 @@ public function currentItem() * Computes the intersection of values to determine if the link is the current item. * * @param mixed $linkIdent The link's value(s) to check. - * @return boolean */ - public function isCurrentItem($linkIdent) + public function isCurrentItem($linkIdent): bool { $context = array_filter([ $this->currentItem(), @@ -274,7 +266,7 @@ public function isCurrentItem($linkIdent) $matches = array_intersect((array)$linkIdent, $context); - return !!$matches; + return (bool)$matches; } /** @@ -291,11 +283,10 @@ public function objType() * Show/hide the widget's title. * * @param boolean $show Show (TRUE) or hide (FALSE) the title. - * @return self */ - public function setShowTitle($show) + public function setShowTitle($show): static { - $this->showTitle = !!$show; + $this->showTitle = (bool)$show; return $this; } @@ -310,7 +301,7 @@ public function showTitle() if ($this->showTitle === false) { return false; } else { - return !!$this->title(); + return (bool)$this->title(); } } @@ -318,9 +309,8 @@ public function showTitle() * Set the title of the secondary menu. * * @param mixed $title A title for the secondary menu. - * @return self */ - public function setTitle($title) + public function setTitle($title): static { $this->title = $this->translator()->translation($title); @@ -352,9 +342,8 @@ public function title() * Set the secondary menu links. * * @param array $links A collection of link objects. - * @return self */ - public function setLinks(array $links) + public function setLinks(array $links): static { $this->links = new ArrayIterator(); @@ -371,9 +360,8 @@ public function setLinks(array $links) * @param string $linkIdent The link identifier. * @param array|object $link The link object or structure. * @throws InvalidArgumentException If the link is invalid. - * @return self */ - public function addLink($linkIdent, $link) + public function addLink($linkIdent, $link): static { if (!is_string($linkIdent) && !is_numeric($linkIdent)) { throw new InvalidArgumentException( @@ -394,7 +382,7 @@ public function addLink($linkIdent, $link) } if (isset($link['active'])) { - $active = !!$link['active']; + $active = (bool)$link['active']; } if (isset($link['name'])) { @@ -423,7 +411,7 @@ public function addLink($linkIdent, $link) } else { throw new InvalidArgumentException(sprintf( 'Link must be an associative array, received %s', - (is_object($link) ? get_class($link) : gettype($link)) + (get_debug_type($link)) )); } @@ -463,10 +451,8 @@ public function links() unset($link['required_acl_permissions']); } - if (isset($link['permissions'])) { - if ($this->hasPermissions($link['permissions']) === false) { - continue; - } + if (isset($link['permissions']) && $this->hasPermissions($link['permissions']) === false) { + continue; } $out[] = $link; @@ -481,9 +467,8 @@ public function links() * * @param mixed $type The display type. * @throws InvalidArgumentException If the display type is invalid. - * @return self */ - public function setDisplayType($type) + public function setDisplayType($type): static { if (!is_string($type)) { throw new InvalidArgumentException('The display type must be a string.'); @@ -517,20 +502,16 @@ public function displayType() /** * Determine if the secondary menu groups should be displayed as panels. - * - * @return boolean */ - public function displayAsPanel() + public function displayAsPanel(): bool { return in_array($this->displayType(), [ 'panel', 'collapsible' ]); } /** * Determine if the display type is "collapsible". - * - * @return boolean */ - public function collapsible() + public function collapsible(): bool { return ($this->displayType() === 'collapsible'); } @@ -540,9 +521,8 @@ public function collapsible() * * @param array $options Display configuration. * @throws InvalidArgumentException If the display options are not an associative array. - * @return self */ - public function setDisplayOptions(array $options) + public function setDisplayOptions(array $options): static { $this->displayOptions = array_replace($this->defaultDisplayOptions(), $options); @@ -579,10 +559,8 @@ public function displayOptions() /** * Retrieve the default display options for the secondary menu. - * - * @return array */ - public function defaultDisplayOptions() + public function defaultDisplayOptions(): array { return [ 'parented' => false, @@ -618,9 +596,8 @@ public function collapsed() * Set the secondary menu's groups. * * @param array $groups A collection of group structures. - * @return self */ - public function setGroups(array $groups) + public function setGroups(array $groups): static { $this->groups = []; @@ -628,12 +605,10 @@ public function setGroups(array $groups) $this->addGroup($groupIdent, $group); } - uasort($this->groups, [ 'Charcoal\Admin\Support\Sorter', 'sortByPriority' ]); + uasort($this->groups, \Charcoal\Admin\Support\Sorter::sortByPriority(...)); // Remove items that are not active and reset keys. - $this->groups = array_values(array_filter($this->groups, function ($item) { - return ($item->active()); - })); + $this->groups = array_values(array_filter($this->groups, fn($item) => $item->active())); return $this; } @@ -644,9 +619,8 @@ public function setGroups(array $groups) * @param string $groupIdent The group identifier. * @param array|SecondaryMenuGroupInterface $group The group object or structure. * @throws InvalidArgumentException If the identifier is not a string or the group is invalid. - * @return self */ - public function addGroup($groupIdent, $group) + public function addGroup($groupIdent, $group): static { if (!is_string($groupIdent)) { throw new InvalidArgumentException( @@ -695,7 +669,7 @@ public function addGroup($groupIdent, $group) throw new InvalidArgumentException(sprintf( 'Group must be an instance of %s or an array of form group options, received %s', 'SecondaryMenuGroupInterface', - (is_object($group) ? get_class($group) : gettype($group)) + (get_debug_type($group)) )); } @@ -734,36 +708,30 @@ public function groups() /** * Retrieve the default secondary menu group class name. - * - * @return string */ - public function defaultGroupType() + public function defaultGroupType(): string { return 'charcoal/ui/secondary-menu/generic'; } /** * Determine if the secondary menu has any links. - * - * @return boolean */ - public function hasLinks() + public function hasLinks(): bool { - return !!$this->numLinks(); + return (bool)$this->numLinks(); } /** * Count the number of secondary menu links. - * - * @return integer */ - public function numLinks() + public function numLinks(): int { if (!is_array($this->links()) && !($this->links() instanceof \Traversable)) { return 0; } - $links = array_filter($this->links, function ($link) { + $links = array_filter($this->links, function (array $link): bool { if (isset($link['active']) && !$link['active']) { return false; } @@ -772,14 +740,7 @@ public function numLinks() $link['permissions'] = $link['required_acl_permissions']; unset($link['required_acl_permissions']); } - - if (isset($link['permissions'])) { - if ($this->hasPermissions($link['permissions']) === false) { - return false; - } - } - - return true; + return !(isset($link['permissions']) && $this->hasPermissions($link['permissions']) === false); }); return count($links); @@ -787,40 +748,32 @@ public function numLinks() /** * Determine if the secondary menu has any groups of links. - * - * @return boolean */ - public function hasGroups() + public function hasGroups(): bool { - return !!$this->numGroups(); + return (bool)$this->numGroups(); } /** * Count the number of secondary menu groups. - * - * @return integer */ - public function numGroups() + public function numGroups(): int { return count($this->groups()); } /** * Alias for {@see self::showSecondaryMenuActions()} - * - * @return boolean */ - public function hasActions() + public function hasActions(): int { return $this->showSecondaryMenuActions(); } /** * Determine if the secondary menu's actions should be shown. - * - * @return boolean */ - public function showSecondaryMenuActions() + public function showSecondaryMenuActions(): int { $actions = $this->secondaryMenuActions(); @@ -837,11 +790,7 @@ public function secondaryMenuActions() if ($this->secondaryMenuActions === null) { $ident = $this->ident(); $metadata = $this->adminSecondaryMenu(); - if (isset($metadata[$ident]['actions'])) { - $actions = $metadata[$ident]['actions']; - } else { - $actions = []; - } + $actions = ($metadata[$ident]['actions'] ?? []); $this->setSecondaryMenuActions($actions); } @@ -857,9 +806,8 @@ public function secondaryMenuActions() * Set the description of the secondary menu. * * @param mixed $description A description for the secondary menu. - * @return self */ - public function setDescription($description) + public function setDescription($description): static { $this->description = $this->translator()->translation($description); @@ -891,11 +839,10 @@ public function description() * Determine if the description is to be displayed. * * @param boolean $show Show (TRUE) or hide (FALSE) the description. - * @return self */ - public function setShowDescription($show) + public function setShowDescription($show): static { - $this->showDescription = !!$show; + $this->showDescription = (bool)$show; return $this; } @@ -909,14 +856,11 @@ public function showDescription() if ($this->showDescription === false) { return false; } else { - return !!$this->description(); + return (bool)$this->description(); } } - /** - * @return string - */ - public function jsActionPrefix() + public function jsActionPrefix(): string { return 'js-secondary-menu'; } @@ -927,6 +871,7 @@ public function jsActionPrefix() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -951,9 +896,8 @@ public function isCurrent() * Set the widget's display state. * * @param boolean $flag A truthy state. - * @return self */ - protected function setIsCurrent($flag) + protected function setIsCurrent($flag): static { $this->isCurrent = boolval($flag); @@ -968,10 +912,10 @@ protected function setIsCurrent($flag) */ protected function secondaryMenu() { - if (!isset($this->secondaryMenu)) { + if ($this->secondaryMenu === null) { throw new RuntimeException(sprintf( 'Secondary Menu Group Factory is not defined for "%s"', - get_class($this) + static::class )); } @@ -982,9 +926,8 @@ protected function secondaryMenu() * Set the secondary menu's actions. * * @param array $actions One or more actions. - * @return self */ - protected function setSecondaryMenuActions(array $actions) + protected function setSecondaryMenuActions(array $actions): static { $this->parsedSecondaryMenuActions = false; @@ -1003,11 +946,9 @@ protected function setSecondaryMenuActions(array $actions) * @param array $actions Actions to resolve. * @return array Secondary menu actions. */ - protected function createSecondaryMenuActions(array $actions) + protected function createSecondaryMenuActions(array $actions): array { - $secondaryMenuActions = $this->parseActions($actions); - - return $secondaryMenuActions; + return $this->parseActions($actions); } /** @@ -1028,9 +969,8 @@ protected function defaultSecondaryMenuActions() * Set a secondary menu group factory. * * @param FactoryInterface $factory The group factory, to create objects. - * @return void */ - private function setSecondaryMenuGroupFactory(FactoryInterface $factory) + private function setSecondaryMenuGroupFactory(FactoryInterface $factory): void { $this->secondaryMenu = $factory; } diff --git a/packages/admin/src/Charcoal/Admin/Widget/SecondaryMenuWidgetInterface.php b/packages/admin/src/Charcoal/Admin/Widget/SecondaryMenuWidgetInterface.php index cc915305e..8ffa0fe1a 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/SecondaryMenuWidgetInterface.php +++ b/packages/admin/src/Charcoal/Admin/Widget/SecondaryMenuWidgetInterface.php @@ -1,5 +1,7 @@ proto(); $objMetadata = $proto->metadata(); - $adminMetadata = (isset($objMetadata['admin']) ? $objMetadata['admin'] : null); + $adminMetadata = ($objMetadata['admin'] ?? null); if (empty($adminMetadata['lists'])) { return []; @@ -260,11 +250,7 @@ public function dataFromObject() return []; } - if (isset($adminMetadata['lists'][$collectionIdent])) { - $objListData = $adminMetadata['lists'][$collectionIdent]; - } else { - $objListData = []; - } + $objListData = ($adminMetadata['lists'][$collectionIdent] ?? []); $collectionConfig = []; @@ -320,7 +306,7 @@ public function dataFromObject() } } - if ($collectionConfig) { + if ($collectionConfig !== []) { $this->mergeCollectionConfig($collectionConfig); } @@ -329,10 +315,9 @@ public function dataFromObject() /** * Retrieve the widget's data options for JavaScript components. - * - * @return array */ - public function widgetDataForJs() + #[\Override] + public function widgetDataForJs(): array { return [ 'obj_type' => $this->objType(), @@ -376,7 +361,7 @@ public function properties() if ($listProperties) { $props = []; foreach ($listProperties as $k => $v) { - $k = lcfirst(implode('', array_map('ucfirst', explode('_', $k)))); + $k = lcfirst(implode('', array_map(ucfirst(...), explode('_', (string)$k)))); $props[$k] = $v; } // Replacing values of listProperties from index to actual property values @@ -398,11 +383,8 @@ public function properties() public function propertiesIdents() { $collectionConfig = $this->collectionConfig(); - if (isset($collectionConfig['properties'])) { - return $collectionConfig['properties']; - } - return []; + return ($collectionConfig['properties'] ?? []); } /** @@ -472,11 +454,7 @@ public function collectionProperties() $options = $this->viewOptions($propertyIdent); $classes = $this->parsePropertyCellClasses($p); - if (isset($options['label'])) { - $label = $this->translator()->translate($options['label']); - } else { - $label = strval($p['label']); - } + $label = isset($options['label']) ? $this->translator()->translate($options['label']) : strval($p['label']); $column = [ 'label' => trim($label) @@ -489,24 +467,20 @@ public function collectionProperties() if (isset($options['attr'])) { $column['attr'] = array_merge($column['attr'], $options['attr']); } + if (isset($column['attr']['class'])) { + if (is_string($classes)) { + $classes = explode(' ', $column['attr']['class']); + } - if (isset($classes)) { - if (isset($column['attr']['class'])) { - if (is_string($classes)) { - $classes = explode(' ', $column['attr']['class']); - } - - if (is_string($column['attr']['class'])) { - $column['attr']['class'] = explode(' ', $column['attr']['class']); - } - - $column['attr']['class'] = array_unique(array_merge($column['attr']['class'], $classes)); - } else { - $column['attr']['class'] = $classes; + if (is_string($column['attr']['class'])) { + $column['attr']['class'] = explode(' ', $column['attr']['class']); } - unset($classes); + $column['attr']['class'] = array_unique(array_merge($column['attr']['class'], $classes)); + } else { + $column['attr']['class'] = $classes; } + unset($classes); $column['attr'] = html_build_attributes($column['attr']); @@ -520,19 +494,17 @@ public function collectionProperties() * @param boolean $show Show (TRUE) or hide (FALSE) the actions. * @return TableWidget Chainable */ - public function setShowObjectActions($show) + public function setShowObjectActions($show): static { - $this->showObjectActions = !!$show; + $this->showObjectActions = (bool)$show; return $this; } /** * Determine if the table's object actions should be shown. - * - * @return boolean */ - public function showObjectActions() + public function showObjectActions(): false|int { if ($this->showObjectActions === false) { return false; @@ -543,10 +515,8 @@ public function showObjectActions() /** * Retrieve the table's object actions. - * - * @return array */ - public function objectActions() + public function objectActions(): array { $this->rawObjectActions(); @@ -571,11 +541,7 @@ public function rawObjectActions() $parsed = $this->parsedObjectActions; $collectionConfig = $this->collectionConfig(); - if (isset($collectionConfig['object_actions'])) { - $actions = $collectionConfig['object_actions']; - } else { - $actions = []; - } + $actions = ($collectionConfig['object_actions'] ?? []); $this->setObjectActions($actions); @@ -596,7 +562,7 @@ public function rawObjectActions() * @param array $actions One or more actions. * @return TableWidget Chainable. */ - public function setObjectActions(array $actions) + public function setObjectActions(array $actions): static { $this->parsedObjectActions = false; @@ -619,7 +585,7 @@ public function setObjectActions(array $actions) * @param array $actions Actions to resolve. * @return array Object actions. */ - public function createObjectActions(array $actions) + public function createObjectActions(array $actions): array { $this->parsingObjectActions = true; $objectActions = $this->parseActions($actions); @@ -632,9 +598,8 @@ public function createObjectActions(array $actions) * Parse the given actions as (row) object actions. * * @param array $actions Actions to resolve. - * @return array */ - protected function parseAsObjectActions(array $actions) + protected function parseAsObjectActions(array $actions): array { $objectActions = []; foreach ($actions as $action) { @@ -654,9 +619,7 @@ protected function parseAsObjectActions(array $actions) if ($action['actions']) { $action['actions'] = $this->parseAsObjectActions($action['actions']); - $action['hasActions'] = !!array_filter($action['actions'], function ($action) { - return $action['active']; - }); + $action['hasActions'] = (bool)array_filter($action['actions'], fn(array $action): mixed => $action['active']); } $objectActions[] = $action; @@ -667,10 +630,8 @@ protected function parseAsObjectActions(array $actions) /** * Determine if the table's empty collection actions should be shown. - * - * @return boolean */ - public function showEmptyListActions() + public function showEmptyListActions(): int { $actions = $this->emptyListActions(); @@ -679,16 +640,12 @@ public function showEmptyListActions() /** * Retrieve the table's empty collection actions. - * - * @return array */ - public function emptyListActions() + public function emptyListActions(): array { $actions = $this->listActions(); - $filteredArray = array_filter($actions, function ($action) { - return $action['empty'] && $action['active']; - }); + $filteredArray = array_filter($actions, fn(array $action): bool => $action['empty'] && $action['active']); return array_values($filteredArray); } @@ -699,19 +656,17 @@ public function emptyListActions() * @param boolean $show Show (TRUE) or hide (FALSE) the actions. * @return TableWidget Chainable */ - public function setShowListActions($show) + public function setShowListActions($show): static { - $this->showListActions = !!$show; + $this->showListActions = (bool)$show; return $this; } /** * Determine if the table's collection actions should be shown. - * - * @return boolean */ - public function showListActions() + public function showListActions(): false|int { if ($this->showListActions === false) { return false; @@ -729,11 +684,7 @@ public function listActions() { if ($this->listActions === null) { $collectionConfig = $this->collectionConfig(); - if (isset($collectionConfig['list_actions'])) { - $actions = $collectionConfig['list_actions']; - } else { - $actions = []; - } + $actions = ($collectionConfig['list_actions'] ?? []); $this->setListActions($actions); } @@ -765,9 +716,9 @@ public function paginationWidget() * @param boolean $show The show flag. * @return TableWidget Chainable */ - public function setShowTableHeader($show) + public function setShowTableHeader($show): static { - $this->showTableHeader = !!$show; + $this->showTableHeader = (bool)$show; return $this; } @@ -784,9 +735,9 @@ public function showTableHeader() * @param boolean $show The show flag. * @return TableWidget Chainable */ - public function setShowTableHead($show) + public function setShowTableHead($show): static { - $this->showTableHead = !!$show; + $this->showTableHead = (bool)$show; return $this; } @@ -803,9 +754,9 @@ public function showTableHead() * @param boolean $show The show flag. * @return TableWidget Chainable */ - public function setShowTableFoot($show) + public function setShowTableFoot($show): static { - $this->showTableFoot = !!$show; + $this->showTableFoot = (bool)$show; return $this; } @@ -822,9 +773,9 @@ public function showTableFoot() * @param boolean $sortable The sortable flag. * @return TableWidget Chainable */ - public function setSortable($sortable) + public function setSortable($sortable): static { - $this->sortable = !!$sortable; + $this->sortable = (bool)$sortable; return $this; } @@ -842,30 +793,21 @@ public function sortable() * * @param mixed $action The action structure. * @param boolean $row Whether to resolve action type for a row. - * @return string */ - protected function resolveActionType($action, $row = false) + protected function resolveActionType(array $action, $row = false): string { if ($row || $this->parsingObjectActions) { - switch ($action['ident']) { - case 'reset': - return 'warning'; - - case 'delete': - return 'danger'; - - default: - return 'seamless'; - } + return match ($action['ident']) { + 'reset' => 'warning', + 'delete' => 'danger', + default => 'seamless', + }; } return $this->resolveDefaultActionType($action); } - /** - * @return string - */ - public function jsActionPrefix() + public function jsActionPrefix(): string { return ($this->currentObj) ? 'js-obj' : 'js-list'; } @@ -880,9 +822,9 @@ public function objectEditUrl() $url = 'object/edit?main_menu={{ main_menu }}&obj_type=' . $this->objType(); if ($this->isObjRenderable($model)) { - $url = $model->render((string)$url); + $url = $model->render($url); } else { - $url = preg_replace('~{{\s*id\s*}}~', $this->currentObjId, $url); + $url = preg_replace('~{{\s*id\s*}}~', (string)$this->currentObjId, $url); } return $url; @@ -897,17 +839,14 @@ public function objectCreateUrl() $actions = $this->listActions(); if ($actions) { foreach ($actions as $action) { - if (isset($action['ident']) && $action['ident'] === 'create') { - if (isset($action['url'])) { - $model = $this->proto(); - if ($this->isObjRenderable($model)) { - $action['url'] = $model->render((string)$action['url']); - } else { - $action['url'] = preg_replace('~{{\s*id\s*}}~', $this->currentObjId, $action['url']); - } - - return $action['url']; + if (isset($action['ident']) && $action['ident'] === 'create' && isset($action['url'])) { + $model = $this->proto(); + if ($this->isObjRenderable($model)) { + $action['url'] = $model->render((string)$action['url']); + } else { + $action['url'] = preg_replace('~{{\s*id\s*}}~', (string)$this->currentObjId, $action['url']); } + return $action['url']; } } } @@ -921,9 +860,9 @@ public function objectCreateUrl() * @param ModelInterface|null $object The object to test. * @return boolean */ - public function isObjActive(ModelInterface $object = null) + public function isObjActive(?ModelInterface $object = null) { - if ($object === null) { + if (!$object instanceof \Charcoal\Model\ModelInterface) { $object = $this->getCurrentObjOrProto(); } @@ -948,9 +887,9 @@ public function isObjActive(ModelInterface $object = null) * @param ModelInterface|null $object The object to test. * @return boolean */ - public function isObjCreatable(ModelInterface $object = null) + public function isObjCreatable(?ModelInterface $object = null) { - if ($object === null) { + if (!$object instanceof \Charcoal\Model\ModelInterface) { $object = $this->proto(); } @@ -971,9 +910,9 @@ public function isObjCreatable(ModelInterface $object = null) * @param ModelInterface|null $object The object to test. * @return boolean */ - public function isObjEditable(ModelInterface $object = null) + public function isObjEditable(?ModelInterface $object = null) { - if ($object === null) { + if (!$object instanceof \Charcoal\Model\ModelInterface) { $object = $this->getCurrentObjOrProto(); } @@ -994,9 +933,9 @@ public function isObjEditable(ModelInterface $object = null) * @param ModelInterface|null $object The object to test. * @return boolean */ - public function isObjDeletable(ModelInterface $object = null) + public function isObjDeletable(?ModelInterface $object = null) { - if ($object === null) { + if (!$object instanceof \Charcoal\Model\ModelInterface) { $object = $this->getCurrentObjOrProto(); } @@ -1017,9 +956,9 @@ public function isObjDeletable(ModelInterface $object = null) * @param ModelInterface|null $object The object to test. * @return boolean */ - public function isObjViewable(ModelInterface $object = null) + public function isObjViewable(?ModelInterface $object = null) { - if ($object === null) { + if (!$object instanceof \Charcoal\Model\ModelInterface) { $object = $this->getCurrentObjOrProto(); } @@ -1039,6 +978,7 @@ public function isObjViewable(ModelInterface $object = null) * @param Container $container Pimple DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -1063,27 +1003,23 @@ protected function setDependencies(Container $container) * @param array|null $data Optional collection data. * @return void */ - protected function configureCollectionLoader(CollectionLoader $loader, array $data = null) + protected function configureCollectionLoader(CollectionLoader $loader, ?array $data = null) { $this->configureCollectionLoaderFromTrait($loader, $data); - if (!isset($loader->hasMainMenuCallback)) { - $mainMenu = filter_input(INPUT_GET, 'main_menu', FILTER_SANITIZE_STRING); + if (!property_exists($loader, 'hasMainMenuCallback') || $loader->hasMainMenuCallback === null) { + $mainMenu = htmlspecialchars(trim(($_GET['main_menu'] ?? '')), ENT_QUOTES, 'UTF-8'); if ($mainMenu) { - $fn = function (&$obj) use ($mainMenu) { + $fn = function (array &$obj) use ($mainMenu): void { if (!$obj['main_menu']) { $obj['main_menu'] = $mainMenu; } }; $callback = $loader->callback(); - if ($callback === null) { - $callback = $fn; - } else { - $callback = function (&$obj) use ($fn) { - $fn($obj); - }; - } + $callback = $callback === null ? $fn : function (&$obj) use ($fn): void { + $fn($obj); + }; $loader->setCallback($callback); $loader->hasMainMenuCallback = true; @@ -1095,13 +1031,12 @@ protected function configureCollectionLoader(CollectionLoader $loader, array $da * Retrieve the widget factory. * * @throws RuntimeException If the widget factory was not previously set. - * @return FactoryInterface */ - protected function widgetFactory() + protected function widgetFactory(): \Charcoal\Factory\FactoryInterface { - if ($this->widgetFactory === null) { + if (!$this->widgetFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException( - sprintf('Widget Factory is not defined for "%s"', get_class($this)) + sprintf('Widget Factory is not defined for "%s"', static::class) ); } @@ -1110,11 +1045,10 @@ protected function widgetFactory() /** * @throws RuntimeException If the property factory was not previously set / injected. - * @return FactoryInterface */ - protected function propertyFactory() + protected function propertyFactory(): \Charcoal\Factory\FactoryInterface { - if ($this->propertyFactory === null) { + if (!$this->propertyFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException( 'Property factory is not set for table widget' ); @@ -1132,6 +1066,7 @@ protected function propertyFactory() * @param mixed $toResolve A callable used when merging data. * @return callable|null */ + #[\Override] protected function resolveDataSourceFilter($toResolve) { if (is_string($toResolve)) { @@ -1162,7 +1097,7 @@ protected function resolveDataSourceFilter($toResolve) * @param array $actions One or more actions. * @return TableWidget Chainable. */ - protected function setListActions(array $actions) + protected function setListActions(array $actions): static { $this->parsedListActions = false; @@ -1183,7 +1118,7 @@ protected function setListActions(array $actions) * @param array $actions Actions to resolve. * @return array List actions. */ - protected function createListActions(array $actions) + protected function createListActions(array $actions): array { $this->actionsPriority = $this->defaultActionPriority(); @@ -1198,9 +1133,8 @@ protected function createListActions(array $actions) * Parse the given actions as collection actions. * * @param array $actions Actions to resolve. - * @return array */ - protected function parseAsListActions(array $actions) + protected function parseAsListActions(array $actions): array { $listActions = []; foreach ($actions as $ident => $action) { @@ -1218,14 +1152,12 @@ protected function parseAsListActions(array $actions) $action['active'] = false; } } else { - $action['empty'] = (isset($action['empty']) ? boolval($action['empty']) : false); + $action['empty'] = (isset($action['empty']) && boolval($action['empty'])); } if (is_array($action['actions'])) { $action['actions'] = $this->parseAsListActions($action['actions']); - $action['hasActions'] = !!array_filter($action['actions'], function ($action) { - return $action['active']; - }); + $action['hasActions'] = (bool)array_filter($action['actions'], fn(array $action): mixed => $action['active']); } if (isset($listActions[$ident])) { @@ -1240,7 +1172,7 @@ protected function parseAsListActions(array $actions) } } - usort($listActions, [ 'Charcoal\Admin\Support\Sorter', 'sortByPriority' ]); + usort($listActions, \Charcoal\Admin\Support\Sorter::sortByPriority(...)); while (($first = reset($listActions)) && $first['isSeparator']) { array_shift($listActions); @@ -1313,19 +1245,18 @@ protected function defaultPropertiesOptions() * @param ModelInterface $object The current row's object. * @param PropertyInterface $property The current property. * @param string $propertyValue The property $key's display value. - * @return array */ protected function parsePropertyCell( ModelInterface $object, PropertyInterface $property, - $propertyValue - ) { + string $propertyValue + ): array { $cell = $this->parseCollectionPropertyCell($object, $property, $propertyValue); $ident = $property->ident(); $options = $this->viewOptions($ident); $classes = $this->parsePropertyCellClasses($property, $object); - $cell['truncate'] = (isset($options['truncate']) ? boolval($options['truncate']) : false); + $cell['truncate'] = (isset($options['truncate']) && boolval($options['truncate'])); if (!isset($cell['attr'])) { $cell['attr'] = []; @@ -1335,24 +1266,20 @@ protected function parsePropertyCell( unset($options['attr']['width']); $cell['attr'] = array_merge($cell['attr'], $options['attr']); } + if (isset($cell['attr']['class'])) { + if (is_string($classes)) { + $classes = explode(' ', $cell['attr']['class']); + } - if (isset($classes)) { - if (isset($cell['attr']['class'])) { - if (is_string($classes)) { - $classes = explode(' ', $cell['attr']['class']); - } - - if (is_string($cell['attr']['class'])) { - $cell['attr']['class'] = explode(' ', $cell['attr']['class']); - } - - $cell['attr']['class'] = array_unique(array_merge($cell['attr']['class'], $classes)); - } else { - $cell['attr']['class'] = $classes; + if (is_string($cell['attr']['class'])) { + $cell['attr']['class'] = explode(' ', $cell['attr']['class']); } - unset($classes); + $cell['attr']['class'] = array_unique(array_merge($cell['attr']['class'], $classes)); + } else { + $cell['attr']['class'] = $classes; } + unset($classes); $cell['attr'] = html_build_attributes($cell['attr']); @@ -1367,12 +1294,11 @@ protected function parsePropertyCell( * * @param PropertyInterface $property The current property. * @param ModelInterface|null $object Optional. The current row's object. - * @return array */ protected function parsePropertyCellClasses( PropertyInterface $property, - ModelInterface $object = null - ) { + ?ModelInterface $object = null + ): array { unset($object); $ident = $property->ident(); @@ -1397,13 +1323,12 @@ protected function parsePropertyCellClasses( * * @param ModelInterface $object The current row's object. * @param array $objectProperties The $object's display properties. - * @return array */ - protected function parseObjectRow(ModelInterface $object, array $objectProperties) + protected function parseObjectRow(ModelInterface $object, array $objectProperties): array { $row = $this->parseCollectionObjectRow($object, $objectProperties); $row['objectActions'] = $this->objectActions(); - $row['showObjectActions'] = ($this->showObjectActions() === false) ? false : !!$row['objectActions']; + $row['showObjectActions'] = ($this->showObjectActions() === false) ? false : (bool)$row['objectActions']; $row['attr'] = [ 'class' => [] @@ -1424,9 +1349,8 @@ protected function parseObjectRow(ModelInterface $object, array $objectPropertie * Set an widget factory. * * @param FactoryInterface $factory The factory to create widgets. - * @return void */ - private function setWidgetFactory(FactoryInterface $factory) + private function setWidgetFactory(FactoryInterface $factory): void { $this->widgetFactory = $factory; } @@ -1435,7 +1359,7 @@ private function setWidgetFactory(FactoryInterface $factory) * @param FactoryInterface $factory The property factory, to create properties. * @return TableWidget Chainable */ - private function setPropertyFactory(FactoryInterface $factory) + private function setPropertyFactory(FactoryInterface $factory): static { $this->propertyFactory = $factory; diff --git a/packages/admin/src/Charcoal/Admin/Widget/TextWidget.php b/packages/admin/src/Charcoal/Admin/Widget/TextWidget.php index d667bc7fd..4cd93ba66 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/TextWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/TextWidget.php @@ -1,5 +1,7 @@ showTitle = !!$show; + $this->showTitle = (bool)$show; return $this; } @@ -68,17 +57,16 @@ public function showTitle() if ($this->showTitle === false) { return false; } else { - return !!$this->title(); + return (bool)$this->title(); } } /** * @param boolean $show The show subtitle flag. - * @return self */ - public function setShowSubtitle($show) + public function setShowSubtitle($show): static { - $this->showSubtitle = !!$show; + $this->showSubtitle = (bool)$show; return $this; } @@ -90,17 +78,16 @@ public function showSubtitle() if ($this->showSubtitle === false) { return false; } else { - return !!$this->subtitle(); + return (bool)$this->subtitle(); } } /** * @param boolean $show The show description flag. - * @return self */ - public function setShowDescription($show) + public function setShowDescription($show): static { - $this->showDescription = !!$show; + $this->showDescription = (bool)$show; return $this; } @@ -112,17 +99,16 @@ public function showDescription() if ($this->showDescription === false) { return false; } else { - return !!$this->description(); + return (bool)$this->description(); } } /** * @param boolean $show The "show notes" flag. - * @return self */ - public function setShowNotes($show) + public function setShowNotes($show): static { - $this->showNotes = !!$show; + $this->showNotes = (bool)$show; return $this; } @@ -134,15 +120,14 @@ public function showNotes() if ($this->showNotes === false) { return false; } else { - return !!$this->notes(); + return (bool)$this->notes(); } } /** * @param mixed $title The text widget title. - * @return self */ - public function setTitle($title) + public function setTitle($title): static { $this->title = $this->translator()->translation($title); @@ -159,9 +144,8 @@ public function title() /** * @param mixed $subtitle The text widget subtitle. - * @return self */ - public function setSubtitle($subtitle) + public function setSubtitle($subtitle): static { $this->subtitle = $this->translator()->translation($subtitle); @@ -178,9 +162,8 @@ public function subtitle() /** * @param mixed $description The text widget description (main content). - * @return self */ - public function setDescription($description) + public function setDescription($description): static { $this->description = $this->translator()->translation($description); @@ -197,9 +180,8 @@ public function description() /** * @param mixed $notes The text widget notes. - * @return self */ - public function setNotes($notes) + public function setNotes($notes): static { $this->notes = $this->translator()->translation($notes); diff --git a/packages/admin/tests/Charcoal/AbstractTestCase.php b/packages/admin/tests/Charcoal/AbstractTestCase.php index 59ba12ea0..80f1772c4 100644 --- a/packages/admin/tests/Charcoal/AbstractTestCase.php +++ b/packages/admin/tests/Charcoal/AbstractTestCase.php @@ -1,5 +1,7 @@ callMethod($this->obj, 'authRequired'); $this->assertFalse($res); } - /** - * @return void - */ - public function testRunWithoutEmailReturns400() + public function testRunWithoutEmailReturns400(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -84,10 +72,7 @@ public function testRunWithoutEmailReturns400() $this->assertFalse($results['success']); } - /** - * @return void - */ - public function testRunWithoutRecaptchaReturns400() + public function testRunWithoutRecaptchaReturns400(): void { $mock = m::mock($this->obj); $mock->shouldAllowMockingProtectedMethods() @@ -107,10 +92,7 @@ public function testRunWithoutRecaptchaReturns400() $this->assertFalse($results['success']); } - /** - * @return void - */ - public function testRunWithInvalidRecaptchaReturns400() + public function testRunWithInvalidRecaptchaReturns400(): void { $mock = m::mock($this->obj); $mock->shouldAllowMockingProtectedMethods() @@ -132,12 +114,10 @@ public function testRunWithInvalidRecaptchaReturns400() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerAdminServices($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/Account/ResetPasswordActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/Account/ResetPasswordActionTest.php index 72255bd13..443760af0 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/Account/ResetPasswordActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/Account/ResetPasswordActionTest.php @@ -38,15 +38,11 @@ class ResetPasswordActionTest extends AbstractTestCase /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -60,19 +56,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsFalse() + public function testAuthRequiredIsFalse(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertFalse($res); } - /** - * @return void - */ - public function testRunWithoutTokenReturns400() + public function testRunWithoutTokenReturns400(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -84,10 +74,7 @@ public function testRunWithoutTokenReturns400() $this->assertFalse($results['success']); } - /** - * @return void - */ - public function testRunWithoutEmailReturns400() + public function testRunWithoutEmailReturns400(): void { $request = Request::createFromEnvironment(Environment::mock([ 'QUERY_STRING' => 'token=foobar' @@ -101,10 +88,7 @@ public function testRunWithoutEmailReturns400() $this->assertFalse($results['success']); } - /** - * @return void - */ - public function testRunWithoutPasswordReturns400() + public function testRunWithoutPasswordReturns400(): void { $request = Request::createFromEnvironment(Environment::mock([ 'QUERY_STRING' => 'token=foobar&email=foobar@foo.bar' @@ -118,10 +102,7 @@ public function testRunWithoutPasswordReturns400() $this->assertFalse($results['success']); } - /** - * @return void - */ - public function testRunWithoutMatchingPasswordsReturns400() + public function testRunWithoutMatchingPasswordsReturns400(): void { $request = Request::createFromEnvironment(Environment::mock([ 'QUERY_STRING' => 'token=foobar&email=foobar@foo.bar&password1=foo&password2=bar' @@ -135,10 +116,7 @@ public function testRunWithoutMatchingPasswordsReturns400() $this->assertFalse($results['success']); } - /** - * @return void - */ - public function testRunWithoutRecaptchaReturns400() + public function testRunWithoutRecaptchaReturns400(): void { $mock = m::mock($this->obj); $mock->shouldAllowMockingProtectedMethods() @@ -158,10 +136,7 @@ public function testRunWithoutRecaptchaReturns400() $this->assertFalse($results['success']); } - /** - * @return void - */ - public function testRunWithInvalidRecaptchaReturns400() + public function testRunWithInvalidRecaptchaReturns400(): void { $mock = m::mock($this->obj); $mock->shouldAllowMockingProtectedMethods() @@ -183,12 +158,10 @@ public function testRunWithInvalidRecaptchaReturns400() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerAdminServices($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/LoginActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/LoginActionTest.php index 8c814c806..4d7f90b32 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/LoginActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/LoginActionTest.php @@ -30,22 +30,16 @@ class LoginActionTest extends AbstractTestCase /** * Tested Class. - * - * @var LoginAction */ - private $obj; + private \Charcoal\Admin\Action\LoginAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -61,19 +55,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsFalse() + public function testAuthRequiredIsFalse(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertFalse($res); } - /** - * @return void - */ - public function testRunWithoutParamsIs400() + public function testRunWithoutParamsIs400(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -82,10 +70,7 @@ public function testRunWithoutParamsIs400() $this->assertEquals(400, $response->getStatusCode()); } - /** - * @return void - */ - public function testRunWithInvalidCredentials() + public function testRunWithInvalidCredentials(): void { $this->createUser('foo@bar.com'); @@ -108,28 +93,25 @@ public function testRunWithInvalidCredentials() public function testRunWithValidCredentials() { $this->createUser('foo@bar.com'); - + $request = Request::createFromEnvironment(Environment::mock([ 'QUERY_STRING' => 'password=qwerty' ])); $response = new Response(); - + $response = $this->obj->run($request, $response); $this->assertEquals(200, $response->getStatusCode()); - + $results = $this->obj->results(); $this->assertTrue($results['success']); } */ - /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/LogoutActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/LogoutActionTest.php index ccaf20f5f..493b4ac4b 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/LogoutActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/LogoutActionTest.php @@ -29,22 +29,16 @@ class LogoutActionTest extends AbstractTestCase /** * Tested Class. - * - * @var LogoutAction */ - private $obj; + private \Charcoal\Admin\Action\LogoutAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -59,19 +53,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRunWithUnauthenticatedUser() + public function testRunWithUnauthenticatedUser(): void { $this->createUser('foo@bar.com'); @@ -85,10 +73,7 @@ public function testRunWithUnauthenticatedUser() $this->assertFalse($results['success']); } - /** - * @return void - */ - public function testRunWithAuthenticatedUser() + public function testRunWithAuthenticatedUser(): void { $user = $this->createUser('foo@bar.com'); $this->getAuthenticator()->setUser($user); @@ -105,12 +90,10 @@ public function testRunWithAuthenticatedUser() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/Object/DeleteActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/Object/DeleteActionTest.php index ea41c1900..5e0b62206 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/Object/DeleteActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/Object/DeleteActionTest.php @@ -29,22 +29,16 @@ class DeleteActionTest extends AbstractTestCase /** * Tested Class. - * - * @var DeleteAction */ - private $obj; + private \Charcoal\Admin\Action\Object\DeleteAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,19 +50,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRunWithoutObjTypeIs400() + public function testRunWithoutObjTypeIs400(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -80,10 +68,7 @@ public function testRunWithoutObjTypeIs400() $this->assertFalse($results['success']); } - /** - * @return void - */ - public function testRunWithoutObjIdIs400() + public function testRunWithoutObjIdIs400(): void { $request = Request::createFromEnvironment(Environment::mock([ 'QUERY_STRING' => 'obj_type=charcoal/admin/user' @@ -97,13 +82,10 @@ public function testRunWithoutObjIdIs400() $this->assertFalse($results['success']); } - /** - * @return void - */ - public function testRunWithInvalidObject() + public function testRunWithInvalidObject(): void { $email = 'foobar@foo.bar'; - $user = $this->createUser($email); + $this->createUser($email); $this->assertTrue($this->userExists($email)); $request = Request::createFromEnvironment(Environment::mock([ @@ -120,10 +102,7 @@ public function testRunWithInvalidObject() $this->assertTrue($this->userExists($email)); } - /** - * @return void - */ - public function testRunWithObjectDelete() + public function testRunWithObjectDelete(): void { $email = 'foobar@foo.bar'; $user = $this->createUser($email); @@ -145,12 +124,10 @@ public function testRunWithObjectDelete() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/Object/ExportActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/Object/ExportActionTest.php index 6fc3c0a81..12789dbcc 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/Object/ExportActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/Object/ExportActionTest.php @@ -28,22 +28,16 @@ class ExportActionTest extends AbstractTestCase /** * Tested Class. - * - * @var ExportAction */ - private $obj; + private \Charcoal\Admin\Action\Object\ExportAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -57,19 +51,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRunWithoutObjTypeIs400() + public function testRunWithoutObjTypeIs400(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -83,12 +71,10 @@ public function testRunWithoutObjTypeIs400() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerAdminServices($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/Object/LoadActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/Object/LoadActionTest.php index e43192b2b..ff137c54d 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/Object/LoadActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/Object/LoadActionTest.php @@ -29,22 +29,16 @@ class LoadActionTest extends AbstractTestCase /** * Tested Class. - * - * @var LoadAction */ - private $obj; + private \Charcoal\Admin\Action\Object\LoadAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,19 +50,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRunWithoutObjTypeIs400() + public function testRunWithoutObjTypeIs400(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -80,10 +68,7 @@ public function testRunWithoutObjTypeIs400() $this->assertFalse($results['success']); } - /** - * @return void - */ - public function testRun() + public function testRun(): void { $user = $this->createUser('foo@bar.com'); @@ -103,12 +88,10 @@ public function testRun() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/Object/ReorderActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/Object/ReorderActionTest.php index 03e60d274..eaf87608c 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/Object/ReorderActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/Object/ReorderActionTest.php @@ -32,36 +32,26 @@ class ReorderActionTest extends AbstractTestCase /** * The primary model to test with. - * - * @var string */ - private $model = Model::class; + private string $model = Model::class; /** * Store the tested instance. - * - * @var ReorderAction */ - private $action; + private \Charcoal\Admin\Action\Object\ReorderAction $action; /** * Store the object collection loader. - * - * @var CollectionLoader */ - private $collectionLoader; + private ?\Charcoal\Loader\CollectionLoader $collectionLoader = null; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -78,7 +68,7 @@ public function setUp(): void /** * @return array */ - public function setUpObjects() + public function setUpObjects(): \ArrayAccess|array { $container = $this->container(); @@ -110,9 +100,9 @@ public function setUpObjects() /** * @return Collection */ - public function getObjects() + public function getObjects(): \ArrayAccess|array { - if ($this->collectionLoader === null) { + if (!$this->collectionLoader instanceof \Charcoal\Loader\CollectionLoader) { $container = $this->container(); $loader = new CollectionLoader([ @@ -129,24 +119,20 @@ public function getObjects() return $this->collectionLoader->load(); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->action, 'authRequired'); $this->assertTrue($res); } /** - * @dataProvider runRequestProvider * * @param integer $status An HTTP status code. * @param string $success Whether the action was successful. * @param array $mock The request parameters to test. - * @return void */ - public function testRun($status, $success, array $mock) + #[\PHPUnit\Framework\Attributes\DataProvider('runRequestProvider')] + public function testRun(int $status, bool $success, array $mock): void { if ($status === 200) { $this->setUpObjects(); @@ -167,29 +153,25 @@ public function testRun($status, $success, array $mock) } } - /** - * @return array - */ - public function runRequestProvider() + public static function runRequestProvider(): array { + $model = Model::class; return [ [ 400, false, [] ], - [ 400, false, [ 'QUERY_STRING' => 'obj_type='.$this->model ] ], - [ 400, false, [ 'QUERY_STRING' => 'obj_type='.$this->model.'&order_property=5' ] ], - [ 400, false, [ 'QUERY_STRING' => 'obj_type='.$this->model.'&order_property=foobar' ] ], - [ 500, false, [ 'QUERY_STRING' => 'obj_type='.$this->model.'&obj_orders[]=xyzzy&obj_orders[]=qwerty' ] ], - [ 200, true, [ 'QUERY_STRING' => 'obj_type='.$this->model.'&obj_orders[]=baz&obj_orders[]=bar&obj_orders[]=qux&obj_orders[]=foo' ] ], + [ 400, false, [ 'QUERY_STRING' => 'obj_type='.$model ] ], + [ 400, false, [ 'QUERY_STRING' => 'obj_type='.$model.'&order_property=5' ] ], + [ 400, false, [ 'QUERY_STRING' => 'obj_type='.$model.'&order_property=foobar' ] ], + [ 500, false, [ 'QUERY_STRING' => 'obj_type='.$model.'&obj_orders[]=xyzzy&obj_orders[]=qwerty' ] ], + [ 200, true, [ 'QUERY_STRING' => 'obj_type='.$model.'&obj_orders[]=baz&obj_orders[]=bar&obj_orders[]=qux&obj_orders[]=foo' ] ], ]; } /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerAdminServices($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/Object/SaveActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/Object/SaveActionTest.php index 7b3ee7c43..17c05fb2a 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/Object/SaveActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/Object/SaveActionTest.php @@ -28,22 +28,16 @@ class SaveActionTest extends AbstractTestCase /** * Tested Class. - * - * @var SaveAction */ - private $obj; + private \Charcoal\Admin\Action\Object\SaveAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -55,19 +49,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRunWithoutObjTypeIs400() + public function testRunWithoutObjTypeIs400(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -81,12 +69,10 @@ public function testRunWithoutObjTypeIs400() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/Object/UpdateActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/Object/UpdateActionTest.php index a412fee17..6bc82a358 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/Object/UpdateActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/Object/UpdateActionTest.php @@ -28,22 +28,16 @@ class UpdateActionTest extends AbstractTestCase /** * Tested Class. - * - * @var UpdateAction */ - private $obj; + private \Charcoal\Admin\Action\Object\UpdateAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -55,19 +49,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRunWithoutObjTypeIs400() + public function testRunWithoutObjTypeIs400(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -81,12 +69,10 @@ public function testRunWithoutObjTypeIs400() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/System/ClearCacheActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/System/ClearCacheActionTest.php index b818971e9..e7d751412 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/System/ClearCacheActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/System/ClearCacheActionTest.php @@ -29,22 +29,16 @@ class ClearCacheActionTest extends AbstractTestCase /** * Tested Class. - * - * @var ClearCacheAction */ - private $obj; + private \Charcoal\Admin\Action\System\ClearCacheAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,19 +50,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRun() + public function testRun(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -82,12 +70,10 @@ public function testRun() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/ActivateActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/ActivateActionTest.php index 82238774e..89f8d7c6b 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/ActivateActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/ActivateActionTest.php @@ -29,22 +29,16 @@ class ActivateActionTest extends AbstractTestCase /** * Tested Class. - * - * @var ActivateAction */ - private $obj; + private \Charcoal\Admin\Action\System\StaticWebsite\ActivateAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,19 +50,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRun() + public function testRun(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -82,12 +70,10 @@ public function testRun() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/AddActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/AddActionTest.php index f84930ea9..2c7e7fd7a 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/AddActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/AddActionTest.php @@ -29,22 +29,16 @@ class AddActionTest extends AbstractTestCase /** * Tested Class. - * - * @var AddAction */ - private $obj; + private \Charcoal\Admin\Action\System\StaticWebsite\AddAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,19 +50,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRun() + public function testRun(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -82,12 +70,10 @@ public function testRun() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeactivateActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeactivateActionTest.php index 800c641ec..d7b7b3eef 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeactivateActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeactivateActionTest.php @@ -29,22 +29,16 @@ class DeactivateActionTest extends AbstractTestCase /** * Tested Class. - * - * @var DeactivateAction */ - private $obj; + private \Charcoal\Admin\Action\System\StaticWebsite\DeactivateAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,19 +50,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRun() + public function testRun(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -82,12 +70,10 @@ public function testRun() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeleteActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeleteActionTest.php index 3107cc470..bb2849be6 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeleteActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeleteActionTest.php @@ -29,22 +29,16 @@ class DeleteActionTest extends AbstractTestCase /** * Tested Class. - * - * @var DeleteAction */ - private $obj; + private \Charcoal\Admin\Action\System\StaticWebsite\DeleteAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,19 +50,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRun() + public function testRun(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -82,12 +70,10 @@ public function testRun() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeleteAllActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeleteAllActionTest.php index dfdaaf235..df1de19ca 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeleteAllActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/DeleteAllActionTest.php @@ -29,22 +29,16 @@ class DeleteAllActionTest extends AbstractTestCase /** * Tested Class. - * - * @var DeleteAllAction */ - private $obj; + private \Charcoal\Admin\Action\System\StaticWebsite\DeleteAllAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,19 +50,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRun() + public function testRun(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -82,12 +70,10 @@ public function testRun() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/PreviewActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/PreviewActionTest.php index bb7506d81..1245fa77d 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/PreviewActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/PreviewActionTest.php @@ -29,22 +29,16 @@ class PreviewActionTest extends AbstractTestCase /** * Tested Class. - * - * @var PreviewAction */ - private $obj; + private \Charcoal\Admin\Action\System\StaticWebsite\PreviewAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,19 +50,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRun() + public function testRun(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -82,12 +70,10 @@ public function testRun() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/UpdateActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/UpdateActionTest.php index c121e60d4..92c646a3e 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/UpdateActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/UpdateActionTest.php @@ -29,22 +29,16 @@ class UpdateActionTest extends AbstractTestCase /** * Tested Class. - * - * @var UpdateAction */ - private $obj; + private \Charcoal\Admin\Action\System\StaticWebsite\UpdateAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,19 +50,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRun() + public function testRun(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -82,12 +70,10 @@ public function testRun() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/UpdateAllActionTest.php b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/UpdateAllActionTest.php index 6f2a53054..2e86a6fa3 100644 --- a/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/UpdateAllActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/Action/System/StaticWebsite/UpdateAllActionTest.php @@ -29,22 +29,16 @@ class UpdateAllActionTest extends AbstractTestCase /** * Tested Class. - * - * @var UpdateAllAction */ - private $obj; + private \Charcoal\Admin\Action\System\StaticWebsite\UpdateAllAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,19 +50,13 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testRun() + public function testRun(): void { $request = Request::createFromEnvironment(Environment::mock()); $response = new Response(); @@ -82,12 +70,10 @@ public function testRun() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/AdminActionTest.php b/packages/admin/tests/Charcoal/Admin/AdminActionTest.php index 9444e06a0..ea4428993 100644 --- a/packages/admin/tests/Charcoal/Admin/AdminActionTest.php +++ b/packages/admin/tests/Charcoal/Admin/AdminActionTest.php @@ -2,6 +2,7 @@ namespace Charcoal\Tests\Admin; +use Psr\Http\Message\ResponseInterface; use ReflectionClass; // From PSR-7 @@ -27,31 +28,30 @@ class AdminActionTest extends AbstractTestCase /** * Tested Class. - * - * @var AdminAction */ - private $obj; + private \Charcoal\Admin\AdminAction $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { $container = $this->container(); - $this->obj = $this->getMockForAbstractClass(AdminAction::class, [[ + $this->obj = new class([ 'logger' => $container['logger'], 'container' => $container - ]]); + ]) extends AdminAction { + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface + { + return $response; + } + }; } /** @@ -63,10 +63,8 @@ public function setUp(): void * - success can be set by ArrayAccess * - success can be set with get() * - success can be accessed by ArrayAccess - * - * @return void */ - public function testSuccess() + public function testSuccess(): void { $this->assertFalse($this->obj->success()); $ret = $this->obj->setSuccess(true); @@ -83,10 +81,7 @@ public function testSuccess() $this->assertFalse($this->obj['success']); } - /** - * @return void - */ - public function testFeedback() + public function testFeedback(): void { $this->assertFalse($this->obj->hasFeedbacks()); $this->assertEquals([], $this->obj->feedbacks()); @@ -105,18 +100,12 @@ public function testFeedback() $this->assertEquals(1, $this->obj->numFeedbacks()); } - /** - * @return void - */ - public function testAdminUrl() + public function testAdminUrl(): void { $this->assertEquals('/admin/', $this->obj->adminUrl()); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); @@ -124,12 +113,10 @@ public function testAuthRequiredIsTrue() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerActionDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/AdminTemplateTest.php b/packages/admin/tests/Charcoal/Admin/AdminTemplateTest.php index 555eb2eeb..1dd3ff197 100644 --- a/packages/admin/tests/Charcoal/Admin/AdminTemplateTest.php +++ b/packages/admin/tests/Charcoal/Admin/AdminTemplateTest.php @@ -23,22 +23,16 @@ class AdminTemplateTest extends AbstractTestCase /** * Tested Class. - * - * @var AdminTemplate */ - private $obj; + private \Charcoal\Admin\AdminTemplate $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -50,10 +44,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testSetIdent() + public function testSetIdent(): void { $this->assertNull($this->obj->ident()); $ret = $this->obj->setIdent('foobar'); @@ -61,10 +52,7 @@ public function testSetIdent() $this->assertEquals('foobar', $this->obj->ident()); } - /** - * @return void - */ - public function testSetLabel() + public function testSetLabel(): void { $this->assertNull($this->obj->label()); $ret = $this->obj->setLabel('foobar'); @@ -72,10 +60,7 @@ public function testSetLabel() $this->assertEquals('foobar', (string)$this->obj->label()); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); @@ -83,17 +68,15 @@ public function testAuthRequiredIsTrue() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerTemplateDependencies($container); - $container['widget/factory'] = $this->createMock('\Charcoal\Factory\FactoryInterface'); + $container['widget/factory'] = $this->createMock(\Charcoal\Factory\FactoryInterface::class); $this->container = $container; } diff --git a/packages/admin/tests/Charcoal/Admin/AdminWidgetTest.php b/packages/admin/tests/Charcoal/Admin/AdminWidgetTest.php index a534248bf..9617919d0 100644 --- a/packages/admin/tests/Charcoal/Admin/AdminWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/AdminWidgetTest.php @@ -17,22 +17,16 @@ class AdminWidgetTest extends AbstractTestCase { /** * Tested Class. - * - * @var AdminWidget */ - private $obj; + private \Charcoal\Admin\AdminWidget $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -44,10 +38,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ @@ -64,10 +55,7 @@ public function testSetData() $this->assertNotTrue($obj->showActions()); } - /** - * @return void - */ - public function testSetType() + public function testSetType(): void { $obj = $this->obj; $this->assertEquals(null, $obj->type()); @@ -80,12 +68,8 @@ public function testSetType() $obj->setType(1); } - /** - * @return void - */ - public function testSetLabel() + public function testSetLabel(): void { - $obj = $this->obj; //$this->assertEquals(null, $obj->label()); $obj = $this->obj; @@ -101,12 +85,10 @@ public function testSetLabel() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerWidgetDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/ConfigTest.php b/packages/admin/tests/Charcoal/Admin/ConfigTest.php index 3bf16bd6f..9244ba664 100644 --- a/packages/admin/tests/Charcoal/Admin/ConfigTest.php +++ b/packages/admin/tests/Charcoal/Admin/ConfigTest.php @@ -11,10 +11,7 @@ */ class ConfigTest extends AbstractTestCase { - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = new Config(); $ret = $obj->merge([ @@ -24,10 +21,7 @@ public function testSetData() $this->assertEquals('foo', $obj->basePath()); } - /** - * @return void - */ - public function testSetBasePath() + public function testSetBasePath(): void { $obj = new Config(); $this->assertEquals('admin', $obj->basePath()); @@ -40,10 +34,7 @@ public function testSetBasePath() $obj->setBasePath([]); } - /** - * @return void - */ - public function testSetBasePathEmptyParamThrowsException() + public function testSetBasePathEmptyParamThrowsException(): void { $obj = new Config(); diff --git a/packages/admin/tests/Charcoal/Admin/ContainerProvider.php b/packages/admin/tests/Charcoal/Admin/ContainerProvider.php index fea6cebe0..58400598d 100644 --- a/packages/admin/tests/Charcoal/Admin/ContainerProvider.php +++ b/packages/admin/tests/Charcoal/Admin/ContainerProvider.php @@ -74,9 +74,8 @@ class ContainerProvider * Register the unit tests required services. * * @param Container $container A DI container. - * @return void */ - public function registerDebug(Container $container) + public function registerDebug(Container $container): void { if (!isset($container['debug'])) { $container['debug'] = false; @@ -87,9 +86,8 @@ public function registerDebug(Container $container) * Register the unit tests required services. * * @param Container $container A DI container. - * @return void */ - public function registerBaseServices(Container $container) + public function registerBaseServices(Container $container): void { $this->registerDebug($container); $this->registerConfig($container); @@ -102,9 +100,8 @@ public function registerBaseServices(Container $container) * Register the admin services. * * @param Container $container A DI container. - * @return void */ - public function registerAdminServices(Container $container) + public function registerAdminServices(Container $container): void { $this->registerBaseServices($container); $this->registerBaseUrl($container); @@ -115,67 +112,57 @@ public function registerAdminServices(Container $container) * Setup the application's base URI. * * @param Container $container A DI container. - * @return void */ - public function registerBaseUrl(Container $container) + public function registerBaseUrl(Container $container): void { - $container['base-url'] = function () { - return Uri::createFromString(''); - }; + $container['base-url'] = (fn() => Uri::createFromString('')); - $container['admin/base-url'] = function () { - return Uri::createFromString('admin'); - }; + $container['admin/base-url'] = (fn() => Uri::createFromString('admin')); } /** * Setup the application configset. * * @param Container $container A DI container. - * @return void */ - public function registerConfig(Container $container) + public function registerConfig(Container $container): void { - $container['config'] = function () { - return new AppConfig([ - 'base_path' => realpath(__DIR__.'/../../..'), - 'apis' => [ - 'google' => [ - 'recaptcha' => [ - 'public_key' => 'foobar', - 'private_key' => 'bazqux', - ], + $container['config'] = (fn(): \Charcoal\App\AppConfig => new AppConfig([ + 'base_path' => realpath(__DIR__.'/../../..'), + 'apis' => [ + 'google' => [ + 'recaptcha' => [ + 'public_key' => 'foobar', + 'private_key' => 'bazqux', ], ], - 'locales' => [ - 'en' => [ - 'locale' => 'en-US', - ], + ], + 'locales' => [ + 'en' => [ + 'locale' => 'en-US', ], - 'translator' => [ - 'paths' => [], + ], + 'translator' => [ + 'paths' => [], + ], + 'metadata' => [ + 'paths' => [ + 'metadata', + // Standalone + 'vendor/charcoal/object/metadata', + 'vendor/charcoal/user/metadata', + // Monorepo + '/../object/metadata', + '/../user/metadata', ], - 'metadata' => [ - 'paths' => [ - 'metadata', - // Standalone - 'vendor/charcoal/object/metadata', - 'vendor/charcoal/user/metadata', - // Monorepo - '/../object/metadata', - '/../user/metadata', - ], - ], - ]); - }; + ], + ])); /** * List of Charcoal module classes. * * Explicitly defined in case of a version mismatch with dependencies. This parameter * is normally defined by {@see \Charcoal\App\ServiceProvider\AppServiceProvider}. - * - * @var array */ $container['module/classes'] = []; } @@ -184,134 +171,110 @@ public function registerConfig(Container $container) * Setup the admin module configset. * * @param Container $container A DI container. - * @return void */ - public function registerAdminConfig(Container $container) + public function registerAdminConfig(Container $container): void { $this->registerConfig($container); - $container['admin/config'] = function () { - return new AdminConfig(); - }; + $container['admin/config'] = (fn(): \Charcoal\Admin\Config => new AdminConfig()); } /** * @param Container $container A DI container. - * @return void */ - public function registerElfinderConfig(Container $container) + public function registerElfinderConfig(Container $container): void { - $container['elfinder/config'] = function () { - return []; - }; + $container['elfinder/config'] = (fn(): array => []); } /** * @param Container $container A DI container. - * @return void */ - public function registerLayoutFactory(Container $container) + public function registerLayoutFactory(Container $container): void { - $container['layout/factory'] = function () { - $layoutFactory = new LayoutFactory(); - return $layoutFactory; - }; + $container['layout/factory'] = (fn(): \Charcoal\Ui\Layout\LayoutFactory => new LayoutFactory()); } /** * @param Container $container A DI container. - * @return void */ - public function registerLayoutBuilder(Container $container) + public function registerLayoutBuilder(Container $container): void { $this->registerLayoutFactory($container); - $container['layout/builder'] = function (Container $container) { + $container['layout/builder'] = function (Container $container): \Charcoal\Ui\Layout\LayoutBuilder { $layoutFactory = $container['layout/factory']; - $layoutBuilder = new LayoutBuilder($layoutFactory, $container); - return $layoutBuilder; + return new LayoutBuilder($layoutFactory, $container); }; } /** * @param Container $container A DI container. - * @return void */ - public function registerDashboardFactory(Container $container) + public function registerDashboardFactory(Container $container): void { $this->registerLogger($container); $this->registerWidgetBuilder($container); $this->registerLayoutBuilder($container); - $container['dashboard/factory'] = function (Container $container) { - return new Factory([ - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'], - 'widget_builder' => $container['widget/builder'], - 'layout_builder' => $container['layout/builder'] - ]], - 'resolver_options' => [ - 'suffix' => 'Dashboard' - ] - ]); - }; + $container['dashboard/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'], + 'widget_builder' => $container['widget/builder'], + 'layout_builder' => $container['layout/builder'] + ]], + 'resolver_options' => [ + 'suffix' => 'Dashboard' + ] + ])); } /** * @param Container $container A DI container. - * @return void */ - public function registerDashboardBuilder(Container $container) + public function registerDashboardBuilder(Container $container): void { $this->registerDashboardFactory($container); - $container['dashboard/builder'] = function (Container $container) { + $container['dashboard/builder'] = function (Container $container): \Charcoal\Ui\Dashboard\DashboardBuilder { $dashboardFactory = $container['dashboard/factory']; - $dashboardBuilder = new DashboardBuilder($dashboardFactory, $container); - return $dashboardBuilder; + return new DashboardBuilder($dashboardFactory, $container); }; } /** * @param Container $container A DI container. - * @return void */ - public function registerWidgetFactory(Container $container) + public function registerWidgetFactory(Container $container): void { $this->registerLogger($container); - $container['widget/factory'] = function (Container $container) { - return new Factory([ - 'resolver_options' => [ - 'suffix' => 'Widget' - ], - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'] - ]] - ]); - }; + $container['widget/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'resolver_options' => [ + 'suffix' => 'Widget' + ], + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'] + ]] + ])); } /** * @param Container $container A DI container. - * @return void */ - public function registerWidgetBuilder(Container $container) + public function registerWidgetBuilder(Container $container): void { $this->registerWidgetFactory($container); - $container['widget/builder'] = function (Container $container) { - return new WidgetBuilder($container['widget/factory'], $container); - }; + $container['widget/builder'] = (fn(Container $container): \Charcoal\App\Template\WidgetBuilder => new WidgetBuilder($container['widget/factory'], $container)); } /** * @param Container $container A DI container. - * @return void */ - public function registerClimate(Container $container) + public function registerClimate(Container $container): void { $container['climate/system'] = function () { $system = Mockery::mock(Linux::class); @@ -338,11 +301,9 @@ public function registerClimate(Container $container) return $reader; }; - $container['climate/util'] = function (Container $container) { - return new UtilFactory($container['climate/system']); - }; + $container['climate/util'] = (fn(Container $container): \League\CLImate\Util\UtilFactory => new UtilFactory($container['climate/system'])); - $container['climate'] = function (Container $container) { + $container['climate'] = function (Container $container): \League\CLImate\CLImate { $climate = new CLImate(); $climate->setOutput($container['climate/output']); @@ -357,35 +318,28 @@ public function registerClimate(Container $container) * Setup the application's logging interface. * * @param Container $container A DI container. - * @return void */ - public function registerLogger(Container $container) + public function registerLogger(Container $container): void { - $container['logger'] = function () { - return new NullLogger(); - }; + $container['logger'] = (fn(): \Psr\Log\NullLogger => new NullLogger()); } /** * Setup the application's caching interface. * * @param Container $container A DI container. - * @return void */ - public function registerCache(Container $container) + public function registerCache(Container $container): void { - $container['cache'] = function () { - return new Pool(); - }; + $container['cache'] = (fn(): \Stash\Pool => new Pool()); } /** * @param Container $container A DI container. - * @return void */ - public function registerDatabase(Container $container) + public function registerDatabase(Container $container): void { - $container['database'] = function () { + $container['database'] = function (): \PDO { $pdo = new PDO('sqlite::memory:'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; @@ -394,9 +348,8 @@ public function registerDatabase(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerModelServiceProvider(Container $container) + public function registerModelServiceProvider(Container $container): void { static $provider = null; @@ -409,9 +362,8 @@ public function registerModelServiceProvider(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerTranslatorServiceProvider(Container $container) + public function registerTranslatorServiceProvider(Container $container): void { static $provider = null; @@ -424,9 +376,8 @@ public function registerTranslatorServiceProvider(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerViewServiceProvider(Container $container) + public function registerViewServiceProvider(Container $container): void { static $provider = null; @@ -439,107 +390,85 @@ public function registerViewServiceProvider(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerAcl(Container $container) + public function registerAcl(Container $container): void { - $container['admin/acl'] = function () { - return new Acl(); - }; + $container['admin/acl'] = (fn(): \Laminas\Permissions\Acl\Acl => new Acl()); - $container['authorizer/acl'] = function ($container) { - return $container['admin/acl']; - }; + $container['authorizer/acl'] = (fn($container) => $container['admin/acl']); } /** * @param Container $container A DI container. - * @return void */ - public function registerAuthenticator(Container $container) + public function registerAuthenticator(Container $container): void { $this->registerLogger($container); $this->registerModelServiceProvider($container); - $container['admin/authenticator'] = function (Container $container) { - return new Authenticator([ - 'logger' => $container['logger'], - 'user_type' => AdminUser::class, - 'user_factory' => $container['model/factory'], - 'token_type' => AdminAuthToken::class, - 'token_factory' => $container['model/factory'], - ]); - }; + $container['admin/authenticator'] = (fn(Container $container): \Charcoal\User\Authenticator => new Authenticator([ + 'logger' => $container['logger'], + 'user_type' => AdminUser::class, + 'user_factory' => $container['model/factory'], + 'token_type' => AdminAuthToken::class, + 'token_factory' => $container['model/factory'], + ])); - $container['authenticator'] = function (Container $container) { - return $container['admin/authenticator']; - }; + $container['authenticator'] = (fn(Container $container): mixed => $container['admin/authenticator']); } /** * @param Container $container A DI container. - * @return void */ - public function registerAuthorizer(Container $container) + public function registerAuthorizer(Container $container): void { $this->registerLogger($container); $this->registerAcl($container); - $container['admin/authorizer'] = function (Container $container) { - return new Authorizer([ - 'logger' => $container['logger'], - 'acl' => $container['admin/acl'], - 'resource' => 'admin', - ]); - }; + $container['admin/authorizer'] = (fn(Container $container): \Charcoal\User\Authorizer => new Authorizer([ + 'logger' => $container['logger'], + 'acl' => $container['admin/acl'], + 'resource' => 'admin', + ])); - $container['authorizer'] = function (Container $container) { - return $container['admin/authorizer']; - }; + $container['authorizer'] = (fn(Container $container): mixed => $container['admin/authorizer']); } /** * @param Container $container A DI container. - * @return void */ - public function registerPropertyDisplayFactory(Container $container) + public function registerPropertyDisplayFactory(Container $container): void { $this->registerDatabase($container); $this->registerLogger($container); - $container['property/display/factory'] = function (Container $container) { - return new Factory([ - 'resolver_options' => [ - 'suffix' => 'Display' - ], - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'] - ]] - ]); - }; + $container['property/display/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'resolver_options' => [ + 'suffix' => 'Display' + ], + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'] + ]] + ])); } /** * @param Container $container A DI container. - * @return void */ - public function registerEmailFactory(Container $container) + public function registerEmailFactory(Container $container): void { - $container['email/factory'] = function () { - return new Factory([ - 'map' => [ - 'email' => Email::class, - ], - ]); - }; + $container['email/factory'] = (fn(): \Charcoal\Factory\GenericFactory => new Factory([ + 'map' => [ + 'email' => Email::class, + ], + ])); } /** * @param Container $container A DI container. - * @return void */ - public function registerActionDependencies(Container $container) + public function registerActionDependencies(Container $container): void { $this->registerDebug($container); $this->registerLogger($container); @@ -559,9 +488,8 @@ public function registerActionDependencies(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerTemplateDependencies(Container $container) + public function registerTemplateDependencies(Container $container): void { $this->registerDebug($container); $this->registerLogger($container); @@ -584,9 +512,8 @@ public function registerTemplateDependencies(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerWidgetDependencies(Container $container) + public function registerWidgetDependencies(Container $container): void { $this->registerDebug($container); $this->registerLogger($container); @@ -606,9 +533,8 @@ public function registerWidgetDependencies(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerInputDependencies(Container $container) + public function registerInputDependencies(Container $container): void { $this->registerDebug($container); $this->registerLogger($container); @@ -628,9 +554,8 @@ public function registerInputDependencies(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerScriptDependencies(Container $container) + public function registerScriptDependencies(Container $container): void { $this->registerDebug($container); $this->registerLogger($container); diff --git a/packages/admin/tests/Charcoal/Admin/Mock/AuthToken.php b/packages/admin/tests/Charcoal/Admin/Mock/AuthToken.php index 88b634a31..19258cbfd 100644 --- a/packages/admin/tests/Charcoal/Admin/Mock/AuthToken.php +++ b/packages/admin/tests/Charcoal/Admin/Mock/AuthToken.php @@ -1,5 +1,7 @@ isEnabled()) { - return false; - } - - return true; + return $this->isEnabled(); } /** * @return boolean */ + #[\Override] public function deleteCookie() { - if (!$this->isEnabled()) { - return false; - } - - return true; + return $this->isEnabled(); } } diff --git a/packages/admin/tests/Charcoal/Admin/Mock/SortableModel.php b/packages/admin/tests/Charcoal/Admin/Mock/SortableModel.php index 61678f63c..46d140d03 100644 --- a/packages/admin/tests/Charcoal/Admin/Mock/SortableModel.php +++ b/packages/admin/tests/Charcoal/Admin/Mock/SortableModel.php @@ -1,5 +1,7 @@ [ diff --git a/packages/admin/tests/Charcoal/Admin/Mock/UserProviderTrait.php b/packages/admin/tests/Charcoal/Admin/Mock/UserProviderTrait.php index 78997e386..8dcb61b01 100644 --- a/packages/admin/tests/Charcoal/Admin/Mock/UserProviderTrait.php +++ b/packages/admin/tests/Charcoal/Admin/Mock/UserProviderTrait.php @@ -56,14 +56,14 @@ protected function createUser( * @param string $email The email to lookup. * @return User */ - protected function userExists($email) + protected function userExists($email): bool { $container = $this->container(); $user = $container['model/factory']->create($this->userClass); $user->loadFrom('email', $email); - return !!$user->id(); + return (bool) $user->id(); } /** diff --git a/packages/admin/tests/Charcoal/Admin/Property/AbstractInputTest.php b/packages/admin/tests/Charcoal/Admin/Property/AbstractInputTest.php index 9a231a339..46f27d752 100644 --- a/packages/admin/tests/Charcoal/Admin/Property/AbstractInputTest.php +++ b/packages/admin/tests/Charcoal/Admin/Property/AbstractInputTest.php @@ -22,30 +22,25 @@ class AbstractInputTest extends AbstractTestCase /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; - /** - * @return void - */ public function setUp(): void { $container = $this->container(); - $this->obj = $this->getMockForAbstractClass(AbstractPropertyInput::class, [ - [ - 'logger' => $container['logger'], - 'metadata_loader' => $container['metadata/loader'], - ], - ]); + $this->obj = new Class([ + 'logger' => $container['logger'], + 'metadata_loader' => $container['metadata/loader'], + ]) extends AbstractPropertyInput { + public function type(): string + { + return 'foo'; + } + }; } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ @@ -63,12 +58,10 @@ public function testSetData() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerInputDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Property/Input/TextInputTest.php b/packages/admin/tests/Charcoal/Admin/Property/Input/TextInputTest.php index 78154afe5..876fb56a5 100644 --- a/packages/admin/tests/Charcoal/Admin/Property/Input/TextInputTest.php +++ b/packages/admin/tests/Charcoal/Admin/Property/Input/TextInputTest.php @@ -15,14 +15,8 @@ */ class TextInputTest extends AbstractTestCase { - /** - * @var TextInput - */ - private $obj; - - /** - * @return void - */ + private \Charcoal\Admin\Property\Input\TextInput $obj; + public function setUp(): void { $container = new Container(); @@ -36,10 +30,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ @@ -53,14 +44,11 @@ public function testSetData() $this->assertEquals(42, $obj->size()); $this->assertEquals(10, $obj->minLength()); $this->assertEquals(100, $obj->maxLength()); - $this->assertEquals('foo', (string)$obj->pattern()); + $this->assertEquals('foo', $obj->pattern()); $this->assertEquals('bar', (string)$obj->placeholder()); } - /** - * @return void - */ - public function testSetSize() + public function testSetSize(): void { $obj = $this->obj; $ret = $obj->setSize(42); @@ -71,10 +59,7 @@ public function testSetSize() $obj->setSize(false); } - /** - * @return void - */ - public function testSetMinLength() + public function testSetMinLength(): void { $obj = $this->obj; $ret = $obj->setMinLength(42); @@ -85,10 +70,7 @@ public function testSetMinLength() $obj->setMinLength(false); } - /** - * @return void - */ - public function testSetMaxLength() + public function testSetMaxLength(): void { $obj = $this->obj; $ret = $obj->setMaxLength(42); @@ -99,10 +81,7 @@ public function testSetMaxLength() $obj->setMaxLength(false); } - /** - * @return void - */ - public function testSetPattern() + public function testSetPattern(): void { $obj = $this->obj; $ret = $obj->setPattern('foo'); @@ -113,10 +92,7 @@ public function testSetPattern() $obj->setPattern(false); } - /** - * @return void - */ - public function testSetPlaceholder() + public function testSetPlaceholder(): void { $obj = $this->obj; $ret = $obj->setPlaceholder('foo'); diff --git a/packages/admin/tests/Charcoal/Admin/Property/Input/TextareaInputTest.php b/packages/admin/tests/Charcoal/Admin/Property/Input/TextareaInputTest.php index 12fce74e1..0a27b823e 100644 --- a/packages/admin/tests/Charcoal/Admin/Property/Input/TextareaInputTest.php +++ b/packages/admin/tests/Charcoal/Admin/Property/Input/TextareaInputTest.php @@ -17,21 +17,14 @@ class TextareaInputTest extends AbstractTestCase { /** * Tested Class. - * - * @var TextareaInput */ - private $obj; + private \Charcoal\Admin\Property\Input\TextareaInput $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; - /** - * @return void - */ public function setUp(): void { $container = $this->container(); @@ -42,10 +35,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ @@ -57,10 +47,7 @@ public function testSetData() $this->assertEquals(84, $obj->rows()); } - /** - * @return void - */ - public function testSetCols() + public function testSetCols(): void { $obj = $this->obj; $ret = $obj->setCols(42); @@ -72,10 +59,7 @@ public function testSetCols() $obj->setCols('foo'); } - /** - * @return void - */ - public function testSetRows() + public function testSetRows(): void { $obj = $this->obj; $ret = $obj->setRows(42); @@ -89,12 +73,10 @@ public function testSetRows() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerInputDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessDailyScriptTest.php b/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessDailyScriptTest.php index 5fb93807f..96a5beb6d 100644 --- a/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessDailyScriptTest.php +++ b/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessDailyScriptTest.php @@ -21,36 +21,25 @@ class ProcessDailyScriptTest extends AbstractTestCase { use ReflectionsTrait; - /** - * @var Container - */ - private $container; + private \Pimple\Container $container; /** * Instance of class under test * @var CreateScript */ - private $obj; + private \Charcoal\Admin\Script\Notification\ProcessDailyScript $obj; - /** - * @return Container - */ - private function getContainer() + private function getContainer(): \Pimple\Container { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerScriptDependencies($container); - $container['email/factory'] = function(Container $container) { - return $container['model/factory']; - }; + $container['email/factory'] = (fn(Container $container): mixed => $container['model/factory']); return $container; } - /** - * @return void - */ public function setUp(): void { $this->container = $this->getContainer(); @@ -66,19 +55,13 @@ public function setUp(): void } - /** - * @return void - */ - public function testDefaultArguments() + public function testDefaultArguments(): void { $args = $this->obj->defaultArguments(); $this->assertArrayHasKey('now', $args); } - /** - * @return void - */ - public function testFrequency() + public function testFrequency(): void { $this->assertEquals('daily', $this->callMethod($this->obj, 'frequency')); } diff --git a/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessHourlyScriptTest.php b/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessHourlyScriptTest.php index 398cbdf37..4c4b78a96 100644 --- a/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessHourlyScriptTest.php +++ b/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessHourlyScriptTest.php @@ -21,36 +21,25 @@ class ProcessHourlyScriptTest extends AbstractTestCase { use ReflectionsTrait; - /** - * @var Container - */ - private $container; + private \Pimple\Container $container; /** * Instance of class under test * @var CreateScript */ - private $obj; + private \Charcoal\Admin\Script\Notification\ProcessHourlyScript $obj; - /** - * @return Container - */ - private function getContainer() + private function getContainer(): \Pimple\Container { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerScriptDependencies($container); - $container['email/factory'] = function(Container $container) { - return $container['model/factory']; - }; + $container['email/factory'] = (fn(Container $container): mixed => $container['model/factory']); return $container; } - /** - * @return void - */ public function setUp(): void { $this->container = $this->getContainer(); @@ -66,19 +55,13 @@ public function setUp(): void } - /** - * @return void - */ - public function testDefaultArguments() + public function testDefaultArguments(): void { $args = $this->obj->defaultArguments(); $this->assertArrayHasKey('now', $args); } - /** - * @return void - */ - public function testFrequency() + public function testFrequency(): void { $this->assertEquals('hourly', $this->callMethod($this->obj, 'frequency')); } diff --git a/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessMinuteScriptTest.php b/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessMinuteScriptTest.php index 9e45bc5ed..216af9ff4 100644 --- a/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessMinuteScriptTest.php +++ b/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessMinuteScriptTest.php @@ -21,36 +21,25 @@ class ProcessMinuteScriptTest extends AbstractTestCase { use ReflectionsTrait; - /** - * @var Container - */ - private $container; + private \Pimple\Container $container; /** * Instance of class under test * @var CreateScript */ - private $obj; + private \Charcoal\Admin\Script\Notification\ProcessMinuteScript $obj; - /** - * @return Container - */ - private function getContainer() + private function getContainer(): \Pimple\Container { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerScriptDependencies($container); - $container['email/factory'] = function(Container $container) { - return $container['model/factory']; - }; + $container['email/factory'] = (fn(Container $container): mixed => $container['model/factory']); return $container; } - /** - * @return void - */ public function setUp(): void { $this->container = $this->getContainer(); @@ -66,19 +55,13 @@ public function setUp(): void } - /** - * @return void - */ - public function testDefaultArguments() + public function testDefaultArguments(): void { $args = $this->obj->defaultArguments(); $this->assertArrayHasKey('now', $args); } - /** - * @return void - */ - public function testFrequency() + public function testFrequency(): void { $this->assertEquals('minute', $this->callMethod($this->obj, 'frequency')); } diff --git a/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessMonthlyScriptTest.php b/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessMonthlyScriptTest.php index 4e4e934a5..e9a14f4f8 100644 --- a/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessMonthlyScriptTest.php +++ b/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessMonthlyScriptTest.php @@ -21,36 +21,25 @@ class ProcessMonthlyScriptTest extends AbstractTestCase { use ReflectionsTrait; - /** - * @var Container - */ - private $container; + private \Pimple\Container $container; /** * Instance of class under test * @var CreateScript */ - private $obj; + private \Charcoal\Admin\Script\Notification\ProcessMonthlyScript $obj; - /** - * @return Container - */ - private function getContainer() + private function getContainer(): \Pimple\Container { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerScriptDependencies($container); - $container['email/factory'] = function(Container $container) { - return $container['model/factory']; - }; + $container['email/factory'] = (fn(Container $container): mixed => $container['model/factory']); return $container; } - /** - * @return void - */ public function setUp(): void { $this->container = $this->getContainer(); @@ -66,19 +55,13 @@ public function setUp(): void } - /** - * @return void - */ - public function testDefaultArguments() + public function testDefaultArguments(): void { $args = $this->obj->defaultArguments(); $this->assertArrayHasKey('now', $args); } - /** - * @return void - */ - public function testFrequency() + public function testFrequency(): void { $this->assertEquals('monthly', $this->callMethod($this->obj, 'frequency')); } diff --git a/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessWeeklyScriptTest.php b/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessWeeklyScriptTest.php index f53a98581..d43177a70 100644 --- a/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessWeeklyScriptTest.php +++ b/packages/admin/tests/Charcoal/Admin/Script/Notification/ProcessWeeklyScriptTest.php @@ -21,36 +21,25 @@ class ProcessWeeklyScriptTest extends AbstractTestCase { use ReflectionsTrait; - /** - * @var Container - */ - private $container; + private \Pimple\Container $container; /** * Instance of class under test * @var CreateScript */ - private $obj; + private \Charcoal\Admin\Script\Notification\ProcessWeeklyScript $obj; - /** - * @return Container - */ - private function getContainer() + private function getContainer(): \Pimple\Container { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerScriptDependencies($container); - $container['email/factory'] = function(Container $container) { - return $container['model/factory']; - }; + $container['email/factory'] = (fn(Container $container): mixed => $container['model/factory']); return $container; } - /** - * @return void - */ public function setUp(): void { $this->container = $this->getContainer(); @@ -66,19 +55,13 @@ public function setUp(): void } - /** - * @return void - */ - public function testDefaultArguments() + public function testDefaultArguments(): void { $args = $this->obj->defaultArguments(); $this->assertArrayHasKey('now', $args); } - /** - * @return void - */ - public function testFrequency() + public function testFrequency(): void { $this->assertEquals('weekly', $this->callMethod($this->obj, 'frequency')); } diff --git a/packages/admin/tests/Charcoal/Admin/Script/Object/Table/CreateScriptTest.php b/packages/admin/tests/Charcoal/Admin/Script/Object/Table/CreateScriptTest.php index aea0c9675..c9889c991 100644 --- a/packages/admin/tests/Charcoal/Admin/Script/Object/Table/CreateScriptTest.php +++ b/packages/admin/tests/Charcoal/Admin/Script/Object/Table/CreateScriptTest.php @@ -31,21 +31,14 @@ */ class CreateScriptTest extends AbstractTestCase { - /** - * @var Container - */ - private $container; + private \Pimple\Container $container; /** * Instance of class under test - * @var CreateScript */ - private $obj; + private \Charcoal\Admin\Script\Object\Table\CreateScript $obj; - /** - * @return Container - */ - private function getContainer() + private function getContainer(): \Pimple\Container { $container = new Container(); $containerProvider = new ContainerProvider(); @@ -53,9 +46,6 @@ private function getContainer() return $container; } - /** - * @return void - */ public function setUp(): void { $this->container = $this->getContainer(); @@ -71,10 +61,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testDefaultArguments() + public function testDefaultArguments(): void { $args = $this->obj->defaultArguments(); diff --git a/packages/admin/tests/Charcoal/Admin/Script/User/CreateScriptTest.php b/packages/admin/tests/Charcoal/Admin/Script/User/CreateScriptTest.php index 18e44d639..d93bcc516 100644 --- a/packages/admin/tests/Charcoal/Admin/Script/User/CreateScriptTest.php +++ b/packages/admin/tests/Charcoal/Admin/Script/User/CreateScriptTest.php @@ -31,21 +31,14 @@ */ class CreateScriptTest extends AbstractTestCase { - /** - * @var Container - */ - private $container; + private \Pimple\Container $container; /** * Instance of class under test - * @var CreateScript */ - private $obj; + private \Charcoal\Admin\Script\User\CreateScript $obj; - /** - * @return Container - */ - private function getContainer() + private function getContainer(): \Pimple\Container { $container = new Container(); $containerProvider = new ContainerProvider(); @@ -53,9 +46,6 @@ private function getContainer() return $container; } - /** - * @return void - */ public function setUp(): void { $this->container = $this->getContainer(); @@ -68,10 +58,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testDefaultArguments() + public function testDefaultArguments(): void { $args = $this->obj->defaultArguments(); @@ -80,10 +67,7 @@ public function testDefaultArguments() $this->assertArrayHasKey('roles', $args); } - /** - * @return void - */ - public function testArguments() + public function testArguments(): void { $args = $this->obj->arguments(); @@ -92,20 +76,6 @@ public function testArguments() $this->assertArrayHasKey('roles', $args); } - /** - * @return integer - */ - private function numAdminUsersInSource() - { - $source = $this->container['model/factory']->create('charcoal/admin/user')->source(); - $source->createTable(); - - $table = $source->table(); - $q = 'select count(`email`) as num from `'.$table.'`'; - $req = $this->container['database']->query($q); - return $req->fetchColumn(0); - } - // public function testInvoke() // { // // Ensure that no admin user exists in test database diff --git a/packages/admin/tests/Charcoal/Admin/Script/User/ResetPasswordScriptTest.php b/packages/admin/tests/Charcoal/Admin/Script/User/ResetPasswordScriptTest.php index fbf9f9140..0caa45b52 100644 --- a/packages/admin/tests/Charcoal/Admin/Script/User/ResetPasswordScriptTest.php +++ b/packages/admin/tests/Charcoal/Admin/Script/User/ResetPasswordScriptTest.php @@ -31,21 +31,15 @@ */ class ResetPasswordScriptTest extends AbstractTestCase { - /** - * @var Container - */ - private $container; + private \Pimple\Container $container; /** * Instance of class under test * @var CreateScript */ - private $obj; + private \Charcoal\Admin\Script\User\ResetPasswordScript $obj; - /** - * @return Container - */ - private function getContainer() + private function getContainer(): \Pimple\Container { $container = new Container(); $containerProvider = new ContainerProvider(); @@ -53,9 +47,6 @@ private function getContainer() return $container; } - /** - * @return void - */ public function setUp(): void { $this->container = $this->getContainer(); @@ -70,10 +61,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testDefaultArguments() + public function testDefaultArguments(): void { $args = $this->obj->defaultArguments(); @@ -81,10 +69,7 @@ public function testDefaultArguments() $this->assertArrayHasKey('password', $args); } - /** - * @return void - */ - public function testArguments() + public function testArguments(): void { $args = $this->obj->arguments(); diff --git a/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php b/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php index 49551abe9..b3a7eb8d8 100644 --- a/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php +++ b/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php @@ -21,51 +21,27 @@ */ class ExporterTest extends AbstractTestCase { - /** - * @var Exporter - */ - private $obj; - /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; - /** - * @return void - */ public function setUp(): void { - $container = $this->container(); - - $this->obj = new Exporter([ - 'logger' => $container['logger'], - 'factory' => $container['model/factory'], - 'propertyFactory' => $container['property/factory'], - 'translator' => $container['translator'], - 'obj_type' => 'charcoal/admin/user', - 'export_ident' => 'y', - ]); + $this->container(); } - /** - * @return void - */ - public function testExport() + public function testExport(): void { $this->assertTrue(true); } /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); @@ -73,7 +49,7 @@ protected function container() $containerProvider->registerModelServiceProvider($container); $containerProvider->registerTranslatorServiceProvider($container); - $container['view'] = $this->createMock('\Charcoal\View\ViewInterface'); + $container['view'] = $this->createMock(\Charcoal\View\ViewInterface::class); $this->container = $container; } diff --git a/packages/admin/tests/Charcoal/Admin/ServiceProvider/AclServiceProviderTest.php b/packages/admin/tests/Charcoal/Admin/ServiceProvider/AclServiceProviderTest.php index fd87dc892..b53310ee0 100644 --- a/packages/admin/tests/Charcoal/Admin/ServiceProvider/AclServiceProviderTest.php +++ b/packages/admin/tests/Charcoal/Admin/ServiceProvider/AclServiceProviderTest.php @@ -14,10 +14,7 @@ */ class AclServiceProviderTest extends AbstractTestCase { - /** - * @return void - */ - public function testProvider() + public function testProvider(): void { $container = new Container([ 'config' => [] diff --git a/packages/admin/tests/Charcoal/Admin/Template/Account/LostPasswordTemplateTest.php b/packages/admin/tests/Charcoal/Admin/Template/Account/LostPasswordTemplateTest.php index 6960e7dd1..d48415a92 100644 --- a/packages/admin/tests/Charcoal/Admin/Template/Account/LostPasswordTemplateTest.php +++ b/packages/admin/tests/Charcoal/Admin/Template/Account/LostPasswordTemplateTest.php @@ -23,11 +23,8 @@ class LostPasswordTemplateTest extends AbstractTestCase * Instance of object under test * @var LoginTemplate */ - private $obj; + private \Charcoal\Admin\Template\Account\LostPasswordTemplate $obj; - /** - * @return void - */ public function setUp(): void { $this->obj = new LostPasswordTemplate([ @@ -35,10 +32,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsFalse() + public function testAuthRequiredIsFalse(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertNotTrue($res); diff --git a/packages/admin/tests/Charcoal/Admin/Template/Account/ResetPasswordTemplateTest.php b/packages/admin/tests/Charcoal/Admin/Template/Account/ResetPasswordTemplateTest.php index 23f551637..69cb2eb62 100644 --- a/packages/admin/tests/Charcoal/Admin/Template/Account/ResetPasswordTemplateTest.php +++ b/packages/admin/tests/Charcoal/Admin/Template/Account/ResetPasswordTemplateTest.php @@ -23,11 +23,8 @@ class ResetPasswordTemplateTest extends AbstractTestCase * Instance of object under test * @var LoginTemplate */ - private $obj; + private \Charcoal\Admin\Template\Account\ResetPasswordTemplate $obj; - /** - * @return void - */ public function setUp(): void { $this->obj = new ResetPasswordTemplate([ @@ -35,10 +32,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsFalse() + public function testAuthRequiredIsFalse(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertNotTrue($res); diff --git a/packages/admin/tests/Charcoal/Admin/Template/ElfinderTemplateTest.php b/packages/admin/tests/Charcoal/Admin/Template/ElfinderTemplateTest.php index 750206148..ac56a0043 100644 --- a/packages/admin/tests/Charcoal/Admin/Template/ElfinderTemplateTest.php +++ b/packages/admin/tests/Charcoal/Admin/Template/ElfinderTemplateTest.php @@ -19,22 +19,16 @@ class ElfinderTemplateTest extends AbstractTestCase { /** * Tested Class. - * - * @var ElfinderTemplate */ - private $obj; + private \Charcoal\Admin\Template\ElfinderTemplate $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -46,10 +40,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAdminAssertsUrl() + public function testAdminAssertsUrl(): void { $ret = $this->obj->adminAssetsUrl(); $this->assertEquals('/assets/admin/', $ret); @@ -57,17 +48,15 @@ public function testAdminAssertsUrl() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerTemplateDependencies($container); $containerProvider->registerElfinderConfig($container); - $container['widget/factory'] = $this->createMock('\Charcoal\Factory\FactoryInterface'); + $container['widget/factory'] = $this->createMock(\Charcoal\Factory\FactoryInterface::class); $this->container = $container; } diff --git a/packages/admin/tests/Charcoal/Admin/Template/LoginTemplateTest.php b/packages/admin/tests/Charcoal/Admin/Template/LoginTemplateTest.php index a216acde6..6869de520 100644 --- a/packages/admin/tests/Charcoal/Admin/Template/LoginTemplateTest.php +++ b/packages/admin/tests/Charcoal/Admin/Template/LoginTemplateTest.php @@ -21,13 +21,9 @@ class LoginTemplateTest extends AbstractTestCase /** * Instance of object under test - * @var LoginTemplate */ - private $obj; + private \Charcoal\Admin\Template\LoginTemplate $obj; - /** - * @return void - */ public function setUp(): void { $this->obj = new LoginTemplate([ @@ -35,10 +31,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsFalse() + public function testAuthRequiredIsFalse(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertNotTrue($res); diff --git a/packages/admin/tests/Charcoal/Admin/Template/LogoutTemplateTest.php b/packages/admin/tests/Charcoal/Admin/Template/LogoutTemplateTest.php index 8dacfb792..5d3731c6f 100644 --- a/packages/admin/tests/Charcoal/Admin/Template/LogoutTemplateTest.php +++ b/packages/admin/tests/Charcoal/Admin/Template/LogoutTemplateTest.php @@ -22,9 +22,6 @@ class LogoutTemplateTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ public function setUp(): void { $this->obj = new LogoutTemplate([ @@ -32,10 +29,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsFalse() + public function testAuthRequiredIsFalse(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertNotTrue($res); diff --git a/packages/admin/tests/Charcoal/Admin/Template/Object/CollectionTemplateTest.php b/packages/admin/tests/Charcoal/Admin/Template/Object/CollectionTemplateTest.php index 2281d714b..f1c44b1f9 100644 --- a/packages/admin/tests/Charcoal/Admin/Template/Object/CollectionTemplateTest.php +++ b/packages/admin/tests/Charcoal/Admin/Template/Object/CollectionTemplateTest.php @@ -22,22 +22,16 @@ class CollectionTemplateTest extends AbstractTestCase /** * Tested Class. - * - * @var CollectionTemplate */ - private $obj; + private \Charcoal\Admin\Template\Object\CollectionTemplate $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -50,28 +44,19 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testInit() + public function testInit(): void { //$ret = $this->obj->init(); $this->assertTrue(true); } - /** - * @return void - */ - public function testTitle() + public function testTitle(): void { $this->obj->setObjType('charcoal/admin/user'); $ret = $this->obj->title(); @@ -82,12 +67,10 @@ public function testTitle() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerTemplateDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Template/Object/CreateTemplateTest.php b/packages/admin/tests/Charcoal/Admin/Template/Object/CreateTemplateTest.php index c392c1d3e..4860ebd7c 100644 --- a/packages/admin/tests/Charcoal/Admin/Template/Object/CreateTemplateTest.php +++ b/packages/admin/tests/Charcoal/Admin/Template/Object/CreateTemplateTest.php @@ -21,22 +21,16 @@ class CreateTemplateTest extends AbstractTestCase /** * Tested Class. - * - * @var CreateTemplate */ - private $obj; + private \Charcoal\Admin\Template\Object\CreateTemplate $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -50,19 +44,13 @@ public function setUp(): void //$this->obj->setDependencies($container); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testTitle() + public function testTitle(): void { $this->obj->setObjType('charcoal/admin/user'); $ret = $this->obj->title(); @@ -73,12 +61,10 @@ public function testTitle() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerTemplateDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Template/Object/EditTemplateTest.php b/packages/admin/tests/Charcoal/Admin/Template/Object/EditTemplateTest.php index 0bae749e0..f26fe68b6 100644 --- a/packages/admin/tests/Charcoal/Admin/Template/Object/EditTemplateTest.php +++ b/packages/admin/tests/Charcoal/Admin/Template/Object/EditTemplateTest.php @@ -21,22 +21,16 @@ class EditTemplateTest extends AbstractTestCase /** * Tested Class. - * - * @var EditTemplate */ - private $obj; + private \Charcoal\Admin\Template\Object\EditTemplate $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -50,19 +44,13 @@ public function setUp(): void //$this->obj->setDependencies($container); } - /** - * @return void - */ - public function testAuthRequiredIsTrue() + public function testAuthRequiredIsTrue(): void { $res = $this->callMethod($this->obj, 'authRequired'); $this->assertTrue($res); } - /** - * @return void - */ - public function testTitle() + public function testTitle(): void { $this->obj->setObjType('charcoal/admin/user'); $ret = $this->obj->title(); @@ -73,12 +61,10 @@ public function testTitle() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerTemplateDependencies($container); diff --git a/packages/admin/tests/Charcoal/Admin/Widget/CollectionMapWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/CollectionMapWidgetTest.php index 55fa2f365..d01e02845 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/CollectionMapWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/CollectionMapWidgetTest.php @@ -19,9 +19,6 @@ class CollectionMapWidgetTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ public function setUp(): void { $logger = new NullLogger(); @@ -30,40 +27,28 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testSetLatProperty() + public function testSetLatProperty(): void { $ret = $this->obj->setLatProperty('foo'); $this->assertSame($ret, $this->obj); $this->assertEquals('foo', $this->obj->latProperty()); } - /** - * @return void - */ - public function testSetLonProperty() + public function testSetLonProperty(): void { $ret = $this->obj->setLonProperty('foo'); $this->assertSame($ret, $this->obj); $this->assertEquals('foo', $this->obj->lonProperty()); } - /** - * @return void - */ - public function testSetPolygonProperty() + public function testSetPolygonProperty(): void { $ret = $this->obj->setPolygonProperty('foo'); $this->assertSame($ret, $this->obj); $this->assertEquals('foo', $this->obj->polygonProperty()); } - /** - * @return void - */ - public function testSetInfoboxTemplate() + public function testSetInfoboxTemplate(): void { $ret = $this->obj->setInfoboxTemplate('foo'); $this->assertSame($ret, $this->obj); diff --git a/packages/admin/tests/Charcoal/Admin/Widget/FormGroupWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/FormGroupWidgetTest.php index d44421d2a..cce0be26f 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/FormGroupWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/FormGroupWidgetTest.php @@ -18,9 +18,7 @@ */ class FormGroupWidgetTest extends AbstractTestCase { - /** - * @return void - */ + public $obj; public function setUp(): void { $container = new Container(); @@ -31,7 +29,7 @@ public function setUp(): void $containerProvider->registerAuthenticator($container); - $container['form/input/builder'] = $this->createMock(\Charcoal\Ui\FormInput\FormInputBuilder::class, ''); + $container['form/input/builder'] = $this->createMock(\Charcoal\Ui\FormInput\FormInputBuilder::class); $container['authorizer'] = $container['admin/authorizer']; $container['authenticator'] = $container['admin/authenticator']; @@ -42,10 +40,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(FormGroupWidget::class, $this->obj); } diff --git a/packages/admin/tests/Charcoal/Admin/Widget/FormPropertyWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/FormPropertyWidgetTest.php index 7ed853709..dc4d8aca9 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/FormPropertyWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/FormPropertyWidgetTest.php @@ -18,9 +18,7 @@ */ class FormPropertyWidgetTest extends AbstractTestCase { - /** - * @return void - */ + public $obj; public function setUp(): void { $container = new Container(); @@ -36,18 +34,12 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(FormPropertyWidget::class, $this->obj); } - /** - * @return void - */ - public function testSetOutputType() + public function testSetOutputType(): void { //$this->assertEquals(FormPropertyWidget::DEFAULT_OUTPUT, $this->obj->outputType()); @@ -68,10 +60,7 @@ public function testSetOutputType() $this->obj->setOutputType('foobar'); } - /** - * @return void - */ - public function testPropertyType() + public function testPropertyType(): void { $this->assertNull($this->obj->propertyType()); diff --git a/packages/admin/tests/Charcoal/Admin/Widget/FormSidebarWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/FormSidebarWidgetTest.php index ad78b17d4..7712df3de 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/FormSidebarWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/FormSidebarWidgetTest.php @@ -18,9 +18,7 @@ */ class FormSidebarWidgetTest extends AbstractTestCase { - /** - * @return void - */ + public $obj; public function setUp(): void { $container = new Container(); @@ -36,10 +34,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(FormSidebarWidget::class, $this->obj); } diff --git a/packages/admin/tests/Charcoal/Admin/Widget/FormWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/FormWidgetTest.php index 1f9665814..422c4274b 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/FormWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/FormWidgetTest.php @@ -17,13 +17,9 @@ class FormWidgetTest extends AbstractTestCase { /** * Object under test - * @var FormWidget */ - private $obj; + private \Charcoal\Admin\Widget\FormWidget $obj; - /** - * @return void - */ public function setUp(): void { $logger = new NullLogger(); @@ -32,21 +28,7 @@ public function setUp(): void ]); } - /** - * @return FormSidebarWidget - */ - private function sidebarWidget() - { - $logger = new NullLogger(); - return new FormSidebarWidget([ - 'logger' => $logger, - ]); - } - - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(FormWidget::class, $this->obj); } diff --git a/packages/admin/tests/Charcoal/Admin/Widget/GraphWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/GraphWidgetTest.php index 679ee6017..990251f3b 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/GraphWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/GraphWidgetTest.php @@ -14,21 +14,26 @@ */ class GraphWidgetTest extends AbstractTestCase { - /** - * @return void - */ + public $obj; public function setUp(): void { $logger = new NullLogger(); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Admin\Widget\Graph\AbstractGraphWidget', [[ - 'logger'=>$logger - ]]); + + $this->obj = new class ([ + 'logger' => $logger + ]) extends AbstractGraphWidget { + public function categories() + { + return ['foo', 'bar']; + } + public function series() + { + return ['foo', 'bar']; + } + }; } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ @@ -40,10 +45,7 @@ public function testSetData() $this->assertEquals(['#ff0000', '#0000ff'], $obj->colors()); } - /** - * @return void - */ - public function testSetHeight() + public function testSetHeight(): void { $obj = $this->obj; $this->assertEquals('400px', $obj->height()); @@ -56,10 +58,7 @@ public function testSetHeight() //$obj->setHeight(false); } - /** - * @return void - */ - public function testSetColors() + public function testSetColors(): void { $obj = $this->obj; $this->assertEquals($obj->defaultColors(), $obj->colors()); diff --git a/packages/admin/tests/Charcoal/Admin/Widget/LayoutWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/LayoutWidgetTest.php index e336da11b..1071b1390 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/LayoutWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/LayoutWidgetTest.php @@ -14,9 +14,7 @@ */ class LayoutWidgetTest extends AbstractTestCase { - /** - * @return void - */ + public $obj; public function setUp(): void { $logger = new NullLogger(); @@ -25,27 +23,18 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testDefaultPosition() + public function testDefaultPosition(): void { $obj = $this->obj; - $this->assertInstanceOf('\Charcoal\Admin\Widget\LayoutWidget', $obj); + $this->assertInstanceOf(\Charcoal\Admin\Widget\LayoutWidget::class, $obj); $this->assertEquals(0, $obj->position()); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $struct = [[ 'columns'=>[1] ]]; - $computed = [ - 'columns'=>[1] - ]; $obj = $this->obj; $ret = $obj->setData([ @@ -55,10 +44,7 @@ public function testSetData() //$this->assertEquals($computed, $obj->structure()); } - /** - * @return void - */ - public function testSetStructure() + public function testSetStructure(): void { $obj = $this->obj; $this->assertEquals([], $obj->structure()); @@ -83,10 +69,7 @@ public function testSetStructure() //$this->assertEquals($struct, $obj->structure()); } - /** - * @return void - */ - public function testNumRows() + public function testNumRows(): void { $obj = $this->obj; $this->assertEquals(0, $obj->numRows()); @@ -98,10 +81,7 @@ public function testNumRows() $this->assertEquals(3, $obj->numRows()); } - /** - * @return void - */ - public function testRowIndex() + public function testRowIndex(): void { $obj = $this->obj; $this->assertNull($obj->rowIndex()); @@ -118,10 +98,7 @@ public function testRowIndex() $this->assertEquals(0, $obj->rowIndex(5)); } - /** - * @return void - */ - public function testRowData() + public function testRowData(): void { $obj = $this->obj; $this->assertNull($obj->rowData()); @@ -138,10 +115,7 @@ public function testRowData() $this->assertNull($obj->rowData(5)); } - /** - * @return void - */ - public function testRowNumColumns() + public function testRowNumColumns(): void { $obj = $this->obj; $this->assertNull($obj->rowNumColumns()); @@ -158,10 +132,7 @@ public function testRowNumColumns() $this->assertNull($obj->rowNumColumns(5)); } - /** - * @return void - */ - public function testRowNumCells() + public function testRowNumCells(): void { $obj = $this->obj; $this->assertNull($obj->rowNumCells()); @@ -178,10 +149,7 @@ public function testRowNumCells() $this->assertNull($obj->rowNumCells(5)); } - /** - * @return void - */ - public function testRowFirstCellIndex() + public function testRowFirstCellIndex(): void { $obj = $this->obj; $this->assertNull($obj->rowFirstCellIndex()); @@ -198,10 +166,7 @@ public function testRowFirstCellIndex() //$this->assertNull($obj->rowFirstCellIndex(5)); } - /** - * @return void - */ - public function testCellRowIndex() + public function testCellRowIndex(): void { $obj = $this->obj; //$this->assertNull($obj->cellRowIndex()); @@ -218,10 +183,7 @@ public function testCellRowIndex() //$this->assertNull($obj->cellRowIndex(5)); } - /** - * @return void - */ - public function testNumCellsTotal() + public function testNumCellsTotal(): void { $obj = $this->obj; $this->assertEquals(0, $obj->numCellsTotal()); @@ -233,10 +195,7 @@ public function testNumCellsTotal() $this->assertEquals(5, $obj->numCellsTotal()); } - /** - * @return void - */ - public function testNumCellSpan() + public function testNumCellSpan(): void { $obj = $this->obj; $this->assertNull($obj->cellSpan()); @@ -253,10 +212,7 @@ public function testNumCellSpan() $this->assertNull($obj->cellSpan(5)); } - /** - * @return void - */ - public function testNumCellSpanBy12() + public function testNumCellSpanBy12(): void { $obj = $this->obj; $this->assertNull($obj->cellSpanBy12()); @@ -273,10 +229,7 @@ public function testNumCellSpanBy12() $this->assertNull($obj->cellSpanBy12(5)); } - /** - * @return void - */ - public function testCellStartsRow() + public function testCellStartsRow(): void { $obj = $this->obj; //$this->assertNull($obj->cellStartsRow()); @@ -293,10 +246,7 @@ public function testCellStartsRow() //$this->assertNull($obj->cellStartsRow(5)); } - /** - * @return void - */ - public function testCellEndsRow() + public function testCellEndsRow(): void { $obj = $this->obj; //$this->assertNull($obj->cellStartsRow()); @@ -313,19 +263,13 @@ public function testCellEndsRow() //$this->assertNull($obj->cellEndsRow(5)); } - /** - * @return void - */ - public function testStart() + public function testStart(): void { $obj = $this->obj; $this->assertEquals('', $obj->start()); } - /** - * @return void - */ - public function testEnd() + public function testEnd(): void { $obj = $this->obj; $this->assertEquals(0, $obj->position()); diff --git a/packages/admin/tests/Charcoal/Admin/Widget/ObjectFormWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/ObjectFormWidgetTest.php index 3d9f9a50a..215a6454b 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/ObjectFormWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/ObjectFormWidgetTest.php @@ -19,9 +19,6 @@ class ObjectFormWidgetTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ public function setUp(): void { $logger = new NullLogger(); @@ -30,10 +27,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testSetFormIdent() + public function testSetFormIdent(): void { $ret = $this->obj->setFormIdent('foobar'); $this->assertSame($ret, $this->obj); diff --git a/packages/admin/tests/Charcoal/Admin/Widget/PaginationWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/PaginationWidgetTest.php index 3f9185543..f9b84d499 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/PaginationWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/PaginationWidgetTest.php @@ -21,9 +21,6 @@ class PaginationWidgetTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ public function setUp(): void { $this->obj = new PaginationWidget([ @@ -31,10 +28,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testPageLogic() + public function testPageLogic(): void { $this->obj->setData([ 'page' => 3, @@ -67,10 +61,7 @@ public function testPageLogic() $this->assertEquals(1, $this->obj->pageNext()); } - /** - * @return void - */ - public function testSetNumTotal() + public function testSetNumTotal(): void { $ret = $this->obj->setNumTotal(42); $this->assertSame($ret, $this->obj); diff --git a/packages/admin/tests/Charcoal/Admin/Widget/SearchWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/SearchWidgetTest.php index f473a6251..9430596dc 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/SearchWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/SearchWidgetTest.php @@ -14,9 +14,7 @@ */ class SearchWidgetTest extends AbstractTestCase { - /** - * @return void - */ + public $obj; public function setUp(): void { $logger = new NullLogger(); @@ -25,10 +23,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(SearchWidget::class, $this->obj); } diff --git a/packages/admin/tests/Charcoal/Admin/Widget/SecondaryMenuWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/SecondaryMenuWidgetTest.php index 5c2793e4b..208f3a217 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/SecondaryMenuWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/SecondaryMenuWidgetTest.php @@ -25,9 +25,6 @@ class SecondaryMenuWidgetTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ public function setUp(): void { $container = new Container(); @@ -44,10 +41,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(SecondaryMenuWidget::class, $this->obj); } diff --git a/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php index a69847d83..b7cf8895f 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php @@ -21,22 +21,16 @@ class TableWidgetTest extends AbstractTestCase { /** * Tested Class. - * - * @var TableWidget */ - private $obj; + private \Charcoal\Admin\Widget\TableWidget|array $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -49,10 +43,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testSetSortable() + public function testSetSortable(): void { $ret = $this->obj->setSortable(true); $this->assertSame($ret, $this->obj); @@ -65,10 +56,7 @@ public function testSetSortable() $this->assertTrue($this->obj['sortable']); } - /** - * @return void - */ - public function testShowTableHeader() + public function testShowTableHeader(): void { $this->assertTrue($this->obj->showTableHeader()); $ret = $this->obj->setShowTableHeader(false); @@ -82,10 +70,7 @@ public function testShowTableHeader() $this->assertFalse($this->obj['show_table_header']); } - /** - * @return void - */ - public function testShowTableHead() + public function testShowTableHead(): void { $this->assertTrue($this->obj->showTableHead()); $ret = $this->obj->setShowTableHead(false); @@ -99,10 +84,7 @@ public function testShowTableHead() $this->assertFalse($this->obj['show_table_head']); } - /** - * @return void - */ - public function testShowTableFoot() + public function testShowTableFoot(): void { $this->assertFalse($this->obj->showTableFoot()); $ret = $this->obj->setShowTableFoot(false); @@ -118,19 +100,17 @@ public function testShowTableFoot() /** * Set up the service container. - * - * @return Container */ - protected function container() + protected function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerWidgetDependencies($container); $containerProvider->registerWidgetFactory($container); $containerProvider->registerPropertyDisplayFactory($container); - $container['view'] = $this->createMock('\Charcoal\View\ViewInterface'); + $container['view'] = $this->createMock(\Charcoal\View\ViewInterface::class); $this->container = $container; } diff --git a/packages/admin/tests/Charcoal/Admin/Widget/TextWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/TextWidgetTest.php index a9e49a6e0..a77e4d22d 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/TextWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/TextWidgetTest.php @@ -18,9 +18,7 @@ */ class TextWidgetTest extends AbstractTestCase { - /** - * @return void - */ + public $obj; public function setUp(): void { $container = new Container(); @@ -33,10 +31,7 @@ public function setUp(): void ]); } - /** - * @return void - */ - public function testSetShowTitle() + public function testSetShowTitle(): void { $this->assertFalse($this->obj->showTitle()); $ret = $this->obj->setShowTitle(false); @@ -48,10 +43,7 @@ public function testSetShowTitle() $this->assertTrue($this->obj->showTitle()); } - /** - * @return void - */ - public function testSetShowSubtitle() + public function testSetShowSubtitle(): void { $this->assertFalse($this->obj->showSubtitle()); $ret = $this->obj->setShowSubtitle(false); @@ -63,10 +55,7 @@ public function testSetShowSubtitle() $this->assertTrue($this->obj->showSubtitle()); } - /** - * @return void - */ - public function testSetShowDescription() + public function testSetShowDescription(): void { $this->assertFalse($this->obj->showDescription()); $ret = $this->obj->setShowDescription(false); @@ -78,10 +67,7 @@ public function testSetShowDescription() $this->assertTrue($this->obj->showDescription()); } - /** - * @return void - */ - public function testSetShowNotes() + public function testSetShowNotes(): void { $this->assertFalse($this->obj->showNotes()); $ret = $this->obj->setShowNotes(false); @@ -93,40 +79,28 @@ public function testSetShowNotes() $this->assertTrue($this->obj->showNotes()); } - /** - * @return void - */ - public function testSetTitle() + public function testSetTitle(): void { $ret = $this->obj->setTitle('Fôö title'); $this->assertSame($ret, $this->obj); $this->assertEquals('Fôö title', (string)$this->obj->title()); } - /** - * @return void - */ - public function testSetSubtitle() + public function testSetSubtitle(): void { $ret = $this->obj->setSubtitle('Fôö subtitle'); $this->assertSame($ret, $this->obj); $this->assertEquals('Fôö subtitle', (string)$this->obj->subtitle()); } - /** - * @return void - */ - public function testSetDescription() + public function testSetDescription(): void { $ret = $this->obj->setDescription('Fôö description'); $this->assertSame($ret, $this->obj); $this->assertEquals('Fôö description', (string)$this->obj->description()); } - /** - * @return void - */ - public function testSetNotes() + public function testSetNotes(): void { $ret = $this->obj->setNotes('Fôö notes'); $this->assertSame($ret, $this->obj); diff --git a/packages/admin/tests/Charcoal/AssertionsTrait.php b/packages/admin/tests/Charcoal/AssertionsTrait.php index 21b2a53f6..0670b2627 100644 --- a/packages/admin/tests/Charcoal/AssertionsTrait.php +++ b/packages/admin/tests/Charcoal/AssertionsTrait.php @@ -15,9 +15,8 @@ trait AssertionsTrait * @param array $expected The expected haystack. * @param array $haystack The actual haystack. * @param string $message The error to report. - * @return void */ - public function assertArrayEquals(array $expected, array $haystack, $message = '') + public function assertArrayEquals(array $expected, array $haystack, $message = ''): void { $this->assertCount(count($expected), $haystack, $message); $this->assertEquals($expected, $haystack, $message); @@ -29,9 +28,8 @@ public function assertArrayEquals(array $expected, array $haystack, $message = ' * @param array $expected The expected haystack. * @param array $haystack The actual haystack. * @param string $message The error to report. - * @return void */ - public function assertArrayContains(array $expected, array $haystack, $message = '') + public function assertArrayContains(array $expected, array $haystack, $message = ''): void { foreach ($expected as $item) { $this->assertContains($item, $haystack, $message); @@ -44,9 +42,8 @@ public function assertArrayContains(array $expected, array $haystack, $message = * @param array $expected The expected haystack. * @param array $haystack The actual haystack. * @param string $message The error to report. - * @return void */ - public function assertArrayHasKeys(array $expected, array $haystack, $message = '') + public function assertArrayHasKeys(array $expected, array $haystack, $message = ''): void { foreach ($expected as $item) { $this->assertArrayHasKey($item, $haystack, $message); @@ -60,14 +57,13 @@ public function assertArrayHasKeys(array $expected, array $haystack, $message = * @param array $haystack The actual haystack. * @param boolean $strict Whether to check for object identity. * @param string $message The error to report. - * @return void */ public function assertArraySubsets( array $expected, array $haystack, $strict = false, $message = '' - ) { + ): void { foreach ($expected as $key => $val) { $this->assertArraySubset([ $key => $val ], $haystack, $strict, $message); } @@ -84,17 +80,16 @@ public function assertArraySubsets( * @param boolean $checkForObjectIdentity Unused. * @param string $message The error to report. * @throws InvalidArgumentException - * @return void */ public function assertArraySubset($subset, $array, $checkForObjectIdentity = false, $message = ''): void { - if (!(is_array($subset) || $subset instanceof ArrayAccess)) { + if (!is_array($subset) && !$subset instanceof ArrayAccess) { throw InvalidArgumentException::create( 1, 'array or ArrayAccess' ); } - if (!(is_array($array) || $array instanceof ArrayAccess)) { + if (!is_array($array) && !$array instanceof ArrayAccess) { throw InvalidArgumentException::create( 2, 'array or ArrayAccess' diff --git a/packages/admin/tests/Charcoal/ReflectionsTrait.php b/packages/admin/tests/Charcoal/ReflectionsTrait.php index 3a63ff2b1..047d2c172 100644 --- a/packages/admin/tests/Charcoal/ReflectionsTrait.php +++ b/packages/admin/tests/Charcoal/ReflectionsTrait.php @@ -18,13 +18,10 @@ trait ReflectionsTrait * * @param mixed $class The class name or object that contains the method. * @param string $name The method name to reflect. - * @return ReflectionMethod */ - public function getMethod($class, $name) + public function getMethod($class, $name): \ReflectionMethod { - $reflected = new ReflectionMethod($class, $name); - $reflected->setAccessible(true); - return $reflected; + return new ReflectionMethod($class, $name); } /** @@ -38,7 +35,7 @@ public function getMethod($class, $name) public function callMethod($object, $name, array $args = []) { $method = $this->getMethod($object, $name); - if (empty($args)) { + if ($args === []) { return $method->invoke($object); } else { return $method->invokeArgs($object, $args); @@ -65,13 +62,10 @@ public function callMethodWith($object, $name, ...$args) * * @param mixed $class The class name or object that contains the property. * @param string $name The property name to reflect. - * @return ReflectionProperty */ - public function getProperty($class, $name) + public function getProperty($class, $name): \ReflectionProperty { - $reflected = new ReflectionProperty($class, $name); - $reflected->setAccessible(true); - return $reflected; + return new ReflectionProperty($class, $name); } /** @@ -92,9 +86,8 @@ public function getPropertyValue($object, $name) * @param mixed $object The object to access. * @param string $name The property name to affect. * @param mixed $value The new value. - * @return void */ - public function setPropertyValue($object, $name, $value) + public function setPropertyValue($object, $name, $value): void { $this->getProperty($object, $name)->setValue($object, $value); } diff --git a/packages/admin/tests/bootstrap.php b/packages/admin/tests/bootstrap.php new file mode 100644 index 000000000..90929e3b5 --- /dev/null +++ b/packages/admin/tests/bootstrap.php @@ -0,0 +1,14 @@ + + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - + ./src/Charcoal + + + diff --git a/packages/app/src/Charcoal/App/Action/AbstractAction.php b/packages/app/src/Charcoal/App/Action/AbstractAction.php index 842eb7325..75edf0525 100644 --- a/packages/app/src/Charcoal/App/Action/AbstractAction.php +++ b/packages/app/src/Charcoal/App/Action/AbstractAction.php @@ -44,25 +44,13 @@ abstract class AbstractAction extends AbstractEntity implements public const MODE_EVENT_STREAM = 'event-stream'; public const DEFAULT_MODE = self::MODE_JSON; - /** - * @var string $mode - */ - private $mode = self::DEFAULT_MODE; + private string $mode = self::DEFAULT_MODE; - /** - * @var boolean $success - */ - private $success = false; + private bool $success = false; - /** - * @var string|null $successUrl - */ - private $successUrl; + private ?string $successUrl = null; - /** - * @var string|null $failureUrl - */ - private $failureUrl; + private ?string $failureUrl = null; /** * @param array|\ArrayAccess $data The dependencies (app and logger). @@ -116,9 +104,7 @@ final public function __invoke(RequestInterface $request, ResponseInterface $res break; case self::MODE_EVENT_STREAM: - $output = new CallbackStream(function () { - return $this->results(); - }); + $output = new CallbackStream(fn(): mixed => $this->results()); $response = $response ->withHeader('Content-Type', 'text/event-stream') @@ -162,7 +148,7 @@ public function mode() */ public function setSuccess($success) { - $this->success = !!$success; + $this->success = (bool)$success; return $this; } @@ -248,13 +234,7 @@ public function failureUrl() */ public function redirectUrl() { - if ($this->success() === true) { - $url = $this->successUrl(); - } else { - $url = $this->failureUrl(); - } - - return $url; + return $this->success() === true ? $this->successUrl() : $this->failureUrl(); } /** diff --git a/packages/app/src/Charcoal/App/Action/ActionInterface.php b/packages/app/src/Charcoal/App/Action/ActionInterface.php index ec5251915..909e0ac36 100644 --- a/packages/app/src/Charcoal/App/Action/ActionInterface.php +++ b/packages/app/src/Charcoal/App/Action/ActionInterface.php @@ -1,5 +1,7 @@ setup(); @@ -116,10 +117,8 @@ public function run($silent = false) /** * Registers the default services and features that Charcoal needs to work. - * - * @return void */ - private function setup() + private function setup(): void { $config = $this->config(); date_default_timezone_set($config['timezone']); @@ -150,9 +149,9 @@ private function setup() */ private function routeManager() { - if (!isset($this->routeManager)) { + if ($this->routeManager === null) { $config = $this->config(); - $routesConfig = (isset($config['routes']) ? $config['routes'] : [] ); + $routesConfig = ($config['routes'] ?? [] ); $this->routeManager = new RouteManager([ 'config' => $routesConfig, @@ -163,10 +162,7 @@ private function routeManager() return $this->routeManager; } - /** - * @return void - */ - private function setupModules() + private function setupModules(): void { $container = $this->getContainer(); $modules = $container['config']['modules']; @@ -180,10 +176,8 @@ private function setupModules() * Setup the application's "global" routables. * * Routables can only be defined globally (app-level) for now. - * - * @return void */ - private function setupRoutables() + private function setupRoutables(): void { $app = $this; @@ -198,7 +192,7 @@ function ( $config = $app->config(); $routables = $config['routables']; - if (is_array($routables) && !empty($routables)) { + if (is_array($routables) && $routables !== []) { $routeFactory = $this['route/factory']; foreach ($routables as $routableType => $routableOptions) { $route = $routeFactory->create($routableType, [ @@ -222,9 +216,8 @@ function ( /** * @throws RuntimeException If the middleware was not set properly on the container. - * @return void */ - private function setupMiddlewares() + private function setupMiddlewares(): void { $container = $this->getContainer(); $middlewaresConfig = $container['config']['middlewares']; @@ -258,29 +251,26 @@ private function setupMiddlewares() /** * @throws LogicException If trying to clone an instance of a singleton. - * @return void */ final public function __clone() { throw new LogicException( sprintf( 'Cloning "%s" is not allowed.', - get_called_class() + static::class ) ); } /** * @throws LogicException If trying to unserialize an instance of a singleton. - * @return void */ - final public function __wakeup() + final public function __unserialize(array $data): void { - throw new LogicException( - sprintf( - 'Unserializing "%s" is not allowed.', - get_called_class() - ) - ); + foreach ($data as $property => $value) { + if (property_exists($this, $property)) { + $this->{$property} = $value; + } + } } } diff --git a/packages/app/src/Charcoal/App/AppAwareInterface.php b/packages/app/src/Charcoal/App/AppAwareInterface.php index 17fa8770f..58f89a4ae 100644 --- a/packages/app/src/Charcoal/App/AppAwareInterface.php +++ b/packages/app/src/Charcoal/App/AppAwareInterface.php @@ -1,5 +1,7 @@ '', @@ -188,11 +150,10 @@ public function defaults() /** * @param array $values Array of values to resolve. - * @return array */ public function resolveValues(array $values): array { - return array_map([$this, 'resolveValue'], $values); + return array_map($this->resolveValue(...), $values); } /** @@ -213,7 +174,7 @@ public function resolveValue($value) ]; if (is_string($value)) { - return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($tags, $value) { + return preg_replace_callback('/%%|%([^%\s]+)%/', function (array $match) use ($tags, $value): string|float|int { // skip escaped %% if (!isset($match[1])) { return '%%'; @@ -224,7 +185,7 @@ public function resolveValue($value) $resolved = ($tags[$tag] ?? null); if (!is_string($resolved) && !is_numeric($resolved)) { - $resolvedType = (is_object($resolved) ? get_class($resolved) : gettype($resolved)); + $resolvedType = (get_debug_type($resolved)); throw new UnexpectedValueException(sprintf( 'Invalid config parameter "%s" inside string value "%s";' . @@ -251,6 +212,7 @@ public function resolveValue($value) * @param string $path The file to load and add. * @return self */ + #[\Override] public function addFile($path) { $path = $this->resolveValue($path); @@ -265,9 +227,8 @@ public function addFile($path) * * @param string $path The absolute path to the application's root directory. * @throws InvalidArgumentException If the argument is not a string. - * @return self */ - public function setBasePath($path) + public function setBasePath($path): static { if ($path === null) { throw new InvalidArgumentException( @@ -290,7 +251,7 @@ public function setBasePath($path) * * @return string|null The absolute path to the application's root directory. */ - public function basePath() + public function basePath(): ?string { return $this->basePath; } @@ -300,9 +261,8 @@ public function basePath() * * @param string $path The path to the application's public directory. * @throws InvalidArgumentException If the argument is not a string. - * @return self */ - public function setPublicPath($path) + public function setPublicPath($path): static { if ($path === null) { $this->publicPath = null; @@ -324,7 +284,7 @@ public function setPublicPath($path) * * @return string The absolute path to the application's public directory. */ - public function publicPath() + public function publicPath(): string { if ($this->publicPath === null) { $this->publicPath = $this->basePath() . DIRECTORY_SEPARATOR . 'www'; @@ -338,9 +298,8 @@ public function publicPath() * * @param string $path The path to the application's cache directory. * @throws InvalidArgumentException If the argument is not a string. - * @return self */ - public function setCachePath($path) + public function setCachePath($path): static { if ($path === null) { $this->cachePath = null; @@ -362,7 +321,7 @@ public function setCachePath($path) * * @return string The absolute path to the application's cache directory. */ - public function cachePath() + public function cachePath(): string { if ($this->cachePath === null) { $this->cachePath = $this->basePath() . DIRECTORY_SEPARATOR . 'var' . DIRECTORY_SEPARATOR . 'cache'; @@ -376,9 +335,8 @@ public function cachePath() * * @param string $path The path to the application's logs directory. * @throws InvalidArgumentException If the argument is not a string. - * @return self */ - public function setLogsPath($path) + public function setLogsPath($path): static { if ($path === null) { $this->logsPath = null; @@ -400,7 +358,7 @@ public function setLogsPath($path) * * @return string The absolute path to the application's logs directory. */ - public function logsPath() + public function logsPath(): string { if ($this->logsPath === null) { $this->logsPath = $this->basePath() . DIRECTORY_SEPARATOR . 'var' . DIRECTORY_SEPARATOR . 'logs'; @@ -413,15 +371,10 @@ public function logsPath() * Set the application's fully qualified base URL to the public web directory. * * @param UriInterface|string $uri The base URI to the application's web directory. - * @return self */ - public function setBaseUrl($uri) + public function setBaseUrl($uri): static { - if (is_string($uri)) { - $this->baseUrl = Uri::createFromString($uri); - } else { - $this->baseUrl = $uri; - } + $this->baseUrl = is_string($uri) ? Uri::createFromString($uri) : $uri; return $this; } @@ -440,9 +393,8 @@ public function baseUrl() * * @param string $timezone The timezone string. * @throws InvalidArgumentException If the argument is not a string. - * @return self */ - public function setTimezone($timezone) + public function setTimezone($timezone): static { if (!is_string($timezone)) { throw new InvalidArgumentException( @@ -458,12 +410,10 @@ public function setTimezone($timezone) * Retrieve the application's default timezone. * * Will be used by the PHP date and date-time functions. - * - * @return string */ - public function timezone() + public function timezone(): string { - if (isset($this->timezone)) { + if ($this->timezone !== null) { return $this->timezone; } else { return 'UTC'; @@ -475,9 +425,8 @@ public function timezone() * * @param string|null $projectName The project name. * @throws InvalidArgumentException If the project argument is not a string (or null). - * @return self */ - public function setProjectName($projectName) + public function setProjectName($projectName): static { if ($projectName === null) { $this->projectName = null; @@ -510,20 +459,16 @@ public function projectName() /** * @param boolean $devMode The "dev mode" flag. - * @return self */ - public function setDevMode($devMode) + public function setDevMode($devMode): static { - $this->devMode = !!$devMode; + $this->devMode = (bool)$devMode; return $this; } - /** - * @return boolean - */ - public function devMode() + public function devMode(): bool { - return !!$this->devMode; + return $this->devMode; } /** @@ -531,9 +476,8 @@ public function devMode() * * @param array $view The global configset for the application's view service. * @throws InvalidArgumentException If the argument is not a configset. - * @return self */ - public function setView(array $view) + public function setView(array $view): static { $this->view = $view; return $this; @@ -553,18 +497,14 @@ public function view() * Parse the application's API configuration. * * @param array $apis The API configuration structure to set. - * @return self */ - public function setApis(array $apis) + public function setApis(array $apis): static { $this->apis = $apis; return $this; } - /** - * @return array - */ - public function apis() + public function apis(): array { return $this->apis; } @@ -574,42 +514,32 @@ public function apis() * * @see \Charcoal\Admin\Config::setRoutes() For a similar implementation. * @param array $routes The route configuration structure to set. - * @return self */ - public function setRoutes(array $routes) + public function setRoutes(array $routes): static { $this->routes = $routes; return $this; } - /** - * @return array - */ - public function routes() + public function routes(): array { return $this->routes; } /** * @param array|boolean $routables The routable configuration structure to set or FALSE to disable dynamic routing. - * @return self */ - public function setRoutables($routables) + public function setRoutables($routables): static { - if ($routables !== false) { - if (!is_array($routables) || empty($routables)) { - $routables = []; - } + if ($routables !== false && (!is_array($routables) || $routables === [])) { + $routables = []; } $this->routables = $routables; return $this; } - /** - * @return array|boolean - */ - public function routables() + public function routables(): bool|array { return $this->routables; } @@ -618,18 +548,14 @@ public function routables() * Parse the application's HTTP middleware. * * @param array $middlewares The middleware configuration structure to set. - * @return self */ - public function setMiddlewares(array $middlewares) + public function setMiddlewares(array $middlewares): static { $this->middlewares = $middlewares; return $this; } - /** - * @return array - */ - public function middlewares() + public function middlewares(): array { return $this->middlewares; } @@ -645,18 +571,14 @@ public function middlewares() * - "phpErrorHandler" * * @param array $handlers The handlers configuration structure to set. - * @return self */ - public function setHandlers(array $handlers) + public function setHandlers(array $handlers): static { $this->handlers = $handlers; return $this; } - /** - * @return array - */ - public function handlers() + public function handlers(): array { return $this->handlers; } @@ -665,18 +587,14 @@ public function handlers() * Set the configuration modules. * * @param array $modules The module configuration structure to set. - * @return self */ - public function setModules(array $modules) + public function setModules(array $modules): static { $this->modules = $modules; return $this; } - /** - * @return array - */ - public function modules() + public function modules(): array { return $this->modules; } @@ -686,9 +604,8 @@ public function modules() * * @param array $cache The global config for the application's cache service. * @throws InvalidArgumentException If the argument is not a configset. - * @return self */ - public function setCache(array $cache) + public function setCache(array $cache): static { $this->cache = $cache; return $this; @@ -699,7 +616,7 @@ public function setCache(array $cache) * * @return array */ - public function cache() + public function cache(): ?array { return $this->cache; } @@ -709,9 +626,8 @@ public function cache() * * @param array $logger The global config for the application's logger service. * @throws InvalidArgumentException If the argument is not a configset. - * @return self */ - public function setLogger(array $logger) + public function setLogger(array $logger): static { $this->logger = $logger; return $this; @@ -722,16 +638,15 @@ public function setLogger(array $logger) * * @return array */ - public function logger() + public function logger(): ?array { return $this->logger; } /** * @param array $databases The avaiable databases config. - * @return self */ - public function setDatabases(array $databases) + public function setDatabases(array $databases): static { $this->databases = $databases; return $this; @@ -739,9 +654,8 @@ public function setDatabases(array $databases) /** * @throws Exception If trying to access this method and no databases were set. - * @return array */ - public function databases() + public function databases(): array { if ($this->databases === null) { throw new Exception( @@ -776,9 +690,8 @@ public function databaseConfig($ident) /** * @param string $defaultDatabase The default database ident. * @throws InvalidArgumentException If the argument is not a string. - * @return self */ - public function setDefaultDatabase($defaultDatabase) + public function setDefaultDatabase($defaultDatabase): static { if (!is_string($defaultDatabase)) { throw new InvalidArgumentException( @@ -793,9 +706,8 @@ public function setDefaultDatabase($defaultDatabase) * @param string $ident The database ident. * @param array $config The database options. * @throws InvalidArgumentException If the arguments are invalid. - * @return self */ - public function addDatabase($ident, array $config) + public function addDatabase($ident, array $config): static { if (!is_string($ident)) { throw new InvalidArgumentException( @@ -812,9 +724,8 @@ public function addDatabase($ident, array $config) /** * @throws Exception If trying to access this method before a setter. - * @return mixed */ - public function defaultDatabase() + public function defaultDatabase(): string { if ($this->defaultDatabase === null) { throw new Exception( @@ -829,9 +740,8 @@ public function defaultDatabase() * * @param array $filesystem The global config for the application's file system. * @throws InvalidArgumentException If the argument is not a configset. - * @return self */ - public function setFilesystem(array $filesystem) + public function setFilesystem(array $filesystem): static { $this->filesystem = $filesystem; return $this; @@ -842,7 +752,7 @@ public function setFilesystem(array $filesystem) * * @return array */ - public function filesystem() + public function filesystem(): ?array { return $this->filesystem; } diff --git a/packages/app/src/Charcoal/App/AppContainer.php b/packages/app/src/Charcoal/App/AppContainer.php index 7b5b3d635..fa494869e 100644 --- a/packages/app/src/Charcoal/App/AppContainer.php +++ b/packages/app/src/Charcoal/App/AppContainer.php @@ -28,7 +28,7 @@ public function __construct(array $values = []) parent::__construct($values); // Ensure "config" is set - $this['config'] = (isset($values['config']) ? $values['config'] : new AppConfig()); + $this['config'] = ($values['config'] ?? new AppConfig()); $this->register(new AppServiceProvider()); @@ -36,30 +36,22 @@ public function __construct(array $values = []) $this->registerConfigProviders(); } - /** - * @return void - */ - private function registerProviderFactory() + private function registerProviderFactory(): void { /** * @return Factory */ if (!isset($this['provider/factory'])) { - $this['provider/factory'] = function () { - return new Factory([ - 'base_class' => ServiceProviderInterface::class, - 'resolver_options' => [ - 'suffix' => 'ServiceProvider' - ] - ]); - }; + $this['provider/factory'] = (fn(): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => ServiceProviderInterface::class, + 'resolver_options' => [ + 'suffix' => 'ServiceProvider' + ] + ])); } } - /** - * @return void - */ - private function registerConfigProviders() + private function registerConfigProviders(): void { if (empty($this['config']['service_providers'])) { return; diff --git a/packages/app/src/Charcoal/App/CallableResolverAwareTrait.php b/packages/app/src/Charcoal/App/CallableResolverAwareTrait.php index de76534ca..44fa5b724 100644 --- a/packages/app/src/Charcoal/App/CallableResolverAwareTrait.php +++ b/packages/app/src/Charcoal/App/CallableResolverAwareTrait.php @@ -72,7 +72,7 @@ protected function resolveCallable($callable, $context = null) { if (!isset($this->callableResolver)) { throw new RuntimeException( - sprintf('Callable Resolver is not defined for "%s"', get_class($this)) + sprintf('Callable Resolver is not defined for "%s"', $this::class) ); } diff --git a/packages/app/src/Charcoal/App/Config/DatabaseConfig.php b/packages/app/src/Charcoal/App/Config/DatabaseConfig.php index c5533aa49..bca2c88f8 100644 --- a/packages/app/src/Charcoal/App/Config/DatabaseConfig.php +++ b/packages/app/src/Charcoal/App/Config/DatabaseConfig.php @@ -1,5 +1,7 @@ 'mysql', @@ -61,9 +43,8 @@ public function defaults() * * @param string $type The database type. * @throws InvalidArgumentException If parameter is not a string. - * @return self */ - public function setType($type) + public function setType($type): static { if (!is_string($type)) { throw new InvalidArgumentException( @@ -79,7 +60,7 @@ public function setType($type) * * @return string */ - public function type() + public function type(): ?string { return $this->type; } @@ -89,9 +70,8 @@ public function type() * * @param string $hostname The database server hostname. * @throws InvalidArgumentException If hostname is not a string. - * @return self */ - public function setHostname($hostname) + public function setHostname($hostname): static { if (!is_string($hostname)) { throw new InvalidArgumentException( @@ -107,7 +87,7 @@ public function setHostname($hostname) * * @return string */ - public function hostname() + public function hostname(): ?string { return $this->hostname; } @@ -117,9 +97,8 @@ public function hostname() * * @param string $username The username. * @throws InvalidArgumentException If username is not a string. - * @return self */ - public function setUsername($username) + public function setUsername($username): static { if (!is_string($username)) { throw new InvalidArgumentException( @@ -135,7 +114,7 @@ public function setUsername($username) * * @return string */ - public function username() + public function username(): ?string { return $this->username; } @@ -145,9 +124,8 @@ public function username() * * @param string $password The password. * @throws InvalidArgumentException If password is not a string. - * @return self */ - public function setPassword($password) + public function setPassword($password): static { if (!is_string($password)) { throw new InvalidArgumentException( @@ -163,7 +141,7 @@ public function setPassword($password) * * @return string */ - public function password() + public function password(): ?string { return $this->password; } @@ -173,9 +151,8 @@ public function password() * * @param string $database The database name. * @throws InvalidArgumentException If database is not a string. - * @return self */ - public function setDatabase($database) + public function setDatabase($database): static { if (!is_string($database)) { throw new InvalidArgumentException( @@ -191,7 +168,7 @@ public function setDatabase($database) * * @return string */ - public function database() + public function database(): ?string { return $this->database; } @@ -200,11 +177,10 @@ public function database() * Set whether to disable UTF-8 compatibility or not. * * @param boolean $disableUtf8 The disable flag. - * @return self */ - public function setDisableUtf8($disableUtf8) + public function setDisableUtf8($disableUtf8): static { - $this->disableUtf8 = !!$disableUtf8; + $this->disableUtf8 = (bool)$disableUtf8; return $this; } @@ -213,7 +189,7 @@ public function setDisableUtf8($disableUtf8) * * @return boolean */ - public function disableUtf8() + public function disableUtf8(): ?bool { return $this->disableUtf8; } diff --git a/packages/app/src/Charcoal/App/Config/FilesystemConfig.php b/packages/app/src/Charcoal/App/Config/FilesystemConfig.php index 57a96f37a..e8eace876 100644 --- a/packages/app/src/Charcoal/App/Config/FilesystemConfig.php +++ b/packages/app/src/Charcoal/App/Config/FilesystemConfig.php @@ -20,22 +20,19 @@ class FilesystemConfig extends AbstractConfig */ public $defaultConnection; - /** - * @return array - */ - public function defaultConnections() + public function defaultConnections(): array { return [ 'public' => [ 'public' => true, 'type' => 'local', - 'path' => '%app.public_path%', + 'path' => './', 'label' => 'Public', ], 'private' => [ 'public' => false, 'type' => 'local', - 'path' => '%app.base_path%', + 'path' => '../', 'label' => 'Private', ], ]; @@ -43,10 +40,8 @@ public function defaultConnections() /** * Ensure connections always return the default connections. - * - * @return array */ - public function connections() + public function connections(): array { return array_merge($this->defaultConnections(), $this->connections); } diff --git a/packages/app/src/Charcoal/App/Config/FilesystemConfig.php.rej b/packages/app/src/Charcoal/App/Config/FilesystemConfig.php.rej new file mode 100644 index 000000000..2cf06ddd5 --- /dev/null +++ b/packages/app/src/Charcoal/App/Config/FilesystemConfig.php.rej @@ -0,0 +1,18 @@ +--- packages/app/src/Charcoal/App/Config/FilesystemConfig.php ++++ packages/app/src/Charcoal/App/Config/FilesystemConfig.php +@@ -29,13 +29,13 @@ class FilesystemConfig extends AbstractConfig + 'public' => [ + 'public' => true, + 'type' => 'local', +- 'path' => '%app.public_path%', ++ 'path' => './', + 'label' => 'Public', + ], + 'private' => [ + 'public' => false, + 'type' => 'local', +- 'path' => '%app.base_path%', ++ 'path' => '../', + 'label' => 'Private', + ], + ]; diff --git a/packages/app/src/Charcoal/App/Config/LoggerConfig.php b/packages/app/src/Charcoal/App/Config/LoggerConfig.php index 800314189..d61dc1865 100644 --- a/packages/app/src/Charcoal/App/Config/LoggerConfig.php +++ b/packages/app/src/Charcoal/App/Config/LoggerConfig.php @@ -15,42 +15,33 @@ class LoggerConfig extends AbstractConfig /** * Whether to enable or disable the logger service. - * - * @var boolean */ - private $active; + private ?bool $active = null; /** * Record handler(s) to use. * * Whenever you add a record to the logger, it traverses the handler stack. - * - * @var array */ - private $handlers; + private ?array $handlers = null; /** * Record processor(s) to use. * * For customizing records added to the logger. - * - * @var array */ - private $processors; + private ?array $processors = null; /** * Channel name. - * - * @var string */ - private $channel = self::DEFAULT_CHANNEL; + private string $channel = self::DEFAULT_CHANNEL; /** * Retrieve the default values. - * - * @return array */ - public function defaults() + #[\Override] + public function defaults(): array { return [ 'active' => true, @@ -88,9 +79,9 @@ public function defaults() * TRUE to enable, FALSE to disable. * @return LoggerConfig Chainable */ - public function setActive($active) + public function setActive($active): static { - $this->active = !!$active; + $this->active = (bool)$active; return $this; } @@ -99,7 +90,7 @@ public function setActive($active) * * @return boolean TRUE if enabled, FALSE if disabled. */ - public function active() + public function active(): ?bool { return $this->active; } @@ -108,9 +99,8 @@ public function active() * Set the record handler(s) to use. * * @param array $handlers One or more (Monolog) record handlers; used as a stack. - * @return self */ - public function setHandlers(array $handlers) + public function setHandlers(array $handlers): static { $this->handlers = []; $this->addHandlers($handlers); @@ -121,9 +111,8 @@ public function setHandlers(array $handlers) * Add record handler(s) to use. * * @param string[] $handlers One or more (Monolog) handlers to stack. - * @return self */ - public function addHandlers(array $handlers) + public function addHandlers(array $handlers): static { foreach ($handlers as $key => $handler) { $this->addHandler($handler, $key); @@ -137,9 +126,8 @@ public function addHandlers(array $handlers) * @param array $handler The record handler structure. * @param string|null $key The handler's key. * @throws InvalidArgumentException If the handler is invalid. - * @return self */ - public function addHandler(array $handler, $key = null) + public function addHandler(array $handler, $key = null): static { if (!isset($handler['type'])) { throw new InvalidArgumentException( @@ -161,7 +149,7 @@ public function addHandler(array $handler, $key = null) * * @return array */ - public function handlers() + public function handlers(): ?array { return $this->handlers; } @@ -170,9 +158,8 @@ public function handlers() * Set the record processor(s) to use. * * @param array $processors One or more (Monolog) record processors; used as a stack. - * @return self */ - public function setProcessors(array $processors) + public function setProcessors(array $processors): static { $this->processors = []; $this->addProcessors($processors); @@ -183,9 +170,8 @@ public function setProcessors(array $processors) * Add record processor(s) to use. * * @param string[] $processors One or more (Monolog) processors to stack. - * @return self */ - public function addProcessors(array $processors) + public function addProcessors(array $processors): static { foreach ($processors as $key => $processor) { $this->addProcessor($processor, $key); @@ -199,9 +185,8 @@ public function addProcessors(array $processors) * @param array $processor The record processor structure. * @param string|null $key The processor's key. * @throws InvalidArgumentException If the processor is invalid. - * @return self */ - public function addProcessor(array $processor, $key = null) + public function addProcessor(array $processor, $key = null): static { if (!isset($processor['type'])) { throw new InvalidArgumentException( @@ -223,7 +208,7 @@ public function addProcessor(array $processor, $key = null) * * @return array */ - public function processors() + public function processors(): ?array { return $this->processors; } @@ -233,9 +218,8 @@ public function processors() * * @param string $name The channe name (namespace). * @throws InvalidArgumentException If the channel name is not a string. - * @return self */ - public function setChannel($name) + public function setChannel($name): static { if (!is_string($name)) { throw new InvalidArgumentException( @@ -249,10 +233,8 @@ public function setChannel($name) /** * Retrieve the cache namespace. - * - * @return string */ - public function channel() + public function channel(): string { return $this->channel; } diff --git a/packages/app/src/Charcoal/App/DebugAwareTrait.php b/packages/app/src/Charcoal/App/DebugAwareTrait.php index 44914d556..15ab462d3 100644 --- a/packages/app/src/Charcoal/App/DebugAwareTrait.php +++ b/packages/app/src/Charcoal/App/DebugAwareTrait.php @@ -22,7 +22,7 @@ trait DebugAwareTrait */ protected function setDebug($debug) { - $this->debug = !!$debug; + $this->debug = (bool)$debug; } /** diff --git a/packages/app/src/Charcoal/App/Handler/AbstractError.php b/packages/app/src/Charcoal/App/Handler/AbstractError.php index 654257bf1..2db73e286 100644 --- a/packages/app/src/Charcoal/App/Handler/AbstractError.php +++ b/packages/app/src/Charcoal/App/Handler/AbstractError.php @@ -21,10 +21,8 @@ abstract class AbstractError extends AbstractHandler { /** * Whether to output the error's details. - * - * @var boolean $displayErrorDetails */ - private $displayErrorDetails; + private ?bool $displayErrorDetails = null; /** * The caught throwable. @@ -50,7 +48,7 @@ public function displayErrorDetails() */ public function hasThrown() { - return !!$this->thrown; + return (bool)$this->thrown; } /** @@ -86,6 +84,7 @@ public function renderHtmlErrorDetails() * * @return integer */ + #[\Override] public function getCode() { return 500; @@ -125,6 +124,7 @@ public function getMessage() * @param Container $container A service locator. * @return self */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -143,7 +143,7 @@ protected function setDependencies(Container $container) */ protected function setDisplayErrorDetails($state) { - $this->displayErrorDetails = !!$state; + $this->displayErrorDetails = (bool)$state; return $this; } @@ -171,7 +171,7 @@ protected function setThrown($throwable) */ protected function renderThrowableAsText($throwable) { - $text = sprintf('Type: %s' . PHP_EOL, get_class($throwable)); + $text = sprintf('Type: %s' . PHP_EOL, $throwable::class); $code = $throwable->getCode(); if (!empty($code)) { @@ -285,7 +285,7 @@ protected function renderJsonMessage($throwable) do { $json['error'][] = [ - 'type' => get_class($throwable), + 'type' => $throwable::class, 'code' => $throwable->getCode(), 'message' => $throwable->getMessage(), 'file' => $throwable->getFile(), @@ -310,7 +310,7 @@ protected function renderXmlMessage($throwable) if ($this->displayErrorDetails()) { do { $xml .= " \n"; - $xml .= ' ' . get_class($throwable) . "\n"; + $xml .= ' ' . $throwable::class . "\n"; $xml .= ' ' . $throwable->getCode() . "\n"; $xml .= ' ' . $this->createCdataSection($throwable->getMessage()) . "\n"; $xml .= ' ' . $throwable->getFile() . "\n"; @@ -319,9 +319,8 @@ protected function renderXmlMessage($throwable) $xml .= " \n"; } while ($throwable = $throwable->getPrevious()); } - $xml .= ''; - return $xml; + return $xml . ''; } /** @@ -349,7 +348,7 @@ protected function renderHtmlError($throwable) $line = $throwable->getLine(); $trace = $throwable->getTraceAsString(); - $html = sprintf('
Type: %s
', get_class($throwable)); + $html = sprintf('
Type: %s
', $throwable::class); if ($code) { $html .= sprintf('
Code: %s
', $code); @@ -381,6 +380,7 @@ protected function renderHtmlError($throwable) * @param array|\ArrayAccess $data Raw template data. * @return array|\ArrayAccess Expanded and processed template data. */ + #[\Override] protected function parseTemplateData($data = []) { $error = $this->getThrown(); diff --git a/packages/app/src/Charcoal/App/Handler/AbstractHandler.php b/packages/app/src/Charcoal/App/Handler/AbstractHandler.php index ddc0a31c9..1f7cc831e 100644 --- a/packages/app/src/Charcoal/App/Handler/AbstractHandler.php +++ b/packages/app/src/Charcoal/App/Handler/AbstractHandler.php @@ -98,8 +98,6 @@ public function __construct(Container $container, $config = null) /** * String representation of the handler. - * - * @return string */ public function __toString(): string { @@ -183,7 +181,7 @@ final protected function templateFactory() if ($this->templateFactory === null) { throw new RuntimeException(sprintf( 'Template Factory is not defined for [%s]', - get_class($this) + static::class )); } @@ -216,7 +214,7 @@ final protected function httpRequest() if ($this->httpRequest === null) { throw new RuntimeException(sprintf( 'HTTP Request is not defined for "%s"', - get_class($this) + static::class )); } @@ -276,9 +274,8 @@ protected function respondWith(ResponseInterface $response, $contentType, $outpu * Set an template factory. * * @param FactoryInterface $factory The factory to create templates. - * @return void */ - private function setTemplateFactory(FactoryInterface $factory) + private function setTemplateFactory(FactoryInterface $factory): void { $this->templateFactory = $factory; } @@ -287,9 +284,8 @@ private function setTemplateFactory(FactoryInterface $factory) * Set container for use with the template controller * * @param Container $container A dependencies container instance. - * @return void */ - private function setContainer(Container $container) + private function setContainer(Container $container): void { $this->container = $container; } diff --git a/packages/app/src/Charcoal/App/Handler/Error.php b/packages/app/src/Charcoal/App/Handler/Error.php index 0f439da48..7bb3df614 100644 --- a/packages/app/src/Charcoal/App/Handler/Error.php +++ b/packages/app/src/Charcoal/App/Handler/Error.php @@ -37,30 +37,16 @@ public function __invoke( $this->setThrown($error); $contentType = $this->determineContentType($request); - switch ($contentType) { - case 'application/json': - $output = $this->renderJsonOutput(); - break; - - case 'text/xml': - case 'application/xml': - $output = $this->renderXmlOutput(); - break; - - case 'text/html': - $output = $this->renderHtmlOutput(); - break; - - case 'text/plain': - $output = $this->renderPlainOutput(); - break; - - default: - throw new UnexpectedValueException(sprintf( - 'Cannot render unknown content type: %s', - $contentType - )); - } + $output = match ($contentType) { + 'application/json' => $this->renderJsonOutput(), + 'text/xml', 'application/xml' => $this->renderXmlOutput(), + 'text/html' => $this->renderHtmlOutput(), + 'text/plain' => $this->renderPlainOutput(), + default => throw new UnexpectedValueException(sprintf( + 'Cannot render unknown content type: %s', + $contentType + )), + }; $this->writeToErrorLog($error); @@ -73,10 +59,8 @@ public function __invoke( /** * Render Text Error - * - * @return string */ - protected function renderPlainOutput() + protected function renderPlainOutput(): string { $message = $this->renderTextMessage($this->getThrown()); @@ -85,10 +69,8 @@ protected function renderPlainOutput() /** * Render JSON Error - * - * @return string */ - protected function renderJsonOutput() + protected function renderJsonOutput(): string { $message = $this->renderJsonMessage($this->getThrown()); @@ -97,10 +79,8 @@ protected function renderJsonOutput() /** * Render XML Error - * - * @return string */ - protected function renderXmlOutput() + protected function renderXmlOutput(): string { $message = $this->renderXmlMessage($this->getThrown()); diff --git a/packages/app/src/Charcoal/App/Handler/HandlerConfig.php b/packages/app/src/Charcoal/App/Handler/HandlerConfig.php index a4944bceb..f51d631de 100644 --- a/packages/app/src/Charcoal/App/Handler/HandlerConfig.php +++ b/packages/app/src/Charcoal/App/Handler/HandlerConfig.php @@ -16,26 +16,20 @@ class HandlerConfig extends AbstractConfig { /** * The view (to load). - * - * @var string|null */ - private $template; + private ?string $template = null; /** * The view engine ident to use. * * For example: "mustache" - * - * @var string|null */ - private $engine; + private ?string $engine = null; /** * The view controller. - * - * @var string|null */ - private $controller; + private ?string $controller = null; /** * Dynamic views to register. @@ -48,31 +42,23 @@ class HandlerConfig extends AbstractConfig /** * Additional view data. - * - * @var array */ - private $templateData = []; + private array $templateData = []; /** * Enable handler-level caching for the view. - * - * @var boolean $cache */ - private $cache = false; + private bool $cache = false; /** * Time-to-live, in seconds, of the cache. (0 = no limit). - * - * @var integer */ - private $cacheTtl = 0; + private int $cacheTtl = 0; /** * Retrieve the default handler types. - * - * @return array */ - public static function defaultHandlerTypes() + public static function defaultHandlerTypes(): array { return [ 'maintenance', @@ -90,7 +76,7 @@ public static function defaultHandlerTypes() * @throws InvalidArgumentException If the template view is invalid. * @return HandlerConfig Chainable */ - public function setTemplate($template) + public function setTemplate($template): static { if (empty($template)) { $this->template = null; @@ -109,10 +95,8 @@ public function setTemplate($template) /** * Retrieve the template view. - * - * @return string */ - public function template() + public function template(): string { if ($this->template === null) { return 'charcoal/app/handler/layout'; @@ -126,9 +110,8 @@ public function template() * * @param string|null $controller Handler controller name. * @throws InvalidArgumentException If the template controller is invalid. - * @return self */ - public function setController($controller) + public function setController($controller): static { if (empty($controller)) { $this->controller = null; @@ -183,9 +166,8 @@ public function defaultController() * * @param string|null $engine The view engine identifier. * @throws InvalidArgumentException If the engine is invalid. - * @return self */ - public function setEngine($engine) + public function setEngine($engine): static { if (empty($engine)) { $this->engine = null; @@ -235,9 +217,8 @@ public function defaultEngine() * Set the "handlerMessage" view ident. * * @param string $templateIdent A template identifier. - * @return self */ - public function setPartial($templateIdent) + public function setPartial($templateIdent): static { $this->partials['handlerMessage'] = $templateIdent; return $this; @@ -259,7 +240,7 @@ public function partial() * @param array $partials Dynamic templates. * @return HandlerConfig Chainable */ - public function setPartials(array $partials) + public function setPartials(array $partials): static { $this->partials = array_replace($this->partials, $partials); return $this; @@ -281,7 +262,7 @@ public function partials() * @param array $data Additional template data. * @return HandlerConfig Chainable */ - public function setTemplateData(array $data) + public function setTemplateData(array $data): static { $this->templateData = array_merge($this->templateData, $data); return $this; @@ -289,10 +270,8 @@ public function setTemplateData(array $data) /** * Retrieve the template data for the view. - * - * @return array */ - public function templateData() + public function templateData(): array { return $this->templateData; } @@ -303,18 +282,16 @@ public function templateData() * @param boolean $cache The cache flag. * @return HandlerConfig Chainable */ - public function setCache($cache) + public function setCache($cache): static { - $this->cache = !!$cache; + $this->cache = (bool)$cache; return $this; } /** * Determine if the cache is enabled or disabled. - * - * @return boolean */ - public function cache() + public function cache(): bool { return $this->cache; } @@ -325,7 +302,7 @@ public function cache() * @param integer $ttl The time-to-live, in seconds. * @return HandlerConfig Chainable */ - public function setCacheTtl($ttl) + public function setCacheTtl($ttl): static { $this->cacheTtl = intval($ttl); return $this; @@ -333,10 +310,8 @@ public function setCacheTtl($ttl) /** * Retrieve the time-to-live for the cached template. - * - * @return integer */ - public function cacheTtl() + public function cacheTtl(): int { return $this->cacheTtl; } diff --git a/packages/app/src/Charcoal/App/Handler/HandlerInterface.php b/packages/app/src/Charcoal/App/Handler/HandlerInterface.php index f371301c2..9c6f69d02 100644 --- a/packages/app/src/Charcoal/App/Handler/HandlerInterface.php +++ b/packages/app/src/Charcoal/App/Handler/HandlerInterface.php @@ -1,5 +1,7 @@ renderPlainOutput(); } else { $contentType = $this->determineContentType($request); - switch ($contentType) { - case 'application/json': - $output = $this->renderJsonOutput(); - break; - - case 'text/xml': - case 'application/xml': - $output = $this->renderXmlOutput(); - break; - - case 'text/html': - $output = $this->renderHtmlOutput(); - break; - - case 'text/plain': - $output = $this->renderPlainOutput(); - break; - - default: - throw new UnexpectedValueException(sprintf( - 'Cannot render unknown content type: %s', - $contentType - )); - } + $output = match ($contentType) { + 'application/json' => $this->renderJsonOutput(), + 'text/xml', 'application/xml' => $this->renderXmlOutput(), + 'text/html' => $this->renderHtmlOutput(), + 'text/plain' => $this->renderPlainOutput(), + default => throw new UnexpectedValueException(sprintf( + 'Cannot render unknown content type: %s', + $contentType + )), + }; } return $this->respondWith( @@ -74,10 +60,8 @@ public function __invoke( /** * Render Text Error - * - * @return string */ - protected function renderPlainOutput() + protected function renderPlainOutput(): string { $message = $this->translator()->translate('Service Unavailable', [], 'charcoal'); @@ -86,10 +70,8 @@ protected function renderPlainOutput() /** * Render JSON Error - * - * @return string */ - protected function renderJsonOutput() + protected function renderJsonOutput(): string { $message = $this->translator()->translate( 'The server is currently unavailable. We will be right back.', @@ -103,10 +85,8 @@ protected function renderJsonOutput() /** * Render XML Error - * - * @return string */ - protected function renderXmlOutput() + protected function renderXmlOutput(): string { $message = $this->translator()->translate( 'The server is currently unavailable. We will be right back.', @@ -129,30 +109,25 @@ protected function renderHtmlOutput() /** * Retrieve the response's HTTP code. - * - * @return integer */ - public function getCode() + #[\Override] + public function getCode(): int { return 503; } /** * Retrieve the handler's summary. - * - * @return string */ - public function getSummary() + public function getSummary(): string { return $this->translator()->translate('Service Unavailable', [], 'charcoal'); } /** * Retrieve the handler's message. - * - * @return string */ - public function getMessage() + public function getMessage(): string { return $this->translator()->translate( 'The server is currently unavailable. We will be right back.', diff --git a/packages/app/src/Charcoal/App/Handler/NotAllowed.php b/packages/app/src/Charcoal/App/Handler/NotAllowed.php index d4a3287c4..bd9aa6be0 100644 --- a/packages/app/src/Charcoal/App/Handler/NotAllowed.php +++ b/packages/app/src/Charcoal/App/Handler/NotAllowed.php @@ -49,30 +49,16 @@ public function __invoke( } else { $status = 405; $contentType = $this->determineContentType($request); - switch ($contentType) { - case 'application/json': - $output = $this->renderJsonOutput(); - break; - - case 'text/xml': - case 'application/xml': - $output = $this->renderXmlOutput(); - break; - - case 'text/html': - $output = $this->renderHtmlOutput(); - break; - - case 'text/plain': - $output = $this->renderPlainOutput(); - break; - - default: - throw new UnexpectedValueException(sprintf( - 'Cannot render unknown content type: %s', - $contentType - )); - } + $output = match ($contentType) { + 'application/json' => $this->renderJsonOutput(), + 'text/xml', 'application/xml' => $this->renderXmlOutput(), + 'text/html' => $this->renderHtmlOutput(), + 'text/plain' => $this->renderPlainOutput(), + default => throw new UnexpectedValueException(sprintf( + 'Cannot render unknown content type: %s', + $contentType + )), + }; } return $this->respondWith( @@ -87,9 +73,8 @@ public function __invoke( * Set the HTTP methods allowed by the current request. * * @param array $methods Case-sensitive array of methods. - * @return self */ - protected function setMethods(array $methods) + protected function setMethods(array $methods): static { $this->methods = implode(', ', $methods); @@ -108,10 +93,8 @@ public function getMethods() /** * Render Text Error - * - * @return string */ - protected function renderPlainOutput() + protected function renderPlainOutput(): string { $message = $this->translator()->translate('Allowed methods: {{ methods }}', [ '{{ methods }}' => $this->getMethods() @@ -122,10 +105,8 @@ protected function renderPlainOutput() /** * Render JSON Error - * - * @return string */ - protected function renderJsonOutput() + protected function renderJsonOutput(): string { $message = $this->translator()->translate('Method not allowed. Must be one of: {{ methods }}', [ '{{ methods }}' => $this->getMethods() @@ -137,10 +118,8 @@ protected function renderJsonOutput() /** * Render XML Error - * - * @return string */ - protected function renderXmlOutput() + protected function renderXmlOutput(): string { $message = $this->translator()->translate('Method not allowed. Must be one of: {{ methods }}', [ '{{ methods }}' => $this->getMethods() @@ -165,6 +144,7 @@ protected function renderHtmlOutput() * @param array|\ArrayAccess $data Raw template data. * @return array|\ArrayAccess Expanded and processed template data. */ + #[\Override] protected function parseTemplateData($data = []) { $data['allowedMethods'] = $this->getMethods(); @@ -174,30 +154,25 @@ protected function parseTemplateData($data = []) /** * Retrieve the response's HTTP code. - * - * @return integer */ - public function getCode() + #[\Override] + public function getCode(): int { return 405; } /** * Retrieve the handler's summary. - * - * @return string */ - public function getSummary() + public function getSummary(): string { return $this->translator()->translate('Method not allowed.', [], 'charcoal'); } /** * Retrieve the handler's message. - * - * @return string */ - public function getMessage() + public function getMessage(): string { return $this->renderPlainOutput(); } diff --git a/packages/app/src/Charcoal/App/Handler/NotFound.php b/packages/app/src/Charcoal/App/Handler/NotFound.php index f9d75ec19..aab322f07 100644 --- a/packages/app/src/Charcoal/App/Handler/NotFound.php +++ b/packages/app/src/Charcoal/App/Handler/NotFound.php @@ -33,30 +33,16 @@ public function __invoke( $this->setHttpRequest($request); $contentType = $this->determineContentType($request); - switch ($contentType) { - case 'application/json': - $output = $this->renderJsonOutput(); - break; - - case 'text/xml': - case 'application/xml': - $output = $this->renderXmlOutput(); - break; - - case 'text/html': - $output = $this->renderHtmlOutput(); - break; - - case 'text/plain': - $output = $this->renderPlainOutput(); - break; - - default: - throw new UnexpectedValueException(sprintf( - 'Cannot render unknown content type: %s', - $contentType - )); - } + $output = match ($contentType) { + 'application/json' => $this->renderJsonOutput(), + 'text/xml', 'application/xml' => $this->renderXmlOutput(), + 'text/html' => $this->renderHtmlOutput(), + 'text/plain' => $this->renderPlainOutput(), + default => throw new UnexpectedValueException(sprintf( + 'Cannot render unknown content type: %s', + $contentType + )), + }; return $this->respondWith( $response->withStatus(404), @@ -67,10 +53,8 @@ public function __invoke( /** * Render Text Error - * - * @return string */ - protected function renderPlainOutput() + protected function renderPlainOutput(): string { $message = $this->translator()->translate('Not Found', [], 'charcoal'); @@ -79,10 +63,8 @@ protected function renderPlainOutput() /** * Render JSON Error - * - * @return string */ - protected function renderJsonOutput() + protected function renderJsonOutput(): string { $message = $this->translator()->translate('Not Found', [], 'charcoal'); $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); @@ -92,10 +74,8 @@ protected function renderJsonOutput() /** * Render XML Error - * - * @return string */ - protected function renderXmlOutput() + protected function renderXmlOutput(): string { $message = $this->translator()->translate('Not Found', [], 'charcoal'); @@ -114,30 +94,25 @@ protected function renderHtmlOutput() /** * Retrieve the response's HTTP code. - * - * @return integer */ - public function getCode() + #[\Override] + public function getCode(): int { return 404; } /** * Retrieve the handler's summary. - * - * @return string */ - public function getSummary() + public function getSummary(): string { return $this->translator()->translate('Page Not Found', [], 'charcoal'); } /** * Retrieve the handler's message. - * - * @return string */ - public function getMessage() + public function getMessage(): string { return $this->translator()->translate( 'The page you are looking for could not be found.', diff --git a/packages/app/src/Charcoal/App/Handler/PhpError.php b/packages/app/src/Charcoal/App/Handler/PhpError.php index f2af5a186..59673cff7 100644 --- a/packages/app/src/Charcoal/App/Handler/PhpError.php +++ b/packages/app/src/Charcoal/App/Handler/PhpError.php @@ -37,30 +37,16 @@ public function __invoke( $this->setThrown($error); $contentType = $this->determineContentType($request); - switch ($contentType) { - case 'application/json': - $output = $this->renderJsonOutput(); - break; - - case 'text/xml': - case 'application/xml': - $output = $this->renderXmlOutput(); - break; - - case 'text/html': - $output = $this->renderHtmlOutput(); - break; - - case 'text/plain': - $output = $this->renderPlainOutput(); - break; - - default: - throw new UnexpectedValueException(sprintf( - 'Cannot render unknown content type: %s', - $contentType - )); - } + $output = match ($contentType) { + 'application/json' => $this->renderJsonOutput(), + 'text/xml', 'application/xml' => $this->renderXmlOutput(), + 'text/html' => $this->renderHtmlOutput(), + 'text/plain' => $this->renderPlainOutput(), + default => throw new UnexpectedValueException(sprintf( + 'Cannot render unknown content type: %s', + $contentType + )), + }; $this->writeToErrorLog($error); @@ -73,10 +59,8 @@ public function __invoke( /** * Render Text Error - * - * @return string */ - protected function renderPlainOutput() + protected function renderPlainOutput(): string { $message = $this->renderTextMessage($this->getThrown()); @@ -85,10 +69,8 @@ protected function renderPlainOutput() /** * Render JSON Error - * - * @return string */ - protected function renderJsonOutput() + protected function renderJsonOutput(): string { $message = $this->renderJsonMessage($this->getThrown()); @@ -97,10 +79,8 @@ protected function renderJsonOutput() /** * Render XML Error - * - * @return string */ - protected function renderXmlOutput() + protected function renderXmlOutput(): string { $message = $this->renderXmlMessage($this->getThrown()); diff --git a/packages/app/src/Charcoal/App/Helper/CallbackStream.php b/packages/app/src/Charcoal/App/Helper/CallbackStream.php index 384da2e90..d8647e164 100644 --- a/packages/app/src/Charcoal/App/Helper/CallbackStream.php +++ b/packages/app/src/Charcoal/App/Helper/CallbackStream.php @@ -19,9 +19,8 @@ class CallbackStream implements StreamInterface /** * Whether or not the callback has been previously invoked. - * @var boolean */ - private $called = false; + private bool $called = false; /** * CallbackStream constructor. @@ -32,12 +31,9 @@ public function __construct(callable $callback) $this->callback = $callback; } - /** - * @return string - */ - public function __toString() + public function __toString(): string { - return $this->output(); + return (string)$this->output(); } /** @@ -77,7 +73,7 @@ public function detach() /** * @return integer|null Returns the size in bytes if known, or null if unknown. */ - public function getSize() + public function getSize(): null { return null; } @@ -85,23 +81,17 @@ public function getSize() /** * @return integer|boolean Position of the file pointer or false on error. */ - public function tell() + public function tell(): int { return 0; } - /** - * @return boolean - */ - public function eof() + public function eof(): bool { return $this->called; } - /** - * @return boolean - */ - public function isSeekable() + public function isSeekable(): bool { return false; } @@ -116,7 +106,7 @@ public function isSeekable() * SEEK_END: Set position to end-of-stream plus offset. * @return boolean Returns TRUE on success or FALSE on failure. */ - public function seek($offset, $whence = SEEK_SET) + public function seek($offset, $whence = SEEK_SET): bool { return false; } @@ -126,15 +116,12 @@ public function seek($offset, $whence = SEEK_SET) * @link http://www.php.net/manual/en/function.fseek.php 1 * @return boolean Returns TRUE on success or FALSE on failure. */ - public function rewind() + public function rewind(): bool { return false; } - /** - * @return boolean - */ - public function isWritable() + public function isWritable(): bool { return false; } @@ -144,15 +131,12 @@ public function isWritable() * @return integer|boolean Returns the number of bytes written to the stream on * success or FALSE on failure. */ - public function write($string) + public function write($string): bool { return false; } - /** - * @return boolean - */ - public function isReadable() + public function isReadable(): bool { return true; } @@ -185,7 +169,7 @@ public function getContents() * provided. Returns a specific key value if a key is provided and the * value is found, or null if the key is not found. */ - public function getMetadata($key = null) + public function getMetadata($key = null): ?array { if ($key === null) { return []; diff --git a/packages/app/src/Charcoal/App/Middleware/IpMiddleware.php b/packages/app/src/Charcoal/App/Middleware/IpMiddleware.php index 3e5678455..633318127 100644 --- a/packages/app/src/Charcoal/App/Middleware/IpMiddleware.php +++ b/packages/app/src/Charcoal/App/Middleware/IpMiddleware.php @@ -61,8 +61,6 @@ public function __construct(array $data) /** * Default middleware options. - * - * @return array */ public function defaults(): array { @@ -97,7 +95,7 @@ public function defaults(): array public function __invoke(RequestInterface $request, ResponseInterface $response, callable $next) { $ip = $this->getClientIp(); - if (!$ip) { + if ($ip === '' || $ip === '0') { if ((!empty($this->disallowed) || !empty($this->allowed)) && $this->failOnInvalidIp === true) { if ($this->errorMessage) { $response->getBody()->write($this->errorMessage); @@ -109,7 +107,7 @@ public function __invoke(RequestInterface $request, ResponseInterface $response, } // Check disallowed. - if ($this->isIpDisallowed($ip) === true) { + if ($this->isIpDisallowed($ip)) { if ($this->disallowedRedirect !== '') { return $response ->withStatus(302) @@ -150,9 +148,8 @@ public function __invoke(RequestInterface $request, ResponseInterface $response, * Note: this method only performs an exact string match on IP address, no IP masking / range features. * * @param string $ip The IP address to check against the disallowed. - * @return boolean */ - private function isIpDisallowed($ip): bool + private function isIpDisallowed(string $ip): bool { if (empty($this->disallowed)) { return false; @@ -168,9 +165,8 @@ private function isIpDisallowed($ip): bool * Note; This method only performs an exact string match on IP address, no IP masking / range features. * * @param string $ip The IP address to check against the allowed. - * @return boolean */ - private function isIpAllowed($ip): bool + private function isIpAllowed(string $ip): bool { if (empty($this->allowed)) { return true; @@ -181,18 +177,17 @@ private function isIpAllowed($ip): bool /** * @param string $ip The IP to check. * @param string[] $cidrs The array of IPs/CIDRs to validate against. "/32" netmask is assumed. - * @return boolean */ private function isIpInRange(string $ip, array $cidrs): bool { foreach ($cidrs as $range) { - if (strpos($range, '/') === false) { + if (!str_contains($range, '/')) { $range .= '/32'; } // $range is in IP/CIDR format eg 127.0.0.1/24 - list($subnet, $netmask) = explode('/', $range, 2); - $netmask = ~(pow(2, (32 - (int)$netmask)) - 1); - if ((ip2long($ip) & $netmask) == (ip2long($subnet) & $netmask)) { + [$subnet, $netmask] = explode('/', $range, 2); + $netmask = ~(2 ** (32 - (int)$netmask) - 1); + if ((ip2long($ip) & $netmask) === (ip2long($subnet) & $netmask)) { return true; } } @@ -200,9 +195,6 @@ private function isIpInRange(string $ip, array $cidrs): bool return false; } - /** - * @return string - */ private function getClientIp(): string { if (isset($_SERVER['REMOTE_ADDR'])) { diff --git a/packages/app/src/Charcoal/App/Module/AbstractModule.php b/packages/app/src/Charcoal/App/Module/AbstractModule.php index d45da11d3..bfc5e3000 100644 --- a/packages/app/src/Charcoal/App/Module/AbstractModule.php +++ b/packages/app/src/Charcoal/App/Module/AbstractModule.php @@ -105,9 +105,9 @@ public function setUp() */ public function setupRoutes() { - if (!isset($this->routeManager)) { + if ($this->routeManager === null) { $config = $this->config(); - $routes = (isset($config['routes']) ? $config['routes'] : [] ); + $routes = ($config['routes'] ?? [] ); $this->routeManager = new RouteManager([ 'config' => $routes, diff --git a/packages/app/src/Charcoal/App/Module/ModuleInterface.php b/packages/app/src/Charcoal/App/Module/ModuleInterface.php index bdd2c30ac..e6683ad96 100644 --- a/packages/app/src/Charcoal/App/Module/ModuleInterface.php +++ b/packages/app/src/Charcoal/App/Module/ModuleInterface.php @@ -1,5 +1,7 @@ createConfig() * * @param mixed|null $data Optional config data. - * @return ActionRouteConfig */ - public function createConfig($data = null) + public function createConfig($data = null): \Charcoal\App\Route\ActionRouteConfig { return new ActionRouteConfig($data); } diff --git a/packages/app/src/Charcoal/App/Route/ActionRouteConfig.php b/packages/app/src/Charcoal/App/Route/ActionRouteConfig.php index e4a7f29d6..aa5510850 100644 --- a/packages/app/src/Charcoal/App/Route/ActionRouteConfig.php +++ b/packages/app/src/Charcoal/App/Route/ActionRouteConfig.php @@ -1,5 +1,7 @@ actionData = $actionData; return $this; @@ -29,10 +28,8 @@ public function setActionData(array $actionData) /** * Get the action data. - * - * @return array */ - public function actionData() + public function actionData(): array { return $this->actionData; } diff --git a/packages/app/src/Charcoal/App/Route/RouteConfig.php b/packages/app/src/Charcoal/App/Route/RouteConfig.php index 97b287c93..eef7e3481 100644 --- a/packages/app/src/Charcoal/App/Route/RouteConfig.php +++ b/packages/app/src/Charcoal/App/Route/RouteConfig.php @@ -13,54 +13,44 @@ class RouteConfig extends AbstractConfig { /** * Route identifier/name - * - * @var string */ - private $ident; + private ?string $ident = null; /** * Route pattern - * - * @var string */ - private $route; + private ?string $route = null; /** * HTTP methods supported by this route * * @var string[] */ - private $methods = [ 'GET' ]; + private array $methods = [ 'GET' ]; /** * Response controller classname * * Should be the class-ident of an action, a script or a template controller. - * - * @var string */ - private $controller; + private ?string $controller = null; /** * Parent route groups * * @var string[] */ - private $groups = []; + private array $groups = []; /** * Optional headers to set on response. - * - * @var array */ - private $headers = []; + private array $headers = []; /** * Retrieve the default route types. - * - * @return array */ - public static function defaultRouteTypes() + public static function defaultRouteTypes(): array { return [ 'templates', @@ -74,9 +64,8 @@ public static function defaultRouteTypes() * * @param string $ident Route identifier. * @throws InvalidArgumentException If the identifier is not a string. - * @return self */ - public function setIdent($ident) + public function setIdent($ident): static { if (!is_string($ident)) { throw new InvalidArgumentException( @@ -94,7 +83,7 @@ public function setIdent($ident) * * @return string */ - public function ident() + public function ident(): ?string { return $this->ident; } @@ -104,9 +93,8 @@ public function ident() * * @param string $pattern Route pattern. * @throws InvalidArgumentException If the pattern argument is not a string. - * @return self */ - public function setRoute($pattern) + public function setRoute($pattern): static { if (!is_string($pattern)) { throw new InvalidArgumentException( @@ -124,7 +112,7 @@ public function setRoute($pattern) * * @return string */ - public function route() + public function route(): ?string { return $this->route; } @@ -133,9 +121,8 @@ public function route() * Set parent route groups * * @param string[] $groups The parent route groups. - * @return self */ - public function setGroups(array $groups) + public function setGroups(array $groups): static { $this->groups = []; @@ -151,9 +138,8 @@ public function setGroups(array $groups) * * @param string $group The parent route group. * @throws InvalidArgumentException If the group is invalid. - * @return self */ - public function addGroup($group) + public function addGroup($group): static { if (!is_string($group)) { throw new InvalidArgumentException( @@ -168,10 +154,8 @@ public function addGroup($group) /** * Get parent route groups - * - * @return array */ - public function groups() + public function groups(): array { return $this->groups; } @@ -180,9 +164,8 @@ public function groups() * Add custom headers * * @param array $headers The custom headers, in key=>val pairs. - * @return self */ - public function setHeaders(array $headers) + public function setHeaders(array $headers): static { $this->headers = []; foreach ($headers as $name => $val) { @@ -197,7 +180,7 @@ public function setHeaders(array $headers) * @throws InvalidArgumentException If the header name or value is not a string. * @return $this */ - public function addHeader($name, $val) + public function addHeader($name, $val): static { if (!is_string($name)) { throw new InvalidArgumentException( @@ -215,10 +198,8 @@ public function addHeader($name, $val) /** * Get custom route headers. - * - * @return array */ - public function headers() + public function headers(): array { return $this->headers; } @@ -228,9 +209,8 @@ public function headers() * * @param string $controller Route controller name. * @throws InvalidArgumentException If the route view controller is not a string. - * @return self */ - public function setController($controller) + public function setController($controller): static { if (!is_string($controller)) { throw new InvalidArgumentException( @@ -250,9 +230,9 @@ public function setController($controller) * * @return string */ - public function controller() + public function controller(): ?string { - if (!isset($this->controller)) { + if ($this->controller === null) { return $this->ident(); } @@ -263,9 +243,8 @@ public function controller() * Set route methods * * @param string[] $methods The route's supported HTTP methods. - * @return self */ - public function setMethods(array $methods) + public function setMethods(array $methods): static { $this->methods = []; @@ -281,15 +260,14 @@ public function setMethods(array $methods) * * @param string $method The route's supported HTTP method. * @throws InvalidArgumentException If the HTTP method is invalid. - * @return self */ - public function addMethod($method) + public function addMethod($method): static { if (!is_string($method)) { throw new InvalidArgumentException( sprintf( 'Unsupported HTTP method; must be a string, received %s', - (is_object($method) ? get_class($method) : gettype($method)) + (get_debug_type($method)) ) ); } @@ -327,7 +305,7 @@ public function addMethod($method) * * @return string[] */ - public function methods() + public function methods(): array { return $this->methods; } diff --git a/packages/app/src/Charcoal/App/Route/RouteInterface.php b/packages/app/src/Charcoal/App/Route/RouteInterface.php index 54bd241a8..51d415832 100644 --- a/packages/app/src/Charcoal/App/Route/RouteInterface.php +++ b/packages/app/src/Charcoal/App/Route/RouteInterface.php @@ -1,5 +1,7 @@ config(); - if (PHP_SAPI == 'cli') { - $scripts = ( isset($routes['scripts']) ? $routes['scripts'] : [] ); + if (PHP_SAPI === 'cli') { + $scripts = ( $routes['scripts'] ?? [] ); foreach ($scripts as $scriptIdent => $scriptConfig) { $this->setupScript($scriptIdent, $scriptConfig); } } else { - $templates = ( isset($routes['templates']) ? $routes['templates'] : [] ); + $templates = ( $routes['templates'] ?? [] ); foreach ($templates as $routeIdent => $templateConfig) { $this->setupTemplate($routeIdent, $templateConfig); } - $actions = ( isset($routes['actions']) ? $routes['actions'] : [] ); + $actions = ( $routes['actions'] ?? [] ); foreach ($actions as $actionIdent => $actionConfig) { $this->setupAction($actionIdent, $actionConfig); } @@ -77,15 +75,11 @@ public function setupRoutes() */ private function setupTemplate($routeIdent, $templateConfig) { - $routePattern = isset($templateConfig['route']) - ? $templateConfig['route'] - : '/' . ltrim($routeIdent, '/'); + $routePattern = ($templateConfig['route'] ?? '/' . ltrim($routeIdent, '/')); $templateConfig['route'] = $routePattern; - $methods = isset($templateConfig['methods']) - ? $templateConfig['methods'] - : [ 'GET' ]; + $methods = ($templateConfig['methods'] ?? [ 'GET' ]); $routeHandler = $this->app->map( $methods, @@ -119,9 +113,7 @@ function ( } $defaultController = $this['route/controller/template/class']; - $routeController = isset($templateConfig['route_controller']) - ? $templateConfig['route_controller'] - : $defaultController; + $routeController = ($templateConfig['route_controller'] ?? $defaultController); $routeFactory = $this['route/factory']; $routeFactory->setDefaultClass($defaultController); @@ -153,15 +145,11 @@ function ( */ private function setupAction($routeIdent, $actionConfig) { - $routePattern = isset($actionConfig['route']) - ? $actionConfig['route'] - : '/' . ltrim($routeIdent, '/'); + $routePattern = ($actionConfig['route'] ?? '/') . ltrim($routeIdent, '/'); $actionConfig['route'] = $routePattern; - $methods = isset($actionConfig['methods']) - ? $actionConfig['methods'] - : [ 'POST' ]; + $methods = ($actionConfig['methods'] ?? [ 'POST' ]); $routeHandler = $this->app->map( $methods, @@ -195,9 +183,7 @@ function ( } $defaultController = $this['route/controller/action/class']; - $routeController = isset($actionConfig['route_controller']) - ? $actionConfig['route_controller'] - : $defaultController; + $routeController = ($actionConfig['route_controller'] ?? $defaultController); $routeFactory = $this['route/factory']; $routeFactory->setDefaultClass($defaultController); @@ -229,15 +215,11 @@ function ( */ private function setupScript($routeIdent, $scriptConfig) { - $routePattern = isset($scriptConfig['route']) - ? $scriptConfig['route'] - : '/' . ltrim($routeIdent, '/'); + $routePattern = ($scriptConfig['route'] ?? '/') . ltrim($routeIdent, '/'); $scriptConfig['route'] = $routePattern; - $methods = isset($scriptConfig['methods']) - ? $scriptConfig['methods'] - : [ 'GET' ]; + $methods = ($scriptConfig['methods'] ?? [ 'GET' ]); $routeHandler = $this->app->map( $methods, @@ -271,9 +253,7 @@ function ( } $defaultController = $this['route/controller/script/class']; - $routeController = isset($scriptConfig['route_controller']) - ? $scriptConfig['route_controller'] - : $defaultController; + $routeController = ($scriptConfig['route_controller'] ?? $defaultController); $routeFactory = $this['route/factory']; $routeFactory->setDefaultClass($defaultController); diff --git a/packages/app/src/Charcoal/App/Route/ScriptRoute.php b/packages/app/src/Charcoal/App/Route/ScriptRoute.php index 5af4e1a3d..0baeb1fc7 100644 --- a/packages/app/src/Charcoal/App/Route/ScriptRoute.php +++ b/packages/app/src/Charcoal/App/Route/ScriptRoute.php @@ -36,10 +36,9 @@ public function __construct(array $data) /** * @param mixed|null $data Optional config data. - * @return ScriptRouteConfig * @see ConfigurableTrait::createConfig() */ - public function createConfig($data = null) + public function createConfig($data = null): \Charcoal\App\Route\ScriptRouteConfig { return new ScriptRouteConfig($data); } diff --git a/packages/app/src/Charcoal/App/Route/ScriptRouteConfig.php b/packages/app/src/Charcoal/App/Route/ScriptRouteConfig.php index f34fa141f..cea95818b 100644 --- a/packages/app/src/Charcoal/App/Route/ScriptRouteConfig.php +++ b/packages/app/src/Charcoal/App/Route/ScriptRouteConfig.php @@ -1,5 +1,7 @@ createConfig() * * @param mixed|null $data Optional config data. - * @return TemplateRouteConfig */ - public function createConfig($data = null) + public function createConfig($data = null): \Charcoal\App\Route\TemplateRouteConfig { return new TemplateRouteConfig($data); } diff --git a/packages/app/src/Charcoal/App/Route/TemplateRouteConfig.php b/packages/app/src/Charcoal/App/Route/TemplateRouteConfig.php index 845ef94b5..7f95deec6 100644 --- a/packages/app/src/Charcoal/App/Route/TemplateRouteConfig.php +++ b/packages/app/src/Charcoal/App/Route/TemplateRouteConfig.php @@ -16,22 +16,19 @@ class TemplateRouteConfig extends RouteConfig { /** * The template ident (to load). - * @var string|null $template */ - private $template; + private ?string $template = null; /** * The view engine ident to use. * Ex: "mustache", "" - * @var string|null $engine */ - private $engine; + private ?string $engine = null; /** * Additional template data. - * @var array $templateData */ - private $templateData = []; + private array $templateData = []; /** * Redirect URL. @@ -41,28 +38,25 @@ class TemplateRouteConfig extends RouteConfig /** * Redirect Mode (HTTP status code). - * @var integer $redirectMode */ - private $redirectMode = 301; + private int $redirectMode = 301; /** * Enable route-level caching for this template. - * @var boolean $cache */ - private $cache = false; + private bool $cache = false; /** * If using cache, the time-to-live, in seconds, of the cache. (0 = no limit). - * @var integer $cacheTtl */ - private $cacheTtl = 0; + private int $cacheTtl = 0; /** * @param string|null $template The template identifier. * @throws InvalidArgumentException If the tempalte parameter is not null or not a string. * @return TemplateRouteConfig Chainable */ - public function setTemplate($template) + public function setTemplate($template): static { if ($template === null) { $this->template = null; @@ -80,7 +74,7 @@ public function setTemplate($template) /** * @return string */ - public function template() + public function template(): ?string { if ($this->template === null) { return $this->ident(); @@ -110,7 +104,7 @@ public function defaultController() * @throws InvalidArgumentException If the engine is not null or not a string. * @return TemplateRouteConfig Chainable */ - public function setEngine($engine) + public function setEngine($engine): static { if ($engine === null) { $this->engine = null; @@ -156,9 +150,9 @@ public function defaultEngine() * @param array $templateData The route template data. * @return TemplateRouteConfig Chainable */ - public function setTemplateData(array $templateData) + public function setTemplateData(array $templateData): static { - if (!isset($this->templateData)) { + if ($this->templateData === null) { $this->templateData = []; } @@ -169,10 +163,8 @@ public function setTemplateData(array $templateData) /** * Get the template data for the view. - * - * @return array */ - public function templateData() + public function templateData(): array { return $this->templateData; } @@ -181,7 +173,7 @@ public function templateData() * @param string|string[] $url Points to a route. * @return TemplateRouteConfig Chainable */ - public function setRedirect($url) + public function setRedirect($url): static { $this->redirect = $url; @@ -205,7 +197,7 @@ public function redirect() * @throws InvalidArgumentException If the redirect mode is not 3xx. * @return TemplateRouteConfig Chainable */ - public function setRedirectMode($redirectMode) + public function setRedirectMode($redirectMode): static { $redirectMode = (int)$redirectMode; if ($redirectMode < 300 || $redirectMode >= 400) { @@ -218,10 +210,7 @@ public function setRedirectMode($redirectMode) return $this; } - /** - * @return integer - */ - public function redirectMode() + public function redirectMode(): int { return $this->redirectMode; } @@ -230,16 +219,13 @@ public function redirectMode() * @param boolean $cache The cache enabled flag. * @return TemplateRouteConfig Chainable */ - public function setCache($cache) + public function setCache($cache): static { - $this->cache = !!$cache; + $this->cache = (bool)$cache; return $this; } - /** - * @return boolean - */ - public function cache() + public function cache(): bool { return $this->cache; } @@ -248,16 +234,13 @@ public function cache() * @param integer $ttl The cache Time-To-Live, in seconds. * @return TemplateRouteConfig Chainable */ - public function setCacheTtl($ttl) + public function setCacheTtl($ttl): static { $this->cacheTtl = intval($ttl); return $this; } - /** - * @return integer - */ - public function cacheTtl() + public function cacheTtl(): int { return $this->cacheTtl; } diff --git a/packages/app/src/Charcoal/App/Script/AbstractScript.php b/packages/app/src/Charcoal/App/Script/AbstractScript.php index 614b39dba..2f8c49415 100644 --- a/packages/app/src/Charcoal/App/Script/AbstractScript.php +++ b/packages/app/src/Charcoal/App/Script/AbstractScript.php @@ -30,50 +30,23 @@ abstract class AbstractScript extends AbstractEntity implements { use LoggerAwareTrait; - /** - * @var string $ident - */ - private $ident; + private ?string $ident = null; - /** - * @var string $description - */ - private $description; + private ?string $description = null; - /** - * @var array $arguments - */ - private $arguments; + private ?array $arguments = null; - /** - * @var CLImate $climate - */ - private $climate; + private \League\CLImate\CLImate $climate; - /** - * @var ReaderInterface $cliamteReader - */ - private $climateReader; + private ?\League\CLImate\Util\Reader\ReaderInterface $climateReader = null; - /** - * @var boolean $quiet - */ - private $quiet = false; + private bool $quiet = false; - /** - * @var boolean $verbose - */ - private $verbose = false; + private bool $verbose = false; - /** - * @var boolean $interactive - */ - private $interactive = false; + private bool $interactive = false; - /** - * @var boolean $dryRun - */ - private $dryRun = false; + private bool $dryRun = false; /** * Return a new CLI script. @@ -231,7 +204,7 @@ public function description() */ public function setQuiet($quiet) { - $this->quiet = !!$quiet; + $this->quiet = (bool)$quiet; return $this; } @@ -249,7 +222,7 @@ public function quiet() */ public function setVerbose($verbose) { - $this->verbose = !!$verbose; + $this->verbose = (bool)$verbose; return $this; } @@ -267,7 +240,7 @@ public function verbose() */ public function setInteractive($interactive) { - $this->interactive = !!$interactive; + $this->interactive = (bool)$interactive; return $this; } @@ -285,7 +258,7 @@ public function interactive() */ public function setDryRun($simulate) { - $this->dryRun = !!$simulate; + $this->dryRun = (bool)$simulate; return $this; } @@ -434,7 +407,7 @@ protected function argOrInput($argName) * @throws RuntimeException If a radio or checkbox prompt has no options. * @return mixed Returns the prompt value. */ - protected function input($name) + protected function input(string $name) { $cli = $this->climate(); $arg = $this->argument($name); @@ -468,19 +441,15 @@ protected function input($name) $accept = false; } - if (!in_array($type, [ 'confirm', 'checkboxes', 'radio' ])) { - if (isset($arg['defaultValue'])) { - $default = $arg['defaultValue']; - - if (is_bool($default) || is_null($default)) { - $default = var_export($default, true); - } - - if ($default && is_string($default) || is_numeric($default)) { - $pattern = '/[\(\[\<]' . preg_quote($default, '/') . '[\)\]\>]/'; - if (!preg_match($pattern, $prompt)) { - $prompt .= ' (' . $default . ')'; - } + if (!in_array($type, [ 'confirm', 'checkboxes', 'radio' ]) && isset($arg['defaultValue'])) { + $default = $arg['defaultValue']; + if (is_bool($default) || is_null($default)) { + $default = var_export($default, true); + } + if ($default && is_string($default) || is_numeric($default)) { + $pattern = '/[\(\[\<]' . preg_quote($default, '/') . '[\)\]\>]/'; + if (!preg_match($pattern, (string)$prompt)) { + $prompt .= ' (' . $default . ')'; } } } @@ -523,12 +492,8 @@ protected function input($name) break; } - if ($accept) { - if (isset($arg['acceptValue'])) { - if (is_array($arg['acceptValue']) || is_callable($arg['acceptValue'])) { - $input->accept($arg['acceptValue']); - } - } + if ($accept && isset($arg['acceptValue']) && (is_array($arg['acceptValue']) || is_callable($arg['acceptValue']))) { + $input->accept($arg['acceptValue']); } if (isset($arg['defaultValue'])) { @@ -540,18 +505,16 @@ protected function input($name) /** * @param CLImate $climate A climate instance. - * @return void */ - private function setClimate(CLImate $climate) + private function setClimate(CLImate $climate): void { $this->climate = $climate; } /** * @param ReaderInterface $climateReader A climate reader. - * @return void */ - private function setClimateReader(ReaderInterface $climateReader) + private function setClimateReader(ReaderInterface $climateReader): void { $this->climateReader = $climateReader; } diff --git a/packages/app/src/Charcoal/App/Script/ArgScriptTrait.php b/packages/app/src/Charcoal/App/Script/ArgScriptTrait.php index 8f0dbb00a..c2fe6e98f 100644 --- a/packages/app/src/Charcoal/App/Script/ArgScriptTrait.php +++ b/packages/app/src/Charcoal/App/Script/ArgScriptTrait.php @@ -31,7 +31,7 @@ protected function parseAsArray($var, $delimiter = '[\s,]+') $var = preg_split('#(?useLock = !!$useLock; + $this->useLock = (bool)$useLock; return $this; } @@ -40,9 +40,8 @@ public function useLock() /** * @throws Exception If the lock file can not be opened or the script is already locked. - * @return boolean */ - public function startLock() + public function startLock(): bool { $lockFile = $this->getLockFileName(); $this->lockFilePointer = fopen($lockFile, 'w'); @@ -60,10 +59,7 @@ public function startLock() } } - /** - * @return void - */ - public function stopLock() + public function stopLock(): void { if ($this->lockFilePointer) { flock($this->lockFilePointer, LOCK_UN); @@ -71,10 +67,7 @@ public function stopLock() } } - /** - * @return string - */ - private function getLockFileName() + private function getLockFileName(): string { $lockName = str_replace('\\', '-', static::class); $lockName .= md5(__DIR__); diff --git a/packages/app/src/Charcoal/App/Script/PathScriptTrait.php b/packages/app/src/Charcoal/App/Script/PathScriptTrait.php index 9b43b7b86..6f267cd1b 100644 --- a/packages/app/src/Charcoal/App/Script/PathScriptTrait.php +++ b/packages/app/src/Charcoal/App/Script/PathScriptTrait.php @@ -45,7 +45,7 @@ public function processMultiplePaths($paths) throw new InvalidArgumentException('Received invalid paths.'); } - if (empty($paths)) { + if ($paths === []) { throw new InvalidArgumentException('Received empty paths.'); } @@ -78,13 +78,13 @@ public function pathExists($path) * @throws InvalidArgumentException If the path is invalid. * @return string Returns the filtered path. */ - public function filterPath($path, $trim = null) + public function filterPath($path, $trim = null): string { if (!is_string($path)) { throw new InvalidArgumentException('The path must be a string.'); } - if ($trim === null && defined(get_called_class() . '::DIRECTORY_SEPARATORS')) { + if ($trim === null && defined(static::class . '::DIRECTORY_SEPARATORS')) { $trim = static::DIRECTORY_SEPARATORS; } @@ -111,7 +111,7 @@ public function filterPath($path, $trim = null) */ public function filterWritablePath($path, $name = null) { - if ($name === null && defined(get_called_class() . '::DEFAULT_BASENAME')) { + if ($name === null && defined(static::class . '::DEFAULT_BASENAME')) { $name = static::DEFAULT_BASENAME; } @@ -135,7 +135,7 @@ public function filterWritablePath($path, $name = null) throw new InvalidArgumentException('The target file is not writeable.'); } } else { - $info = pathinfo($path); + $info = pathinfo((string)$path); $path = $this->filterWritablePath($info['dirname'], $info['basename']); } @@ -169,7 +169,7 @@ public function globRecursive($pattern, $flags = 0) } } - static::$globCache[$pattern][$depthKey] = array_filter($files, 'is_file'); + static::$globCache[$pattern][$depthKey] = array_filter($files, is_file(...)); return $files; } diff --git a/packages/app/src/Charcoal/App/Script/ScriptInterface.php b/packages/app/src/Charcoal/App/Script/ScriptInterface.php index 9a9b66ee2..0c6a1873b 100644 --- a/packages/app/src/Charcoal/App/Script/ScriptInterface.php +++ b/packages/app/src/Charcoal/App/Script/ScriptInterface.php @@ -1,5 +1,7 @@ register(new CacheServiceProvider()); $container->register(new DatabaseServiceProvider()); @@ -104,13 +103,13 @@ protected function registerKernelServices(Container $container) * @param Container $container A service container. * @return boolean */ - $container['debug'] = function (Container $container) { + $container['debug'] = function (Container $container): bool { if (isset($container['config']['debug'])) { - return !!$container['config']['debug']; + return (bool)$container['config']['debug']; } if (isset($container['config']['dev_mode'])) { - return !!$container['config']['dev_mode']; + return (bool)$container['config']['dev_mode']; } return false; @@ -273,19 +272,17 @@ protected function registerRouteServices(Container $container) * @param Container $container A service container. * @return \Charcoal\Factory\FactoryInterface */ - $container['route/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => RouteInterface::class, - 'resolver_options' => [ - 'suffix' => 'Route', - ], - 'arguments' => [ - [ - 'logger' => $container['logger'], - ], + $container['route/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => RouteInterface::class, + 'resolver_options' => [ + 'suffix' => 'Route', + ], + 'arguments' => [ + [ + 'logger' => $container['logger'], ], - ]); - }; + ], + ])); } /** @@ -298,7 +295,7 @@ protected function registerMiddlewareServices(Container $container) * @param Container $container A service container. * @return IpMiddleware */ - $container['middlewares/charcoal/app/middleware/ip'] = function (container $container) { + $container['middlewares/charcoal/app/middleware/ip'] = function (container $container): \Charcoal\App\Middleware\IpMiddleware { $wareConfig = $container['config']['middlewares']['charcoal/app/middleware/ip']; return new IpMiddleware($wareConfig); }; @@ -319,20 +316,18 @@ protected function registerRequestControllerServices(Container $container) * @param Container $container A service container. * @return \Charcoal\Factory\FactoryInterface */ - $container['action/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => ActionInterface::class, - 'resolver_options' => [ - 'suffix' => 'Action', + $container['action/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => ActionInterface::class, + 'resolver_options' => [ + 'suffix' => 'Action', + ], + 'arguments' => [ + [ + 'container' => $container, + 'logger' => $container['logger'], ], - 'arguments' => [ - [ - 'container' => $container, - 'logger' => $container['logger'], - ], - ], - ]); - }; + ], + ])); /** * The Template Factory service is used to instanciate new templates. @@ -343,20 +338,18 @@ protected function registerRequestControllerServices(Container $container) * @param Container $container A service container. * @return \Charcoal\Factory\FactoryInterface */ - $container['template/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => TemplateInterface::class, - 'resolver_options' => [ - 'suffix' => 'Template', - ], - 'arguments' => [ - [ - 'container' => $container, - 'logger' => $container['logger'], - ], + $container['template/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => TemplateInterface::class, + 'resolver_options' => [ + 'suffix' => 'Template', + ], + 'arguments' => [ + [ + 'container' => $container, + 'logger' => $container['logger'], ], - ]); - }; + ], + ])); /** * The Widget Factory service is used to instanciate new widgets. @@ -367,28 +360,24 @@ protected function registerRequestControllerServices(Container $container) * @param Container $container A service container. * @return \Charcoal\Factory\FactoryInterface */ - $container['widget/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => WidgetInterface::class, - 'resolver_options' => [ - 'suffix' => 'Widget', + $container['widget/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => WidgetInterface::class, + 'resolver_options' => [ + 'suffix' => 'Widget', + ], + 'arguments' => [ + [ + 'container' => $container, + 'logger' => $container['logger'], ], - 'arguments' => [ - [ - 'container' => $container, - 'logger' => $container['logger'], - ], - ], - ]); - }; + ], + ])); /** * @param Container $container A service container. * @return WidgetBuilder */ - $container['widget/builder'] = function (Container $container) { - return new WidgetBuilder($container['widget/factory'], $container); - }; + $container['widget/builder'] = (fn(Container $container): \Charcoal\App\Template\WidgetBuilder => new WidgetBuilder($container['widget/factory'], $container)); } /** @@ -405,19 +394,17 @@ protected function registerModuleServices(Container $container) * @param Container $container A service container. * @return \Charcoal\Factory\FactoryInterface */ - $container['module/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => ModuleInterface::class, - 'resolver_options' => [ - 'suffix' => 'Module', - ], - 'arguments' => [ - [ - 'logger' => $container['logger'], - ], + $container['module/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => ModuleInterface::class, + 'resolver_options' => [ + 'suffix' => 'Module', + ], + 'arguments' => [ + [ + 'logger' => $container['logger'], ], - ]); - }; + ], + ])); /** * The modules as PHP classes. @@ -425,7 +412,7 @@ protected function registerModuleServices(Container $container) * @param Container $container A service container. * @return array */ - $container['module/classes'] = function (Container $container) { + $container['module/classes'] = function (Container $container): array { $appConfig = $container['config']; $modules = $appConfig['modules']; @@ -435,13 +422,9 @@ protected function registerModuleServices(Container $container) 'suffix' => 'Module', ]); - $modules = array_map(function ($module) use ($moduleResolver) { - return $moduleResolver->resolve($module); - }, $modules); + $modules = array_map($moduleResolver->resolve(...), $modules); - array_filter($modules, function ($class) { - return class_exists($class); - }); + array_filter($modules, class_exists(...)); return $modules; }; @@ -462,14 +445,11 @@ protected function registerViewServices(Container $container) /** * @param Container $container The DI container. - * @return void */ protected function registerMustacheHelpersServices(Container $container): void { if (!isset($container['view/mustache/helpers'])) { - $container['view/mustache/helpers'] = function () { - return []; - }; + $container['view/mustache/helpers'] = (fn(): array => []); } /** @@ -477,7 +457,7 @@ protected function registerMustacheHelpersServices(Container $container): void * * @return array */ - $container->extend('view/mustache/helpers', function (array $helpers, Container $container) { + $container->extend('view/mustache/helpers', function (array $helpers, Container $container): array { $baseUrl = $container['base-url']; $urls = [ /** @@ -504,34 +484,28 @@ protected function registerMustacheHelpersServices(Container $container): void * @param string $uri A URI path to wrap. * @return UriInterface|null */ - 'withBaseUrl' => function ($uri, LambdaHelper $helper = null) use ($baseUrl) { - if ($helper) { + 'withBaseUrl' => function ($uri, ?LambdaHelper $helper = null) use ($baseUrl) { + if ($helper instanceof LambdaHelper) { $uri = $helper->render($uri); } - $uri = strval($uri); if ($uri === '') { $uri = $baseUrl->withPath(''); } else { $parts = parse_url($uri); - if (!isset($parts['scheme'])) { - if (!in_array($uri[0], [ '/', '#', '?' ])) { - $path = isset($parts['path']) ? $parts['path'] : ''; - $query = isset($parts['query']) ? $parts['query'] : ''; - $hash = isset($parts['fragment']) ? $parts['fragment'] : ''; - - $uri = $baseUrl->withPath($path) - ->withQuery($query) - ->withFragment($hash); - } + if (!isset($parts['scheme']) && !in_array($uri[0], [ '/', '#', '?' ])) { + $path = ($parts['path'] ?? ''); + $query = ($parts['query'] ?? ''); + $hash = ($parts['fragment'] ?? ''); + $uri = $baseUrl->withPath($path) + ->withQuery($query) + ->withFragment($hash); } } - return $uri; - }, - 'renderContext' => function ($text, LambdaHelper $helper = null) { - return $helper->render('{{>' . $helper->render($text) . '}}'); + return (string)$uri; }, + 'renderContext' => fn($text, ?LambdaHelper $helper = null) => $helper->render('{{>' . $helper->render($text) . '}}'), ]; return array_merge($helpers, $urls); @@ -540,14 +514,11 @@ protected function registerMustacheHelpersServices(Container $container): void /** * @param Container $container The DI container. - * @return void */ protected function registerTwigHelpersServices(Container $container): void { if (!isset($container['view/twig/helpers'])) { - $container['view/twig/helpers'] = function () { - return []; - }; + $container['view/twig/helpers'] = (fn(): array => []); } /** @@ -555,22 +526,18 @@ protected function registerTwigHelpersServices(Container $container): void * * @return TwigUrlHelpers */ - $container['view/twig/helpers/url'] = function (Container $container): TwigHelpersInterface { - return new TwigUrlHelpers([ - 'baseUrl' => $container['base-url'], - ]); - }; + $container['view/twig/helpers/url'] = (fn(Container $container): TwigHelpersInterface => new TwigUrlHelpers([ + 'baseUrl' => $container['base-url'], + ])); /** * Debug helpers for Twig. * * @return TwigDebugHelpers */ - $container['view/twig/helpers/debug'] = function (Container $container): TwigHelpersInterface { - return new TwigDebugHelpers([ - 'debug' => $container['debug'], - ]); - }; + $container['view/twig/helpers/debug'] = (fn(Container $container): TwigHelpersInterface => new TwigDebugHelpers([ + 'debug' => $container['debug'], + ])); /** * Extend global helpers for the Twig Engine. @@ -579,12 +546,10 @@ protected function registerTwigHelpersServices(Container $container): void * @param Container $container A container instance. * @return array */ - $container->extend('view/twig/helpers', function (array $helpers, Container $container): array { - return array_merge( - $helpers, - $container['view/twig/helpers/url']->toArray(), - $container['view/twig/helpers/debug']->toArray(), - ); - }); + $container->extend('view/twig/helpers', fn(array $helpers, Container $container): array => array_merge( + $helpers, + $container['view/twig/helpers/url']->toArray(), + $container['view/twig/helpers/debug']->toArray(), + )); } } diff --git a/packages/app/src/Charcoal/App/ServiceProvider/DatabaseServiceProvider.php b/packages/app/src/Charcoal/App/ServiceProvider/DatabaseServiceProvider.php index fb1f6c3ab..ab723b96b 100644 --- a/packages/app/src/Charcoal/App/ServiceProvider/DatabaseServiceProvider.php +++ b/packages/app/src/Charcoal/App/ServiceProvider/DatabaseServiceProvider.php @@ -32,15 +32,14 @@ class DatabaseServiceProvider implements ServiceProviderInterface * It should not get services. * * @param Container $container A service container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { /** * @param Container $container A service container. * @return Container A map of database configsets. */ - $container['databases/config'] = function (Container $container) { + $container['databases/config'] = function (Container $container): \Pimple\Container { $databases = ($container['config']['databases'] ?? []); $configs = new Container(); @@ -48,9 +47,7 @@ public function register(Container $container) /** * @return DatabaseConfig */ - $configs[$dbIdent] = function () use ($dbOptions) { - return new DatabaseConfig($dbOptions); - }; + $configs[$dbIdent] = (fn(): \Charcoal\App\Config\DatabaseConfig => new DatabaseConfig($dbOptions)); } return $configs; @@ -60,7 +57,7 @@ public function register(Container $container) * @param Container $container A service container. * @return Container A map of database handlers. */ - $container['databases'] = function (Container $container) { + $container['databases'] = function (Container $container): \Pimple\Container { $databases = ($container['config']['databases'] ?? []); $dbs = new Container(); @@ -68,7 +65,7 @@ public function register(Container $container) /** * @return PDO */ - $dbs[$dbIdent] = function () use ($dbIdent, $container) { + $dbs[$dbIdent] = function () use ($dbIdent, $container): \PDO { $dbConfig = $container['databases/config'][$dbIdent]; $type = $dbConfig['type']; @@ -80,23 +77,19 @@ public function register(Container $container) // Set UTf-8 compatibility by default. Disable it if it is set as such in config $extraOptions = null; - if (!isset($dbConfig['disable_utf8']) || !$dbConfig['disable_utf8']) { + if ($type !== 'sqlite' && (!isset($dbConfig['disable_utf8']) || !$dbConfig['disable_utf8'])) { $extraOptions = [ - PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4', + \Pdo\Mysql::ATTR_INIT_COMMAND => 'SET NAMES utf8mb4', ]; } - if ($type === 'sqlite') { - $dsn = $type . ':' . $database; - } else { - $dsn = $type . ':host=' . $host . ';dbname=' . $database; - } + $dsn = $type === 'sqlite' ? $type . ':' . $database : $type . ':host=' . $host . ';dbname=' . $database; $db = new PDO($dsn, $username, $password, $extraOptions); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); if ($type === 'mysql') { - $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); + $db->setAttribute(\Pdo\Mysql::ATTR_USE_BUFFERED_QUERY, true); } return $db; diff --git a/packages/app/src/Charcoal/App/ServiceProvider/FilesystemServiceProvider.php b/packages/app/src/Charcoal/App/ServiceProvider/FilesystemServiceProvider.php index 48b93ae39..2b050c6ba 100644 --- a/packages/app/src/Charcoal/App/ServiceProvider/FilesystemServiceProvider.php +++ b/packages/app/src/Charcoal/App/ServiceProvider/FilesystemServiceProvider.php @@ -33,15 +33,14 @@ class FilesystemServiceProvider implements ServiceProviderInterface { /** * @param Container $container A service container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { /** * @param Container $container A service container. * @return FilesystemConfig */ - $container['filesystem/config'] = function (Container $container) { + $container['filesystem/config'] = function (Container $container): \Charcoal\App\Config\FilesystemConfig { $fsConfig = ($container['config']['filesystem'] ?? null); return new FilesystemConfig($fsConfig); }; @@ -50,15 +49,13 @@ public function register(Container $container) * @param Container $container A service container. * @return MountManager */ - $container['filesystem/manager'] = function () { - return new MountManager(); - }; + $container['filesystem/manager'] = (fn(): \League\Flysystem\MountManager => new MountManager()); /** * @param Container $container A service container. * @return array */ - $container['filesystems'] = function (Container $container) { + $container['filesystems'] = function (Container $container): \Pimple\Container { $filesystemConfig = $container['filesystem/config']; $filesystems = new Container(); @@ -77,9 +74,8 @@ public function register(Container $container) * @param Container $container A service container. * @throws Exception If the filesystem type is not defined in config. * @throws UnexpectedValueException If the filesystem type is invalid / unsupported. - * @return Filesystem */ - private function createConnection(array $config, Container $container) + private function createConnection(array $config, Container $container): \League\Flysystem\Filesystem { if (!isset($config['type'])) { throw new Exception( @@ -89,36 +85,17 @@ private function createConnection(array $config, Container $container) $type = $config['type']; - switch ($type) { - case 'local': - $adapter = $this->createLocalAdapter($config, $container); - break; - - case 's3': - $adapter = $this->createS3Adapter($config); - break; - - case 'ftp': - $adapter = $this->createFtpAdapter($config); - break; - - case 'sftp': - $adapter = $this->createSftpAdapter($config); - break; - - case 'memory': - $adapter = $this->createMemoryAdapter(); - break; - - case 'noop': - $adapter = $this->createNullAdapter(); - break; - - default: - throw new UnexpectedValueException( - sprintf('Invalid filesystem type "%s"', $type) - ); - } + $adapter = match ($type) { + 'local' => $this->createLocalAdapter($config, $container), + 's3' => $this->createS3Adapter($config), + 'ftp' => $this->createFtpAdapter($config), + 'sftp' => $this->createSftpAdapter($config), + 'memory' => $this->createMemoryAdapter(), + 'noop' => $this->createNullAdapter(), + default => throw new UnexpectedValueException( + sprintf('Invalid filesystem type "%s"', $type) + ), + }; return new Filesystem($adapter); } @@ -127,9 +104,8 @@ private function createConnection(array $config, Container $container) * @param array $config The driver (adapter) configuration. * @param Container $container A service container. * @throws InvalidArgumentException If the path is not defined. - * @return LocalAdapter */ - private function createLocalAdapter(array $config, Container $container) + private function createLocalAdapter(array $config, Container $container): \League\Flysystem\Adapter\Local { if (empty($config['path'])) { throw new InvalidArgumentException( @@ -138,10 +114,8 @@ private function createLocalAdapter(array $config, Container $container) } $path = $config['path']; - if (is_string($path)) { - if (isset($container['config']) && ($container['config'] instanceof AppConfig)) { - $path = $container['config']->resolveValue($path); - } + if (is_string($path) && (isset($container['config']) && $container['config'] instanceof AppConfig)) { + $path = $container['config']->resolveValue($path); } $defaults = [ @@ -157,9 +131,8 @@ private function createLocalAdapter(array $config, Container $container) /** * @param array $config The driver (adapter) configuration. * @throws InvalidArgumentException If the key, secret or bucket is not defined in config. - * @return AwsS3Adapter */ - private function createS3Adapter(array $config) + private function createS3Adapter(array $config): \League\Flysystem\AwsS3v3\AwsS3Adapter { if (!isset($config['key']) || !$config['key']) { throw new InvalidArgumentException( @@ -195,13 +168,9 @@ private function createS3Adapter(array $config) 'version' => $config['version'], ]); - if (isset($config['public']) && !$config['public']) { - $permissions = null; - } else { - $permissions = [ - 'ACL' => 'public-read', - ]; - } + $permissions = isset($config['public']) && !$config['public'] ? null : [ + 'ACL' => 'public-read', + ]; return new AwsS3Adapter($client, $config['bucket'], $config['prefix'], $permissions); } @@ -209,9 +178,8 @@ private function createS3Adapter(array $config) /** * @param array $config The driver (adapter) configuration. * @throws InvalidArgumentException If the host, username or password is not defined in config. - * @return FtpAdapter */ - private function createFtpAdapter(array $config) + private function createFtpAdapter(array $config): \League\Flysystem\Adapter\Ftp { if (!$config['host']) { throw new InvalidArgumentException( @@ -246,9 +214,8 @@ private function createFtpAdapter(array $config) /** * @param array $config The driver (adapter) configuration. * @throws InvalidArgumentException If the host, username or password is not defined in config. - * @return SftpAdapter */ - private function createSftpAdapter(array $config) + private function createSftpAdapter(array $config): \League\Flysystem\Sftp\SftpAdapter { if (!$config['host']) { throw new InvalidArgumentException( @@ -279,18 +246,12 @@ private function createSftpAdapter(array $config) return new SftpAdapter($config); } - /** - * @return MemoryAdapter - */ - private function createMemoryAdapter() + private function createMemoryAdapter(): \League\Flysystem\Memory\MemoryAdapter { return new MemoryAdapter(); } - /** - * @return NullAdapter - */ - private function createNullAdapter() + private function createNullAdapter(): \League\Flysystem\Adapter\NullAdapter { return new NullAdapter(); } diff --git a/packages/app/src/Charcoal/App/ServiceProvider/LoggerServiceProvider.php b/packages/app/src/Charcoal/App/ServiceProvider/LoggerServiceProvider.php index ee36758b3..3f4113899 100644 --- a/packages/app/src/Charcoal/App/ServiceProvider/LoggerServiceProvider.php +++ b/packages/app/src/Charcoal/App/ServiceProvider/LoggerServiceProvider.php @@ -44,15 +44,14 @@ class LoggerServiceProvider implements ServiceProviderInterface * It should not get services. * * @param Container $container A service container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { /** * @param Container $container A service container. * @return LoggerConfig */ - $container['logger/config'] = function (Container $container) { + $container['logger/config'] = function (Container $container): \Charcoal\App\Config\LoggerConfig { $loggerConfig = ($container['config']['logger'] ?? null); return new LoggerConfig($loggerConfig); }; @@ -62,7 +61,7 @@ public function register(Container $container) * @throws InvalidArgumentException If the path is not defined or invalid. * @return StreamHandler|null */ - $container['logger/handler/stream'] = function (Container $container) { + $container['logger/handler/stream'] = function (Container $container): ?\Monolog\Handler\StreamHandler { $loggerConfig = $container['logger/config']; $handlerConfig = $loggerConfig['handlers.stream']; @@ -77,10 +76,8 @@ public function register(Container $container) } $stream = $handlerConfig['stream']; - if (is_string($stream)) { - if (isset($container['config']) && ($container['config'] instanceof AppConfig)) { - $stream = $container['config']->resolveValue($stream); - } + if (is_string($stream) && (isset($container['config']) && $container['config'] instanceof AppConfig)) { + $stream = $container['config']->resolveValue($stream); } $level = $handlerConfig['level'] ?: $loggerConfig['level']; @@ -91,7 +88,7 @@ public function register(Container $container) * @param Container $container A service container. * @return BrowserConsoleHandler|null */ - $container['logger/handler/browser-console'] = function (Container $container) { + $container['logger/handler/browser-console'] = function (Container $container): ?\Monolog\Handler\BrowserConsoleHandler { $loggerConfig = $container['logger/config']; $handlerConfig = $loggerConfig['handlers.console']; @@ -109,7 +106,7 @@ public function register(Container $container) * @param Container $container A service container. * @return LoggerInterface */ - $container['logger'] = function (Container $container) { + $container['logger'] = function (Container $container): \Psr\Log\NullLogger|\Monolog\Logger { $loggerConfig = $container['logger/config']; if ($loggerConfig['active'] !== true) { diff --git a/packages/app/src/Charcoal/App/ServiceProvider/ScriptServiceProvider.php b/packages/app/src/Charcoal/App/ServiceProvider/ScriptServiceProvider.php index a7c0ec6f2..73dda4365 100644 --- a/packages/app/src/Charcoal/App/ServiceProvider/ScriptServiceProvider.php +++ b/packages/app/src/Charcoal/App/ServiceProvider/ScriptServiceProvider.php @@ -1,5 +1,7 @@ ScriptInterface::class, - 'resolver_options' => [ - 'suffix' => 'Script', - ], - 'arguments' => [ - [ - 'container' => $container, - 'logger' => $container['logger'], - 'climate' => $container['script/climate'], - 'climate_reader' => $container['script/climate/reader'], - ], + $container['script/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => ScriptInterface::class, + 'resolver_options' => [ + 'suffix' => 'Script', + ], + 'arguments' => [ + [ + 'container' => $container, + 'logger' => $container['logger'], + 'climate' => $container['script/climate'], + 'climate_reader' => $container['script/climate/reader'], ], - ]); - }; + ], + ])); } /** * @param Container $container A service container. - * @return void */ - private function registerClimate(Container $container) + private function registerClimate(Container $container): void { /** * @param Container $container A service container. * @return \League\CLImate\Util\Reader\ReaderInterface|null */ - $container['script/climate/reader'] = function () { - return null; - }; + $container['script/climate/reader'] = (fn(): null => null); /** * @param Container $container A service container. * @return CLImate */ - $container['script/climate'] = function () { - $climate = new CLImate(); - return $climate; - }; + $container['script/climate'] = (fn(): \League\CLImate\CLImate => new CLImate()); } } diff --git a/packages/app/src/Charcoal/App/Template/AbstractTemplate.php b/packages/app/src/Charcoal/App/Template/AbstractTemplate.php index 1d156e67e..09a4bb19b 100644 --- a/packages/app/src/Charcoal/App/Template/AbstractTemplate.php +++ b/packages/app/src/Charcoal/App/Template/AbstractTemplate.php @@ -49,14 +49,14 @@ public function __construct($data = null) */ public function templateName() { - $key = substr(strrchr('\\' . get_class($this), '\\'), 1); + $key = substr(strrchr('\\' . static::class, '\\'), 1); if (!isset(static::$templateNameCache[$key])) { $value = $key; if (!ctype_lower($value)) { $value = preg_replace('/\s+/u', '', $value); - $value = mb_strtolower(preg_replace('/(.)(?=[A-Z])/u', '$1-', $value), 'UTF-8'); + $value = mb_strtolower((string)preg_replace('/(.)(?=[A-Z])/u', '$1-', (string)$value), 'UTF-8'); } $value = str_replace( diff --git a/packages/app/src/Charcoal/App/Template/AbstractWidget.php b/packages/app/src/Charcoal/App/Template/AbstractWidget.php index 2721ee557..a63fa545e 100644 --- a/packages/app/src/Charcoal/App/Template/AbstractWidget.php +++ b/packages/app/src/Charcoal/App/Template/AbstractWidget.php @@ -26,10 +26,7 @@ abstract class AbstractWidget extends AbstractEntity implements use LoggerAwareTrait; use ViewableTrait; - /** - * @var boolean $active - */ - private $active = true; + private bool $active = true; /** * @param array|\ArrayAccess $data Optional dependencies. @@ -49,7 +46,7 @@ public function __construct($data = null) */ public function setActive($active) { - $this->active = !!$active; + $this->active = (bool)$active; return $this; } diff --git a/packages/app/src/Charcoal/App/Template/GenericTemplate.php b/packages/app/src/Charcoal/App/Template/GenericTemplate.php index 3a9d77ba5..cf5c7d1bc 100644 --- a/packages/app/src/Charcoal/App/Template/GenericTemplate.php +++ b/packages/app/src/Charcoal/App/Template/GenericTemplate.php @@ -1,5 +1,7 @@ factory = $factory; - $this->container = $container; } /** diff --git a/packages/app/src/Charcoal/App/Template/WidgetInterface.php b/packages/app/src/Charcoal/App/Template/WidgetInterface.php index 23afe7e5b..3ec065347 100644 --- a/packages/app/src/Charcoal/App/Template/WidgetInterface.php +++ b/packages/app/src/Charcoal/App/Template/WidgetInterface.php @@ -1,5 +1,7 @@ container(); - $this->obj = $this->getMockForAbstractClass(AbstractAction::class, [[ + $this->obj = new class ([ 'logger' => $container['logger'], 'container' => $container - ]]); + ]) extends AbstractAction { + public function results() + { + return ''; // Works for both JSON and XML + } + + public function run(RequestInterface $request, ResponseInterface $response) + { + return $response; + } + }; } - public function testSetData() + public function testSetData(): void { $ret = $this->obj->setData([ 'mode' => 'redirect', @@ -63,7 +70,7 @@ public function testSetData() $this->assertEquals('fail', $this->obj->failureUrl()); } - public function testSetMode() + public function testSetMode(): void { $this->assertEquals('json', $this->obj->mode()); $ret = $this->obj->setMode('redirect'); @@ -74,7 +81,7 @@ public function testSetMode() $this->obj->setMode(false); } - public function testSetSuccess() + public function testSetSuccess(): void { $ret = $this->obj->setSuccess(false); $this->assertSame($ret, $this->obj); @@ -86,7 +93,7 @@ public function testSetSuccess() $this->assertTrue($this->obj->success()); } - public function testSuccessUrl() + public function testSuccessUrl(): void { $this->assertEquals('', $this->obj->successUrl()); $ret = $this->obj->setSuccessUrl('foo'); @@ -99,7 +106,7 @@ public function testSuccessUrl() $this->obj->setSuccessUrl([]); } - public function testSetFailureUrl() + public function testSetFailureUrl(): void { $this->assertEquals('', $this->obj->failureUrl()); $ret = $this->obj->setFailureUrl('foo'); @@ -112,7 +119,7 @@ public function testSetFailureUrl() $this->obj->setFailureUrl([]); } - public function testRedirectUrlSuccess() + public function testRedirectUrlSuccess(): void { $this->obj->setData([ 'failure_url' => 'fail', @@ -130,30 +137,22 @@ public function testRedirectUrlSuccess() * * For this, the `run` method must be added as public in the mock object. */ - public function testInvokable() + public function testInvokable(): void { - $request = $this->createMock(RequestInterface::class); + $request = $this->createStub(RequestInterface::class); $response = new Response(); - $this->obj->expects($this->any()) - ->method('run') - ->will($this->returnValue($response)); - $obj = $this->obj; $res = $obj($request, $response); $this->assertInstanceOf(Response::class, $res); } - public function testDefaultModeisJson() + public function testDefaultModeisJson(): void { - $request = $this->createMock(RequestInterface::class); + $request = $this->createStub(RequestInterface::class); $response = new Response(); - $this->obj->expects($this->any()) - ->method('run') - ->will($this->returnValue($response)); - $obj = $this->obj; $res = $obj($request, $response); @@ -161,15 +160,11 @@ public function testDefaultModeisJson() $this->assertEquals('application/json', $headers['Content-Type'][0]); } - public function testInvokeModeJson() + public function testInvokeModeJson(): void { - $request = $this->createMock(RequestInterface::class); + $request = $this->createStub(RequestInterface::class); $response = new Response(); - $this->obj->expects($this->any()) - ->method('run') - ->will($this->returnValue($response)); - $this->obj->setMode('json'); $obj = $this->obj; $res = $obj($request, $response); @@ -178,15 +173,11 @@ public function testInvokeModeJson() $this->assertEquals('application/json', $headers['Content-Type'][0]); } - public function testInvokeModeXml() + public function testInvokeModeXml(): void { - $request = $this->createMock(RequestInterface::class); + $request = $this->createStub(RequestInterface::class); $response = new Response(); - $this->obj->expects($this->any()) - ->method('run') - ->will($this->returnValue($response)); - $this->obj->setMode('xml'); $obj = $this->obj; $res = $obj($request, $response); @@ -195,15 +186,11 @@ public function testInvokeModeXml() $this->assertEquals('text/xml', $headers['Content-Type'][0]); } - public function testInvokeModeRedirect() + public function testInvokeModeRedirect(): void { - $request = $this->createMock(RequestInterface::class); + $request = $this->createStub(RequestInterface::class); $response = new Response(); - $this->obj->expects($this->any()) - ->method('run') - ->will($this->returnValue($response)); - $this->obj->setMode('redirect'); $this->obj->setFailureUrl('example.com'); $obj = $this->obj; @@ -215,20 +202,18 @@ public function testInvokeModeRedirect() $this->assertEquals('example.com', $headers['Location'][0]); } - public function testInitIsTrue() + public function testInitIsTrue(): void { - $request = $this->createMock(RequestInterface::class); + $request = $this->createStub(RequestInterface::class); $this->assertTrue($this->obj->init($request)); } /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerLogger($container); diff --git a/packages/app/tests/Charcoal/App/AppConfigTest.php b/packages/app/tests/Charcoal/App/AppConfigTest.php index b699bd4d9..7047f7255 100644 --- a/packages/app/tests/Charcoal/App/AppConfigTest.php +++ b/packages/app/tests/Charcoal/App/AppConfigTest.php @@ -1,5 +1,7 @@ assertInstanceOf(AppConfig::class, $obj); diff --git a/packages/app/tests/Charcoal/App/AppTest.php b/packages/app/tests/Charcoal/App/AppTest.php index 65984146d..6d150b1db 100644 --- a/packages/app/tests/Charcoal/App/AppTest.php +++ b/packages/app/tests/Charcoal/App/AppTest.php @@ -1,5 +1,7 @@ obj = new App($container); } - public function testAppIsConstructed() + public function testAppIsConstructed(): void { $app = new App(); $this->assertInstanceOf(App::class, $app); } - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(App::class, $this->obj); } - public function testRun() + public function testRun(): void { $res = $this->obj->run(true); $this->assertInstanceOf(ResponseInterface::class, $res); diff --git a/packages/app/tests/Charcoal/App/Config/DatabaseConfigTest.php b/packages/app/tests/Charcoal/App/Config/DatabaseConfigTest.php index 980014fe5..9b9475041 100644 --- a/packages/app/tests/Charcoal/App/Config/DatabaseConfigTest.php +++ b/packages/app/tests/Charcoal/App/Config/DatabaseConfigTest.php @@ -17,7 +17,7 @@ public function setUp(): void $this->obj = new DatabaseConfig(); } - public function testDefaults() + public function testDefaults(): void { $this->assertEquals('mysql', $this->obj->type()); $this->assertEquals('localhost', $this->obj->hostname()); @@ -26,7 +26,7 @@ public function testDefaults() $this->assertFalse($this->obj->disableUtf8()); } - public function testSetType() + public function testSetType(): void { $ret = $this->obj->setType('sqlite'); $this->assertSame($ret, $this->obj); @@ -36,7 +36,7 @@ public function testSetType() $this->obj->setType([]); } - public function testSetHostname() + public function testSetHostname(): void { $ret = $this->obj->setHostname('foo'); $this->assertSame($ret, $this->obj); @@ -46,7 +46,7 @@ public function testSetHostname() $this->obj->setHostname([]); } - public function testSetUsername() + public function testSetUsername(): void { $ret = $this->obj->setUsername('foobar'); $this->assertSame($ret, $this->obj); @@ -56,7 +56,7 @@ public function testSetUsername() $this->obj->setUsername([]); } - public function testSetPassword() + public function testSetPassword(): void { $ret = $this->obj->setPassword('baz'); $this->assertSame($ret, $this->obj); @@ -66,7 +66,7 @@ public function testSetPassword() $this->obj->setPassword([]); } - public function testSetDatabase() + public function testSetDatabase(): void { $ret = $this->obj->setDatabase('barbaz'); $this->assertSame($ret, $this->obj); @@ -76,7 +76,7 @@ public function testSetDatabase() $this->obj->setDatabase([]); } - public function testSetDIsableUtf8() + public function testSetDIsableUtf8(): void { $ret = $this->obj->setDIsableUtf8(true); $this->assertSame($ret, $this->obj); diff --git a/packages/app/tests/Charcoal/App/Config/FilesystemConfigTest.php b/packages/app/tests/Charcoal/App/Config/FilesystemConfigTest.php index 1c8357bab..5f0a4cc02 100644 --- a/packages/app/tests/Charcoal/App/Config/FilesystemConfigTest.php +++ b/packages/app/tests/Charcoal/App/Config/FilesystemConfigTest.php @@ -17,7 +17,7 @@ public function setUp(): void $this->obj = new FilesystemConfig(); } - public function testDefaultConnections() + public function testDefaultConnections(): void { $this->assertArrayHasKey('private', $this->obj->defaultConnections()); $this->assertArrayHasKey('public', $this->obj->defaultConnections()); @@ -26,7 +26,7 @@ public function testDefaultConnections() $this->assertArrayHasKey('public', $this->obj->connections()); } - public function testConnectionsAlwaysHaveDefaultConnections() + public function testConnectionsAlwaysHaveDefaultConnections(): void { $this->obj->setData([ 'connections' => [ diff --git a/packages/app/tests/Charcoal/App/Config/LoggerConfigTest.php b/packages/app/tests/Charcoal/App/Config/LoggerConfigTest.php index 3a71a17e6..8d71ac2b3 100644 --- a/packages/app/tests/Charcoal/App/Config/LoggerConfigTest.php +++ b/packages/app/tests/Charcoal/App/Config/LoggerConfigTest.php @@ -25,7 +25,7 @@ public function setUp(): void $this->obj = new LoggerConfig(); } - public function testDefaults() + public function testDefaults(): void { $this->assertEquals('charcoal', LoggerConfig::DEFAULT_CHANNEL); @@ -46,14 +46,14 @@ public function testDefaults() $this->assertEquals(LoggerConfig::DEFAULT_CHANNEL, $this->obj->channel()); } - public function testSetActive() + public function testSetActive(): void { $ret = $this->obj->setActive(false); $this->assertSame($ret, $this->obj); $this->assertFalse($this->obj->active()); } - public function testSetHandlers() + public function testSetHandlers(): void { $ret = $this->obj->setHandlers([ 'errlog' => [ 'type' => 'error-log' ], [ 'type' => 'mail' ] ]); $this->assertSame($ret, $this->obj); @@ -68,7 +68,7 @@ public function testSetHandlers() $this->obj->setHandlers([ [ 'foo' => 'baz' ] ]); } - public function testSetProcessors() + public function testSetProcessors(): void { $ret = $this->obj->setProcessors([ 'web' => [ 'type' => 'web' ], [ 'type' => 'process-id' ] ]); $this->assertSame($ret, $this->obj); @@ -83,7 +83,7 @@ public function testSetProcessors() $this->obj->setProcessors([ [ 'foo' => 'baz' ] ]); } - public function testSetChannel() + public function testSetChannel(): void { $ret = $this->obj->setChannel('foo'); $this->assertSame($ret, $this->obj); diff --git a/packages/app/tests/Charcoal/App/ContainerProvider.php b/packages/app/tests/Charcoal/App/ContainerProvider.php index f4286074c..cb24697d5 100644 --- a/packages/app/tests/Charcoal/App/ContainerProvider.php +++ b/packages/app/tests/Charcoal/App/ContainerProvider.php @@ -59,9 +59,8 @@ class ContainerProvider * Register the unit tests required services. * * @param Container $container A DI container. - * @return void */ - public function registerBaseServices(Container $container) + public function registerBaseServices(Container $container): void { $this->registerConfig($container); $this->registerBaseUrl($container); @@ -74,57 +73,47 @@ public function registerBaseServices(Container $container) * Setup the application's base URI. * * @param Container $container A DI container. - * @return void */ - public function registerBaseUrl(Container $container) + public function registerBaseUrl(Container $container): void { - $container['base-url'] = function (Container $container) { - return Uri::createFromString('https://example.com:8080/foo/bar?abc=123'); - }; + $container['base-url'] = (fn(Container $container) => Uri::createFromString('https://example.com:8080/foo/bar?abc=123')); } /** * Setup the application configset. * * @param Container $container A DI container. - * @return void */ - public function registerConfig(Container $container) + public function registerConfig(Container $container): void { - $container['config'] = function (Container $container) { - return new AppConfig([ - 'base_path' => realpath(__DIR__ . '/../../..'), - ]); - }; + $container['config'] = (fn(Container $container): \Charcoal\App\AppConfig => new AppConfig([ + 'base_path' => realpath(__DIR__ . '/../../..'), + ])); } - public function registerWidgetFactory(Container $container) + public function registerWidgetFactory(Container $container): void { $this->registerLogger($container); - $container['widget/factory'] = function (Container $container) { - return new Factory([ - 'resolver_options' => [ - 'suffix' => 'Widget' - ], - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'] - ]] - ]); - }; + $container['widget/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'resolver_options' => [ + 'suffix' => 'Widget' + ], + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'] + ]] + ])); } - public function registerWidgetBuilder(Container $container) + public function registerWidgetBuilder(Container $container): void { $this->registerWidgetFactory($container); - $container['widget/builder'] = function (Container $container) { - return new WidgetBuilder($container['widget/factory'], $container); - }; + $container['widget/builder'] = (fn(Container $container): \Charcoal\App\Template\WidgetBuilder => new WidgetBuilder($container['widget/factory'], $container)); } - public function registerClimate(Container $container) + public function registerClimate(Container $container): void { $container['climate/system'] = function (Container $container) { $system = Mockery::mock(Linux::class); @@ -151,11 +140,9 @@ public function registerClimate(Container $container) return $reader; }; - $container['climate/util'] = function (Container $container) { - return new UtilFactory($container['climate/system']); - }; + $container['climate/util'] = (fn(Container $container): \League\CLImate\Util\UtilFactory => new UtilFactory($container['climate/system'])); - $container['climate'] = function (Container $container) { + $container['climate'] = function (Container $container): \League\CLImate\CLImate { $climate = new CLImate(); $climate->setOutput($container['climate/output']); @@ -170,162 +157,136 @@ public function registerClimate(Container $container) * Setup the framework's view renderer. * * @param Container $container A DI container. - * @return void */ - public function registerView(Container $container) + public function registerView(Container $container): void { - $container['view/loader'] = function (Container $container) { - return new MustacheLoader([ - 'logger' => $container['logger'], - 'base_path' => $container['config']['base_path'], - 'paths' => [ - 'views' - ] - ]); - }; - - $container['view/engine'] = function (Container $container) { - return new MustacheEngine([ - 'logger' => $container['logger'], - 'cache' => MustacheEngine::DEFAULT_CACHE_PATH, - 'loader' => $container['view/loader'] - ]); - }; - - $container['view'] = function (Container $container) { - return new GenericView([ - 'logger' => $container['logger'], - 'engine' => $container['view/engine'] - ]); - }; + $container['view/loader'] = (fn(Container $container): \Charcoal\View\Mustache\MustacheLoader => new MustacheLoader([ + 'logger' => $container['logger'], + 'base_path' => $container['config']['base_path'], + 'paths' => [ + 'views' + ] + ])); + + $container['view/engine'] = (fn(Container $container): \Charcoal\View\Mustache\MustacheEngine => new MustacheEngine([ + 'logger' => $container['logger'], + 'cache' => MustacheEngine::DEFAULT_CACHE_PATH, + 'loader' => $container['view/loader'] + ])); + + $container['view'] = (fn(Container $container): \Charcoal\View\GenericView => new GenericView([ + 'logger' => $container['logger'], + 'engine' => $container['view/engine'] + ])); } /** * Setup the application's translator service. * * @param Container $container A DI container. - * @return void */ - public function registerTranslator(Container $container) + public function registerTranslator(Container $container): void { - $container['locales/manager'] = function (Container $container) { - return new LocalesManager([ - 'locales' => [ - 'en' => [ 'locale' => 'en-US' ] - ] - ]); - }; - - $container['translator'] = function (Container $container) { - return new Translator([ - 'manager' => $container['locales/manager'] - ]); - }; + $container['locales/manager'] = (fn(Container $container): \Charcoal\Translator\LocalesManager => new LocalesManager([ + 'locales' => [ + 'en' => [ 'locale' => 'en-US' ] + ] + ])); + + $container['translator'] = (fn(Container $container): \Charcoal\Translator\Translator => new Translator([ + 'manager' => $container['locales/manager'] + ])); } /** * Setup the application's logging interface. * * @param Container $container A DI container. - * @return void */ - public function registerLogger(Container $container) + public function registerLogger(Container $container): void { - $container['logger'] = function (Container $container) { - return new NullLogger(); - }; + $container['logger'] = (fn(Container $container): \Psr\Log\NullLogger => new NullLogger()); } /** * Setup the application's caching interface. * * @param Container $container A DI container. - * @return void */ - public function registerCache(Container $container) + public function registerCache(Container $container): void { - $container['cache/config'] = function (Container $container) { - return new CacheConfig(); - }; + $container['cache/config'] = (fn(Container $container): \Charcoal\Cache\CacheConfig => new CacheConfig()); - $container['cache'] = function ($container) { - return new Pool(); - }; + $container['cache'] = (fn($container): \Stash\Pool => new Pool()); } - public function registerDatabase(Container $container) + public function registerDatabase(Container $container): void { - $container['database'] = function (Container $container) { + $container['database'] = function (Container $container): \PDO { $pdo = new PDO('sqlite::memory:'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; }; } - public function registerMetadataLoader(Container $container) + public function registerMetadataLoader(Container $container): void { $this->registerLogger($container); $this->registerCache($container); - $container['metadata/loader'] = function (Container $container) { - return new MetadataLoader([ - 'logger' => $container['logger'], - 'cache' => $container['cache'], - 'base_path' => $container['config']['base_path'], - 'paths' => [ - 'metadata', - // Standalone - 'vendor/charcoal/object/metadata', - 'vendor/charcoal/user/metadata', - // Monorepo - '/../object/metadata', - '/../user/metadata' - ] - ]); - }; + $container['metadata/loader'] = (fn(Container $container): \Charcoal\Model\Service\MetadataLoader => new MetadataLoader([ + 'logger' => $container['logger'], + 'cache' => $container['cache'], + 'base_path' => $container['config']['base_path'], + 'paths' => [ + 'metadata', + // Standalone + 'vendor/charcoal/object/metadata', + 'vendor/charcoal/user/metadata', + // Monorepo + '/../object/metadata', + '/../user/metadata' + ] + ])); } - public function registerSourceFactory(Container $container) + public function registerSourceFactory(Container $container): void { $this->registerLogger($container); $this->registerDatabase($container); - $container['source/factory'] = function (Container $container) { - return new Factory([ - 'map' => [ - 'database' => DatabaseSource::class - ], - 'arguments' => [[ - 'logger' => $container['logger'], - 'pdo' => $container['database'] - ]] - ]); - }; + $container['source/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'map' => [ + 'database' => DatabaseSource::class + ], + 'arguments' => [[ + 'logger' => $container['logger'], + 'pdo' => $container['database'] + ]] + ])); } - public function registerPropertyFactory(Container $container) + public function registerPropertyFactory(Container $container): void { $this->registerTranslator($container); $this->registerDatabase($container); $this->registerLogger($container); - $container['property/factory'] = function (Container $container) { - return new Factory([ - 'resolver_options' => [ - 'prefix' => '\\Charcoal\\Property\\', - 'suffix' => 'Property' - ], - 'arguments' => [[ - 'container' => $container, - 'database' => $container['database'], - 'translator' => $container['translator'], - 'logger' => $container['logger'] - ]] - ]); - }; + $container['property/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'resolver_options' => [ + 'prefix' => '\\Charcoal\\Property\\', + 'suffix' => 'Property' + ], + 'arguments' => [[ + 'container' => $container, + 'database' => $container['database'], + 'translator' => $container['translator'], + 'logger' => $container['logger'] + ]] + ])); } - public function registerModelFactory(Container $container) + public function registerModelFactory(Container $container): void { $this->registerLogger($container); $this->registerTranslator($container); @@ -333,51 +294,45 @@ public function registerModelFactory(Container $container) $this->registerPropertyFactory($container); $this->registerSourceFactory($container); - $container['model/factory'] = function (Container $container) { - return new Factory([ - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'], - 'metadata_loader' => $container['metadata/loader'], - 'property_factory' => $container['property/factory'], - 'source_factory' => $container['source/factory'] - ]] - ]); - }; + $container['model/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'], + 'metadata_loader' => $container['metadata/loader'], + 'property_factory' => $container['property/factory'], + 'source_factory' => $container['source/factory'] + ]] + ])); } - public function registerCollectionLoader(Container $container) + public function registerCollectionLoader(Container $container): void { $this->registerLogger($container); $this->registerModelFactory($container); - $container['model/collection/loader'] = function (Container $container) { - return new \Charcoal\Loader\CollectionLoader([ - 'logger' => $container['logger'], - 'factory' => $container['model/factory'] - ]); - }; + $container['model/collection/loader'] = (fn(Container $container): \Charcoal\Loader\CollectionLoader => new \Charcoal\Loader\CollectionLoader([ + 'logger' => $container['logger'], + 'factory' => $container['model/factory'] + ])); } - public function registerModuleFactory(Container $container) + public function registerModuleFactory(Container $container): void { $this->registerLogger($container); $this->registerDatabase($container); - $container['module/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => ModuleInterface::class, - 'resolver_options' => [ - 'suffix' => 'Module' - ], - 'arguments' => [[ - 'logger' => $container['logger'] - ]] - ]); - }; + $container['module/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => ModuleInterface::class, + 'resolver_options' => [ + 'suffix' => 'Module' + ], + 'arguments' => [[ + 'logger' => $container['logger'] + ]] + ])); } - public function registerAppDependencies(Container $container) + public function registerAppDependencies(Container $container): void { $this->registerConfig($container); $this->registerBaseUrl($container); @@ -387,21 +342,21 @@ public function registerAppDependencies(Container $container) $this->registerModuleFactory($container); } - public function registerActionDependencies(Container $container) + public function registerActionDependencies(Container $container): void { $this->registerLogger($container); $this->registerTranslator($container); $this->registerBaseUrl($container); } - public function registerTemplateDependencies(Container $container) + public function registerTemplateDependencies(Container $container): void { $this->registerLogger($container); $this->registerTranslator($container); $this->registerBaseUrl($container); } - public function registerWidgetDependencies(Container $container) + public function registerWidgetDependencies(Container $container): void { $this->registerLogger($container); $this->registerTranslator($container); diff --git a/packages/app/tests/Charcoal/App/Route/ActionRouteConfigTest.php b/packages/app/tests/Charcoal/App/Route/ActionRouteConfigTest.php index 49ee92040..d4ff47317 100644 --- a/packages/app/tests/Charcoal/App/Route/ActionRouteConfigTest.php +++ b/packages/app/tests/Charcoal/App/Route/ActionRouteConfigTest.php @@ -14,7 +14,7 @@ public function setUp(): void $this->obj = new ActionRouteConfig(); } - public function testSetActionData() + public function testSetActionData(): void { $ret = $this->obj->setActionData([ 'foo' => 'bar' ]); $this->assertSame($ret, $this->obj); diff --git a/packages/app/tests/Charcoal/App/Route/ActionRouteTest.php b/packages/app/tests/Charcoal/App/Route/ActionRouteTest.php index d32b3bd4a..9eba4948e 100644 --- a/packages/app/tests/Charcoal/App/Route/ActionRouteTest.php +++ b/packages/app/tests/Charcoal/App/Route/ActionRouteTest.php @@ -14,17 +14,13 @@ class ActionRouteTest extends AbstractTestCase { /** * Tested Class. - * - * @var ActionRoute */ - private $obj; + private \Charcoal\App\Route\ActionRoute $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. @@ -39,19 +35,17 @@ public function setUp(): void ]); } - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(ActionRoute::class, $this->obj); } /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerLogger($container); diff --git a/packages/app/tests/Charcoal/App/Route/RouteConfigTest.php b/packages/app/tests/Charcoal/App/Route/RouteConfigTest.php index a2890b0b9..5a80df703 100644 --- a/packages/app/tests/Charcoal/App/Route/RouteConfigTest.php +++ b/packages/app/tests/Charcoal/App/Route/RouteConfigTest.php @@ -16,7 +16,7 @@ public function setUp(): void $this->obj = new RouteConfig(); } - public function testSetIdent() + public function testSetIdent(): void { $this->assertNull($this->obj->ident()); $ret = $this->obj->setIdent('foobar'); @@ -28,7 +28,7 @@ public function testSetIdent() $this->obj->setIdent(false); } - public function testSetRoute() + public function testSetRoute(): void { $this->assertNull($this->obj->route()); $ret = $this->obj->setRoute('foobar'); @@ -40,7 +40,7 @@ public function testSetRoute() $this->obj->setRoute(false); } - public function testSetGroups() + public function testSetGroups(): void { $this->assertEquals([], $this->obj->groups()); $ret = $this->obj->setGroups(['foo', 'bar']); @@ -49,7 +49,7 @@ public function testSetGroups() $this->assertEquals(['foo', 'bar'], $this->obj->groups()); } - public function testAddGroup() + public function testAddGroup(): void { $this->obj->addGroup('foo'); $this->obj->addGroup('bar'); @@ -60,7 +60,7 @@ public function testAddGroup() $this->obj->addGroup(false); } - public function testSetController() + public function testSetController(): void { $this->assertNull($this->obj->controller()); $ret = $this->obj->setController('foobar'); @@ -72,7 +72,7 @@ public function testSetController() $this->obj->setController(false); } - public function testSetMethods() + public function testSetMethods(): void { $this->assertEquals(['GET'], $this->obj->methods()); $ret = $this->obj->setMethods(['POST']); @@ -81,7 +81,7 @@ public function testSetMethods() $this->assertEquals(['POST'], $this->obj->methods()); } - public function testAddMethod() + public function testAddMethod(): void { $this->assertEquals(['GET'], $this->obj->methods()); $ret = $this->obj->addMethod('post'); @@ -93,13 +93,13 @@ public function testAddMethod() $this->obj->addMethod([]); } - public function testAddMethodInvalidMethodThrowsException() + public function testAddMethodInvalidMethodThrowsException(): void { $this->expectException(InvalidArgumentException::class); $this->obj->addMethod('invalid'); } - public function testSetHeaders() + public function testSetHeaders(): void { $this->assertEquals([], $this->obj->headers()); $ret = $this->obj->setHeaders(['Foo'=>'Bar']); @@ -110,7 +110,7 @@ public function testSetHeaders() $this->assertArrayNotHasKey('Foo', $this->obj->headers()); } - public function testAddHeader() + public function testAddHeader(): void { $this->assertEquals([], $this->obj->headers()); $ret = $this->obj->addHeader('Foo', 'Bar'); diff --git a/packages/app/tests/Charcoal/App/Route/RouteManagerTest.php b/packages/app/tests/Charcoal/App/Route/RouteManagerTest.php index f28385a3f..fc7ec11dd 100644 --- a/packages/app/tests/Charcoal/App/Route/RouteManagerTest.php +++ b/packages/app/tests/Charcoal/App/Route/RouteManagerTest.php @@ -1,5 +1,7 @@ obj->setupRoutes(); } - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(RouteManager::class, $this->obj); } - public function testSetupTemplate() + public function testSetupTemplate(): void { $config = [ 'templates' => [ @@ -64,14 +66,13 @@ public function testSetupTemplate() $reflector = new \ReflectionObject($obj); $method = $reflector->getMethod('setupTemplate'); - $method->setAccessible(true); foreach($config['templates'] as $routeIdent => $templateConfig) { $ret = $method->invoke($obj, $routeIdent, $templateConfig); $this->assertInstanceOf(RouteInterface::class, $ret); } } - public function testSetupAction() + public function testSetupAction(): void { $config = [ 'actions' => [ @@ -88,14 +89,13 @@ public function testSetupAction() $reflector = new \ReflectionObject($obj); $method = $reflector->getMethod('setupAction'); - $method->setAccessible(true); foreach($config['actions'] as $routeIdent => $actionConfig) { $ret = $method->invoke($obj, $routeIdent, $actionConfig); $this->assertInstanceOf(RouteInterface::class, $ret); } } - public function testSetupScript() + public function testSetupScript(): void { $config = [ 'scripts' => [ @@ -112,7 +112,6 @@ public function testSetupScript() $reflector = new \ReflectionObject($obj); $method = $reflector->getMethod('setupScript'); - $method->setAccessible(true); foreach($config['scripts'] as $routeIdent => $scriptConfig) { $ret = $method->invoke($obj, $routeIdent, $scriptConfig); $this->assertInstanceOf(RouteInterface::class, $ret); diff --git a/packages/app/tests/Charcoal/App/Route/ScriptRouteTest.php b/packages/app/tests/Charcoal/App/Route/ScriptRouteTest.php index 630f4ece7..f9f0d20c0 100644 --- a/packages/app/tests/Charcoal/App/Route/ScriptRouteTest.php +++ b/packages/app/tests/Charcoal/App/Route/ScriptRouteTest.php @@ -25,17 +25,13 @@ class ScriptRouteTest extends AbstractTestCase { /** * Tested Class. - * - * @var ScriptRoute */ - private $obj; + private \Charcoal\App\Route\ScriptRoute $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. @@ -49,30 +45,26 @@ public function setUp(): void ]); } - public function testInvoke() + public function testInvoke(): void { $container = $this->container(); - $container['script/factory'] = function($c) { - return new Factory(); - }; + $container['script/factory'] = (fn($c): \Charcoal\Factory\GenericFactory => new Factory()); - $request = $this->createMock(RequestInterface::class); - $response = $this->createMock(ResponseInterface::class); + $request = $this->createStub(RequestInterface::class); + $response = $this->createStub(ResponseInterface::class); // Invalid because "foo/bar" is not a valid script controller $this->expectException('\Exception'); - $ret = call_user_func([$this->obj, '__invoke'], $container, $request, $response); + call_user_func($this->obj->__invoke(...), $container, $request, $response); } /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerLogger($container); diff --git a/packages/app/tests/Charcoal/App/Route/TemplateRouteConfigTest.php b/packages/app/tests/Charcoal/App/Route/TemplateRouteConfigTest.php index 175db9cd8..b7d020fcc 100644 --- a/packages/app/tests/Charcoal/App/Route/TemplateRouteConfigTest.php +++ b/packages/app/tests/Charcoal/App/Route/TemplateRouteConfigTest.php @@ -14,7 +14,7 @@ public function setUp(): void $this->obj = new TemplateRouteConfig(); } - public function testSetEngine() + public function testSetEngine(): void { //$this->assertEquals('mustache', $this->obj->engine()); $ret = $this->obj->setEngine('twig'); @@ -28,7 +28,7 @@ public function testSetEngine() $this->obj->setEngine(false); } - public function testSetTemplate() + public function testSetTemplate(): void { $this->assertNull($this->obj->template()); $ret = $this->obj->setTemplate('foobar'); @@ -40,7 +40,7 @@ public function testSetTemplate() $this->obj->setTemplate(false); } - public function testRedirect() + public function testRedirect(): void { $this->assertNull($this->obj->redirect()); $ret = $this->obj->setRedirect('foobar'); @@ -49,7 +49,7 @@ public function testRedirect() $this->assertEquals('foobar', $this->obj->redirect()); } - public function testSetRedirectMode() + public function testSetRedirectMode(): void { $this->assertEquals(301, $this->obj->redirectMode()); $ret = $this->obj->setRedirectMode(302); @@ -60,7 +60,7 @@ public function testSetRedirectMode() $this->obj->setRedirectMode(666); } - public function testSetCache() + public function testSetCache(): void { $this->assertFalse($this->obj->cache()); $ret = $this->obj->setCache(true); @@ -68,7 +68,7 @@ public function testSetCache() $this->assertTrue($this->obj->cache()); } - public function testSetCacheTtl() + public function testSetCacheTtl(): void { $this->assertEquals(0, $this->obj->cacheTtl()); $ret = $this->obj->setCacheTtl('42'); diff --git a/packages/app/tests/Charcoal/App/Script/AbstractScriptTest.php b/packages/app/tests/Charcoal/App/Script/AbstractScriptTest.php index 990d0165a..7dca938d0 100644 --- a/packages/app/tests/Charcoal/App/Script/AbstractScriptTest.php +++ b/packages/app/tests/Charcoal/App/Script/AbstractScriptTest.php @@ -21,17 +21,13 @@ class AbstractScriptTest extends AbstractTestCase { /** * Tested Class. - * - * @var AbstractScript */ - private $obj; + private \Charcoal\App\Script\AbstractScript $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. @@ -40,28 +36,33 @@ public function setUp(): void { $container = $this->container(); - $this->obj = $this->getMockForAbstractClass(AbstractScript::class, [[ + $this->obj = new class ([ 'climate' => $container['climate'], 'logger' => $container['logger'], 'container' => $container - ]]); + ]) extends AbstractScript { + public function run(RequestInterface $request, ResponseInterface $response) + { + return $response; + } + }; } - public function testSetIdent() + public function testSetIdent(): void { $ret = $this->obj->setIdent('foobar'); $this->assertSame($ret, $this->obj); $this->assertEquals('foobar', $this->obj->ident()); } - public function testSetDescription() + public function testSetDescription(): void { $ret = $this->obj->setDescription('Foo Description'); $this->assertSame($ret, $this->obj); $this->assertEQuals('Foo Description', $this->obj->description()); } - public function testSetQuiet() + public function testSetQuiet(): void { $this->assertFalse($this->obj->quiet()); $ret = $this->obj->setQuiet(true); @@ -69,7 +70,7 @@ public function testSetQuiet() $this->assertTrue($this->obj->quiet()); } - public function testSetVerbose() + public function testSetVerbose(): void { $this->assertFalse($this->obj->verbose()); $ret = $this->obj->setVerbose(true); @@ -77,9 +78,9 @@ public function testSetVerbose() $this->assertTrue($this->obj->verbose()); } - public function testSetArguments() + public function testSetArguments(): void { - $defaultArgs = $this->obj->arguments(); + $this->obj->arguments(); $ret = $this->obj->setArguments([ 'foo'=>[] ]); @@ -90,12 +91,10 @@ public function testSetArguments() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerLogger($container); diff --git a/packages/app/tests/Charcoal/App/ServerTestTrait.php b/packages/app/tests/Charcoal/App/ServerTestTrait.php index ea84e6730..b7309e1f1 100644 --- a/packages/app/tests/Charcoal/App/ServerTestTrait.php +++ b/packages/app/tests/Charcoal/App/ServerTestTrait.php @@ -14,7 +14,7 @@ trait ServerTestTrait /** * @var mixed The process identifier of the built-in PHP server. */ - static private $serverProcess = null; + static private $serverProcess; /** * @var string The hostname for the built-in PHP server. @@ -29,7 +29,7 @@ trait ServerTestTrait /** * @var null|string The server root directory, where it should be ran from. */ - static protected $serverRoot = null; + static protected $serverRoot; /** * @var string The APPLICATION_ENV environment variable. @@ -44,15 +44,13 @@ trait ServerTestTrait * @param boolean $checkForObjectIdentity Unused. * @param string $message The error to report. * @throws InvalidArgumentException - * @return void */ abstract public function assertArraySubset($subset, $array, $checkForObjectIdentity = false, $message = ''): void; /** * Retrieve the built-in PHP server URL. - * @return string */ - protected static function serverURL() + protected static function serverURL(): string { return static::$serverHost.':'.static::$serverPort; } @@ -71,18 +69,17 @@ protected static function serverRoot() /** * Retrieve wether the tests are run on windows or not. - * @return boolean */ - protected static function isWindows() + protected static function isWindows(): bool { return (stristr(php_uname('s'), 'win') !== false); } /** * Start a built-in PHP server process. - * @beforeClass */ - public static function bootUpBuiltInServer() + #[\PHPUnit\Framework\Attributes\BeforeClass] + public static function bootUpBuiltInServer(): void { $command = sprintf( 'php -S %s -t %s', @@ -110,18 +107,17 @@ public static function bootUpBuiltInServer() /** * Terminates the built-in PHP server process. - * @afterClass */ - public static function turnDownBuiltInServer() + #[\PHPUnit\Framework\Attributes\AfterClass] + public static function turnDownBuiltInServer(): void { pclose(static::$serverProcess); } /** * @param array $request The request data (method, route, options). - * @return \Psr\Http\Message\ResponseInterface */ - protected function callRequest(array $request) + protected function callRequest(array $request): \Psr\Http\Message\ResponseInterface { $route = str_replace('.', '', $request['route']); $client = new HttpClient(); @@ -132,10 +128,6 @@ protected function callRequest(array $request) ); } - /** - * @param array $expected - * @param ResponseInterface $response - */ protected function assertResponseMatchesExpected(array $expected, ResponseInterface $response) { if (isset($expected['statusCode']) && $expected['statusCode']) { @@ -157,7 +149,6 @@ protected function assertResponseMatchesExpected(array $expected, ResponseInterf /** * @param integer $expectedStatusCode - * @param ResponseInterface $response */ protected function assertResponseHasStatusCode($expectedStatusCode, ResponseInterface $response) { @@ -166,7 +157,6 @@ protected function assertResponseHasStatusCode($expectedStatusCode, ResponseInte /** * @param array|string $json - * @param ResponseInterface $response */ protected function assertResponseBodyMatchesJson($json, ResponseInterface $response) { @@ -187,7 +177,6 @@ protected function assertResponseBodyMatchesJson($json, ResponseInterface $respo /** * @param string $pattern - * @param ResponseInterface $response */ protected function assertResponseBodyRegExp($pattern, ResponseInterface $response) { diff --git a/packages/app/tests/Charcoal/App/ServiceProvider/AppServiceProviderTest.php b/packages/app/tests/Charcoal/App/ServiceProvider/AppServiceProviderTest.php index 790c95518..2061ad9ec 100644 --- a/packages/app/tests/Charcoal/App/ServiceProvider/AppServiceProviderTest.php +++ b/packages/app/tests/Charcoal/App/ServiceProvider/AppServiceProviderTest.php @@ -12,7 +12,7 @@ */ class AppServiceProviderTest extends AbstractTestCase { - public function testProvider() + public function testProvider(): void { $container = new Container(); $provider = new AppServiceProvider(); diff --git a/packages/app/tests/Charcoal/App/ServiceProvider/DatabaseServiceProviderTest.php b/packages/app/tests/Charcoal/App/ServiceProvider/DatabaseServiceProviderTest.php index c3b737005..f2238f152 100644 --- a/packages/app/tests/Charcoal/App/ServiceProvider/DatabaseServiceProviderTest.php +++ b/packages/app/tests/Charcoal/App/ServiceProvider/DatabaseServiceProviderTest.php @@ -12,7 +12,7 @@ */ class DatabaseServiceProviderTest extends AbstractTestCase { - public function testProvider() + public function testProvider(): void { $container = new Container([ 'config' => [] diff --git a/packages/app/tests/Charcoal/App/ServiceProvider/FilesystemServiceProviderTest.php b/packages/app/tests/Charcoal/App/ServiceProvider/FilesystemServiceProviderTest.php index a9a6e9cc4..65416b0f3 100644 --- a/packages/app/tests/Charcoal/App/ServiceProvider/FilesystemServiceProviderTest.php +++ b/packages/app/tests/Charcoal/App/ServiceProvider/FilesystemServiceProviderTest.php @@ -30,14 +30,14 @@ */ class FilesystemServiceProviderTest extends AbstractTestCase { - private $obj; + private \Charcoal\App\ServiceProvider\FilesystemServiceProvider $obj; public function setUp(): void { $this->obj = new FilesystemServiceProvider(); } - public function testProvider() + public function testProvider(): void { $container = $this->getContainer([ 'config' => $this->createAppConfig([ @@ -54,7 +54,7 @@ public function testProvider() $this->assertInstanceOf(Container::class, $container['filesystems']); } - public function testProviderDefaultAdapters() + public function testProviderDefaultAdapters(): void { $container = $this->getContainer([ 'config' => $this->createAppConfig([ @@ -69,7 +69,7 @@ public function testProviderDefaultAdapters() $this->assertInstanceOf(Filesystem::class, $container['filesystems']['public']); } - public function testProviderLocalAdapter() + public function testProviderLocalAdapter(): void { $container = $this->getContainer([ 'config' => $this->createAppConfig([ @@ -88,7 +88,7 @@ public function testProviderLocalAdapter() $this->assertInstanceOf(Filesystem::class, $container['filesystems']['local']); } - public function testProviderS3Adapter() + public function testProviderS3Adapter(): void { $container = $this->getContainer([ 'config' => $this->createAppConfig([ @@ -110,7 +110,7 @@ public function testProviderS3Adapter() $this->assertInstanceOf(Filesystem::class, $container['filesystems']['s3']); } - public function testProviderFtpAdapter() + public function testProviderFtpAdapter(): void { $container = $this->getContainer([ 'config' => $this->createAppConfig([ @@ -131,7 +131,7 @@ public function testProviderFtpAdapter() $this->assertInstanceOf(Filesystem::class, $container['filesystems']['ftp']); } - public function testProviderSftpAdapter() + public function testProviderSftpAdapter(): void { $container = $this->getContainer([ 'config' => $this->createAppConfig([ @@ -152,7 +152,7 @@ public function testProviderSftpAdapter() $this->assertInstanceOf(Filesystem::class, $container['filesystems']['sftp']); } - public function testProviderMemorypAdapter() + public function testProviderMemoryAdapter(): void { $container = $this->getContainer([ 'config' => $this->createAppConfig([ @@ -171,7 +171,7 @@ public function testProviderMemorypAdapter() $this->assertInstanceOf(Filesystem::class, $container['filesystems']['memory']); } - public function testProviderNullAdapter() + public function testProviderNullAdapter(): void { $container = $this->getContainer([ 'config' => $this->createAppConfig([ @@ -189,7 +189,7 @@ public function testProviderNullAdapter() $this->assertInstanceOf(Filesystem::class, $container['filesystems']['test']); } - public function testConfigWithoutTypeThrowsException() + public function testConfigWithoutTypeThrowsException(): void { $this->expectException('\Exception'); $container = $this->getContainer([ @@ -201,16 +201,15 @@ public function testConfigWithoutTypeThrowsException() ] ]) ]); - - $test = $container['filesystem/test']; + $container['filesystems']['test']; } - private function createAppConfig($defaults = null) + private function createAppConfig($defaults = null): \Charcoal\App\AppConfig { return new AppConfig(array_replace(['base_path' => sys_get_temp_dir()], $defaults)); } - private function getContainer($defaults = null) + private function getContainer($defaults = null): \Pimple\Container { $container = new Container($defaults); $this->obj->register($container); diff --git a/packages/app/tests/Charcoal/App/ServiceProvider/LoggerServiceProviderTest.php b/packages/app/tests/Charcoal/App/ServiceProvider/LoggerServiceProviderTest.php index 31b04e18a..41b1d8565 100644 --- a/packages/app/tests/Charcoal/App/ServiceProvider/LoggerServiceProviderTest.php +++ b/packages/app/tests/Charcoal/App/ServiceProvider/LoggerServiceProviderTest.php @@ -12,7 +12,7 @@ */ class LoggerServiceProviderTest extends AbstractTestCase { - public function testProvider() + public function testProvider(): void { $container = new Container([ 'config' => [] diff --git a/packages/app/tests/Charcoal/App/ServiceProvider/ScriptServiceProviderTest.php b/packages/app/tests/Charcoal/App/ServiceProvider/ScriptServiceProviderTest.php index 414ffc43a..1bd759abf 100644 --- a/packages/app/tests/Charcoal/App/ServiceProvider/ScriptServiceProviderTest.php +++ b/packages/app/tests/Charcoal/App/ServiceProvider/ScriptServiceProviderTest.php @@ -12,7 +12,7 @@ */ class ScriptServiceProviderTest extends AbstractTestCase { - public function testProvider() + public function testProvider(): void { $container = new Container(); $provider = new ScriptServiceProvider(); diff --git a/packages/app/tests/Charcoal/App/Template/AbstractTemplateTest.php b/packages/app/tests/Charcoal/App/Template/AbstractTemplateTest.php index b4b284e66..a453deef5 100644 --- a/packages/app/tests/Charcoal/App/Template/AbstractTemplateTest.php +++ b/packages/app/tests/Charcoal/App/Template/AbstractTemplateTest.php @@ -23,17 +23,13 @@ class AbstractTemplateTest extends AbstractTestCase { /** * Tested Class. - * - * @var AbstractTemplate */ - private $obj; + private \Charcoal\App\Template\AbstractTemplate $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. @@ -42,26 +38,24 @@ public function setUp(): void { $container = $this->container(); - $this->obj = $this->getMockForAbstractClass(AbstractTemplate::class, [[ + $this->obj = new class ([ 'logger' => $container['logger'], 'container' => $container - ]]); + ]) extends AbstractTemplate {}; } - public function testInitIsTrue() + public function testInitIsTrue(): void { - $request = $this->createMock(RequestInterface::class); + $request = $this->createStub(RequestInterface::class); $this->assertTrue($this->obj->init($request)); } /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerLogger($container); diff --git a/packages/app/tests/Charcoal/App/Template/AbstractWidgetTest.php b/packages/app/tests/Charcoal/App/Template/AbstractWidgetTest.php index a2f526bba..80e415b74 100644 --- a/packages/app/tests/Charcoal/App/Template/AbstractWidgetTest.php +++ b/packages/app/tests/Charcoal/App/Template/AbstractWidgetTest.php @@ -23,17 +23,13 @@ class AbstractWidgetTest extends AbstractTestCase { /** * Tested Class. - * - * @var AbstractWidget */ - private $obj; + private \Charcoal\App\Template\AbstractWidget $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. @@ -42,10 +38,10 @@ public function setUp(): void { $container = $this->container(); - $this->obj = $this->getMockForAbstractClass(AbstractWidget::class, [[ + $this->obj = new class ([ 'logger' => $container['logger'], 'container' => $container - ]]); + ]) extends AbstractWidget {}; } /** @@ -54,7 +50,7 @@ public function setUp(): void * - `setActive()` method is chainable * - `setActive()` actually sets the active value. */ - public function testSetActive() + public function testSetActive(): void { $obj = $this->obj; $this->assertTrue($obj->active()); @@ -65,12 +61,10 @@ public function testSetActive() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerConfig($container); diff --git a/packages/app/tests/Charcoal/AssertionsTrait.php b/packages/app/tests/Charcoal/AssertionsTrait.php index 47f7837dc..767f81794 100644 --- a/packages/app/tests/Charcoal/AssertionsTrait.php +++ b/packages/app/tests/Charcoal/AssertionsTrait.php @@ -16,14 +16,13 @@ trait AssertionsTrait * @param array $haystack The actual haystack. * @param boolean $strict Whether to check for object identity. * @param string $message The error to report. - * @return void */ public function assertArraySubsets( array $expected, array $haystack, $strict = false, $message = '' - ) { + ): void { foreach ($expected as $key => $val) { $this->assertArraySubset([ $key => $val ], $haystack, $strict, $message); } @@ -40,18 +39,17 @@ public function assertArraySubsets( * @param boolean $checkForObjectIdentity Unused. * @param string $message The error to report. * @throws InvalidArgumentException - * @return void */ public function assertArraySubset($subset, $array, $checkForObjectIdentity = false, $message = ''): void { - if (!(is_array($subset) || $subset instanceof ArrayAccess)) { + if (!is_array($subset) && !$subset instanceof ArrayAccess) { throw InvalidArgumentException::create( 1, 'array or ArrayAccess' ); } - if (!(is_array($array) || $array instanceof ArrayAccess)) { + if (!is_array($array) && !$array instanceof ArrayAccess) { throw InvalidArgumentException::create( 2, 'array or ArrayAccess' diff --git a/packages/app/tests/bootstrap.php b/packages/app/tests/bootstrap.php index 53295f7d8..90929e3b5 100644 --- a/packages/app/tests/bootstrap.php +++ b/packages/app/tests/bootstrap.php @@ -1,10 +1,12 @@ - + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/attachment/src/Charcoal/Admin/Action/AddJoinAction.php b/packages/attachment/src/Charcoal/Admin/Action/AddJoinAction.php index 64d3cc65f..d9ed6abfb 100644 --- a/packages/attachment/src/Charcoal/Admin/Action/AddJoinAction.php +++ b/packages/attachment/src/Charcoal/Admin/Action/AddJoinAction.php @@ -21,9 +21,8 @@ class AddJoinAction extends AdminAction /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { $params = $request->getParams(); @@ -44,7 +43,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $group = $params['group']; // Need more attachments... - if (!count($attachments)) { + if (count($attachments) === 0) { $this->setSuccess(false); return $response; @@ -53,7 +52,7 @@ public function run(RequestInterface $request, ResponseInterface $response) // Try loading the object try { $obj = $this->modelFactory()->create($objType)->load($objId); - } catch (Exception $e) { + } catch (Exception) { $this->setSuccess(false); return $response; diff --git a/packages/attachment/src/Charcoal/Admin/Action/JoinAction.php b/packages/attachment/src/Charcoal/Admin/Action/JoinAction.php index 2f41bc59e..2e9663384 100644 --- a/packages/attachment/src/Charcoal/Admin/Action/JoinAction.php +++ b/packages/attachment/src/Charcoal/Admin/Action/JoinAction.php @@ -21,9 +21,8 @@ class JoinAction extends AdminAction /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { $params = $request->getParams(); @@ -44,7 +43,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $group = $params['group']; // Need more attachments... - if (!count($attachments)) { + if (count($attachments) === 0) { $this->setSuccess(false); return $response; @@ -53,7 +52,7 @@ public function run(RequestInterface $request, ResponseInterface $response) // Try loading the object try { $obj = $this->modelFactory()->create($objType)->load($objId); - } catch (Exception $e) { + } catch (Exception) { $this->setSuccess(false); return $response; diff --git a/packages/attachment/src/Charcoal/Admin/Action/RemoveJoinAction.php b/packages/attachment/src/Charcoal/Admin/Action/RemoveJoinAction.php index b75fbcbaa..905b75272 100644 --- a/packages/attachment/src/Charcoal/Admin/Action/RemoveJoinAction.php +++ b/packages/attachment/src/Charcoal/Admin/Action/RemoveJoinAction.php @@ -22,9 +22,8 @@ class RemoveJoinAction extends AdminAction /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { $params = $request->getParams(); @@ -47,7 +46,7 @@ public function run(RequestInterface $request, ResponseInterface $response) // Try loading the object try { $obj = $this->modelFactory()->create($objType)->load($objId); - } catch (Exception $e) { + } catch (Exception) { $this->setSuccess(false); return $response; @@ -84,7 +83,7 @@ public function run(RequestInterface $request, ResponseInterface $response) if ($attachment['id'] !== null) { $attachment->delete(); } - } catch (Exception $error) { + } catch (Exception) { $this->setSuccess(false); return $response; } diff --git a/packages/attachment/src/Charcoal/Admin/Widget/AddAttachmentWidget.php b/packages/attachment/src/Charcoal/Admin/Widget/AddAttachmentWidget.php index 49094eb64..9cf191a40 100644 --- a/packages/attachment/src/Charcoal/Admin/Widget/AddAttachmentWidget.php +++ b/packages/attachment/src/Charcoal/Admin/Widget/AddAttachmentWidget.php @@ -1,5 +1,7 @@ 'paperclip' ]; - /** - * @var array - */ - private $attachmentOptions; + private ?array $attachmentOptions = null; /** * Inject dependencies from a DI Container. @@ -112,6 +114,7 @@ class AttachmentWidget extends AdminWidget implements * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -143,20 +146,16 @@ protected function createOrLoadObj() /** * Determine if the widget has any attachment types. - * - * @return boolean */ - public function hasAttachmentTypes() + public function hasAttachmentTypes(): bool { return !empty($this->attachableObjects()); } /** * Retrieve the attachment types with their collections. - * - * @return array */ - public function attachmentTypes() + public function attachmentTypes(): array { $attachableObjects = $this->attachableObjects(); @@ -172,17 +171,17 @@ public function attachmentTypes() $label = $attMeta['label']; $out[] = [ - 'id' => (isset($attMeta['att_id']) ? $attMeta['att_id'] : null), + 'id' => ($attMeta['att_id'] ?? null), 'ident' => $this->createIdent($attType), 'skipForm' => $attMeta['skipForm'], 'formIdent' => $attMeta['formIdent'], 'quickFormIdent' => $attMeta['quickFormIdent'], - 'hasFaIcon' => !!$attMeta['faIcon'], + 'hasFaIcon' => (bool)$attMeta['faIcon'], 'faIcon' => $attMeta['faIcon'], 'label' => $label, 'val' => $attType, 'locked' => $attMeta['locked'], - 'active' => ($i == 1) + 'active' => ($i === 1) ]; } @@ -220,20 +219,16 @@ public function attachments() /** * Determine the number of attachments. - * - * @return boolean */ - public function hasAttachments() + public function hasAttachments(): int { return count(iterator_to_array($this->attachments())); } /** * The default set of settings for attachment widget. - * - * @return array */ - public function defaultAttachmentOptions() + public function defaultAttachmentOptions(): array { return [ 'header' => null, @@ -251,9 +246,8 @@ public function defaultAttachmentOptions() * @param string $key The setting to add/replace. * @param mixed $val The settings's value to apply. * @throws InvalidArgumentException If the identifier is not a string. - * @return self */ - public function addAttachmentOption($key, $val) + public function addAttachmentOption($key, $val): static { if (!is_string($key)) { throw new InvalidArgumentException( @@ -291,20 +285,15 @@ public function attachmentOption($key) $this->attachmentOptions(); } - if (isset($this->attachmentOptions[$key])) { - return $this->attachmentOptions[$key]; - } - - return null; + return ($this->attachmentOptions[$key] ?? null); } /** * Merge (replacing or adding) attachment options. * * @param array $settings The attachment options. - * @return self */ - public function mergeAttachmentOptions(array $settings) + public function mergeAttachmentOptions(array $settings): static { // Make sure default options are loaded. if ($this->attachmentOptions === null) { @@ -323,12 +312,10 @@ public function mergeAttachmentOptions(array $settings) * @param array $settings The Attachment options. * @return array Returns the parsed options. */ - protected function parseAttachmentOptions(array $settings) + protected function parseAttachmentOptions(array $settings): array { - if (isset($settings['show_header']) && isset($settings['show_preview'])) { - if (!$settings['show_header'] && !$settings['show_preview']) { - $settings['show_header'] = true; - } + if (isset($settings['show_header']) && isset($settings['show_preview']) && (!$settings['show_header'] && !$settings['show_preview'])) { + $settings['show_header'] = true; } return $settings; @@ -336,14 +323,13 @@ protected function parseAttachmentOptions(array $settings) // Setters // ========================================================================= - /** * Set the widget's data. * * @param array $data The widget data. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { $this->isMergingData = true; /** @@ -375,14 +361,12 @@ public function setData(array $data) * @throws InvalidArgumentException If the argument is not a string. * @return UserDataInterface Chainable */ - public function setLang($lang) + public function setLang($lang): static { - if ($lang !== null) { - if (!is_string($lang)) { - throw new InvalidArgumentException( - 'Language must be a string' - ); - } + if ($lang !== null && !is_string($lang)) { + throw new InvalidArgumentException( + 'Language must be a string' + ); } $this->lang = $lang; @@ -394,9 +378,8 @@ public function setLang($lang) * Set the attachment widget settings. * * @param array $settings Attachments options array. - * @return self */ - public function setAttachmentOptions(array $settings) + public function setAttachmentOptions(array $settings): static { $this->attachmentOptions = array_merge( $this->defaultAttachmentOptions(), @@ -413,14 +396,13 @@ public function setAttachmentOptions(array $settings) * * @param string $group The group identifier. * @throws InvalidArgumentException If the group key is invalid. - * @return self */ - public function setGroup($group) + public function setGroup($group): static { if (!is_string($group) && $group !== null) { throw new InvalidArgumentException(sprintf( 'Attachment group must be string, received %s', - is_object($group) ? get_class($group) : gettype($group) + get_debug_type($group) )); } @@ -433,9 +415,8 @@ public function setGroup($group) * Set an widget factory. * * @param FactoryInterface $factory The factory to create widgets. - * @return self */ - protected function setWidgetFactory(FactoryInterface $factory) + protected function setWidgetFactory(FactoryInterface $factory): static { $this->widgetFactory = $factory; @@ -446,9 +427,8 @@ protected function setWidgetFactory(FactoryInterface $factory) * Set the widget's title. * * @param mixed $title The title for the current widget. - * @return self */ - public function setTitle($title) + public function setTitle($title): static { $this->title = $this->translator()->translation($title); @@ -460,9 +440,8 @@ public function setTitle($title) * * @param integer $num The number of results to retrieve, per page. * @throws InvalidArgumentException If the parameter is not numeric or < 0. - * @return self */ - public function setNumPerPage($num) + public function setNumPerPage($num): static { if (!is_numeric($num)) { throw new InvalidArgumentException( @@ -488,9 +467,8 @@ public function setNumPerPage($num) * * @param integer $page The current page. Start at 0. * @throws InvalidArgumentException If the parameter is not numeric or < 0. - * @return self */ - public function setPage($page) + public function setPage($page): static { if (!is_numeric($page)) { throw new InvalidArgumentException( @@ -520,7 +498,7 @@ public function setPage($page) * @param array|AttachableInterface[] $attachableObjects A list of available attachment types. * @return self|boolean */ - public function setAttachableObjects($attachableObjects) + public function setAttachableObjects($attachableObjects): false|self { if (!$this->isMergingData) { $attachableObjects = $this->mergePresetAttachableObjects($attachableObjects); @@ -564,7 +542,7 @@ public function setAttachableObjects($attachableObjects) } // Useful for attaching a pre-existing attachment - $attId = (isset($attMeta['attachment_id']) ? $attMeta['attachment_id'] : null); + $attId = ($attMeta['attachment_id'] ?? null); if (isset($attMeta['label'])) { $label = $this->translator()->translation($attMeta['label']); @@ -609,14 +587,14 @@ public function setAttachableObjects($attachableObjects) $icon = 'fa fa-' . $icon; } } else { - $attParts = explode('/', $attType); + $attParts = explode('/', (string)$attType); if (isset($this->defaultIcons[end($attParts)])) { $faIcon = 'fa fa-' . $this->defaultIcons[end($attParts)]; } } if (isset($attMeta['show_icon'])) { - $showIcon = !!$attMeta['show_icon']; + $showIcon = (bool)$attMeta['show_icon']; } if (isset($attMeta['locked'])) { @@ -633,7 +611,7 @@ public function setAttachableObjects($attachableObjects) 'skipForm' => $skipForm, 'formIdent' => $formIdent, 'quickFormIdent' => $quickFormIdent, - 'hasFaIcon' => !!$faIcon, + 'hasFaIcon' => (bool)$faIcon, 'faIcon' => $faIcon, 'showIcon' => $showIcon, 'filters' => $filters, @@ -652,19 +630,17 @@ public function setAttachableObjects($attachableObjects) // Getters // ========================================================================= - /** * Retrieve the widget factory. * * @throws RuntimeException If the widget factory was not previously set. - * @return FactoryInterface */ - public function widgetFactory() + public function widgetFactory(): \Charcoal\Factory\FactoryInterface { - if (!isset($this->widgetFactory)) { + if (!$this->widgetFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException(sprintf( 'Widget Factory is not defined for "%s"', - get_class($this) + static::class )); } @@ -683,10 +659,8 @@ public function lang() /** * Retrieve the attachment options. - * - * @return array */ - public function attachmentOptions() + public function attachmentOptions(): array { if ($this->attachmentOptions === null) { $this->attachmentOptions = $this->defaultAttachmentOptions(); @@ -729,10 +703,8 @@ public function attachableObjects() return $this->attachableObjects; } - /** - * @return array - */ - public function widgetDataForJs() + #[\Override] + public function widgetDataForJs(): array { return [ 'obj_type' => $this->obj()->objType(), @@ -743,10 +715,8 @@ public function widgetDataForJs() /** * Retrieve the widget's options. - * - * @return array */ - public function widgetOptions() + public function widgetOptions(): array { return [ 'obj_type' => $this->obj()->objType(), @@ -769,7 +739,7 @@ final public function widgetOptionsAsJson() $options = (JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); if ($this->debug()) { - $options = ($options | JSON_PRETTY_PRINT); + $options |= JSON_PRETTY_PRINT; } return json_encode($this->widgetOptions(), $options); @@ -780,7 +750,7 @@ final public function widgetOptionsAsJson() * * @return string Returns a stringified JSON object, protected from Mustache rendering. */ - final public function escapedWidgetOptionsAsJson() + final public function escapedWidgetOptionsAsJson(): string { return '{{=<% %>=}}' . $this->widgetOptionsAsJson() . '<%={{ }}=%>'; } @@ -802,7 +772,7 @@ public function defaultIcons() * @param string $string A dirty string to filter. * @return string */ - public function createIdent($string) + public function createIdent($string): ?string { return preg_replace('~/~', '-', $string); } diff --git a/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php b/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php index 3f32f6cf7..f1bcdd4d5 100644 --- a/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php +++ b/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php @@ -42,25 +42,21 @@ class AttachmentFormGroup extends AbstractFormGroup implements /** * Store the widget factory instance for the current class. - * - * @var FactoryInterface */ - private $widgetFactory; + private ?\Charcoal\Factory\FactoryInterface $widgetFactory = null; /** * Whether notes should be display before or after the form fields. - * - * @var boolean */ - private $showNotesAbove = false; + private bool $showNotesAbove = false; /** * Set the widget's data. * * @param array $data The widget data. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { /** * @todo Kinda hacky, but works with the concept of form. @@ -80,10 +76,8 @@ public function setData(array $data) /** * Retrieve the default nested widget options. - * - * @return array */ - public function defaultWidgetData() + public function defaultWidgetData(): array { return [ 'type' => 'charcoal/admin/widget/attachment', @@ -114,9 +108,8 @@ public function widgetId() * Set the widget's ID. * * @param string $widgetId The widget identifier. - * @return self */ - public function setWidgetId($widgetId) + public function setWidgetId($widgetId): static { $this->widgetId = $widgetId; @@ -126,7 +119,8 @@ public function setWidgetId($widgetId) /** * @return Translation|string|null */ - public function description() + #[\Override] + public function description(): string { return $this->renderTemplate((string)parent::description()); } @@ -134,7 +128,8 @@ public function description() /** * @return Translation|string|null */ - public function notes() + #[\Override] + public function notes(): string { return $this->renderTemplate((string)parent::notes()); } @@ -145,7 +140,8 @@ public function notes() * @param boolean|string $show Whether to show or hide notes. * @return self Chainable */ - public function setShowNotes($show) + #[\Override] + public function setShowNotes($show): static { $this->showNotesAbove = ($show === 'above'); parent::setShowNotes($show); @@ -153,10 +149,7 @@ public function setShowNotes($show) return $this; } - /** - * @return boolean - */ - public function showNotesAbove() + public function showNotesAbove(): bool { return $this->showNotesAbove && $this->showNotes(); } @@ -165,6 +158,7 @@ public function showNotesAbove() * @param Container $container The DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -186,9 +180,8 @@ protected function setDependencies(Container $container) * Set the widget factory. * * @param FactoryInterface $factory The factory to create widgets. - * @return self */ - protected function setWidgetFactory(FactoryInterface $factory) + protected function setWidgetFactory(FactoryInterface $factory): static { $this->widgetFactory = $factory; @@ -198,15 +191,14 @@ protected function setWidgetFactory(FactoryInterface $factory) /** * Retrieve the widget factory. * - * @return FactoryInterface * @throws RuntimeException If the widget factory was not previously set. */ - protected function widgetFactory() + protected function widgetFactory(): \Charcoal\Factory\FactoryInterface { - if ($this->widgetFactory === null) { + if (!$this->widgetFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException(sprintf( 'Widget Factory is not defined for "%s"', - get_class($this) + static::class )); } diff --git a/packages/attachment/src/Charcoal/Attachment/AttachmentsConfig.php b/packages/attachment/src/Charcoal/Attachment/AttachmentsConfig.php index 481b508b4..fc4f3e65f 100644 --- a/packages/attachment/src/Charcoal/Attachment/AttachmentsConfig.php +++ b/packages/attachment/src/Charcoal/Attachment/AttachmentsConfig.php @@ -13,24 +13,18 @@ class AttachmentsConfig extends AbstractConfig { /** * Available attachment widget structures. - * - * @var array */ - private $widgets = []; + private array $widgets = []; /** * Attachment type groupings. - * - * @var array */ - private $groups = []; + private array $groups = []; /** * Available attachment types. - * - * @var array */ - private $attachables = []; + private array $attachables = []; /** * Set attachments settings in a specific order. @@ -38,6 +32,7 @@ class AttachmentsConfig extends AbstractConfig * @param array $data New config values. * @return AttachmentsConfig Chainable */ + #[\Override] public function setData(array $data) { if (isset($data['attachables'])) { @@ -64,7 +59,7 @@ public function setData(array $data) * @throws InvalidArgumentException If the attachment type or structure is invalid. * @return AttachmentsConfig Chainable */ - public function setAttachables(array $attachables) + public function setAttachables(array $attachables): static { foreach ($attachables as $attType => $attStruct) { if (!is_array($attStruct)) { @@ -94,10 +89,8 @@ public function setAttachables(array $attachables) /** * Retrieve the available attachment types. - * - * @return array */ - public function attachables() + public function attachables(): array { return $this->attachables; } @@ -109,7 +102,7 @@ public function attachables() * @throws InvalidArgumentException If the group identifier or structure is invalid. * @return AttachmentsConfig Chainable */ - public function setGroups(array $groups) + public function setGroups(array $groups): static { foreach ($groups as $groupIdent => $groupStruct) { if (!is_array($groupStruct)) { @@ -144,10 +137,8 @@ public function setGroups(array $groups) /** * Retrieve the available attachment type groups. - * - * @return array */ - public function groups() + public function groups(): array { return $this->groups; } @@ -159,7 +150,7 @@ public function groups() * @throws InvalidArgumentException If the widget identifier or structure is invalid. * @return AttachmentsConfig Chainable */ - public function setWidgets(array $widgets) + public function setWidgets(array $widgets): static { foreach ($widgets as $widgetIdent => $widgetStruct) { if (!is_array($widgetStruct)) { @@ -188,10 +179,8 @@ public function setWidgets(array $widgets) /** * Retrieve the available attachment widget structures. - * - * @return array */ - public function widgets() + public function widgets(): array { return $this->widgets; } diff --git a/packages/attachment/src/Charcoal/Attachment/Interfaces/AttachableInterface.php b/packages/attachment/src/Charcoal/Attachment/Interfaces/AttachableInterface.php index d4dc9e187..311f27456 100644 --- a/packages/attachment/src/Charcoal/Attachment/Interfaces/AttachableInterface.php +++ b/packages/attachment/src/Charcoal/Attachment/Interfaces/AttachableInterface.php @@ -1,5 +1,7 @@ defaultData(...))) { $defaultData = $this->metadata()->defaultData(); if ($defaultData) { $this->setData($defaultData); @@ -203,6 +197,7 @@ public function __construct(array $data = null) * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -217,7 +212,7 @@ protected function setDependencies(Container $container) * @param boolean $presenter The presenter flag. * @return boolean Returns TRUE if model is used for presentation; FALSE for editing. */ - public function isPresentable($presenter = null) + public function isPresentable($presenter = null): bool { if (is_bool($presenter)) { $this->presentable = $presenter; @@ -245,10 +240,8 @@ public function containerId() /** * Determine if the attachment belongs to a container. - * - * @return boolean */ - public function hasContainerObj() + public function hasContainerObj(): bool { return boolval($this->containerObj); } @@ -268,9 +261,8 @@ public function containerObj() * * @param AttachmentContainerInterface|null $obj The container object or NULL. * @throws InvalidArgumentException If the given object is invalid. - * @return Attachment */ - public function setContainerObj($obj) + public function setContainerObj($obj): static { if ($obj === null) { $this->containerObj = null; @@ -282,14 +274,14 @@ public function setContainerObj($obj) throw new InvalidArgumentException(sprintf( 'Container object must be an instance of %s; received %s', AttachmentContainerInterface::class, - (is_object($obj) ? get_class($obj) : gettype($obj)) + (get_debug_type($obj)) )); } if (!$obj->id()) { throw new InvalidArgumentException(sprintf( 'Container object must have an ID.', - (is_object($obj) ? get_class($obj) : gettype($obj)) + (get_debug_type($obj)) )); } @@ -319,7 +311,7 @@ public function type() * @throws InvalidArgumentException If provided argument is not of type 'string'. * @return string */ - public function setType($type) + public function setType($type): static { if (!is_string($type)) { throw new InvalidArgumentException('Attachment type must be a string.'); @@ -354,7 +346,7 @@ public function typeLabel() */ public function microType() { - $classname = get_called_class(); + $classname = static::class; if (!isset(static::$resolvedType[$classname])) { $reflect = new ReflectionClass($this); @@ -367,10 +359,8 @@ public function microType() /** * Retrieve the image attachment type. - * - * @return string */ - public function imageType() + public function imageType(): string { return self::IMAGE_TYPE; } @@ -384,7 +374,7 @@ public function heading() { $heading = $this->renderTemplate((string)$this->heading); - if (!$heading) { + if ($heading === '' || $heading === '0') { $heading = $this->translator()->translation('{{ objType }} #{{ id }}', [ '{{ objType }}' => $this->typeLabel(), '{{ id }}' => $this->id() @@ -410,7 +400,7 @@ public function rawHeading() * @param string $template The attachment heading. * @return Attachment Chainable */ - public function setHeading($template) + public function setHeading($template): static { $this->heading = $this->translator()->translation($template); @@ -422,7 +412,7 @@ public function setHeading($template) * * @return Translation|string|null */ - public function preview() + public function preview(): string { if ($this->preview) { return $this->renderTemplate((string)$this->preview); @@ -447,7 +437,7 @@ public function rawPreview() * @param string $template The attachment preview. * @return Attachment Chainable */ - public function setPreview($template) + public function setPreview($template): static { $this->preview = $this->translator()->translation($template); @@ -456,90 +446,72 @@ public function setPreview($template) /** * Determine if the attachment type is an image. - * - * @return boolean */ - public function isImage() + public function isImage(): bool { return ($this->microType() === 'image'); } /** * Determine if the attachment type is an embed object. - * - * @return boolean */ - public function isEmbed() + public function isEmbed(): bool { return ($this->microType() === 'embed'); } /** * Determine if the attachment type is a video. - * - * @return boolean */ - public function isVideo() + public function isVideo(): bool { return ($this->microType() === 'video'); } /** * Determine if the attachment type is a file attachment. - * - * @return boolean */ - public function isFile() + public function isFile(): bool { return ($this->microType() === 'file'); } /** * Determine if the attachment type is a text-area. - * - * @return boolean */ - public function isText() + public function isText(): bool { return ($this->microType() === 'text'); } /** * Determine if the attachment type is an image gallery. - * - * @return boolean */ - public function isGallery() + public function isGallery(): bool { return ($this->microType() === 'gallery'); } /** * Determine if the attachment type is an accordion. - * - * @return boolean */ - public function isAccordion() + public function isAccordion(): bool { return ($this->microType() === 'accordion'); } /** * Determine if the attachment type is a link. - * - * @return boolean */ - public function isLink() + public function isLink(): bool { return ($this->microType() === 'link'); } /** * Determine if this attachment is a container. - * - * @return boolean */ - public function isAttachmentContainer() + public function isAttachmentContainer(): bool { return ($this instanceof AttachmentContainerInterface); } @@ -553,9 +525,9 @@ public function isAttachmentContainer() * @param boolean $show Show (TRUE) or hide (FALSE) the title. * @return UiItemInterface Chainable */ - public function setShowTitle($show) + public function setShowTitle($show): static { - $this->showTitle = !!$show; + $this->showTitle = (bool)$show; return $this; } @@ -564,9 +536,8 @@ public function setShowTitle($show) * Set the attachment's title. * * @param string $title The object title. - * @return self */ - public function setTitle($title) + public function setTitle($title): static { $this->title = $this->translator()->translation($title); @@ -577,9 +548,8 @@ public function setTitle($title) * Set the attachment's sub-title. * * @param string $title The object title. - * @return self */ - public function setSubtitle($title) + public function setSubtitle($title): static { $this->subtitle = $this->translator()->translation($title); @@ -590,9 +560,8 @@ public function setSubtitle($title) * Set the attachment's description. * * @param string $description The description of the object. - * @return self */ - public function setDescription($description) + public function setDescription($description): static { $this->description = $this->translator()->translation($description); @@ -609,9 +578,8 @@ public function setDescription($description) * Set the attachment's keywords. * * @param string|string[] $keywords One or more entries. - * @return self */ - public function setKeywords($keywords) + public function setKeywords($keywords): static { $this->keywords = $keywords; @@ -622,9 +590,8 @@ public function setKeywords($keywords) * Set the path to the thumbnail associated with the object. * * @param string $path A path to an image. - * @return self */ - public function setThumbnail($path) + public function setThumbnail($path): static { $this->thumbnail = $this->translator()->translation($path); @@ -635,9 +602,8 @@ public function setThumbnail($path) * Set the path to the attached file. * * @param string $path A path to a file. - * @return self */ - public function setFile($path) + public function setFile($path): static { $this->file = $this->translator()->translation($path); @@ -648,9 +614,8 @@ public function setFile($path) * Set the URL. * * @param string $link An external url. - * @return self */ - public function setLink($link) + public function setLink($link): static { $this->link = $this->translator()->translation($link); @@ -661,9 +626,8 @@ public function setLink($link) * Set the file label. * * @param string $label A descriptor. - * @return self */ - public function setFileLabel($label) + public function setFileLabel($label): static { $this->fileLabel = $this->translator()->translation($label); @@ -674,9 +638,8 @@ public function setFileLabel($label) * Set the link label. * * @param string $label A descriptor. - * @return self */ - public function setLinkLabel($label) + public function setLinkLabel($label): static { $this->linkLabel = $this->translator()->translation($label); @@ -688,9 +651,8 @@ public function setLinkLabel($label) * * @param integer|float $size A file size in bytes; the one of the attached. * @throws InvalidArgumentException If provided argument is not of type 'integer' or 'float'. - * @return self */ - public function setFileSize($size) + public function setFileSize($size): static { if ($size === null) { $this->fileSize = null; @@ -711,9 +673,8 @@ public function setFileSize($size) * Set file extension. * * @param string $type File extension. - * @return self */ - public function setFileType($type) + public function setFileType($type): static { $this->fileType = $type; @@ -725,9 +686,8 @@ public function setFileType($type) * * @param string $embed A URI or an HTML media element. * @throws InvalidArgumentException If provided argument is not of type 'string'. - * @return self */ - public function setEmbed($embed) + public function setEmbed($embed): static { $this->embed = $this->translator()->translation($embed); @@ -736,9 +696,8 @@ public function setEmbed($embed) /** * @param string|\string[] $categories Category elements. - * @return self */ - public function setCategories($categories) + public function setCategories($categories): static { $this->categories = $categories; @@ -758,7 +717,7 @@ public function showTitle() if (is_bool($this->showTitle)) { return $this->showTitle; } else { - return !!$this->title(); + return (bool)$this->title(); } } @@ -847,7 +806,7 @@ public function fileOrLink() * * @return string[]|null */ - public function fileAndLink() + public function fileAndLink(): array { $prop = $this->property('file'); $files = $prop->parseValAsFileList($this['file']); @@ -855,16 +814,15 @@ public function fileAndLink() $items = array_merge($files, $links); $items = array_unique($items); - $items = array_values($items); - return $items; + return array_values($items); } /** * Basename of the associated file. * @return string Basename of file. */ - public function basename() + public function basename(): string { if (!$this->file()) { return ''; @@ -940,9 +898,8 @@ public function presenter() /** * @param ModelInterface|mixed $presenter Presenter for Attachment. - * @return self */ - public function setPresenter($presenter) + public function setPresenter($presenter): static { $this->presenter = $presenter; @@ -951,15 +908,14 @@ public function setPresenter($presenter) // Events // ============================================================================= - /** * Event called before _deleting_ the attachment. * * @see Charcoal\Source\StorableTrait::preDelete() For the "create" Event. * @see Charcoal\Attachment\Traits\AttachmentAwareTrait::removeJoins - * @return boolean */ - public function preDelete() + #[\Override] + public function preDelete(): bool { $joinCollection = $this->collectionLoader() ->reset() @@ -976,15 +932,13 @@ public function preDelete() // Utilities // ============================================================================= - /** * Set the base URI of the project. * * @see \Charcoal\Admin\Support\setBaseUrl::baseUrl() * @param UriInterface $uri The base URI. - * @return self */ - protected function setBaseUrl(UriInterface $uri) + protected function setBaseUrl(UriInterface $uri): static { $this->baseUrl = $uri; @@ -995,14 +949,13 @@ protected function setBaseUrl(UriInterface $uri) * Retrieve the base URI of the project. * * @throws RuntimeException If the base URI is missing. - * @return UriInterface|null */ - public function baseUrl() + public function baseUrl(): \Psr\Http\Message\UriInterface { - if (!isset($this->baseUrl)) { + if (!$this->baseUrl instanceof \Psr\Http\Message\UriInterface) { throw new RuntimeException(sprintf( 'The base URI is not defined for [%s]', - get_class($this) + static::class )); } @@ -1024,9 +977,9 @@ public function createAbsoluteUrl($uri) $uri = strval($uri); if ($this->isRelativeUri($uri)) { $parts = parse_url($uri); - $path = isset($parts['path']) ? $parts['path'] : ''; - $query = isset($parts['query']) ? $parts['query'] : ''; - $hash = isset($parts['fragment']) ? $parts['fragment'] : ''; + $path = ($parts['path'] ?? ''); + $query = ($parts['query'] ?? ''); + $hash = ($parts['fragment'] ?? ''); return $this->baseUrl()->withPath($path)->withQuery($query)->withFragment($hash); } @@ -1040,7 +993,7 @@ public function createAbsoluteUrl($uri) * @param string $text A string to parse relative URIs. * @return UriInterface|null */ - protected function resolveUrls($text) + protected function resolveUrls($text): ?string { static $search; @@ -1050,20 +1003,16 @@ protected function resolveUrls($text) $search = sprintf( '(?<=%1$s=")(?!%2$s)(\S+)(?=")', - implode('="|', array_map('preg_quote', $attr, [ '~' ])), - implode('|', array_map('preg_quote', $scheme, [ '~' ])) + implode('="|', array_map(preg_quote(...), $attr, [ '~' ])), + implode('|', array_map(preg_quote(...), $scheme, [ '~' ])) ); } - $text = preg_replace_callback( + return preg_replace_callback( '~' . $search . '~i', - function ($matches) { - return $this->createAbsoluteUrl($matches[1]); - }, + fn($matches) => $this->createAbsoluteUrl($matches[1]), $text ); - - return $text; } /** @@ -1082,21 +1031,15 @@ protected function isRelativeUri($uri) if (\parse_url($uri, PHP_URL_SCHEME)) { return false; } - - if (\preg_match('/^([\/\#\?]|[a-z][a-z0-9+.-]*:)/i', $uri)) { - return false; - } - - return true; + return !\preg_match('/^([\/\#\?]|[a-z][a-z0-9+.-]*:)/i', $uri); } /** * Set a model collection loader. * * @param CollectionLoader $loader The collection loader. - * @return self */ - protected function setCollectionLoader(CollectionLoader $loader) + protected function setCollectionLoader(CollectionLoader $loader): static { $this->collectionLoader = $loader; @@ -1107,14 +1050,13 @@ protected function setCollectionLoader(CollectionLoader $loader) * Retrieve the model collection loader. * * @throws Exception If the collection loader was not previously set. - * @return CollectionLoader */ - public function collectionLoader() + public function collectionLoader(): \Charcoal\Loader\CollectionLoader { - if (!isset($this->collectionLoader)) { + if (!$this->collectionLoader instanceof \Charcoal\Loader\CollectionLoader) { throw new Exception(sprintf( 'Collection Loader is not defined for "%s"', - get_class($this) + static::class )); } diff --git a/packages/attachment/src/Charcoal/Attachment/Object/Category/Generic.php b/packages/attachment/src/Charcoal/Attachment/Object/Category/Generic.php index 0c8506862..304d3e3ec 100644 --- a/packages/attachment/src/Charcoal/Attachment/Object/Category/Generic.php +++ b/packages/attachment/src/Charcoal/Attachment/Object/Category/Generic.php @@ -1,5 +1,7 @@ name = $this->translator()->translation($name); @@ -42,10 +44,7 @@ public function name() return $this->name; } - /** - * @return array - */ - public function loadCategoryItems() + public function loadCategoryItems(): array { return []; } diff --git a/packages/attachment/src/Charcoal/Attachment/Object/Container.php b/packages/attachment/src/Charcoal/Attachment/Object/Container.php index ea282fdcb..1933d8edc 100644 --- a/packages/attachment/src/Charcoal/Attachment/Object/Container.php +++ b/packages/attachment/src/Charcoal/Attachment/Object/Container.php @@ -33,6 +33,7 @@ class Container extends Attachment implements * @param ServiceContainer $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(ServiceContainer $container) { parent::setDependencies($container); @@ -54,14 +55,10 @@ protected function setDependencies(ServiceContainer $container) public function attachments(...$args) { $attachables = $this->attachableObjects(); - $attachments = call_user_func_array([ $this, 'getAttachments' ], $args); + $attachments = call_user_func_array($this->getAttachments(...), $args); foreach ($attachments as $attachment) { - if (isset($attachables[$attachment->objType()])) { - $attachment->attachmentType = $attachables[$attachment->objType()]; - } else { - $attachment->attachmentType = []; - } + $attachment->attachmentType = ($attachables[$attachment->objType()] ?? []); } return $attachments; @@ -70,14 +67,14 @@ public function attachments(...$args) /** * Event called before _deleting_ the attachment. * - * @return boolean * @see Charcoal\Attachment\Traits\AttachmentAwareTrait::removeJoins * @see Charcoal\Source\StorableTrait::preDelete() For the "create" Event. */ - public function preDelete() + #[\Override] + public function preDelete(): bool { // Delete nested attachments - array_map(function ($attachment) { + array_map(function ($attachment): void { $attachment->delete(); }, $this->attachments()->values()); diff --git a/packages/attachment/src/Charcoal/Attachment/Object/Embed.php b/packages/attachment/src/Charcoal/Attachment/Object/Embed.php index 0c7aa2fc0..a3bb35988 100644 --- a/packages/attachment/src/Charcoal/Attachment/Object/Embed.php +++ b/packages/attachment/src/Charcoal/Attachment/Object/Embed.php @@ -1,5 +1,7 @@ generateThumbnail(); @@ -56,9 +54,9 @@ public function preSave() * * @see StorableTrait::preUpdate() For the "update" Event. * @param array $properties Optional. The list of properties to update. - * @return boolean */ - public function preUpdate(array $properties = null) + #[\Override] + public function preUpdate(?array $properties = null): bool { $this->generateThumbnail(); diff --git a/packages/attachment/src/Charcoal/Attachment/Object/Gallery.php b/packages/attachment/src/Charcoal/Attachment/Object/Gallery.php index f64628c1f..ab6bcd72f 100644 --- a/packages/attachment/src/Charcoal/Attachment/Object/Gallery.php +++ b/packages/attachment/src/Charcoal/Attachment/Object/Gallery.php @@ -21,10 +21,8 @@ class Gallery extends Container /** * Retrieve the container's attachments as rows containing columns. - * - * @return array */ - public function attachmentsAsRows() + public function attachmentsAsRows(): array { $rows = []; @@ -32,7 +30,7 @@ public function attachmentsAsRows() $rows = array_chunk($this->attachments()->values(), $this->numColumns); /** Map row content with useful front-end properties. */ - array_walk($rows, function (&$attachment, $index) { + array_walk($rows, function (&$attachment, $index): void { $attachment = [ 'columns' => $attachment, 'isFirst' => ($index === 0), @@ -45,10 +43,8 @@ public function attachmentsAsRows() /** * Retrieve the Bootstrap column width to be used in front-end templating. - * - * @return string */ - public function columnWidth() + public function columnWidth(): string { return (string)ceil(12 / $this->numColumns); } diff --git a/packages/attachment/src/Charcoal/Attachment/Object/Image.php b/packages/attachment/src/Charcoal/Attachment/Object/Image.php index 7af407710..f173e7117 100644 --- a/packages/attachment/src/Charcoal/Attachment/Object/Image.php +++ b/packages/attachment/src/Charcoal/Attachment/Object/Image.php @@ -14,6 +14,7 @@ class Image extends File * * @return string|null */ + #[\Override] public function src() { $src = $this->thumbnail(); @@ -31,9 +32,9 @@ public function src() * @todo Generate thumbnail from the main image (or not.). * @used-by StorableTrait::preSave() For the "create" Event. * @used-by StorableTrait::preUpdate() For the "update" Event. - * @return boolean */ - public function generateThumbnail() + #[\Override] + public function generateThumbnail(): bool { return true; } diff --git a/packages/attachment/src/Charcoal/Attachment/Object/Join.php b/packages/attachment/src/Charcoal/Attachment/Object/Join.php index be69ce330..a797cc864 100644 --- a/packages/attachment/src/Charcoal/Attachment/Object/Join.php +++ b/packages/attachment/src/Charcoal/Attachment/Object/Join.php @@ -112,14 +112,12 @@ class Join extends AbstractModel implements * * @var JoinInterface[]|null */ - private $hierarchy; + private ?array $hierarchy = null; /** * Store the factory instance. - * - * @var FactoryInterface */ - private $modelFactory; + private ?\Charcoal\Factory\FactoryInterface $modelFactory = null; /** * Set the model's dependencies. @@ -127,6 +125,7 @@ class Join extends AbstractModel implements * @param ServiceContainer $container Service container. * @return void */ + #[\Override] protected function setDependencies(ServiceContainer $container) { parent::setDependencies($container); @@ -234,9 +233,8 @@ public function getParent() * * @todo Add support for multiple masters. * @throws LogicException If the relationship is broken or incomplete. - * @return JoinInterface|null */ - public function getMaster() + public function getMaster(): ?\Charcoal\Attachment\Interfaces\JoinInterface { $hierarchy = $this->invertedHierarchy(); if (isset($hierarchy[0])) { @@ -250,10 +248,8 @@ public function getMaster() * Reset this relationship's hierarchy. * * The relationship's hierarchy can be rebuilt with {@see self::hierarchy()}. - * - * @return self */ - public function resetHierarchy() + public function resetHierarchy(): static { $this->hierarchy = null; @@ -265,7 +261,7 @@ public function resetHierarchy() * * @return JoinInterface[] */ - public function hierarchy() + public function hierarchy(): array { if ($this->hierarchy === null) { $hierarchy = []; @@ -287,7 +283,7 @@ public function hierarchy() * * @return JoinInterface[] */ - public function invertedHierarchy() + public function invertedHierarchy(): array { return array_reverse($this->hierarchy()); } @@ -295,16 +291,14 @@ public function invertedHierarchy() // Setters -// ============================================================================= - + // ============================================================================= /** * Set the source object type. * * @param string $type The object type identifier. * @throws InvalidArgumentException If provided argument is not of type 'string'. - * @return self */ - public function setObjectType($type) + public function setObjectType($type): static { if (!is_string($type)) { throw new InvalidArgumentException('Object type must be a string.'); @@ -320,9 +314,8 @@ public function setObjectType($type) * * @param mixed $id The object ID to join the attachment to. * @throws InvalidArgumentException If provided argument is not a string or numerical value. - * @return self */ - public function setObjectId($id) + public function setObjectId($id): static { if (!is_scalar($id)) { throw new InvalidArgumentException( @@ -340,9 +333,8 @@ public function setObjectId($id) * * @param mixed $id The object ID to attach. * @throws InvalidArgumentException If provided argument is not a string or numerical value. - * @return self */ - public function setAttachmentId($id) + public function setAttachmentId($id): static { if (!is_scalar($id)) { throw new InvalidArgumentException( @@ -360,9 +352,8 @@ public function setAttachmentId($id) * * @param mixed $id The group ID describing the relationship. * @throws InvalidArgumentException If provided argument is not a string. - * @return self */ - public function setGroup($id) + public function setGroup($id): static { if (!is_string($id)) { throw new InvalidArgumentException( @@ -383,9 +374,8 @@ public function setGroup($id) * * @param integer $position A position. * @throws InvalidArgumentException If the position is not an integer (or numeric integer string). - * @return self */ - public function setPosition($position) + public function setPosition($position): static { if ($position === null) { $this->position = null; @@ -407,11 +397,10 @@ public function setPosition($position) * Enable/Disable the relationship. * * @param boolean $active The active flag. - * @return self */ - public function setActive($active) + public function setActive($active): static { - $this->active = !!$active; + $this->active = (bool)$active; return $this; } @@ -420,9 +409,8 @@ public function setActive($active) * Set an model factory. * * @param FactoryInterface $factory The factory to create models. - * @return self */ - protected function setModelFactory(FactoryInterface $factory) + protected function setModelFactory(FactoryInterface $factory): static { $this->modelFactory = $factory; @@ -498,14 +486,13 @@ public function active() * Retrieve the model factory. * * @throws RuntimeException If the model factory is missing. - * @return FactoryInterface */ - public function modelFactory() + public function modelFactory(): \Charcoal\Factory\FactoryInterface { - if (!isset($this->modelFactory)) { + if (!$this->modelFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException(sprintf( 'Model Factory is not defined for [%s]', - get_class($this) + static::class )); } diff --git a/packages/attachment/src/Charcoal/Attachment/Object/Link.php b/packages/attachment/src/Charcoal/Attachment/Object/Link.php index 13b03ee17..f56ddd69c 100644 --- a/packages/attachment/src/Charcoal/Attachment/Object/Link.php +++ b/packages/attachment/src/Charcoal/Attachment/Object/Link.php @@ -1,5 +1,7 @@ setModelFactory($container['model/factory']); } - /** - * @return boolean - */ - public function interactive() + #[\Override] + public function interactive(): bool { return true; } /** * Retrieve the script's supported arguments. - * - * @return array */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'hard' => [ @@ -166,9 +165,8 @@ public function defaultArguments() * * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { unset($request); @@ -183,10 +181,8 @@ public function run(RequestInterface $request, ResponseInterface $response) /** * Execute the prime directive. - * - * @return self */ - public function start() + public function start(): static { $cli = $this->climate(); @@ -202,16 +198,13 @@ public function start() /** * Prune relationships of dead objects. - * - * @return self */ - protected function pruneRelationships() + protected function pruneRelationships(): static { - $cli = $this->climate(); - $ask = $this->interactive(); - $dry = $this->dryRun(); - $verb = $this->verbose(); - $mucho = ($dry || $verb); + $this->climate(); + $this->interactive(); + $this->dryRun(); + $this->verbose(); $attach = $this->modelFactory()->get(Attachment::class); $pivot = $this->modelFactory()->get(Join::class); @@ -227,7 +220,7 @@ protected function pruneRelationships() $sql = 'SELECT DISTINCT `%sourceType` FROM `%pivotTable`;'; $rows = $db->query(strtr($sql, $binds), PDO::FETCH_ASSOC); if ($rows->rowCount()) { - error_log(get_called_class() . '::' . __FUNCTION__); + error_log(static::class . '::' . __FUNCTION__); /** @todo Confirm each distinct source type */ @@ -305,10 +298,8 @@ protected function pruneRelationships() /** * Prune orphan attachments. - * - * @return self */ - protected function pruneAttachments() + protected function pruneAttachments(): static { $cli = $this->climate(); $ask = $this->interactive(); @@ -366,7 +357,7 @@ protected function pruneAttachments() $this->indent = str_repeat(' ', (($length * 2) + 4)); $prop = $attach->property($attach->key()); - if ($prop && preg_match('~\b\w+\((?\d+)\)~', $prop->sqlType(), $matches)) { + if ($prop && preg_match('~\b\w+\((?\d+)\)~', (string)$prop->sqlType(), $matches)) { $pad = (intval($matches['length']) + 5); } else { $pad = 20; @@ -396,8 +387,8 @@ protected function pruneAttachments() if ($ask) { $type = sprintf('[%s]', $obj->microType()); - $label = sprintf('#%1$s %2$s', str_pad($objId, $pad), str_pad($type, 20)); - if ($title) { + $label = sprintf('#%1$s %2$s', str_pad((string)$objId, $pad), str_pad($type, 20)); + if ($title !== '' && $title !== '0') { $label = sprintf('%1$s "%2$s"', $label, $title); } @@ -506,10 +497,8 @@ protected function pruneAttachments() /** * Display stored messages or a generic conclusion. - * - * @return self */ - protected function conclude() + protected function conclude(): static { $cli = $this->climate(); @@ -531,15 +520,14 @@ protected function conclude() * @param string $singular The message when the count is 1. * @param string $zero The message when the count is zero. * @throws InvalidArgumentException If the given argument is not an integer. - * @return boolean */ - protected function describeCount($count, $plural, $singular, $zero) + protected function describeCount($count, $plural, $singular, $zero): bool { if (!is_int($count)) { throw new InvalidArgumentException( sprintf( 'Must be an integer', - is_object($count) ? get_class($count) : gettype($count) + get_debug_type($count) ) ); } @@ -573,9 +561,8 @@ protected function describeCount($count, $plural, $singular, $zero) * @param integer|null $pruned Count the number of deleted objects. * @param integer|null $failed Count the number of failed deletions. * @param array|null $feedback Update the feedback. - * @return boolean */ - protected function deleteObject(AttachableInterface $obj, &$pruned = null, &$failed = null, array &$feedback = null) + protected function deleteObject(AttachableInterface $obj, &$pruned = null, &$failed = null, ?array &$feedback = null): bool { $verb = $this->verbose(); diff --git a/packages/attachment/src/Charcoal/Attachment/Script/MigrateScript.php b/packages/attachment/src/Charcoal/Attachment/Script/MigrateScript.php index ab745426b..0757de3c7 100644 --- a/packages/attachment/src/Charcoal/Attachment/Script/MigrateScript.php +++ b/packages/attachment/src/Charcoal/Attachment/Script/MigrateScript.php @@ -31,6 +31,7 @@ class MigrateScript extends AlterPrimaryKeyScript /** * @return void */ + #[\Override] protected function init() { $this->setArguments($this->defaultArguments()); @@ -44,10 +45,9 @@ protected function init() /** * Execute the prime directive. - * - * @return self */ - public function start() + #[\Override] + public function start(): static { $cli = $this->climate(); @@ -166,7 +166,6 @@ public function start() // Alter Table // ========================================================================= - /** * Sync the new primary keys to pivot table. * @@ -175,14 +174,14 @@ public function start() * @param IdProperty $oldProp The previous ID property. * @param PropertyField $oldField The previous ID field. * @throws InvalidArgumentException If the new property does not implement the proper mode. - * @return self */ + #[\Override] protected function syncRelatedFields( IdProperty $newProp, PropertyField $newField, IdProperty $oldProp, PropertyField $oldField - ) { + ): static { unset($newProp, $oldProp, $oldField); $cli = $this->climate(); @@ -243,6 +242,7 @@ protected function syncRelatedFields( * * @return array */ + #[\Override] public function defaultArguments() { static $arguments; @@ -267,9 +267,10 @@ public function defaultArguments() * * @return ModelInterface */ + #[\Override] public function targetModel() { - if (!isset($this->targetModel)) { + if ($this->targetModel === null) { $this->targetModel = $this->modelFactory()->get(Attachment::class); } @@ -283,7 +284,7 @@ public function targetModel() */ public function pivotModel() { - if (!isset($this->pivotModel)) { + if ($this->pivotModel === null) { $this->pivotModel = $this->modelFactory()->get(Join::class); } diff --git a/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentAwareTrait.php b/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentAwareTrait.php index 29c269507..6a8a714b6 100644 --- a/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentAwareTrait.php +++ b/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentAwareTrait.php @@ -57,8 +57,8 @@ trait AttachmentAwareTrait public function getAttachments( $group = null, $type = null, - callable $before = null, - callable $after = null + ?callable $before = null, + ?callable $after = null ) { if (is_array($group)) { $options = $group; @@ -81,23 +81,20 @@ public function getAttachments( $options = $this->parseAttachmentOptions($options); extract($options); - if ($group !== 0) { - if (!is_string($group)) { - throw new InvalidArgumentException(sprintf( - 'The "group" must be a string, received %s', - is_object($group) ? get_class($group) : gettype($group) - )); - } + if ($group !== 0 && !is_string($group)) { + throw new InvalidArgumentException(sprintf( + 'The "group" must be a string, received %s', + get_debug_type($group) + )); } if ($type !== 0) { if (!is_string($type)) { throw new InvalidArgumentException(sprintf( 'The "type" must be a string, received %s', - is_object($type) ? get_class($type) : gettype($type) + get_debug_type($type) )); } - $type = preg_replace('/([a-z])([A-Z])/', '$1-$2', $type); $type = strtolower(str_replace('\\', '/', $type)); } @@ -140,7 +137,7 @@ public function getAttachments( attachment.active = 1'; } - if ($type) { + if ($type !== '' && $type !== 0) { $query .= sprintf(' AND attachment.type = "%s"', $type); @@ -152,7 +149,7 @@ public function getAttachments( AND joined.object_id = "%s"', $objType, $objId); - if ($group) { + if ($group !== '' && $group !== 0) { $query .= sprintf(' AND joined.group = "%s"', $group); @@ -165,7 +162,7 @@ public function getAttachments( $loader->setModel($attProto); $loader->setDynamicTypeField('type'); - $callable = function (&$att) use ($before) { + $callable = function (&$att) use ($before): void { if ($this instanceof AttachableInterface) { $att->setContainerObj($this); } @@ -194,17 +191,15 @@ public function getAttachments( * * @return boolean Whether $this has any nodes (TRUE) or not (FALSE). */ - public function hasAttachments() + public function hasAttachments(): bool { - return !!($this->numAttachments()); + return (bool)$this->numAttachments(); } /** * Count the number of nodes associated to the current object. - * - * @return integer */ - public function numAttachments() + public function numAttachments(): int { return count($this->getAttachments([ 'group' => null @@ -243,9 +238,9 @@ public function addAttachment($attachment, $group = 'contents') /** * Remove all joins linked to a specific attachment. * - * @deprecated in favour of AttachmentAwareTrait::removeAttachmentJoins() * @return boolean */ + #[\Deprecated(message: 'in favour of AttachmentAwareTrait::removeAttachmentJoins()')] public function removeJoins() { $this->logger->warning( @@ -259,10 +254,8 @@ public function removeJoins() /** * Remove all joins linked to a specific attachment. - * - * @return boolean */ - public function removeAttachmentJoins() + public function removeAttachmentJoins(): bool { $joinProto = $this->modelFactory()->get(Join::class); @@ -285,9 +278,8 @@ public function removeAttachmentJoins() * Delete the objects associated to the current object. * * @param array $options Filter the attachments by an option list. - * @return boolean */ - public function deleteAttachments(array $options = []) + public function deleteAttachments(array $options = []): bool { foreach ($this->getAttachments($options) as $attachment) { $attachment->delete(); @@ -310,7 +302,7 @@ public function deleteAttachments(array $options = []) * ] * @return array Attachment obj_types. */ - public function attachmentObjTypes() + public function attachmentObjTypes(): array { $defaultEditDashboard = $this->metadata()->get('admin.default_edit_dashboard'); $dashboards = $this->metadata()->get('admin.dashboards'); @@ -318,7 +310,7 @@ public function attachmentObjTypes() $widgets = $editDashboard['widgets']; $formIdent = ''; - foreach ($widgets as $ident => $val) { + foreach ($widgets as $val) { if ($val['type'] == 'charcoal/admin/widget/object-form') { $formIdent = $val['form_ident']; } @@ -364,17 +356,15 @@ public function attachmentObjTypes() * @param array $options A list of options. * Option keys not present in {@see self::getDefaultAttachmentOptions() default options} * are rejected. - * @return array */ - protected function parseAttachmentOptions(array $options) + protected function parseAttachmentOptions(array $options): array { $defaults = $this->getDefaultAttachmentOptions(); $options = array_intersect_key($options, $defaults); $options = array_filter($options, [ $this, 'filterAttachmentOption' ], ARRAY_FILTER_USE_BOTH); - $options = array_replace($defaults, $options); - return $options; + return array_replace($defaults, $options); } /** @@ -389,25 +379,17 @@ protected function filterAttachmentOption($val, $key) if ($val === null) { return false; } - - switch ($key) { - case 'isActive': - return is_bool($val); - - case 'before': - case 'after': - return is_callable($val); - } - - return true; + return match ($key) { + 'isActive' => is_bool($val), + 'before', 'after' => is_callable($val), + default => true, + }; } /** * Retrieve the default options for loading a collection of attachments. - * - * @return array */ - protected function getDefaultAttachmentOptions() + protected function getDefaultAttachmentOptions(): array { return [ 'group' => 0, diff --git a/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentContainerTrait.php b/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentContainerTrait.php index d3b6250c3..51296ffc0 100644 --- a/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentContainerTrait.php +++ b/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentContainerTrait.php @@ -126,10 +126,8 @@ public function attachmentGroup() /** * Retrieve the attachment types with their collections. - * - * @return array */ - public function attachmentTypes() + public function attachmentTypes(): array { return array_values($this->attachableObjects()); } @@ -165,7 +163,7 @@ public function attachableObjects() if (isset($attMeta['label'])) { $attMeta['label'] = $this->translator()->translation($attMeta['label']); } else { - $attMeta['label'] = ucfirst(basename($attType)); + $attMeta['label'] = ucfirst(basename((string)$attType)); } $faIcon = ''; @@ -174,20 +172,12 @@ public function attachableObjects() } $attMeta['faIcon'] = $faIcon; - $attMeta['hasFaIcon'] = !!$faIcon; + $attMeta['hasFaIcon'] = (bool)$faIcon; // Custom forms - if (isset($attMeta['form_ident'])) { - $attMeta['formIdent'] = $attMeta['form_ident']; - } else { - $attMeta['formIdent'] = null; - } + $attMeta['formIdent'] = ($attMeta['form_ident'] ?? null); - if (isset($attMeta['quick_form_ident'])) { - $attMeta['quickFormIdent'] = $attMeta['quick_form_ident']; - } else { - $attMeta['quickFormIdent'] = null; - } + $attMeta['quickFormIdent'] = ($attMeta['quick_form_ident'] ?? null); $this->attachableObjects[$attType] = $attMeta; } @@ -199,10 +189,8 @@ public function attachableObjects() /** * Determine if this attachment is a container. - * - * @return boolean */ - public function isAttachmentContainer() + public function isAttachmentContainer(): bool { return true; } diff --git a/packages/attachment/src/Charcoal/Attachment/Traits/ConfigurableAttachmentsTrait.php b/packages/attachment/src/Charcoal/Attachment/Traits/ConfigurableAttachmentsTrait.php index f5455b41c..b6d5fcfbe 100644 --- a/packages/attachment/src/Charcoal/Attachment/Traits/ConfigurableAttachmentsTrait.php +++ b/packages/attachment/src/Charcoal/Attachment/Traits/ConfigurableAttachmentsTrait.php @@ -76,7 +76,7 @@ public function config($key = null) * @param array|null $data Optional data to pass to the new configset. * @return ConfigInterface */ - protected function createConfig($data = null) + protected function createConfig($data = null): \Charcoal\Attachment\AttachmentsConfig { return new AttachmentsConfig($data); } diff --git a/packages/attachment/tests/Charcoal/ContainerIntegrationTrait.php b/packages/attachment/tests/Charcoal/ContainerIntegrationTrait.php index 4ad02d1c1..0f4c9eaa5 100644 --- a/packages/attachment/tests/Charcoal/ContainerIntegrationTrait.php +++ b/packages/attachment/tests/Charcoal/ContainerIntegrationTrait.php @@ -51,9 +51,8 @@ protected function getContainerProvider() /** * @see ContainerProvider - * @return void */ - private function setupContainer() + private function setupContainer(): void { $provider = new ContainerProvider(); $container = new Container(); diff --git a/packages/attachment/tests/Charcoal/ContainerProvider.php b/packages/attachment/tests/Charcoal/ContainerProvider.php index 1cacbbbd7..b192e8772 100644 --- a/packages/attachment/tests/Charcoal/ContainerProvider.php +++ b/packages/attachment/tests/Charcoal/ContainerProvider.php @@ -55,9 +55,8 @@ class ContainerProvider * Register the unit tests required services. * * @param Container $container A DI container. - * @return void */ - public function registerBaseServices(Container $container) + public function registerBaseServices(Container $container): void { $this->registerConfig($container); $this->registerDatabase($container); @@ -69,9 +68,8 @@ public function registerBaseServices(Container $container) * Register the admin services. * * @param Container $container A DI container. - * @return void */ - public function registerAdminServices(Container $container) + public function registerAdminServices(Container $container): void { $this->registerBaseUrl($container); $this->registerAdminConfig($container); @@ -81,67 +79,57 @@ public function registerAdminServices(Container $container) * Setup the application's base URI. * * @param Container $container A DI container. - * @return void */ - public function registerBaseUrl(Container $container) + public function registerBaseUrl(Container $container): void { - $container['base-url'] = function () { - return Uri::createFromString(''); - }; + $container['base-url'] = (fn() => Uri::createFromString('')); - $container['admin/base-url'] = function () { - return Uri::createFromString('admin'); - }; + $container['admin/base-url'] = (fn() => Uri::createFromString('admin')); } /** * Setup the application configset. * * @param Container $container A DI container. - * @return void */ - public function registerConfig(Container $container) + public function registerConfig(Container $container): void { - $container['config'] = function () { - return new AppConfig([ - 'base_path' => realpath(__DIR__ . '/../../..'), - 'apis' => [ - 'google' => [ - 'recaptcha' => [ - 'public_key' => 'foobar', - 'private_key' => 'bazqux', - ], - ], - ], - 'locales' => [ - 'en' => [ - 'locale' => 'en-US', + $container['config'] = (fn(): \Charcoal\App\AppConfig => new AppConfig([ + 'base_path' => realpath(__DIR__ . '/../../..'), + 'apis' => [ + 'google' => [ + 'recaptcha' => [ + 'public_key' => 'foobar', + 'private_key' => 'bazqux', ], ], - 'translator' => [ - 'paths' => [], + ], + 'locales' => [ + 'en' => [ + 'locale' => 'en-US', ], - 'metadata' => [ - 'paths' => [ - 'metadata', - // Standalone - 'vendor/charcoal/object/metadata', - 'vendor/charcoal/user/metadata', - // Monorepo - '/../object/metadata', - '/../user/metadata', - ], + ], + 'translator' => [ + 'paths' => [], + ], + 'metadata' => [ + 'paths' => [ + 'metadata', + // Standalone + 'vendor/charcoal/object/metadata', + 'vendor/charcoal/user/metadata', + // Monorepo + '/../object/metadata', + '/../user/metadata', ], - ]); - }; + ], + ])); /** * List of Charcoal module classes. * * Explicitly defined in case of a version mismatch with dependencies. This parameter * is normally defined by {@see \Charcoal\App\ServiceProvider\AppServiceProvider}. - * - * @var array */ $container['module/classes'] = []; } @@ -150,22 +138,18 @@ public function registerConfig(Container $container) * Setup the admin module configset. * * @param Container $container A DI container. - * @return void */ - public function registerAdminConfig(Container $container) + public function registerAdminConfig(Container $container): void { $this->registerConfig($container); - $container['admin/config'] = function () { - return new AdminConfig(); - }; + $container['admin/config'] = (fn(): \Charcoal\Admin\Config => new AdminConfig()); } /** * @param Container $container A DI container. - * @return void */ - public function registerClimate(Container $container) + public function registerClimate(Container $container): void { $container['climate/system'] = function () { $system = Mockery::mock(Linux::class); @@ -192,11 +176,9 @@ public function registerClimate(Container $container) return $reader; }; - $container['climate/util'] = function (Container $container) { - return new UtilFactory($container['climate/system']); - }; + $container['climate/util'] = (fn(Container $container): \League\CLImate\Util\UtilFactory => new UtilFactory($container['climate/system'])); - $container['climate'] = function (Container $container) { + $container['climate'] = function (Container $container): \League\CLImate\CLImate { $climate = new CLImate(); $climate->setOutput($container['climate/output']); @@ -209,11 +191,10 @@ public function registerClimate(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerDatabase(Container $container) + public function registerDatabase(Container $container): void { - $container['database'] = function () { + $container['database'] = function (): \PDO { $pdo = new PDO('sqlite::memory:'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; @@ -222,9 +203,8 @@ public function registerDatabase(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerModelServiceProvider(Container $container) + public function registerModelServiceProvider(Container $container): void { static $provider = null; @@ -237,9 +217,8 @@ public function registerModelServiceProvider(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerAuthServiceProvider(Container $container) + public function registerAuthServiceProvider(Container $container): void { static $provider = null; @@ -252,9 +231,8 @@ public function registerAuthServiceProvider(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerTranslatorServiceProvider(Container $container) + public function registerTranslatorServiceProvider(Container $container): void { static $provider = null; @@ -267,9 +245,8 @@ public function registerTranslatorServiceProvider(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerViewServiceProvider(Container $container) + public function registerViewServiceProvider(Container $container): void { static $provider = null; @@ -282,9 +259,8 @@ public function registerViewServiceProvider(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerAdminServiceProvider(Container $container) + public function registerAdminServiceProvider(Container $container): void { static $provider = null; @@ -297,23 +273,17 @@ public function registerAdminServiceProvider(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerLogger(Container $container) + public function registerLogger(Container $container): void { - $container['logger'] = function () { - return new NullLogger(); - }; + $container['logger'] = (fn(): \Psr\Log\NullLogger => new NullLogger()); } /** * @param Container $container A DI container. - * @return void */ - public function registerCache(Container $container) + public function registerCache(Container $container): void { - $container['cache'] = function () { - return new Pool(); - }; + $container['cache'] = (fn(): \Stash\Pool => new Pool()); } } diff --git a/packages/attachment/tests/bootstrap.php b/packages/attachment/tests/bootstrap.php new file mode 100644 index 000000000..90929e3b5 --- /dev/null +++ b/packages/attachment/tests/bootstrap.php @@ -0,0 +1,14 @@ + - -> + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/cache/src/Charcoal/Cache/CacheBuilder.php b/packages/cache/src/Charcoal/Cache/CacheBuilder.php index a8b2123fa..ef099014d 100644 --- a/packages/cache/src/Charcoal/Cache/CacheBuilder.php +++ b/packages/cache/src/Charcoal/Cache/CacheBuilder.php @@ -27,31 +27,23 @@ final class CacheBuilder /** * Default logger instance. - * - * @var \Psr\Log\LoggerInterface|null */ - private $logger; + private ?\Psr\Log\LoggerInterface $logger = null; /** * Default namespace for new pools. - * - * @var string|null */ - private $namespace; + private ?string $namespace = null; /** * Default "Pool" class to use for making new pools. - * - * @var string */ - private $poolClass = Pool::class; + private string $poolClass = Pool::class; /** * Default "Item" class to use for making new items. - * - * @var string|null */ - private $itemClass; + private ?string $itemClass = null; /** * Create a cache pool builder. @@ -88,7 +80,7 @@ public function __construct(array $data) * @param mixed $poolOptions Optional settings for the new pool. * @return PoolInterface */ - public function __invoke($cacheDriver, $poolOptions = null) + public function __invoke($cacheDriver, $poolOptions = null): object { return $this->build($cacheDriver, $poolOptions); } @@ -105,7 +97,7 @@ public function __invoke($cacheDriver, $poolOptions = null) * Otherwise, the default settings are used. * @return PoolInterface */ - public function build($cacheDriver, $poolOptions = null) + public function build($cacheDriver, $poolOptions = null): object { if (!($cacheDriver instanceof DriverInterface)) { $cacheDriver = $this->resolveDriver($cacheDriver); @@ -123,9 +115,8 @@ public function build($cacheDriver, $poolOptions = null) * Prepare any pool options for the new pool object. * * @param mixed $options Settings for the new pool. - * @return array */ - private function parsePoolOptions($options) + private function parsePoolOptions($options): array { $defaults = [ 'pool_class' => $this->poolClass, @@ -156,9 +147,8 @@ private function parsePoolOptions($options) * * @param PoolInterface $pool The new pool. * @param array $options Settings for the new pool. - * @return void */ - private function applyPoolOptions(PoolInterface $pool, array $options) + private function applyPoolOptions(PoolInterface $pool, array $options): void { if (isset($options['logger'])) { $pool->setLogger($options['logger']); @@ -188,7 +178,7 @@ private function resolveDriver($driver) foreach ($driver as $drv) { try { return $this->resolveOneDriver($drv); - } catch (InvalidArgumentException $e) { + } catch (InvalidArgumentException) { continue; } } @@ -223,7 +213,7 @@ private function resolveOneDriver($driver) } else { throw new InvalidArgumentException(sprintf( 'Driver class %s must implement %s', - get_class($driver), + $driver::class, DriverInterface::class )); } @@ -246,7 +236,7 @@ private function resolveOneDriver($driver) throw new InvalidArgumentException(sprintf( 'Driver "%s": Class %s must implement %s', $name, - get_class($driver), + $driver::class, DriverInterface::class )); } @@ -267,9 +257,8 @@ private function resolveOneDriver($driver) * * @param ArrayAccess|array $drivers The driver list used to create cache drivers. * @throws InvalidArgumentException If the drivers list is invalid. - * @return void */ - private function setDrivers($drivers) + private function setDrivers($drivers): void { if ($this->isAccessible($drivers)) { $this->drivers = $drivers; @@ -285,12 +274,11 @@ private function setDrivers($drivers) * * @param \Psr\Log\LoggerInterface $logger A PSR-3 logger. * @throws InvalidArgumentException If the logger is invalid PSR-3 client. - * @return void */ - private function setLogger($logger) + private function setLogger($logger): void { - $psr = 'Psr\\Log\\LoggerInterface'; - if (!is_a($logger, $psr)) { + $psr = \Psr\Log\LoggerInterface::class; + if (!$logger instanceof $psr) { throw new InvalidArgumentException( sprintf('Expected an instance of %s', $psr) ); @@ -306,9 +294,8 @@ private function setLogger($logger) * * @param string $namespace The pool namespace. * @throws InvalidArgumentException If the namespaces is invalid. - * @return void */ - private function setNamespace($namespace) + private function setNamespace($namespace): void { if (!ctype_alnum($namespace)) { throw new InvalidArgumentException( @@ -326,9 +313,8 @@ private function setNamespace($namespace) * * @param string $class The pool class name. * @throws InvalidArgumentException When passed an invalid or nonexistant class. - * @return void */ - private function setPoolClass($class) + private function setPoolClass($class): void { if (!class_exists($class)) { throw new InvalidArgumentException( @@ -356,9 +342,8 @@ private function setPoolClass($class) * * @param string $class The item class name. * @throws InvalidArgumentException When passed an invalid or nonexistant class. - * @return void */ - private function setItemClass($class) + private function setItemClass($class): void { if (!class_exists($class)) { throw new InvalidArgumentException( @@ -385,9 +370,9 @@ private function setItemClass($class) * @param mixed $var The value to check * @return boolean TRUE if $var is iterable, FALSE otherwise. */ - private function isIterable($var) + private function isIterable($var): bool { - return is_array($var) || ($var instanceof Traversable); + return is_iterable($var); } /** @@ -396,7 +381,7 @@ private function isIterable($var) * @param mixed $var The value to check * @return boolean TRUE if $var is an array or accessible like an array, FALSE otherwise. */ - private function isAccessible($var) + private function isAccessible($var): bool { return is_array($var) || ($var instanceof ArrayAccess); } diff --git a/packages/cache/src/Charcoal/Cache/CacheConfig.php b/packages/cache/src/Charcoal/Cache/CacheConfig.php index 041df2bc9..6712684f8 100644 --- a/packages/cache/src/Charcoal/Cache/CacheConfig.php +++ b/packages/cache/src/Charcoal/Cache/CacheConfig.php @@ -33,40 +33,31 @@ class CacheConfig extends AbstractConfig * Note: * - When TRUE, the {@see self::$types} are used. * - When FALSE, the "memory" type is used. - * - * @var boolean */ - private $active = true; + private bool $active = true; /** * Cache type(s) to use. * * Represents a cache driver. - * - * @var array */ - private $types; + private ?array $types = null; /** * Default maximum time an item will be cached. - * - * @var integer */ - private $defaultTtl = self::WEEK_IN_SECONDS; + private int $defaultTtl = self::WEEK_IN_SECONDS; /** * Cache namespace. - * - * @var string */ - private $prefix = self::DEFAULT_NAMESPACE; + private string $prefix = self::DEFAULT_NAMESPACE; /** * Retrieve the default values. - * - * @return array */ - public function defaults() + #[\Override] + public function defaults(): array { return [ 'active' => true, @@ -83,9 +74,9 @@ public function defaults() * TRUE to enable, FALSE to disable. * @return CacheConfig Chainable */ - public function setActive($active) + public function setActive($active): static { - $this->active = !!$active; + $this->active = (bool)$active; return $this; } @@ -94,7 +85,7 @@ public function setActive($active) * * @return boolean TRUE if enabled, FALSE if disabled. */ - public function active() + public function active(): bool { return $this->active; } @@ -107,7 +98,7 @@ public function active() * @param string[] $types One or more types to try as cache driver until success. * @return CacheConfig Chainable */ - public function setTypes(array $types) + public function setTypes(array $types): static { $this->types = []; $this->addTypes($types); @@ -120,7 +111,7 @@ public function setTypes(array $types) * @param string[] $types One or more types to try as cache driver until success. * @return CacheConfig Chainable */ - public function addTypes(array $types) + public function addTypes(array $types): static { foreach ($types as $type) { $this->addType($type); @@ -135,7 +126,7 @@ public function addTypes(array $types) * @throws InvalidArgumentException If the type is not a string or unsupported. * @return CacheConfig Chainable */ - public function addType($type) + public function addType($type): static { if (!in_array($type, $this->validTypes())) { throw new InvalidArgumentException( @@ -153,10 +144,8 @@ public function addType($type) * Note: * 1. The default cache type is always appended. * 2. Duplicate types are removed. - * - * @return array */ - public function types() + public function types(): array { $types = ($this->types + self::DEFAULT_TYPES); return array_keys($types); @@ -167,7 +156,7 @@ public function types() * * @return string[] */ - public function defaultTypes() + public function defaultTypes(): array { return array_keys(self::DEFAULT_TYPES); } @@ -177,7 +166,7 @@ public function defaultTypes() * * @return string[] */ - public function validTypes() + public function validTypes(): array { return [ 'apc', @@ -197,7 +186,7 @@ public function validTypes() * @throws InvalidArgumentException If the TTL is not numeric. * @return CacheConfig Chainable */ - public function setDefaultTtl($ttl) + public function setDefaultTtl($ttl): static { if (!is_numeric($ttl)) { throw new InvalidArgumentException( @@ -211,10 +200,8 @@ public function setDefaultTtl($ttl) /** * Retrieve the default time-to-live for cached items. - * - * @return integer */ - public function defaultTtl() + public function defaultTtl(): int { return $this->defaultTtl; } @@ -226,7 +213,7 @@ public function defaultTtl() * @throws InvalidArgumentException If the prefix is not a string. * @return CacheConfig Chainable */ - public function setPrefix($prefix) + public function setPrefix($prefix): static { if (!is_string($prefix)) { throw new InvalidArgumentException( @@ -247,10 +234,8 @@ public function setPrefix($prefix) /** * Retrieve the cache namespace. - * - * @return string */ - public function prefix() + public function prefix(): string { return $this->prefix; } diff --git a/packages/cache/src/Charcoal/Cache/CachePoolAwareTrait.php b/packages/cache/src/Charcoal/Cache/CachePoolAwareTrait.php index 644d47dd7..e2039c0af 100644 --- a/packages/cache/src/Charcoal/Cache/CachePoolAwareTrait.php +++ b/packages/cache/src/Charcoal/Cache/CachePoolAwareTrait.php @@ -41,7 +41,7 @@ protected function cachePool() if ($this->cachePool === null) { throw new RuntimeException(sprintf( 'Cache Pool is not defined for "%s"', - get_class($this) + $this::class )); } diff --git a/packages/cache/src/Charcoal/Cache/Facade/CachePoolFacade.php b/packages/cache/src/Charcoal/Cache/Facade/CachePoolFacade.php index b053e8368..81878f734 100644 --- a/packages/cache/src/Charcoal/Cache/Facade/CachePoolFacade.php +++ b/packages/cache/src/Charcoal/Cache/Facade/CachePoolFacade.php @@ -61,7 +61,7 @@ public function __construct(array $data) * @param mixed $ttl An integer, interval, date, or NULL to use the facade's default value. * @return mixed The value corresponding to this cache item's $key, or NULL if not found. */ - public function get($key, callable $resolve = null, $ttl = null) + public function get(string $key, ?callable $resolve = null, $ttl = null) { $pool = $this->cachePool(); $item = $pool->getItem($key); @@ -86,7 +86,7 @@ public function get($key, callable $resolve = null, $ttl = null) * @param string $key The key for which to check existence. * @return boolean TRUE if item exists in the cache, FALSE otherwise. */ - public function has($key) + public function has(string $key) { return $this->cachePool()->getItem($key)->isHit(); } @@ -99,7 +99,7 @@ public function has($key) * @param mixed $ttl An integer, interval, date, or NULL to use the facade's default value. * @return boolean TRUE if the item was successfully persisted. FALSE if there was an error. */ - public function set($key, $value, $ttl = null) + public function set(string $key, $value, $ttl = null) { $item = $this->cachePool()->getItem($key); @@ -163,9 +163,8 @@ public function defaultTtl() * Set the facade's default time-to-live for cached items. * * @param mixed $ttl An integer, date interval, or date. - * @return void */ - public function setDefaultTtl($ttl) + public function setDefaultTtl($ttl): void { $this->defaultTtl = $ttl; } diff --git a/packages/cache/src/Charcoal/Cache/Middleware/CacheMiddleware.php b/packages/cache/src/Charcoal/Cache/Middleware/CacheMiddleware.php index 1c94a670c..a85b6f8e6 100644 --- a/packages/cache/src/Charcoal/Cache/Middleware/CacheMiddleware.php +++ b/packages/cache/src/Charcoal/Cache/Middleware/CacheMiddleware.php @@ -44,14 +44,14 @@ class CacheMiddleware * * @var string[] */ - private $methods; + private readonly array $methods; /** * Cache response if the request matches one of the HTTP status codes. * * @var integer[] */ - private $statusCodes; + private readonly array $statusCodes; /** * Time-to-live in seconds. @@ -142,10 +142,8 @@ public function __construct(array $data) /** * Default middleware options. - * - * @return array */ - public function defaults() + public function defaults(): array { return [ 'ttl' => CacheConfig::DAY_IN_SECONDS, @@ -191,7 +189,7 @@ public function __invoke(RequestInterface $request, ResponseInterface $response, return $next($request, $response); } - if ($this->isSkipCache($request)) { + if ($this->isSkipCache()) { return $next($request, $response); } @@ -230,7 +228,7 @@ public function __invoke(RequestInterface $request, ResponseInterface $response, if (!$this->isQueryIncluded($query)) { $queryArr = $this->parseIgnoredParams($query); - if (!empty($queryArr)) { + if ($queryArr !== []) { return $this->disableCacheHeadersOnResponse($response); } } @@ -286,20 +284,16 @@ private function cacheKeyFromRequest(RequestInterface $request) * Determine if the HTTP request method matches the accepted choices. * * @param RequestInterface $request The PSR-7 HTTP request. - * @return boolean */ - private function isRequestMethodValid(RequestInterface $request) + private function isRequestMethodValid(RequestInterface $request): bool { return in_array($request->getMethod(), $this->methods); } /** * Determine if the HTTP request method matches the accepted choices. - * - * @param RequestInterface $request The PSR-7 HTTP request. - * @return boolean */ - private function isSkipCache(RequestInterface $request) + private function isSkipCache(): bool { if (isset($this->skipCache['session_vars'])) { $skip = $this->skipCache['session_vars']; @@ -315,7 +309,6 @@ private function isSkipCache(RequestInterface $request) } } } - return false; } @@ -323,9 +316,8 @@ private function isSkipCache(RequestInterface $request) * Determine if the HTTP response status matches the accepted choices. * * @param ResponseInterface $response The PSR-7 HTTP response. - * @return boolean */ - private function isResponseStatusValid(ResponseInterface $response) + private function isResponseStatusValid(ResponseInterface $response): bool { return in_array($response->getStatusCode(), $this->statusCodes); } @@ -334,9 +326,8 @@ private function isResponseStatusValid(ResponseInterface $response) * Determine if the request should be cached based on the URI path. * * @param string $path The request path (route) to verify. - * @return boolean */ - private function isPathIncluded($path) + private function isPathIncluded($path): bool { if ($this->includedPath === '*') { return true; @@ -345,23 +336,22 @@ private function isPathIncluded($path) if (empty($this->includedPath) && !is_numeric($this->includedPath)) { return false; } - + $found = false; foreach ((array)$this->includedPath as $included) { if (preg_match('@' . $included . '@', $path)) { - return true; + $found = true; + break; } } - - return false; + return $found; } /** * Determine if the request should NOT be cached based on the URI path. * * @param string $path The request path (route) to verify. - * @return boolean */ - private function isPathExcluded($path) + private function isPathExcluded($path): bool { if ($this->excludedPath === '*') { return true; @@ -370,14 +360,14 @@ private function isPathExcluded($path) if (empty($this->excludedPath) && !is_numeric($this->excludedPath)) { return false; } - + $found = false; foreach ((array)$this->excludedPath as $excluded) { if (preg_match('@' . $excluded . '@', $path)) { - return true; + $found = true; + break; } } - - return false; + return $found; } /** @@ -388,7 +378,7 @@ private function isPathExcluded($path) */ private function isQueryIncluded(array $queryParams) { - if (empty($queryParams)) { + if ($queryParams === []) { return true; } @@ -412,7 +402,7 @@ private function isQueryIncluded(array $queryParams) */ private function isQueryExcluded(array $queryParams) { - if (empty($queryParams)) { + if ($queryParams === []) { return false; } @@ -432,11 +422,10 @@ private function isQueryExcluded(array $queryParams) * Returns the query parameters that are NOT ignored. * * @param array $queryParams The query parameters to filter. - * @return array */ - private function parseIgnoredParams(array $queryParams) + private function parseIgnoredParams(array $queryParams): array { - if (empty($queryParams)) { + if ($queryParams === []) { return $queryParams; } @@ -479,9 +468,8 @@ private function disableCacheHeadersOnResponse(ResponseInterface $response) /** * @param Closure|null $processCacheKeyCallback ProcessCacheKeyCallback for CacheMiddleware. - * @return self */ - public function setProcessCacheKeyCallback($processCacheKeyCallback) + public function setProcessCacheKeyCallback($processCacheKeyCallback): static { $this->processCacheKeyCallback = $processCacheKeyCallback; diff --git a/packages/cache/src/Charcoal/Cache/ServiceProvider/CacheServiceProvider.php b/packages/cache/src/Charcoal/Cache/ServiceProvider/CacheServiceProvider.php index 9070ee892..708a4b04b 100644 --- a/packages/cache/src/Charcoal/Cache/ServiceProvider/CacheServiceProvider.php +++ b/packages/cache/src/Charcoal/Cache/ServiceProvider/CacheServiceProvider.php @@ -44,9 +44,8 @@ class CacheServiceProvider implements ServiceProviderInterface { /** * @param Container $container A container instance. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { $this->registerDrivers($container); $this->registerService($container); @@ -55,14 +54,11 @@ public function register(Container $container) /** * @param Container $container A container instance. - * @return void */ - public function registerDrivers(Container $container) + public function registerDrivers(Container $container): void { /** * The collection of cache drivers that are supported by this system. - * - * @var array An associative array structured as `"Driver Name" => "Class Name"`. */ $container['cache/available-drivers'] = DriverList::getAvailableDrivers(); @@ -72,14 +68,14 @@ public function registerDrivers(Container $container) * @param Container $container The service container. * @return Container Service container of cache drivers from Stash. */ - $container['cache/drivers'] = function (Container $container) { + $container['cache/drivers'] = function (Container $container): \Pimple\Container { $drivers = new Container(); /** * @param Container $container The service container. * @return \Stash\Driver\Apc|null */ - $drivers['apc'] = function () use ($container) { + $drivers['apc'] = function () use ($container): ?object { $drivers = $container['cache/available-drivers']; if (!isset($drivers['Apc'])) { // Apc is not available on system @@ -99,7 +95,7 @@ public function registerDrivers(Container $container) * @param Container $container A container instance. * @return \Stash\Driver\Sqlite|null */ - $drivers['db'] = function () use ($container) { + $drivers['db'] = function () use ($container): ?object { $drivers = $container['cache/available-drivers']; if (!isset($drivers['SQLite'])) { // SQLite is not available on system @@ -113,7 +109,7 @@ public function registerDrivers(Container $container) * @param Container $container A container instance. * @return \Stash\Driver\FileSystem */ - $drivers['file'] = function () use ($container) { + $drivers['file'] = function () use ($container): object { $drivers = $container['cache/available-drivers']; return new $drivers['FileSystem'](); }; @@ -122,7 +118,7 @@ public function registerDrivers(Container $container) * @param Container $container A container instance. * @return \Stash\Driver\Memcache|null */ - $drivers['memcache'] = function () use ($container) { + $drivers['memcache'] = function () use ($container): ?object { $drivers = $container['cache/available-drivers']; if (!isset($drivers['Memcache'])) { // Memcache is not available on system @@ -152,7 +148,7 @@ public function registerDrivers(Container $container) * @param Container $container A container instance. * @return \Stash\Driver\Ephemeral */ - $drivers['memory'] = function () use ($container) { + $drivers['memory'] = function () use ($container): object { $drivers = $container['cache/available-drivers']; return new $drivers['Ephemeral'](); }; @@ -161,7 +157,7 @@ public function registerDrivers(Container $container) * @param Container $container A container instance. * @return \Stash\Driver\BlackHole */ - $drivers['noop'] = function () use ($container) { + $drivers['noop'] = function () use ($container): object { $drivers = $container['cache/available-drivers']; return new $drivers['BlackHole'](); }; @@ -170,7 +166,7 @@ public function registerDrivers(Container $container) * @param Container $container A container instance. * @return \Stash\Driver\Redis|null */ - $drivers['redis'] = function () use ($container) { + $drivers['redis'] = function () use ($container): ?object { $drivers = $container['cache/available-drivers']; if (!isset($drivers['Redis'])) { // Redis is not available on system @@ -186,9 +182,8 @@ public function registerDrivers(Container $container) /** * @param Container $container A container instance. - * @return void */ - public function registerService(Container $container) + public function registerService(Container $container): void { /** * The cache configset. @@ -196,9 +191,9 @@ public function registerService(Container $container) * @param Container $container The service container. * @return CacheConfig */ - $container['cache/config'] = function (Container $container) { - $appConfig = isset($container['config']) ? $container['config'] : []; - $cacheConfig = isset($appConfig['cache']) ? $appConfig['cache'] : null; + $container['cache/config'] = function (Container $container): \Charcoal\Cache\CacheConfig { + $appConfig = ($container['config'] ?? []); + $cacheConfig = ($appConfig['cache'] ?? null); return new CacheConfig($cacheConfig); }; @@ -208,7 +203,7 @@ public function registerService(Container $container) * @param Container $container A Pimple DI container. * @return CacheBuilder */ - $container['cache/builder'] = function (Container $container) { + $container['cache/builder'] = function (Container $container): \Charcoal\Cache\CacheBuilder { $cacheConfig = $container['cache/config']; return new CacheBuilder([ @@ -224,9 +219,7 @@ public function registerService(Container $container) * @param Container $container The service container. * @return DriverInterface Primary cache driver from Stash. */ - $container['cache/driver'] = $container->factory(function (Container $container) { - return $container['cache']->getDriver(); - }); + $container['cache/driver'] = $container->factory(fn(Container $container) => $container['cache']->getDriver()); /** * The main cache item pool. @@ -238,11 +231,7 @@ public function registerService(Container $container) $cacheBuilder = $container['cache/builder']; $cacheConfig = $container['cache/config']; - if ($cacheConfig['active'] === true) { - $cacheDrivers = $cacheConfig['types']; - } else { - $cacheDrivers = $cacheConfig['default_types']; - } + $cacheDrivers = $cacheConfig['active'] === true ? $cacheConfig['types'] : $cacheConfig['default_types']; return $cacheBuilder($cacheDrivers); }; @@ -253,7 +242,7 @@ public function registerService(Container $container) * @param Container $container The service container. * @return CachePoolFacade The facade for the main cache pool. */ - $container['cache/facade'] = function (Container $container) { + $container['cache/facade'] = function (Container $container): \Charcoal\Cache\Facade\CachePoolFacade { $args = [ 'cache' => $container['cache'], ]; @@ -269,9 +258,8 @@ public function registerService(Container $container) /** * @param Container $container A container instance. - * @return void */ - private function registerMiddleware(Container $container) + private function registerMiddleware(Container $container): void { /** * The cache middleware configset. @@ -280,7 +268,7 @@ private function registerMiddleware(Container $container) * @return array */ $container['cache/middleware/config'] = function (Container $container) { - $appConfig = isset($container['config']) ? $container['config'] : []; + $appConfig = ($container['config'] ?? []); if (isset($appConfig['middlewares']['charcoal/cache/middleware/cache'])) { $wareConfig = $appConfig['middlewares']['charcoal/cache/middleware/cache']; @@ -299,8 +287,6 @@ private function registerMiddleware(Container $container) * @param Container $container A container instance. * @return CacheMiddleware */ - $container['middlewares/charcoal/cache/middleware/cache'] = function (Container $container) { - return new CacheMiddleware($container['cache/middleware/config']); - }; + $container['middlewares/charcoal/cache/middleware/cache'] = (fn(Container $container): \Charcoal\Cache\Middleware\CacheMiddleware => new CacheMiddleware($container['cache/middleware/config'])); } } diff --git a/packages/cache/tests/Charcoal/AbstractTestCase.php b/packages/cache/tests/Charcoal/AbstractTestCase.php index 59ba12ea0..80f1772c4 100644 --- a/packages/cache/tests/Charcoal/AbstractTestCase.php +++ b/packages/cache/tests/Charcoal/AbstractTestCase.php @@ -1,5 +1,7 @@ assertEquals('charcoal', CacheConfig::DEFAULT_NAMESPACE); $this->assertEquals((60 * 60), CacheConfig::HOUR_IN_SECONDS); @@ -70,11 +73,7 @@ public function testDefaults() $this->assertEquals($defaults['prefix'], $this->cfg->prefix()); } - /** - * @covers ::setActive - * @covers ::active - */ - public function testActive() + public function testActive(): void { // Chainable $that = $this->cfg->setActive(false); @@ -84,11 +83,7 @@ public function testActive() $this->assertFalse($this->cfg->active()); } - /** - * @covers ::setTypes - * @covers ::types - */ - public function testReplaceDrivers() + public function testReplaceDrivers(): void { // Chainable $that = $this->cfg->setTypes([ 'memcache', 'noop' ]); @@ -99,10 +94,7 @@ public function testReplaceDrivers() $this->assertEquals([ 'memcache', 'noop', 'memory' ], $types); } - /** - * @covers ::types - */ - public function testUniqueDrivers() + public function testUniqueDrivers(): void { $this->cfg->setTypes([ 'memcache', 'memory', 'file', 'memcache' ]); @@ -110,12 +102,7 @@ public function testUniqueDrivers() $this->assertEquals([ 'memcache', 'memory', 'file' ], $types); } - /** - * @covers ::addTypes - * @covers ::addType - * @covers ::types - */ - public function testAddDrivers() + public function testAddDrivers(): void { // Chainable $that = $this->cfg->addTypes([ 'memcache', 'noop' ]); @@ -128,22 +115,14 @@ public function testAddDrivers() $this->assertContains('noop', $types); } - /** - * @covers ::validTypes - * @covers ::addType - */ - public function testAddDriverOnInvalidType() + public function testAddDriverOnInvalidType(): void { $this->expectExceptionMessage('Invalid cache type: "foobar"'); $this->expectException(InvalidArgumentException::class); $this->cfg->addType('foobar'); } - /** - * @covers ::setDefaultTtl - * @covers ::defaultTtl - */ - public function testDefaultTtl() + public function testDefaultTtl(): void { // Chainable $that = $this->cfg->setDefaultTtl(42); @@ -153,21 +132,14 @@ public function testDefaultTtl() $this->assertEquals(42, $this->cfg->defaultTtl()); } - /** - * @covers ::setDefaultTtl - */ - public function testSetDefaultTtlOnInvalidType() + public function testSetDefaultTtlOnInvalidType(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('TTL must be an integer (seconds)'); $this->cfg->setDefaultTtl('foo'); } - /** - * @covers ::setPrefix - * @covers ::prefix - */ - public function testPrefix() + public function testPrefix(): void { // Chainable $that = $this->cfg->setPrefix('foo'); @@ -177,20 +149,14 @@ public function testPrefix() $this->assertEquals('foo', $this->cfg->prefix()); } - /** - * @covers ::setPrefix - */ - public function testSetPrefixOnInvalidType() + public function testSetPrefixOnInvalidType(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Prefix must be a string'); $this->cfg->setPrefix(false); } - /** - * @covers ::setPrefix - */ - public function testSetPrefixOnInvalidValue() + public function testSetPrefixOnInvalidValue(): void { $this->expectExceptionMessage('Prefix must be alphanumeric'); $this->expectException(InvalidArgumentException::class); diff --git a/packages/cache/tests/Charcoal/Cache/CachePoolAwareTest.php b/packages/cache/tests/Charcoal/Cache/CachePoolAwareTest.php index 2b9762e5b..37f708309 100644 --- a/packages/cache/tests/Charcoal/Cache/CachePoolAwareTest.php +++ b/packages/cache/tests/Charcoal/Cache/CachePoolAwareTest.php @@ -11,16 +11,13 @@ /** * Test CachePoolAwareTrait - * - * @coversDefaultClass \Charcoal\Cache\CachePoolAwareTrait */ +#[\PHPUnit\Framework\Attributes\CoversTrait(\Charcoal\Cache\CachePoolAwareTrait::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CachePoolAwareTrait::class, 'setCachePool')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CachePoolAwareTrait::class, 'cachePool')] class CachePoolAwareTest extends AbstractTestCase { - /** - * @covers ::setCachePool - * @covers ::cachePool - */ - public function testCachePool() + public function testCachePool(): void { $obj = new CachePoolAware(); $pool = new Pool(); @@ -31,9 +28,8 @@ public function testCachePool() /** * testSetPrefixOnInvalidValue - * @covers ::cachePool */ - public function testMissingPool() + public function testMissingPool(): void { $this->expectExceptionMessage('Cache Pool is not defined for "Charcoal\Tests\Mocks\CachePoolAware"'); $this->expectException(\RuntimeException::class); diff --git a/packages/cache/tests/Charcoal/Cache/CachePoolTrait.php b/packages/cache/tests/Charcoal/Cache/CachePoolTrait.php index 7e5adb1eb..bcbbeb46c 100644 --- a/packages/cache/tests/Charcoal/Cache/CachePoolTrait.php +++ b/packages/cache/tests/Charcoal/Cache/CachePoolTrait.php @@ -1,5 +1,7 @@ setNamespace('tests'); diff --git a/packages/cache/tests/Charcoal/Cache/Facade/CachePoolFacadeTest.php b/packages/cache/tests/Charcoal/Cache/Facade/CachePoolFacadeTest.php index 561c8839b..62b721246 100644 --- a/packages/cache/tests/Charcoal/Cache/Facade/CachePoolFacadeTest.php +++ b/packages/cache/tests/Charcoal/Cache/Facade/CachePoolFacadeTest.php @@ -23,9 +23,16 @@ * Test CachePoolFacade * * This class is based on {@see \Stash\Test\AbstractPoolTest}. - * - * @coversDefaultClass \Charcoal\Cache\Facade\CachePoolFacade */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Cache\Facade\CachePoolFacade::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Facade\CachePoolFacade::class, '__construct')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Facade\CachePoolFacade::class, 'get')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Facade\CachePoolFacade::class, 'save')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Facade\CachePoolFacade::class, 'has')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Facade\CachePoolFacade::class, 'set')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Facade\CachePoolFacade::class, 'delete')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Facade\CachePoolFacade::class, 'defaultTtl')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Facade\CachePoolFacade::class, 'setDefaultTtl')] class CachePoolFacadeTest extends AbstractTestCase { use CachePoolTrait; @@ -43,8 +50,6 @@ class CachePoolFacadeTest extends AbstractTestCase /** * Prepare the cache pool. - * - * @return void */ public function setUp(): void { @@ -53,8 +58,6 @@ public function setUp(): void /** * Empty the cache pool. - * - * @return void */ public function tearDown(): void { @@ -65,9 +68,8 @@ public function tearDown(): void * Create a new CachePoolFacade instance. * * @param array $args Parameters for the initialization of a CachePoolFacade. - * @return CachePoolFacade */ - protected function facadeFactory(array $args = []) + protected function facadeFactory(array $args = []): \Charcoal\Cache\Facade\CachePoolFacade { if (!isset($args['cache'])) { $args['cache'] = static::getCachePool(); @@ -76,10 +78,7 @@ protected function facadeFactory(array $args = []) return new CachePoolFacade($args); } - /** - * @covers ::__construct - */ - public function testConstruct() + public function testConstruct(): void { $facade = $this->facadeFactory([ 'default_ttl' => 120, @@ -88,13 +87,7 @@ public function testConstruct() $this->assertInstanceOf(CachePoolFacade::class, $facade); } - /** - * @covers ::get - * @covers ::save - * - * @return void - */ - public function testGet() + public function testGet(): void { $facade = $this->facadeFactory(); @@ -105,19 +98,12 @@ public function testGet() $data = $facade->get('base/one'); $this->assertEquals($this->data, $data); - $func = function () { - return $this->data; - }; + $func = (fn() => $this->data); $data = $facade->get('base/two', $func); $this->assertEquals($this->data, $data); } - /** - * @covers ::has - * - * @return void - */ - public function testHas() + public function testHas(): void { $facade = $this->facadeFactory(); @@ -128,8 +114,6 @@ public function testHas() } /** - * @covers ::set - * @covers ::save * * @return CachePoolFacade To use the same cache pool facade for the next test. */ @@ -150,13 +134,10 @@ public function testSet() } /** - * @depends testSet - * @covers ::delete - * * @param CachePoolFacade $facade The cache pool facade from the previous test. - * @return void */ - public function testDelete(CachePoolFacade $facade) + #[\PHPUnit\Framework\Attributes\Depends('testSet')] + public function testDelete(CachePoolFacade $facade): void { $keys = array_keys($this->multiData); @@ -170,17 +151,15 @@ public function testDelete(CachePoolFacade $facade) /** * Test a numeric expiration time for this cache item. * - * @covers ::save * - * @dataProvider provideTtlOnSave * * @param DateTimeInterface $expected The expected expiration time * from {@see \Stash\Interfaces\ItemInterface::getExpiration()}. * @param mixed $itemTtl The cache item's expiration time. * @param DateTimeInterface $defaultTtl The facade default expiration time. - * @return void */ - public function testTtlOnSave(DateTimeInterface $expected, $itemTtl, DateTimeInterface $defaultTtl) + #[\PHPUnit\Framework\Attributes\DataProvider('provideTtlOnSave')] + public function testTtlOnSave(DateTimeInterface $expected, $itemTtl, DateTimeInterface $defaultTtl): void { $stash = static::getCachePool(); $facade = $this->facadeFactory([ @@ -199,9 +178,8 @@ public function testTtlOnSave(DateTimeInterface $expected, $itemTtl, DateTimeInt * Provide data for testing the expiration time per cache item. * * @used-by self::testTtlOnSave() - * @return array */ - public function provideTtlOnSave() + public static function provideTtlOnSave(): array { $data = []; $date = new DateTimeImmutable('now'); @@ -231,13 +209,7 @@ public function provideTtlOnSave() return $data; } - /** - * @covers ::defaultTtl - * @covers ::setDefaultTtl - * - * @return void - */ - public function testSetDefaultTtl() + public function testSetDefaultTtl(): void { $time = new \DateInterval('P1D'); $facade = $this->facadeFactory([ diff --git a/packages/cache/tests/Charcoal/Cache/Factory/AbstractCacheBuilderTest.php b/packages/cache/tests/Charcoal/Cache/Factory/AbstractCacheBuilderTest.php index 6494b8a2b..83494c732 100644 --- a/packages/cache/tests/Charcoal/Cache/Factory/AbstractCacheBuilderTest.php +++ b/packages/cache/tests/Charcoal/Cache/Factory/AbstractCacheBuilderTest.php @@ -115,9 +115,8 @@ public function getDefaultPoolAttributes() * Reports an error if $builder does not use the default options. * * @param CacheBuilder $builder The cache builder to test. - * @return void */ - public function assertCacheBuilderHasDefaultAttributes(CacheBuilder $builder) + public function assertCacheBuilderHasDefaultAttributes(CacheBuilder $builder): void { $builderDefaults = $this->getDefaultBuilderAttributes(); @@ -131,9 +130,8 @@ public function assertCacheBuilderHasDefaultAttributes(CacheBuilder $builder) * Reports an error if $pool does not use the default options. * * @param PoolInterface $pool The cache pool to test. - * @return void */ - public function assertCachePoolHasDefaultAttributes(PoolInterface $pool) + public function assertCachePoolHasDefaultAttributes(PoolInterface $pool): void { $builderDefaults = $this->getDefaultBuilderAttributes(); $poolDefaults = $this->getDefaultPoolAttributes(); diff --git a/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderClassTest.php b/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderClassTest.php index ca178955b..7f02abd06 100644 --- a/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderClassTest.php +++ b/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderClassTest.php @@ -14,42 +14,36 @@ /** * Test constructor and class attributes from the CacheBuilder. - * - * @coversDefaultClass \Charcoal\Cache\CacheBuilder */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Cache\CacheBuilder::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, '__construct')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'setDrivers')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'isAccessible')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'setLogger')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'setNamespace')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'setItemClass')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'setPoolClass')] class CacheBuilderClassTest extends AbstractCacheBuilderTest { - /** - * @covers ::__construct - * @covers ::setDrivers - * @covers ::isAccessible - */ - public function testSetDriversWithInvalidType() + public function testSetDriversWithInvalidType(): void { $this->expectExceptionMessage('Driver list must be an accessible array'); $this->expectException(InvalidArgumentException::class); - $builder = $this->createBuilder([ + $this->createBuilder([ 'drivers' => false, ]); } - /** - * @covers ::setLogger - */ - public function testSetLoggerWithInvalidType() + public function testSetLoggerWithInvalidType(): void { $this->expectExceptionMessage('Expected an instance of Psr\Log\LoggerInterface'); $this->expectException(InvalidArgumentException::class); - $builder = $this->createBuilder([ + $this->createBuilder([ 'logger' => new \stdClass(), ]); } - /** - * @covers ::__construct - * @covers ::setNamespace - */ - public function testSetNamespace() + public function testSetNamespace(): void { $driver = $this->createDriver('BlackHole'); $builder = $this->createBuilder([ @@ -65,26 +59,19 @@ public function testSetNamespace() $this->assertEquals('foo', $pool->getNamespace()); } - /** - * @covers ::setNamespace - */ - public function testSetInvalidNamespace() + public function testSetInvalidNamespace(): void { $this->expectExceptionMessage('Namespace must be alphanumeric'); $this->expectException(InvalidArgumentException::class); - $builder = $this->createBuilder([ + $this->createBuilder([ 'namespace' => '!@#$%^&*(', ]); } - /** - * @covers ::__construct - * @covers ::setItemClass - */ - public function testSetItemClass() + public function testSetItemClass(): void { - $mockItem = $this->createMock(ItemInterface::class); - $mockClassName = get_class($mockItem); + $mockItem = $this->createStub(ItemInterface::class); + $mockClassName = $mockItem::class; $driver = $this->createDriver('BlackHole'); $builder = $this->createBuilder([ @@ -97,40 +84,28 @@ public function testSetItemClass() $this->assertInstanceOf($mockClassName, $item); } - /** - * - * @covers ::setItemClass - */ - public function testSetFakeItemClass() + public function testSetFakeItemClass(): void { $this->expectExceptionMessage('Item class FakeClassName does not exist'); $this->expectException(InvalidArgumentException::class); - $builder = $this->createBuilder([ + $this->createBuilder([ 'item_class' => 'FakeClassName', ]); } - /** - * - * @covers ::setItemClass - */ - public function testSetInvalidItemClass() + public function testSetInvalidItemClass(): void { $this->expectExceptionMessage('Item class stdClass must inherit from Stash\Interfaces\ItemInterface'); $this->expectException(InvalidArgumentException::class); - $builder = $this->createBuilder([ + $this->createBuilder([ 'item_class' => 'stdClass', ]); } - /** - * @covers ::__construct - * @covers ::setPoolClass - */ - public function testSetPoolClass() + public function testSetPoolClass(): void { - $mockPool = $this->createMock(PoolInterface::class); - $mockClassName = get_class($mockPool); + $mockPool = $this->createStub(PoolInterface::class); + $mockClassName = $mockPool::class; $driver = $this->createDriver('BlackHole'); $builder = $this->createBuilder([ @@ -142,26 +117,20 @@ public function testSetPoolClass() $this->assertInstanceOf($mockClassName, $pool); } - /** - * @covers ::setPoolClass - */ - public function testSetFakePoolClass() + public function testSetFakePoolClass(): void { $this->expectExceptionMessage('Pool class FakeClassName does not exist'); $this->expectException(InvalidArgumentException::class); - $builder = $this->createBuilder([ + $this->createBuilder([ 'pool_class' => 'FakeClassName', ]); } - /** - * @covers ::setPoolClass - */ - public function testSetInvalidPoolClass() + public function testSetInvalidPoolClass(): void { $this->expectExceptionMessage('Pool class stdClass must inherit from Stash\Interfaces\PoolInterface'); $this->expectException(InvalidArgumentException::class); - $builder = $this->createBuilder([ + $this->createBuilder([ 'pool_class' => 'stdClass', ]); } diff --git a/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderDriverTest.php b/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderDriverTest.php index dd6c80ffa..57956de00 100644 --- a/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderDriverTest.php +++ b/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderDriverTest.php @@ -13,17 +13,18 @@ /** * Test the cache driver resolution from the CacheBuilder. - * - * @coversDefaultClass \Charcoal\Cache\CacheBuilder */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Cache\CacheBuilder::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'build')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'isIterable')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'resolveDriver')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'resolveOneDriver')] class CacheBuilderDriverTest extends AbstractCacheBuilderTest { /** * Test builder with a {@see DriverInterface driver object}. - * - * @covers ::build */ - public function testBuildOnDriverInstance() + public function testBuildOnDriverInstance(): void { $builder = $this->createBuilder(); $driver = $this->createDriver('BlackHole'); @@ -36,16 +37,10 @@ public function testBuildOnDriverInstance() // Resolve One Driver // ========================================================================= - /** * Test builder with a driver class. - * - * @covers ::build - * @covers ::isIterable - * @covers ::resolveDriver - * @covers ::resolveOneDriver */ - public function testBuildOnDriverClass() + public function testBuildOnDriverClass(): void { $builder = $this->createBuilder(); $driver = $this->getDriverClass('BlackHole'); @@ -56,13 +51,8 @@ public function testBuildOnDriverClass() /** * Test builder with a named driver associated to a {@see DriverInterface driver object}. - * - * @covers ::build - * @covers ::isIterable - * @covers ::resolveDriver - * @covers ::resolveOneDriver */ - public function testBuildOnNamedDriverWithInstance() + public function testBuildOnNamedDriverWithInstance(): void { $driver = $this->createDriver('BlackHole'); $builder = $this->createBuilder([ @@ -77,13 +67,8 @@ public function testBuildOnNamedDriverWithInstance() /** * Test builder with a named driver associated to a driver class. - * - * @covers ::build - * @covers ::isIterable - * @covers ::resolveDriver - * @covers ::resolveOneDriver */ - public function testBuildOnNamedDriverWithClass() + public function testBuildOnNamedDriverWithClass(): void { $driver = $this->getDriverClass('BlackHole'); $builder = $this->createBuilder([ @@ -97,13 +82,10 @@ public function testBuildOnNamedDriverWithClass() } // ================================= - /** * Test builder with an empty driver name. - * - * @covers ::resolveOneDriver */ - public function testBuildOnEmptyDriver() + public function testBuildOnEmptyDriver(): void { $this->expectExceptionMessage('Driver is empty'); $this->expectException(InvalidArgumentException::class); @@ -114,10 +96,8 @@ public function testBuildOnEmptyDriver() /** * Test builder with an invalid driver instance. - * - * @covers ::resolveOneDriver */ - public function testBuildOnInvalidDriverInstance() + public function testBuildOnInvalidDriverInstance(): void { $this->expectExceptionMessage('Driver class stdClass must implement Stash\Interfaces\DriverInterface'); $this->expectException(InvalidArgumentException::class); @@ -125,15 +105,13 @@ public function testBuildOnInvalidDriverInstance() $builder = $this->createBuilder(); $driver = new StdClass(); - $pool = $builder->build($driver); + $builder->build($driver); } /** * Test builder with a named driver associated to an empty value. - * - * @covers ::resolveOneDriver */ - public function testBuildOnNamedDriverWithEmptyEntry() + public function testBuildOnNamedDriverWithEmptyEntry(): void { $this->expectExceptionMessage('Driver "foobar" does not exist'); $this->expectException(InvalidArgumentException::class); @@ -144,15 +122,13 @@ public function testBuildOnNamedDriverWithEmptyEntry() ] ]); - $pool = $builder->build('foobar'); + $builder->build('foobar'); } /** * Test builder with a named driver associated to an invalid instance. - * - * @covers ::resolveOneDriver */ - public function testBuildOnNamedDriverWithBadEntry() + public function testBuildOnNamedDriverWithBadEntry(): void { $this->expectExceptionMessage('Driver "foobar": Class stdClass must implement Stash\Interfaces\DriverInterface'); $this->expectException(InvalidArgumentException::class); @@ -164,15 +140,13 @@ public function testBuildOnNamedDriverWithBadEntry() ] ]); - $pool = $builder->build('foobar'); + $builder->build('foobar'); } /** * Test builder with an invalid driver class. - * - * @covers ::resolveOneDriver */ - public function testBuildOnInvalidDriverClass() + public function testBuildOnInvalidDriverClass(): void { $this->expectExceptionMessage('Driver "FakeClassName" cannot be resolved'); $this->expectException(InvalidArgumentException::class); @@ -180,23 +154,17 @@ public function testBuildOnInvalidDriverClass() $builder = $this->createBuilder(); $driver = 'FakeClassName'; - $pool = $builder->build($driver); + $builder->build($driver); } // Resolve Many Drivers // ========================================================================= - /** * Test builder with an array of {@see DriverInterface driver objects}. - * - * @covers ::build - * @covers ::isIterable - * @covers ::resolveDriver - * @covers ::resolveOneDriver */ - public function testBuildOnArrayOfDriverInstances() + public function testBuildOnArrayOfDriverInstances(): void { $builder = $this->createBuilder(); $driver = $this->createDriver('BlackHole'); @@ -206,13 +174,10 @@ public function testBuildOnArrayOfDriverInstances() } // ================================= - /** * Test builder with an invalid array of drivers. - * - * @covers ::resolveDriver */ - public function testBuildOnArrayOfInvalidDrivers() + public function testBuildOnArrayOfInvalidDrivers(): void { $this->expectExceptionMessage('Drivers cannot be resolved'); $this->expectException(InvalidArgumentException::class); diff --git a/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderPoolTest.php b/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderPoolTest.php index 10aac436d..8de1ab3a1 100644 --- a/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderPoolTest.php +++ b/packages/cache/tests/Charcoal/Cache/Factory/CacheBuilderPoolTest.php @@ -14,17 +14,17 @@ /** * Test the cache pool creation and pool attributes from the CacheBuilder. - * - * @coversDefaultClass \Charcoal\Cache\CacheBuilder */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Cache\CacheBuilder::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, '__invoke')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'parsePoolOptions')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\CacheBuilder::class, 'applyPoolOptions')] class CacheBuilderPoolTest extends AbstractCacheBuilderTest { /** * Asserts that the CacheBuilder is invokable. - * - * @covers ::__invoke */ - public function testBuildIsInvokable() + public function testBuildIsInvokable(): void { $builder = $this->createBuilder(); $driver = $this->createDriver('BlackHole'); @@ -35,11 +35,8 @@ public function testBuildIsInvokable() /** * Asserts that the Pool logger can be assigned from build options. - * - * @covers ::parsePoolOptions - * @covers ::applyPoolOptions */ - public function testBuildWithLoggerOnOptions() + public function testBuildWithLoggerOnOptions(): void { $builder = $this->createBuilder(); $driver = $this->createDriver('BlackHole'); @@ -54,11 +51,8 @@ public function testBuildWithLoggerOnOptions() /** * Asserts that the Pool namespace can be customized from build options. - * - * @covers ::parsePoolOptions - * @covers ::applyPoolOptions */ - public function testBuildWithNamespaceOnOptions() + public function testBuildWithNamespaceOnOptions(): void { $builder = $this->createBuilder(); $driver = $this->createDriver('BlackHole'); @@ -76,17 +70,14 @@ public function testBuildWithNamespaceOnOptions() /** * Asserts that the Item class can be customized from build options. - * - * @covers ::parsePoolOptions - * @covers ::applyPoolOptions */ - public function testBuildWithItemClassOnOptions() + public function testBuildWithItemClassOnOptions(): void { $builder = $this->createBuilder(); $driver = $this->createDriver('BlackHole'); - $mockItem = $this->createMock(ItemInterface::class); - $mockClassName = get_class($mockItem); + $mockItem = $this->createStub(ItemInterface::class); + $mockClassName = $mockItem::class; $pool = $builder($driver, [ 'item_class' => $mockClassName, @@ -98,17 +89,14 @@ public function testBuildWithItemClassOnOptions() /** * Asserts that the Pool class can be customized from build options. - * - * @covers ::parsePoolOptions - * @covers ::applyPoolOptions */ - public function testBuildWithPoolClassOnOptions() + public function testBuildWithPoolClassOnOptions(): void { $builder = $this->createBuilder(); $driver = $this->createDriver('BlackHole'); - $mockPool = $this->createMock(PoolInterface::class); - $mockClassName = get_class($mockPool); + $mockPool = $this->createStub(PoolInterface::class); + $mockClassName = $mockPool::class; // Custom Pool Class $pool = $builder($driver, [ @@ -119,10 +107,8 @@ public function testBuildWithPoolClassOnOptions() /** * Asserts that the CacheBuilder uses default options when given NULL. - * - * @covers ::parsePoolOptions */ - public function testBuildWithNullOnOptions() + public function testBuildWithNullOnOptions(): void { $builder = $this->createBuilder(); $driver = $this->createDriver('BlackHole'); @@ -135,10 +121,8 @@ public function testBuildWithNullOnOptions() /** * Asserts that the CacheBuilder uses default options when given NULL. - * - * @covers ::parsePoolOptions */ - public function testBuildWithInvalidTypeOnOptions() + public function testBuildWithInvalidTypeOnOptions(): void { $builder = $this->createBuilder(); $driver = $this->createDriver('BlackHole'); diff --git a/packages/cache/tests/Charcoal/Cache/Middleware/AbstractCacheMiddlewareTest.php b/packages/cache/tests/Charcoal/Cache/Middleware/AbstractCacheMiddlewareTest.php index 16b9bb5fa..02372cb7e 100644 --- a/packages/cache/tests/Charcoal/Cache/Middleware/AbstractCacheMiddlewareTest.php +++ b/packages/cache/tests/Charcoal/Cache/Middleware/AbstractCacheMiddlewareTest.php @@ -24,9 +24,9 @@ /** * Test CacheMiddleware - * - * @coversDefaultClass \Charcoal\Cache\Middleware\CacheMiddleware */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Cache\Middleware\CacheMiddleware::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, 'disableCacheHeadersOnResponse')] abstract class AbstractCacheMiddlewareTest extends AbstractTestCase { use CachePoolTrait; @@ -41,9 +41,7 @@ protected function middlewareFactory(array $args = []) { if (!isset($args['cache'])) { $args['cache'] = static::getCachePool(); - $args['processCacheKeyCallback'] = function ($key) { - return $key; - }; + $args['processCacheKeyCallback'] = (fn($key) => $key); } return new CacheMiddleware($args); @@ -56,9 +54,7 @@ protected function middlewareFactory(array $args = []) */ protected function mockNextMiddleware() { - return function ($request, $response) { - return $response; - }; + return fn($request, $response) => $response; } /** @@ -120,9 +116,7 @@ protected function createRequest($method = 'GET', $uri = '/', $query = null) if ($query !== null) { $env['QUERY_STRING'] = is_array($query) ? http_build_query($query) : $query; } - - $request = Request::createFromEnvironment($env); - return $request; + return Request::createFromEnvironment($env); } /** @@ -156,19 +150,16 @@ protected function createResponse($status = 200, $body = null) } $headers = new Headers([ 'Content-Type' => 'text/html; charset=UTF-8' ]); - $response = new Response($status, $headers, $body); - return $response; + return new Response($status, $headers, $body); } /** * Reports an error if the HTTP response headers does not have disabled cache headers. * - * @covers ::disableCacheHeadersOnResponse * * @param array $headers The HTTP response headers to test. - * @return void */ - public function assertResponseHasDisabledCacheHeaders(array $headers) + public function assertResponseHasDisabledCacheHeaders(array $headers): void { $this->assertArrayHasKey('Cache-Control', $headers); $this->assertContains('no-cache, no-store, must-revalidate', $headers['Cache-Control']); diff --git a/packages/cache/tests/Charcoal/Cache/Middleware/CacheMiddlewareRequestTest.php b/packages/cache/tests/Charcoal/Cache/Middleware/CacheMiddlewareRequestTest.php index 6c8ac02df..85f4d2e8c 100644 --- a/packages/cache/tests/Charcoal/Cache/Middleware/CacheMiddlewareRequestTest.php +++ b/packages/cache/tests/Charcoal/Cache/Middleware/CacheMiddlewareRequestTest.php @@ -11,15 +11,21 @@ /** * Test HTTP Requests with CacheMiddleware. - * - * @coversDefaultClass \Charcoal\Cache\Middleware\CacheMiddleware */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Cache\Middleware\CacheMiddleware::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, '__invoke')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, 'isRequestMethodValid')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, 'isResponseStatusValid')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, 'isPathIncluded')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, 'isPathExcluded')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, 'isQueryIncluded')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, 'isQueryExcluded')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, 'parseIgnoredParams')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, 'disableCacheHeadersOnResponse')] class CacheMiddlewareRequestTest extends AbstractCacheMiddlewareTest { /** * Prepare the cache pool. - * - * @return void */ public function setUp(): void { @@ -28,8 +34,6 @@ public function setUp(): void /** * Empty the cache pool. - * - * @return void */ public function tearDown(): void { @@ -39,25 +43,15 @@ public function tearDown(): void /** * Test middleware with an invalid HTTP request method. * - * @covers ::__invoke - * @covers ::isRequestMethodValid - * @covers ::isResponseStatusValid - * @covers ::isPathIncluded - * @covers ::isPathExcluded - * @covers ::isQueryIncluded - * @covers ::isQueryExcluded - * @covers ::parseIgnoredParams - * @covers ::disableCacheHeadersOnResponse * - * @dataProvider provideInvokableSituations * * @param boolean $expected The expected result from {@see \Psr\Cache\CacheItemInterface::isHit()}. * @param boolean $checkHttpHeaders Whether to test the HTTP response's headers. * @param stromg $requestUri The request URI for {@see self::createRequest()}. * @param array $cacheConfig The CacheMiddleware settings. - * @return void */ - public function testInvoke($expected, $checkHttpHeaders, $requestUri, array $cacheConfig) + #[\PHPUnit\Framework\Attributes\DataProvider('provideInvokableSituations')] + public function testInvoke(bool $expected, bool $checkHttpHeaders, string $requestUri, array $cacheConfig): void { $middleware = $this->middlewareFactory($cacheConfig); $request = $this->createRequest('GET', $requestUri); @@ -85,9 +79,8 @@ public function testInvoke($expected, $checkHttpHeaders, $requestUri, array $cac * Provide data for testing the middleware. * * @used-by self::testInvoke() - * @return array */ - public function provideInvokableSituations() + public static function provideInvokableSituations(): array { $target1 = '/foo/bar'; $target2 = '/foo/bar?abc=123'; diff --git a/packages/cache/tests/Charcoal/Cache/Middleware/CacheMiddlewareResponseTest.php b/packages/cache/tests/Charcoal/Cache/Middleware/CacheMiddlewareResponseTest.php index 4127bc4b3..61471fa20 100644 --- a/packages/cache/tests/Charcoal/Cache/Middleware/CacheMiddlewareResponseTest.php +++ b/packages/cache/tests/Charcoal/Cache/Middleware/CacheMiddlewareResponseTest.php @@ -14,15 +14,14 @@ /** * Test HTTP Responses from CacheMiddleware. - * - * @coversDefaultClass \Charcoal\Cache\Middleware\CacheMiddleware */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Cache\Middleware\CacheMiddleware::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, '__invoke')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\Middleware\CacheMiddleware::class, 'cacheKeyFromRequest')] class CacheMiddlewareResponseTest extends AbstractCacheMiddlewareTest { /** * Prepare the cache pool. - * - * @return void */ public static function setUpBeforeClass(): void { @@ -31,8 +30,6 @@ public static function setUpBeforeClass(): void /** * Empty the cache pool. - * - * @return void */ public static function tearDownAfterClass(): void { @@ -42,8 +39,6 @@ public static function tearDownAfterClass(): void /** * Test the initial state. * - * @covers ::__invoke - * @covers ::cacheKeyFromRequest * * @return CacheMiddleware To use the same cache middleware for the next test. */ @@ -83,14 +78,11 @@ public function testInitialState() /** * Test the cached state. * - * @covers ::__invoke - * @covers ::cacheKeyFromRequest - * @depends testInitialState * * @param CacheMiddleware $middleware The cache middleware from the previous test. - * @return void */ - public function testCachedState(CacheMiddleware $middleware) + #[\PHPUnit\Framework\Attributes\Depends('testInitialState')] + public function testCachedState(CacheMiddleware $middleware): void { $txt = 'Lorem ipsum dolor sit amet.'; diff --git a/packages/cache/tests/Charcoal/Cache/ServiceProvider/CacheServiceProviderTest.php b/packages/cache/tests/Charcoal/Cache/ServiceProvider/CacheServiceProviderTest.php index 198f9be5e..66884f185 100644 --- a/packages/cache/tests/Charcoal/Cache/ServiceProvider/CacheServiceProviderTest.php +++ b/packages/cache/tests/Charcoal/Cache/ServiceProvider/CacheServiceProviderTest.php @@ -26,18 +26,15 @@ /** * Test CacheServiceProvider - * - * @coversDefaultClass \Charcoal\Cache\ServiceProvider\CacheServiceProvider */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Cache\ServiceProvider\CacheServiceProvider::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\ServiceProvider\CacheServiceProvider::class, 'register')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\ServiceProvider\CacheServiceProvider::class, 'registerDrivers')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\ServiceProvider\CacheServiceProvider::class, 'registerService')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Cache\ServiceProvider\CacheServiceProvider::class, 'registerMiddleware')] class CacheServiceProviderTest extends AbstractTestCase { - /** - * @covers ::register - * @covers ::registerDrivers - * @covers ::registerService - * @covers ::registerMiddleware - */ - public function testProvider() + public function testProvider(): void { $container = $this->providerFactory(); @@ -68,10 +65,8 @@ public function testProvider() /** * Test "middlewares/charcoal/cache/middleware/cache" with a user-preferences. - * - * @covers ::registerMiddleware */ - public function testCustomizedMiddleware() + public function testCustomizedMiddleware(): void { $container = $this->providerFactory([ 'config' => [ @@ -87,17 +82,14 @@ public function testCustomizedMiddleware() $middleware = $container['middlewares/charcoal/cache/middleware/cache']; $reflection = new ReflectionClass($middleware); $reflectionProperty = $reflection->getProperty('cacheTtl'); - $reflectionProperty->setAccessible(true); $this->assertEquals(1, $reflectionProperty->getValue($middleware)); } /** * Test "cache/drivers"; basic drivers are instances of {@see DriverInterface}. - * - * @covers ::registerDrivers */ - public function testBasicDriverInstances() + public function testBasicDriverInstances(): void { $container = $this->providerFactory(); @@ -121,10 +113,8 @@ public function testBasicDriverInstances() /** * Test "cache/drivers"; vendor drivers are instances of {@see DriverInterface}. - * - * @covers ::registerDrivers */ - public function testAvailableVendorDriverInstances() + public function testAvailableVendorDriverInstances(): void { $container = $this->providerFactory(); @@ -146,7 +136,7 @@ public function testAvailableVendorDriverInstances() try { $driver = $driverCollection[$driverKey]; $this->assertInstanceOf($className, $driver); - } catch (Throwable $t) { + } catch (Throwable) { // Do nothing; Some cache drivers, such as Redis, // are not correctly implemented. } @@ -160,10 +150,8 @@ public function testAvailableVendorDriverInstances() /** * Test "cache/drivers"; unavailable vendor drivers return NULL. - * - * @covers ::registerDrivers */ - public function testUnavailableVendorDriverInstances() + public function testUnavailableVendorDriverInstances(): void { $container = $this->providerFactory(); @@ -191,16 +179,13 @@ public function testUnavailableVendorDriverInstances() /** * Assert "cache/driver" resolves as expected. * - * @covers ::registerDrivers - * @covers ::registerService * - * @dataProvider provideConfigsForMainDriver * * @param string $className The expected driver class name. * @param array $cacheConfig The cache configset to resolve the main driver. - * @return void */ - public function testMainDriverInstance($className, array $cacheConfig) + #[\PHPUnit\Framework\Attributes\DataProvider('provideConfigsForMainDriver')] + public function testMainDriverInstance(string $className, array $cacheConfig): void { $container = $this->providerFactory([ 'config' => [ @@ -215,9 +200,8 @@ public function testMainDriverInstance($className, array $cacheConfig) * Provide data for testing the "cache/driver" service. * * @used-by self::testMainDriverInstance() - * @return array */ - public function provideConfigsForMainDriver() + public static function provideConfigsForMainDriver(): array { $driverClassNames = DriverList::getAvailableDrivers(); @@ -260,9 +244,8 @@ public function getKeys($value) * Determine whether the given value is array accessible. * * @param mixed $value The variable being evaluated. - * @return boolean */ - public function isAccessible($value) + public function isAccessible($value): bool { return is_array($value) || $value instanceof \ArrayAccess; } @@ -271,9 +254,8 @@ public function isAccessible($value) * Create a new Container instance. * * @param array $args Parameters for the initialization of a Container. - * @return Container */ - public function providerFactory(array $args = []) + public function providerFactory(array $args = []): \Pimple\Container { $container = new Container($args); diff --git a/packages/cache/tests/Charcoal/Mocks/CachePoolAware.php b/packages/cache/tests/Charcoal/Mocks/CachePoolAware.php index b38f09e22..d4bd63c4d 100644 --- a/packages/cache/tests/Charcoal/Mocks/CachePoolAware.php +++ b/packages/cache/tests/Charcoal/Mocks/CachePoolAware.php @@ -1,5 +1,7 @@ itemClass; } - /** - * @return false|string - */ - public function getNamespace(): ?string - { - return $this->namespace; - } - /** * @return Boolean|LoggerInterface */ diff --git a/packages/cache/tests/Charcoal/Mocks/DefaultsAwareCacheMiddlewares.php b/packages/cache/tests/Charcoal/Mocks/DefaultsAwareCacheMiddlewares.php index 75ef83aa9..085f37406 100644 --- a/packages/cache/tests/Charcoal/Mocks/DefaultsAwareCacheMiddlewares.php +++ b/packages/cache/tests/Charcoal/Mocks/DefaultsAwareCacheMiddlewares.php @@ -1,5 +1,7 @@ logger; diff --git a/packages/cache/tests/bootstrap.php b/packages/cache/tests/bootstrap.php new file mode 100644 index 000000000..90929e3b5 --- /dev/null +++ b/packages/cache/tests/bootstrap.php @@ -0,0 +1,14 @@ + - + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/cms/src/Charcoal/Admin/Widget/Cms/HierarchicalSectionTableWidget.php b/packages/cms/src/Charcoal/Admin/Widget/Cms/HierarchicalSectionTableWidget.php index 6dcba5266..36a534ebc 100644 --- a/packages/cms/src/Charcoal/Admin/Widget/Cms/HierarchicalSectionTableWidget.php +++ b/packages/cms/src/Charcoal/Admin/Widget/Cms/HierarchicalSectionTableWidget.php @@ -24,10 +24,9 @@ class HierarchicalSectionTableWidget extends TableWidget /** * Provide a template to fullfill UIItem interface. - * - * @return string */ - public function template() + #[\Override] + public function template(): string { return 'charcoal/admin/widget/table'; } @@ -38,6 +37,7 @@ public function template() * @see \Charcoal\Admin\Ui\CollectionContainerTrait::sortObjects() * @return array */ + #[\Override] public function sortObjects() { $collection = new HierarchicalCollection($this->objects(), false); @@ -55,6 +55,7 @@ public function sortObjects() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -71,6 +72,7 @@ protected function setDependencies(Container $container) * @param PropertyInterface $property The current property. * @return void */ + #[\Override] protected function setupDisplayPropertyValue( ModelInterface $object, PropertyInterface $property diff --git a/packages/cms/src/Charcoal/Admin/Widget/Cms/SectionTableTrait.php b/packages/cms/src/Charcoal/Admin/Widget/Cms/SectionTableTrait.php index 4ea99fb2b..d8501e2a7 100644 --- a/packages/cms/src/Charcoal/Admin/Widget/Cms/SectionTableTrait.php +++ b/packages/cms/src/Charcoal/Admin/Widget/Cms/SectionTableTrait.php @@ -48,7 +48,7 @@ public function sectionFactory() { if (!isset($this->sectionFactory)) { throw new RuntimeException( - sprintf('Section Model Factory is not defined for "%s"', get_class($this)) + sprintf('Section Model Factory is not defined for "%s"', $this::class) ); } @@ -89,30 +89,26 @@ protected function parsePropertyCell( case 'menu_label': $sectionType = $object->sectionType(); - switch ($sectionType) { - case AbstractSection::TYPE_EXTERNAL: - $externalUrl = (string)$object->externalUrl(); - $linkExcerpt = ''; - $tagTemplate = ''; - - if ($externalUrl) { - $tagTemplate = '' . - ' ' . - 'URL: %3$s' . - ''; - - $linkExcerpt = $this->abridgeUri($externalUrl); - } - - $p = $object->p('section_type'); - $propertyValue .= sprintf( - '   ' . $tagTemplate, - $p->displayVal($p->val()), - $externalUrl, - $linkExcerpt - ); - break; + if ($sectionType === AbstractSection::TYPE_EXTERNAL) { + $externalUrl = (string)$object->externalUrl(); + $linkExcerpt = ''; + $tagTemplate = ''; + if ($externalUrl !== '' && $externalUrl !== '0') { + $tagTemplate = '' . + ' ' . + 'URL: %3$s' . + ''; + + $linkExcerpt = $this->abridgeUri($externalUrl); + } + $p = $object->p('section_type'); + $propertyValue .= sprintf( + '   ' . $tagTemplate, + $p->displayVal($p->val()), + $externalUrl, + $linkExcerpt + ); } break; } diff --git a/packages/cms/src/Charcoal/Admin/Widget/Cms/SectionTableWidget.php b/packages/cms/src/Charcoal/Admin/Widget/Cms/SectionTableWidget.php index 8586e3621..0733d7e75 100644 --- a/packages/cms/src/Charcoal/Admin/Widget/Cms/SectionTableWidget.php +++ b/packages/cms/src/Charcoal/Admin/Widget/Cms/SectionTableWidget.php @@ -19,6 +19,7 @@ class SectionTableWidget extends TableWidget * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/cms/src/Charcoal/Admin/Widget/FormGroup/GroupAttachmentFormGroup.php b/packages/cms/src/Charcoal/Admin/Widget/FormGroup/GroupAttachmentFormGroup.php index ab2f420a5..44c98700a 100644 --- a/packages/cms/src/Charcoal/Admin/Widget/FormGroup/GroupAttachmentFormGroup.php +++ b/packages/cms/src/Charcoal/Admin/Widget/FormGroup/GroupAttachmentFormGroup.php @@ -1,5 +1,7 @@ hasGroups()) { diff --git a/packages/cms/src/Charcoal/Admin/Widget/FormGroup/MultiGroupFormGroup.php b/packages/cms/src/Charcoal/Admin/Widget/FormGroup/MultiGroupFormGroup.php index 0e660bc4b..cfa828d7e 100644 --- a/packages/cms/src/Charcoal/Admin/Widget/FormGroup/MultiGroupFormGroup.php +++ b/packages/cms/src/Charcoal/Admin/Widget/FormGroup/MultiGroupFormGroup.php @@ -22,24 +22,19 @@ class MultiGroupFormGroup extends MultiGroupWidget implements use FormGroupTrait; use UiItemTrait; - /** - * @return string - */ - public function template() + #[\Override] + public function template(): string { return 'charcoal/admin/widget/multi-group'; } - /** - * @return array - */ - public function dataFromObject() + public function dataFromObject(): array { $obj = $this->obj(); $objMetadata = $obj->metadata(); - $adminMetadata = (isset($objMetadata['admin']) ? $objMetadata['admin'] : null); - $adminFormGroups = (isset($adminMetadata['form_groups']) ? $adminMetadata['form_groups'] : null); + $adminMetadata = ($objMetadata['admin'] ?? null); + $adminFormGroups = ($adminMetadata['form_groups'] ?? null); $groups = $this->groups(); @@ -70,8 +65,8 @@ public function dataFromMetadata() return []; } - $adminMetadata = (isset($data['admin']) ? $data['admin'] : null); - $adminFormGroups = (isset($adminMetadata['form_groups']) ? $adminMetadata['form_groups'] : null); + $adminMetadata = ($data['admin'] ?? null); + $adminFormGroups = ($adminMetadata['form_groups'] ?? null); if (isset($data['groups']) && isset($adminFormGroups)) { $extraFormGroups = array_intersect( @@ -100,10 +95,10 @@ public function dataFromMetadata() * @throws \UnexpectedValueException If a property data is invalid. * @return FormPropertyWidget[] */ - public function formProperties(array $group = null) + public function formProperties(?array $group = null): array { if ( - !key_exists(self::DATA_SOURCE_METADATA, array_flip($this->dataSources())) || + !array_key_exists(self::DATA_SOURCE_METADATA, array_flip($this->dataSources())) || !$this->widgetMetadata() ) { return iterator_to_array($this->form()->formProperties()); @@ -114,7 +109,7 @@ public function formProperties(array $group = null) try { $store = $this->storageProperty(); - } catch (\Exception $e) { + } catch (\Exception) { $store = null; } @@ -128,7 +123,7 @@ public function formProperties(array $group = null) $props = $this->widgetMetadata()['properties']; // We need to sort form properties by form group property order if a group exists - if (!empty($group)) { + if ($group !== null && $group !== []) { $props = array_merge(array_flip($group), $props); } @@ -139,7 +134,7 @@ public function formProperties(array $group = null) throw new \UnexpectedValueException(sprintf( 'Invalid property data for "%1$s", received %2$s', $propertyIdent, - (is_object($propertyMetadata) ? get_class($propertyMetadata) : gettype($propertyMetadata)) + (get_debug_type($propertyMetadata)) )); } @@ -172,9 +167,10 @@ public function formProperties(array $group = null) * * @return FormInterface|self */ + #[\Override] protected function formWidget() { - if (!key_exists(self::DATA_SOURCE_METADATA, array_flip($this->dataSources()))) { + if (!array_key_exists(self::DATA_SOURCE_METADATA, array_flip($this->dataSources()))) { return $this->form(); } diff --git a/packages/cms/src/Charcoal/Admin/Widget/GroupAttachmentWidget.php b/packages/cms/src/Charcoal/Admin/Widget/GroupAttachmentWidget.php index 39a5f6570..71231c669 100644 --- a/packages/cms/src/Charcoal/Admin/Widget/GroupAttachmentWidget.php +++ b/packages/cms/src/Charcoal/Admin/Widget/GroupAttachmentWidget.php @@ -32,10 +32,8 @@ class GroupAttachmentWidget extends AttachmentWidget implements /** * Store the metadata loader instance. - * - * @var MetadataLoader */ - private $metadataLoader; + private ?\Charcoal\Model\Service\MetadataLoader $metadataLoader = null; /** * @var boolean @@ -57,21 +55,17 @@ class GroupAttachmentWidget extends AttachmentWidget implements protected function sortItemsByPriority( PrioritizableInterface $a, PrioritizableInterface $b - ) { + ): int { $priorityA = $a->priority(); $priorityB = $b->priority(); - - if ($priorityA === $priorityB) { - return 0; - } - - return ($priorityA < $priorityB) ? (-1) : 1; + return ($priorityA <=> $priorityB); } /** * @param Container $container The DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -87,9 +81,8 @@ protected function setDependencies(Container $container) * Set a metadata loader. * * @param MetadataLoader $loader The loader instance, used to load metadata. - * @return self */ - protected function setMetadataLoader(MetadataLoader $loader) + protected function setMetadataLoader(MetadataLoader $loader): static { $this->metadataLoader = $loader; @@ -100,14 +93,13 @@ protected function setMetadataLoader(MetadataLoader $loader) * Retrieve the metadata loader. * * @throws RuntimeException If the metadata loader was not previously set. - * @return MetadataLoader */ - protected function metadataLoader() + protected function metadataLoader(): \Charcoal\Model\Service\MetadataLoader { - if ($this->metadataLoader === null) { + if (!$this->metadataLoader instanceof \Charcoal\Model\Service\MetadataLoader) { throw new RuntimeException(sprintf( 'Metadata Loader is not defined for "%s"', - \get_class($this) + static::class )); } @@ -123,16 +115,15 @@ protected function metadataLoader() protected function loadMetadata($metadataIdent) { $metadataLoader = $this->metadataLoader(); - $metadata = $metadataLoader->load($metadataIdent, $this->createMetadata()); - return $metadata; + return $metadataLoader->load($metadataIdent, $this->createMetadata()); } /** * @throws InvalidArgumentException If structureMetadata $data is note defined. * @return MetadataInterface */ - protected function createMetadata() + protected function createMetadata(): \Charcoal\Property\Structure\StructureMetadata { return new StructureMetadata(); } @@ -141,9 +132,9 @@ protected function createMetadata() * Sets data on this widget. * * @param array $data Key-value array of data to append. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -173,7 +164,7 @@ protected function addAttachmentGroupFromMetadata($reload = false) $interfaces = [$this->objType()]; if ($controllerInterface) { - array_push($interfaces, $controllerInterface); + $interfaces[] = $controllerInterface; } $structureMetadata = $this->createMetadata(); @@ -204,9 +195,8 @@ protected function addAttachmentGroupFromMetadata($reload = false) * Set the form object's template controller identifier. * * @param mixed $ident The template controller identifier. - * @return self */ - public function setControllerIdent($ident) + public function setControllerIdent(string $ident): static { if (class_exists($ident)) { $this->controllerIdent = $ident; @@ -214,7 +204,7 @@ public function setControllerIdent($ident) return $this; } - if (substr($ident, -9) !== '-template') { + if (!str_ends_with($ident, '-template')) { $ident .= '-template'; } @@ -235,10 +225,8 @@ public function controllerIdent() /** * Disable the pill nav if there is only one group. - * - * @return boolean */ - public function displayPills() + public function displayPills(): bool { return $this->numGroups() > 1; } diff --git a/packages/cms/src/Charcoal/Admin/Widget/MultiGroupWidget.php b/packages/cms/src/Charcoal/Admin/Widget/MultiGroupWidget.php index 51417f576..f283da9a7 100644 --- a/packages/cms/src/Charcoal/Admin/Widget/MultiGroupWidget.php +++ b/packages/cms/src/Charcoal/Admin/Widget/MultiGroupWidget.php @@ -81,22 +81,17 @@ class MultiGroupWidget extends AdminWidget implements protected function sortItemsByPriority( PrioritizableInterface $a, PrioritizableInterface $b - ) { + ): int { $priorityA = $a->priority(); $priorityB = $b->priority(); - - if ($priorityA === $priorityB) { - return 0; - } - - return ($priorityA < $priorityB) ? (-1) : 1; + return ($priorityA <=> $priorityB); } /** * @param array $data The widget data. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -109,6 +104,7 @@ public function setData(array $data) * @param Container $container The DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -122,10 +118,7 @@ protected function setDependencies(Container $container) $this->setLayoutBuilder($container['layout/builder']); } - /** - * @return string - */ - public function defaultGroupType() + public function defaultGroupType(): string { return 'charcoal/admin/widget/form-group/generic'; } @@ -135,7 +128,8 @@ public function defaultGroupType() * * @return string[] */ - protected function defaultDataSources() + #[\Override] + protected function defaultDataSources(): array { return [self::DATA_SOURCE_OBJECT]; } @@ -144,9 +138,8 @@ protected function defaultDataSources() * Set an widget factory. * * @param FactoryInterface $factory The factory to create widgets. - * @return self */ - protected function setWidgetFactory(FactoryInterface $factory) + protected function setWidgetFactory(FactoryInterface $factory): static { $this->widgetFactory = $factory; @@ -161,10 +154,10 @@ protected function setWidgetFactory(FactoryInterface $factory) */ public function widgetFactory() { - if (!isset($this->widgetFactory)) { + if ($this->widgetFactory === null) { throw new RuntimeException(sprintf( 'Widget Factory is not defined for "%s"', - get_class($this) + static::class )); } @@ -181,9 +174,8 @@ public function formGroups() /** * @param mixed $formGroups FormGroups for MultiGroupWidget. - * @return self */ - public function setFormGroups($formGroups) + public function setFormGroups($formGroups): static { $this->formGroups = $formGroups; @@ -200,18 +192,13 @@ public function widgetMetadata() /** * @param array|mixed $widgetMetadata WidgetMetadata for MultiGroupWidget. - * @return self */ - public function setWidgetMetadata($widgetMetadata) + public function setWidgetMetadata($widgetMetadata): static { if (is_string($widgetMetadata) && $this->view()) { $widgetMetadata = $this->view()->renderTemplate($widgetMetadata, $this->obj()); - if ($widgetMetadata !== '') { - $widgetMetadata = json_decode($widgetMetadata, true); - } else { - $widgetMetadata = null; - } + $widgetMetadata = $widgetMetadata !== '' ? json_decode($widgetMetadata, true) : null; } $this->widgetMetadata = $widgetMetadata; @@ -228,9 +215,8 @@ public function setWidgetMetadata($widgetMetadata) * @param string|ModelStructureProperty $propertyIdent The property identifier—or instance—of a storage property. * @throws \InvalidArgumentException If the property identifier is not a string. * @throws \UnexpectedValueException If a property is invalid. - * @return self */ - public function setStorageProperty($propertyIdent) + public function setStorageProperty($propertyIdent): static { $property = null; if ($propertyIdent instanceof PropertyInterface) { @@ -247,11 +233,11 @@ public function setStorageProperty($propertyIdent) throw new \UnexpectedValueException(sprintf( 'The "%1$s" property is not defined on [%2$s]', $propertyIdent, - get_class($obj) + $obj::class )); } - if ($property === null) { + if (!$property instanceof \Charcoal\Property\PropertyInterface) { $property = $obj->property($propertyIdent); } @@ -261,8 +247,8 @@ public function setStorageProperty($propertyIdent) throw new \UnexpectedValueException(sprintf( '"%s" [%s] is not a model structure property on [%s].', $propertyIdent, - (is_object($property) ? get_class($property) : gettype($property)), - (is_object($obj) ? get_class($obj) : gettype($obj)) + (get_debug_type($property)), + (get_debug_type($obj)) )); } @@ -280,7 +266,7 @@ public function storageProperty() if ($this->storageProperty === null) { throw new RuntimeException(sprintf( 'Storage property owner is not defined for "%s"', - get_class($this) + static::class )); } diff --git a/packages/cms/src/Charcoal/Cms/AbstractEvent.php b/packages/cms/src/Charcoal/Cms/AbstractEvent.php index 99350d4bf..a214aeac3 100644 --- a/packages/cms/src/Charcoal/Cms/AbstractEvent.php +++ b/packages/cms/src/Charcoal/Cms/AbstractEvent.php @@ -50,15 +50,9 @@ abstract class AbstractEvent extends Content implements EventInterface */ private $image; - /** - * @var DateTimeInterface|null - */ - private $startDate; + private ?\DateTimeInterface $startDate = null; - /** - * @var DateTimeInterface|null - */ - private $endDate; + private ?\DateTimeInterface $endDate = null; /** * @var Translation|string|null @@ -71,15 +65,9 @@ abstract class AbstractEvent extends Content implements EventInterface private $infoPhone; - /** - * @var float|null - */ - private $ticketPriceMin; + private ?float $ticketPriceMin = null; - /** - * @var float|null - */ - private $ticketPriceMax; + private ?float $ticketPriceMax = null; /** * @var Translation|string|null @@ -105,11 +93,11 @@ abstract class AbstractEvent extends Content implements EventInterface * Section constructor. * @param array $data The data. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { parent::__construct($data); - if (is_callable([ $this, 'defaultData' ])) { + if (is_callable($this->defaultData(...))) { $this->setData($this->defaultData()); } } @@ -125,9 +113,8 @@ public function canonicalUrl() /** * Some dates cannot be null - * @return void */ - public function verifyDates() + public function verifyDates(): void { if (!$this['startDate']) { $this->setStartDate('now'); @@ -150,13 +137,7 @@ public function adminDateFilter() $start = $this['startDate']->format('Y-m-d'); $end = $this['endDate']->format('Y-m-d'); - if ($start === $end) { - $date = $start; - } else { - $date = $start . ' - ' . $end; - } - - return $date; + return $start === $end ? $start : $start . ' - ' . $end; } /** @@ -506,10 +487,9 @@ public function isActiveRoute() /** * {@inheritdoc} - * - * @return boolean */ - protected function preSave() + #[\Override] + protected function preSave(): bool { $this->verifyDates(); $this->setSlug($this->generateSlug()); @@ -521,9 +501,9 @@ protected function preSave() * {@inheritdoc} * * @param array $properties Optional properties to update. - * @return boolean */ - protected function preUpdate(array $properties = null) + #[\Override] + protected function preUpdate(?array $properties = null): bool { $this->verifyDates(); $this->setSlug($this->generateSlug()); @@ -534,7 +514,8 @@ protected function preUpdate(array $properties = null) /** * @return boolean Parent postSave(). */ - protected function postSave() + #[\Override] + protected function postSave(): bool { // RoutableTrait $this->generateObjectRoute($this['slug']); @@ -544,9 +525,9 @@ protected function postSave() /** * @param array|null $properties Properties. - * @return boolean */ - protected function postUpdate(array $properties = null) + #[\Override] + protected function postUpdate(?array $properties = null): bool { // RoutableTrait $this->generateObjectRoute($this['slug']); diff --git a/packages/cms/src/Charcoal/Cms/AbstractFaq.php b/packages/cms/src/Charcoal/Cms/AbstractFaq.php index 5db4eba6e..46a5aef10 100644 --- a/packages/cms/src/Charcoal/Cms/AbstractFaq.php +++ b/packages/cms/src/Charcoal/Cms/AbstractFaq.php @@ -1,5 +1,7 @@ defaultData(...))) { $this->setData($this->defaultData()); } } @@ -92,9 +89,8 @@ public function dateTimeDate() /** * Some dates cannot be null - * @return void */ - public function verifyDates() + public function verifyDates(): void { if (!$this['newsDate']) { $this->setNewsDate('now'); @@ -350,9 +346,9 @@ public function isActiveRoute() * {@inheritdoc} * * @see \Charcoal\Source\StorableTrait::preSave() - * @return boolean */ - protected function preSave() + #[\Override] + protected function preSave(): bool { $this->verifyDates(); $this->setSlug($this->generateSlug()); @@ -365,9 +361,9 @@ protected function preSave() * * @see \Charcoal\Source\StorableTrait::preUpdate() * @param array $properties Optional properties to update. - * @return boolean */ - protected function preUpdate(array $properties = null) + #[\Override] + protected function preUpdate(?array $properties = null): bool { $this->verifyDates(); $this->setSlug($this->generateSlug()); @@ -379,7 +375,8 @@ protected function preUpdate(array $properties = null) * @see \Charcoal\Source\StorableTrait::postSave() * @return boolean Parent postSave(). */ - protected function postSave() + #[\Override] + protected function postSave(): bool { // RoutableTrait $this->generateObjectRoute($this['slug']); @@ -390,9 +387,9 @@ protected function postSave() /** * @see \Charcoal\Source\StorableTrait::postUpdate() * @param array|null $properties Properties. - * @return boolean */ - protected function postUpdate(array $properties = null) + #[\Override] + protected function postUpdate(?array $properties = null): bool { // RoutableTrait $this->generateObjectRoute($this['slug']); diff --git a/packages/cms/src/Charcoal/Cms/AbstractSection.php b/packages/cms/src/Charcoal/Cms/AbstractSection.php index 2076af6f2..0df37b219 100644 --- a/packages/cms/src/Charcoal/Cms/AbstractSection.php +++ b/packages/cms/src/Charcoal/Cms/AbstractSection.php @@ -47,10 +47,7 @@ abstract class AbstractSection extends Content implements SectionInterface public const TYPE_EXTERNAL = 'charcoal/cms/section/external-section'; public const DEFAULT_TYPE = self::TYPE_CONTENT; - /** - * @var string - */ - private $sectionType = self::DEFAULT_TYPE; + private string $sectionType = self::DEFAULT_TYPE; /** * @var Translation|string|null @@ -103,11 +100,11 @@ abstract class AbstractSection extends Content implements SectionInterface * Section constructor. * @param array $data Init data. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { parent::__construct($data); - if (is_callable([ $this, 'defaultData' ])) { + if (is_callable($this->defaultData(...))) { $this->setData($this->defaultData()); } } @@ -119,7 +116,7 @@ public function __construct(array $data = null) */ public function isDeletable() { - return !!$this->id() && !$this->locked(); + return (bool)$this->id() && !$this->locked(); } /** @@ -423,10 +420,9 @@ public function defaultMetaImage() * Route generated on postSave in case * it contains the ID of the section, which * you only get once you have save - * - * @return boolean */ - protected function postSave() + #[\Override] + protected function postSave(): bool { // RoutableTrait if (!$this->locked()) { @@ -440,9 +436,9 @@ protected function postSave() * Check whatever before the update. * * @param array|null $properties Properties. - * @return boolean */ - protected function postUpdate(array $properties = null) + #[\Override] + protected function postUpdate(?array $properties = null): bool { if (!$this->locked()) { $this->generateObjectRoute($this['slug']); @@ -453,10 +449,9 @@ protected function postUpdate(array $properties = null) /** * {@inheritdoc} - * - * @return boolean */ - protected function preSave() + #[\Override] + protected function preSave(): bool { if (!$this->locked()) { $this->setSlug($this->generateSlug()); @@ -469,9 +464,9 @@ protected function preSave() * {@inheritdoc} * * @param array $properties Optional properties to update. - * @return boolean */ - protected function preUpdate(array $properties = null) + #[\Override] + protected function preUpdate(?array $properties = null): bool { if (!$this->locked()) { $this->setSlug($this->generateSlug()); @@ -484,9 +479,9 @@ protected function preUpdate(array $properties = null) * Event called before _deleting_ the object. * * @see \Charcoal\Model\AbstractModel::preDelete() For the "delete" Event. - * @return boolean */ - protected function preDelete() + #[\Override] + protected function preDelete(): bool { if ($this->locked()) { return false; diff --git a/packages/cms/src/Charcoal/Cms/AbstractTag.php b/packages/cms/src/Charcoal/Cms/AbstractTag.php index 29f281069..bca5e1559 100644 --- a/packages/cms/src/Charcoal/Cms/AbstractTag.php +++ b/packages/cms/src/Charcoal/Cms/AbstractTag.php @@ -47,7 +47,7 @@ abstract class AbstractTag extends Content implements TagInterface /** * @param array $data The object's data options. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { parent::__construct($data); diff --git a/packages/cms/src/Charcoal/Cms/AbstractWebTemplate.php b/packages/cms/src/Charcoal/Cms/AbstractWebTemplate.php index f07337ca2..64804ae76 100644 --- a/packages/cms/src/Charcoal/Cms/AbstractWebTemplate.php +++ b/packages/cms/src/Charcoal/Cms/AbstractWebTemplate.php @@ -61,10 +61,8 @@ abstract class AbstractWebTemplate extends AbstractTemplate /** * Additional SEO metadata. - * - * @var array */ - private $seoMetadata = []; + private \ArrayIterator|array $seoMetadata = []; /** * Inject dependencies from a DI Container. @@ -72,6 +70,7 @@ abstract class AbstractWebTemplate extends AbstractTemplate * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -343,7 +342,7 @@ public function opengraphImage() $img = (string)$this->fallbackOpengraphImage(); } - if ($img) { + if ($img !== '' && $img !== '0') { $uri = $this->baseUrl(); return $uri->withPath(strval($img)); } @@ -384,7 +383,7 @@ public function hasSeoMetadata() return (count($this->seoMetadata) > 0); } - return !empty($this->seoMetadata); + return $this->seoMetadata !== []; } /** @@ -443,12 +442,10 @@ public function appConfig($key = null, $default = null) if ($key) { if (isset($this->appConfig[$key])) { return $this->appConfig[$key]; + } elseif (!is_string($default) && is_callable($default)) { + return $default(); } else { - if (!is_string($default) && is_callable($default)) { - return $default(); - } else { - return $default; - } + return $default; } } @@ -477,10 +474,10 @@ protected function setBaseUrl(UriInterface $uri) */ public function baseUrl() { - if (!isset($this->baseUrl)) { + if ($this->baseUrl === null) { throw new RuntimeException(sprintf( 'The base URI is not defined for [%s]', - get_class($this) + static::class )); } @@ -500,13 +497,11 @@ public function createAbsoluteUrl($uri) $uri = $this->baseUrl()->withPath(''); } else { $parts = parse_url($uri); - if (!isset($parts['scheme'])) { - if (!in_array($uri[0], [ '/', '#', '?' ])) { - $path = isset($parts['path']) ? $parts['path'] : ''; - $query = isset($parts['query']) ? $parts['query'] : ''; - $hash = isset($parts['fragment']) ? $parts['fragment'] : ''; - $uri = $this->baseUrl()->withPath($path)->withQuery($query)->withFragment($hash); - } + if (!isset($parts['scheme']) && !in_array($uri[0], [ '/', '#', '?' ])) { + $path = ($parts['path'] ?? ''); + $query = ($parts['query'] ?? ''); + $hash = ($parts['fragment'] ?? ''); + $uri = $this->baseUrl()->withPath($path)->withQuery($query)->withFragment($hash); } } diff --git a/packages/cms/src/Charcoal/Cms/Config.php b/packages/cms/src/Charcoal/Cms/Config.php index 1a663185d..4c0bfdc09 100644 --- a/packages/cms/src/Charcoal/Cms/Config.php +++ b/packages/cms/src/Charcoal/Cms/Config.php @@ -53,11 +53,11 @@ class Config extends Content implements * Section constructor. * @param array $data The data. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { parent::__construct($data); - if (is_callable([$this, 'defaultData'])) { + if (is_callable($this->defaultData(...))) { $this->setData($this->defaultData()); } } @@ -65,12 +65,10 @@ public function __construct(array $data = null) // ========================================================================== // SETTERS // ========================================================================== - /** * @param mixed $defaultMetaTitle The default meta title. - * @return self */ - public function setDefaultMetaTitle($defaultMetaTitle) + public function setDefaultMetaTitle($defaultMetaTitle): static { $this->defaultMetaTitle = $this->translator()->translation($defaultMetaTitle); @@ -79,9 +77,8 @@ public function setDefaultMetaTitle($defaultMetaTitle) /** * @param mixed $defaultMetaDescription The default meta description. - * @return self */ - public function setDefaultMetaDescription($defaultMetaDescription) + public function setDefaultMetaDescription($defaultMetaDescription): static { $this->defaultMetaDescription = $this->translator()->translation($defaultMetaDescription); @@ -90,9 +87,8 @@ public function setDefaultMetaDescription($defaultMetaDescription) /** * @param mixed $defaultMetaImage The default meta image. - * @return self */ - public function setDefaultMetaImage($defaultMetaImage) + public function setDefaultMetaImage($defaultMetaImage): static { $this->defaultMetaImage = $defaultMetaImage; @@ -101,9 +97,8 @@ public function setDefaultMetaImage($defaultMetaImage) /** * @param mixed $defaultMetaUrl The default meta url. - * @return self */ - public function setDefaultMetaUrl($defaultMetaUrl) + public function setDefaultMetaUrl($defaultMetaUrl): static { $this->defaultMetaUrl = $this->translator()->translation($defaultMetaUrl); @@ -112,9 +107,8 @@ public function setDefaultMetaUrl($defaultMetaUrl) /** * @param array|StructureMetadata|mixed $socialMedias The social media array. - * @return self */ - public function setSocialMedias($socialMedias) + public function setSocialMedias($socialMedias): static { $this->socialMedias = $socialMedias; @@ -123,9 +117,8 @@ public function setSocialMedias($socialMedias) /** * @param string $defaultFromEmail The default email to send from. - * @return self */ - public function setDefaultFromEmail($defaultFromEmail) + public function setDefaultFromEmail($defaultFromEmail): static { $this->defaultFromEmail = $defaultFromEmail; diff --git a/packages/cms/src/Charcoal/Cms/Config/CmsConfig.php b/packages/cms/src/Charcoal/Cms/Config/CmsConfig.php index 9e6862af0..201f87343 100644 --- a/packages/cms/src/Charcoal/Cms/Config/CmsConfig.php +++ b/packages/cms/src/Charcoal/Cms/Config/CmsConfig.php @@ -74,12 +74,10 @@ class CmsConfig extends AbstractConfig // ========================================================================== // INIT // ========================================================================== - /** * @param ModelInterface $model The object model. - * @return void */ - public function addModel(ModelInterface $model) + public function addModel(ModelInterface $model): void { $this->setData($model->data()); } @@ -87,12 +85,10 @@ public function addModel(ModelInterface $model) // ========================================================================== // SETTERS // ========================================================================== - /** * @param mixed $defaultFromEmail The default email for contact forms. - * @return self */ - public function setDefaultFromEmail($defaultFromEmail) + public function setDefaultFromEmail($defaultFromEmail): static { $this->defaultFromEmail = $defaultFromEmail; @@ -101,9 +97,8 @@ public function setDefaultFromEmail($defaultFromEmail) /** * @param mixed $homeNews The news to display on home page. - * @return self */ - public function setHomeNews($homeNews) + public function setHomeNews($homeNews): static { $this->homeNews = $homeNews; @@ -112,9 +107,8 @@ public function setHomeNews($homeNews) /** * @param mixed $homeEvents The events to display on home page. - * @return self */ - public function setHomeEvents($homeEvents) + public function setHomeEvents($homeEvents): static { $this->homeEvents = $homeEvents; @@ -125,7 +119,7 @@ public function setHomeEvents($homeEvents) * @param array $newsConfig The news configuration object. * @return $this */ - public function setNews(array $newsConfig) + public function setNews(array $newsConfig): static { if (!$this->newsConfig) { $this->newsConfig = new NewsConfig(); @@ -140,7 +134,7 @@ public function setNews(array $newsConfig) * @param array $eventConfig The event configuration object. * @return $this */ - public function setEvent(array $eventConfig) + public function setEvent(array $eventConfig): static { if (!$this->eventConfig) { $this->eventConfig = new EventConfig(); @@ -155,7 +149,7 @@ public function setEvent(array $eventConfig) * @param array $sectionConfig The section configuration object. * @return $this */ - public function setSection(array $sectionConfig) + public function setSection(array $sectionConfig): static { if (!$this->sectionConfig) { $this->sectionConfig = new SectionConfig(); @@ -168,9 +162,8 @@ public function setSection(array $sectionConfig) /** * @param string $contactCategory Must conform City\\Support\\Interface\\ContactCategoryInterface. - * @return self */ - public function setContactCategoryObj($contactCategory) + public function setContactCategoryObj($contactCategory): static { $this->contactCategoryObj = $contactCategory; @@ -179,9 +172,8 @@ public function setContactCategoryObj($contactCategory) /** * @param string $contactObj Must conform City\\Support\\Interface\\ContactInterface. - * @return self */ - public function setContactObj($contactObj) + public function setContactObj($contactObj): static { $this->contactObj = $contactObj; @@ -190,9 +182,8 @@ public function setContactObj($contactObj) /** * @param string $defaultContactCategory The default contact category fallback. - * @return self */ - public function setDefaultContactCategory($defaultContactCategory) + public function setDefaultContactCategory($defaultContactCategory): static { $this->defaultContactCategory = $defaultContactCategory; @@ -201,9 +192,8 @@ public function setDefaultContactCategory($defaultContactCategory) /** * @param array $dateFormats Formats for full dates. - * @return self */ - public function setDateFormats(array $dateFormats) + public function setDateFormats(array $dateFormats): static { $this->dateFormats = array_replace_recursive( $this->dateFormats, @@ -215,9 +205,8 @@ public function setDateFormats(array $dateFormats) /** * @param array $timeFormats Formats for time. - * @return self */ - public function setTimeFormats(array $timeFormats) + public function setTimeFormats(array $timeFormats): static { $this->timeFormats = array_replace_recursive( $this->timeFormats, diff --git a/packages/cms/src/Charcoal/Cms/Config/EventConfig.php b/packages/cms/src/Charcoal/Cms/Config/EventConfig.php index 4d70a901a..e10ccaffc 100644 --- a/packages/cms/src/Charcoal/Cms/Config/EventConfig.php +++ b/packages/cms/src/Charcoal/Cms/Config/EventConfig.php @@ -1,5 +1,7 @@ thumbnail; } @@ -120,7 +119,7 @@ public function parentSectionSlug() * @param integer $numPerPage Number of event per page. * @return EventConfig */ - public function setNumPerPage($numPerPage) + public function setNumPerPage($numPerPage): static { $this->numPerPage = $numPerPage; @@ -131,7 +130,7 @@ public function setNumPerPage($numPerPage) * @param boolean $entryCycle Cycle event or not. * @return EventConfig */ - public function setEntryCycle($entryCycle) + public function setEntryCycle($entryCycle): static { $this->entryCycle = $entryCycle; @@ -143,7 +142,7 @@ public function setEntryCycle($entryCycle) * @param string $lifespan Event expiry. * @return EventConfig */ - public function setLifespan($lifespan) + public function setLifespan($lifespan): static { $this->lifespan = $lifespan; @@ -154,7 +153,7 @@ public function setLifespan($lifespan) * @param string $objType Event object type. * @return EventConfig */ - public function setObjType($objType) + public function setObjType($objType): static { $this->objType = $objType; @@ -165,7 +164,7 @@ public function setObjType($objType) * @param string $category Event category object. * @return EventConfig */ - public function setCategory($category) + public function setCategory($category): static { $this->category = $category; @@ -177,7 +176,7 @@ public function setCategory($category) * @param string $configFeatIdent Config property containing featured event. * @return EventConfig */ - public function setConfigFeatIdent($configFeatIdent) + public function setConfigFeatIdent($configFeatIdent): static { $this->configFeatIdent = $configFeatIdent; @@ -189,7 +188,7 @@ public function setConfigFeatIdent($configFeatIdent) * @param array $thumbnail Event thumbnail size. * @return EventConfig */ - public function setThumbnail(array $thumbnail) + public function setThumbnail(array $thumbnail): static { $this->thumbnail = $thumbnail; @@ -200,7 +199,7 @@ public function setThumbnail(array $thumbnail) * @param string $parentSectionSlug Event parent section (slug). * @return EventConfig */ - public function setParentSectionSlug($parentSectionSlug) + public function setParentSectionSlug($parentSectionSlug): static { $this->parentSectionSlug = $parentSectionSlug; diff --git a/packages/cms/src/Charcoal/Cms/Config/NewsConfig.php b/packages/cms/src/Charcoal/Cms/Config/NewsConfig.php index 68f6f100f..debefc86e 100644 --- a/packages/cms/src/Charcoal/Cms/Config/NewsConfig.php +++ b/packages/cms/src/Charcoal/Cms/Config/NewsConfig.php @@ -1,5 +1,7 @@ thumbnail; } @@ -131,9 +130,8 @@ public function parentSectionSlug() /** * @param integer $numPerPage Number of news per page. - * @return NewsConfig */ - public function setNumPerPage($numPerPage) + public function setNumPerPage($numPerPage): static { $this->numPerPage = $numPerPage; @@ -142,9 +140,8 @@ public function setNumPerPage($numPerPage) /** * @param boolean $entryCycle Cycle news or not. - * @return NewsConfig */ - public function setEntryCycle($entryCycle) + public function setEntryCycle($entryCycle): static { $this->entryCycle = $entryCycle; @@ -154,9 +151,8 @@ public function setEntryCycle($entryCycle) /** * Accept all DateTime string. * @param string $defaultExpiry Expiry. - * @return NewsConfig */ - public function setDefaultExpiry($defaultExpiry) + public function setDefaultExpiry($defaultExpiry): static { $this->defaultExpiry = $defaultExpiry; @@ -165,9 +161,8 @@ public function setDefaultExpiry($defaultExpiry) /** * @param string $median DateTime string. - * @return NewsConfig */ - public function setMedian($median) + public function setMedian($median): static { $this->median = $median; @@ -176,9 +171,8 @@ public function setMedian($median) /** * @param string $objType News object type. - * @return NewsConfig */ - public function setObjType($objType) + public function setObjType($objType): static { $this->objType = $objType; @@ -187,9 +181,8 @@ public function setObjType($objType) /** * @param string $category News category object. - * @return NewsConfig */ - public function setCategory($category) + public function setCategory($category): static { $this->category = $category; @@ -199,9 +192,8 @@ public function setCategory($category) /** * Might be overkill. * @param string $configFeatIdent Config property containing featured news. - * @return NewsConfig */ - public function setConfigFeatIdent($configFeatIdent) + public function setConfigFeatIdent($configFeatIdent): static { $this->configFeatIdent = $configFeatIdent; @@ -211,9 +203,8 @@ public function setConfigFeatIdent($configFeatIdent) /** * resize -> width. * @param array $thumbnail News thumbnail size. - * @return NewsConfig */ - public function setThumbnail(array $thumbnail) + public function setThumbnail(array $thumbnail): static { $this->thumbnail = $thumbnail; @@ -222,9 +213,8 @@ public function setThumbnail(array $thumbnail) /** * @param string $parentSectionSlug News parent section (slug). - * @return NewsConfig */ - public function setParentSectionSlug($parentSectionSlug) + public function setParentSectionSlug($parentSectionSlug): static { $this->parentSectionSlug = $parentSectionSlug; diff --git a/packages/cms/src/Charcoal/Cms/Config/SectionConfig.php b/packages/cms/src/Charcoal/Cms/Config/SectionConfig.php index ce6f8eb95..e324e26cc 100644 --- a/packages/cms/src/Charcoal/Cms/Config/SectionConfig.php +++ b/packages/cms/src/Charcoal/Cms/Config/SectionConfig.php @@ -1,5 +1,7 @@ baseSection = $baseSection; @@ -45,9 +46,8 @@ public function setBaseSection($baseSection) * Set the available section types * * @param mixed $sectionTypes Section types. - * @return SectionConfig */ - public function setSectionTypes($sectionTypes) + public function setSectionTypes($sectionTypes): static { $this->sectionTypes = $sectionTypes; return $this; @@ -55,9 +55,8 @@ public function setSectionTypes($sectionTypes) /** * @param string $objType Section object type. - * @return SectionConfig */ - public function setObjType($objType) + public function setObjType($objType): static { $this->objType = $objType; diff --git a/packages/cms/src/Charcoal/Cms/ConfigInterface.php b/packages/cms/src/Charcoal/Cms/ConfigInterface.php index 9c64641bb..047272138 100644 --- a/packages/cms/src/Charcoal/Cms/ConfigInterface.php +++ b/packages/cms/src/Charcoal/Cms/ConfigInterface.php @@ -1,5 +1,7 @@ defaultData(...))) { $this->setData($this->defaultData()); } } /** * CategoryTrait > itemType() - * - * @return string */ - public function itemType() + public function itemType(): string { return Event::class; } @@ -48,7 +46,7 @@ public function itemType() /** * @return \Charcoal\Model\Collection|array */ - public function loadCategoryItems() + public function loadCategoryItems(): array { return []; } @@ -63,9 +61,8 @@ public function name() /** * @param mixed $name The category name. - * @return self */ - public function setName($name) + public function setName($name): static { $this->name = $this->translator()->translation($name); @@ -74,9 +71,9 @@ public function setName($name) /** * @param ValidatorInterface $v Optional. A custom validator object to use for validation. If null, use object's. - * @return boolean */ - public function validate(ValidatorInterface &$v = null) + #[\Override] + public function validate(?ValidatorInterface &$v = null): bool { parent::validate($v); diff --git a/packages/cms/src/Charcoal/Cms/EventInterface.php b/packages/cms/src/Charcoal/Cms/EventInterface.php index 01426e2e7..2934c471a 100644 --- a/packages/cms/src/Charcoal/Cms/EventInterface.php +++ b/packages/cms/src/Charcoal/Cms/EventInterface.php @@ -1,5 +1,7 @@ categoryType() - * - * @return string */ - public function categoryType() + public function categoryType(): string { return FaqCategory::class; } diff --git a/packages/cms/src/Charcoal/Cms/FaqCategory.php b/packages/cms/src/Charcoal/Cms/FaqCategory.php index fd1d9b41a..180ac340b 100644 --- a/packages/cms/src/Charcoal/Cms/FaqCategory.php +++ b/packages/cms/src/Charcoal/Cms/FaqCategory.php @@ -1,5 +1,7 @@ itemType() - * - * @return string */ - public function itemType() + public function itemType(): string { return Faq::class; } @@ -27,7 +27,7 @@ public function itemType() /** * @return \Charcoal\Model\Collection|array */ - public function loadCategoryItems() + public function loadCategoryItems(): array { return []; } diff --git a/packages/cms/src/Charcoal/Cms/FaqInterface.php b/packages/cms/src/Charcoal/Cms/FaqInterface.php index 04c82a310..ce78ec5e0 100644 --- a/packages/cms/src/Charcoal/Cms/FaqInterface.php +++ b/packages/cms/src/Charcoal/Cms/FaqInterface.php @@ -1,5 +1,7 @@ data() as $lang => $val) { + foreach ($meta->data() as $val) { if ($val && $val != '') { $empty = false; } diff --git a/packages/cms/src/Charcoal/Cms/Mixin/HasContentBlocksInterface.php b/packages/cms/src/Charcoal/Cms/Mixin/HasContentBlocksInterface.php index d5685c7ce..31218c3be 100644 --- a/packages/cms/src/Charcoal/Cms/Mixin/HasContentBlocksInterface.php +++ b/packages/cms/src/Charcoal/Cms/Mixin/HasContentBlocksInterface.php @@ -1,5 +1,7 @@ numContentBlocks()); + return (bool)$this->numContentBlocks(); } /** * Count the number of content blocks associated to this object. - * - * @return integer */ - public function numContentBlocks() + public function numContentBlocks(): int { return count($this->contentBlocks()); } @@ -78,9 +74,7 @@ private function metaDescFromAttachments() if ($attachment->isText()) { $content = $attachment->description(); - $content = $this->ellipsis($content); - - return $content; + return $this->ellipsis($content); } } @@ -122,7 +116,7 @@ private function ellipsis($content, $length = 200) abstract public function getAttachments( $group = null, $type = null, - callable $before = null, - callable $after = null + ?callable $before = null, + ?callable $after = null ); } diff --git a/packages/cms/src/Charcoal/Cms/News.php b/packages/cms/src/Charcoal/Cms/News.php index c1bf4913c..842615668 100644 --- a/packages/cms/src/Charcoal/Cms/News.php +++ b/packages/cms/src/Charcoal/Cms/News.php @@ -1,5 +1,7 @@ categoryType() - * - * @return string */ - public function categoryType() + public function categoryType(): string { return NewsCategory::class; } diff --git a/packages/cms/src/Charcoal/Cms/NewsCategory.php b/packages/cms/src/Charcoal/Cms/NewsCategory.php index f09b9337a..e1afce7bc 100644 --- a/packages/cms/src/Charcoal/Cms/NewsCategory.php +++ b/packages/cms/src/Charcoal/Cms/NewsCategory.php @@ -26,21 +26,19 @@ class NewsCategory extends Content implements CategoryInterface * Section constructor. * @param array $data Init data. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { parent::__construct($data); - if (is_callable([ $this, 'defaultData' ])) { + if (is_callable($this->defaultData(...))) { $this->setData($this->defaultData()); } } /** * CategoryTrait > itemType() - * - * @return string */ - public function itemType() + public function itemType(): string { return News::class; } @@ -48,7 +46,7 @@ public function itemType() /** * @return \Charcoal\Model\Collection|array */ - public function loadCategoryItems() + public function loadCategoryItems(): array { return []; } @@ -63,9 +61,8 @@ public function name() /** * @param mixed $name The category name. - * @return self */ - public function setName($name) + public function setName($name): static { $this->name = $this->translator()->translation($name); @@ -74,14 +71,14 @@ public function setName($name) /** * @param ValidatorInterface $v Optional. A custom validator object to use for validation. If null, use object's. - * @return boolean */ - public function validate(ValidatorInterface &$v = null) + #[\Override] + public function validate(?ValidatorInterface &$v = null): bool { parent::validate($v); foreach ($this->translator()->locales() as $locale => $value) { - if (!(string)$this['name'][$locale]) { + if ((string)$this['name'][$locale] === '' || (string)$this['name'][$locale] === '0') { $this->validator()->error( (string)$this->translator()->translation([ 'fr' => 'Le NOM doit être rempli dans toutes les langues.', diff --git a/packages/cms/src/Charcoal/Cms/NewsInterface.php b/packages/cms/src/Charcoal/Cms/NewsInterface.php index ba3fc7b4f..cc785d5e8 100644 --- a/packages/cms/src/Charcoal/Cms/NewsInterface.php +++ b/packages/cms/src/Charcoal/Cms/NewsInterface.php @@ -1,5 +1,7 @@ path = ltrim($data['path'], '/'); + $this->path = ltrim((string)$data['path'], '/'); } /** * Determine if the URI path resolves to an object. * * @param Container $container A DI (Pimple) container. - * @return boolean */ - public function pathResolvable(Container $container) + public function pathResolvable(Container $container): bool { $event = $this->loadEventFromPath($container); return ($event instanceof EventInterface) && $event->id(); @@ -72,6 +67,7 @@ public function pathResolvable(Container $container) * @param ResponseInterface $response A PSR-7 compatible Response instance. * @return ResponseInterface */ + #[\Override] public function __invoke( Container $container, RequestInterface $request, @@ -87,11 +83,11 @@ public function __invoke( $templateIdent = (string)$event['templateIdent']; $templateController = (string)$event['templateIdent']; - if (!$templateController) { + if ($templateController === '' || $templateController === '0') { $container['logger']->warning(sprintf( '[%s] Missing template controller on model [%s] for ID [%s]', - get_class($this), - get_class($event), + static::class, + $event::class, $event['id'] )); return $response->withStatus(500); @@ -110,8 +106,8 @@ public function __invoke( if ($templateContent === $templateIdent || $templateContent === '') { $container['logger']->warning(sprintf( '[%s] Missing or bad template identifier on model [%s] for ID [%s]', - get_class($this), - get_class($event), + static::class, + $event::class, $templateIdent )); return $response->withStatus(500); @@ -131,7 +127,7 @@ protected function loadEventFromPath(Container $container) { if ($this->event === null) { $config = $this->config(); - $objType = (isset($config['obj_type']) ? $config['obj_type'] : $this->objType); + $objType = ($config['obj_type'] ?? $this->objType); try { $model = $container['model/factory']->create($objType); @@ -146,11 +142,11 @@ protected function loadEventFromPath(Container $container) $this->event = $model; return $model; } - } catch (Exception $e) { + } catch (Exception) { $container['logger']->debug(sprintf( '[%s] Unable to load model [%s] for path [%s]', - get_class($this), - get_class($model), + static::class, + $model::class, $this->path )); } diff --git a/packages/cms/src/Charcoal/Cms/Route/GenericRoute.php b/packages/cms/src/Charcoal/Cms/Route/GenericRoute.php index 08e66ee41..39401a3ea 100644 --- a/packages/cms/src/Charcoal/Cms/Route/GenericRoute.php +++ b/packages/cms/src/Charcoal/Cms/Route/GenericRoute.php @@ -58,17 +58,13 @@ class GenericRoute extends TemplateRoute /** * Store the factory instance for the current class. - * - * @var FactoryInterface */ - private $modelFactory; + private ?\Charcoal\Factory\FactoryInterface $modelFactory = null; /** * Store the collection loader for the current class. - * - * @var CollectionLoader */ - private $collectionLoader; + private ?\Charcoal\Loader\CollectionLoader $collectionLoader = null; /** * Track the state of required dependencies. @@ -103,7 +99,7 @@ public function __construct(array $data) { parent::__construct($data); - $this->setPath(ltrim($data['path'], '/')); + $this->setPath(ltrim((string)$data['path'], '/')); } /** @@ -124,11 +120,7 @@ public function pathResolvable(Container $container) } $contextObject = $this->getContextObject(); - if (!$contextObject || !$this->isValidContextObject($contextObject)) { - return false; - } - - return true; + return $contextObject && $this->isValidContextObject($contextObject); } /** @@ -139,6 +131,7 @@ public function pathResolvable(Container $container) * @param ResponseInterface $response A PSR-7 compatible Response instance. * @return ResponseInterface */ + #[\Override] public function __invoke( Container $container, RequestInterface $request, @@ -173,8 +166,8 @@ public function __invoke( if ($templateContent === $templateIdent || $templateContent === '') { $container['logger']->warning(sprintf( '[%s] Missing or bad template identifier on model [%s] for ID [%s]', - get_class($this), - get_class($this->getContextObject()), + static::class, + $this->getContextObject()::class, $templateIdent )); return $response->withStatus(500); @@ -193,9 +186,7 @@ public function __invoke( */ public function createRouteObject() { - $route = $this->modelFactory()->create($this->objectRouteClass()); - - return $route; + return $this->modelFactory()->create($this->objectRouteClass()); } /** @@ -253,10 +244,7 @@ protected function resolveLatestObjectRoute( return $response; } - /** - * @return self - */ - protected function resolveTemplateContextObject() + protected function resolveTemplateContextObject(): static { $config = $this->config(); @@ -320,10 +308,8 @@ protected function resolveTemplateContextObject() } // Overwrite from custom object template_options - if ($contextObject instanceof TemplateableInterface) { - if (!empty($contextObject['templateOptions'])) { - $templateOptions = $contextObject['templateOptions']; - } + if ($contextObject instanceof TemplateableInterface && !empty($contextObject['templateOptions'])) { + $templateOptions = $contextObject['templateOptions']; } if (isset($templateOptions) && $templateOptions) { @@ -347,6 +333,7 @@ protected function resolveTemplateContextObject() * @param RequestInterface $request The request to intialize the template with. * @return string */ + #[\Override] protected function createTemplate(Container $container, RequestInterface $request) { $template = parent::createTemplate($container, $request); @@ -362,9 +349,8 @@ protected function createTemplate(Container $container, RequestInterface $reques * * @param string $className The class name of the object route model. * @throws InvalidArgumentException If the class name is not a string. - * @return self */ - protected function setObjectRouteClass($className) + protected function setObjectRouteClass($className): static { if (!is_string($className)) { throw new InvalidArgumentException( @@ -402,16 +388,7 @@ protected function isValidContextObject(RoutableInterface $contextObject) if (!$contextObject->id()) { return false; } - - if ($contextObject instanceof RoutableInterface) { - return $contextObject->isActiveRoute(); - } - - if (isset($contextObject['active'])) { - return (bool)$contextObject['active']; - } - - return true; + return $contextObject->isActiveRoute(); } /** @@ -467,9 +444,8 @@ protected function assertValidObjectRoute(ObjectRouteInterface $route) * Determine if the object route is valid. * * @param ObjectRouteInterface $route An object route to test. - * @return boolean */ - protected function isValidObjectRoute(ObjectRouteInterface $route) + protected function isValidObjectRoute(ObjectRouteInterface $route): bool { return ($route->id() && $route->getRouteObjType() && $route->getRouteObjId()); } @@ -552,14 +528,12 @@ public function getLatestObjectPathHistory(ObjectRouteInterface $route) /** * SETTERS */ - /** * Set the specified URI path. * * @param string $path The path to use for route resolution. - * @return self */ - protected function setPath($path) + protected function setPath($path): static { $this->path = $path; @@ -570,9 +544,8 @@ protected function setPath($path) * Set an object model factory. * * @param FactoryInterface $factory The model factory, to create objects. - * @return self */ - protected function setModelFactory(FactoryInterface $factory) + protected function setModelFactory(FactoryInterface $factory): static { $this->modelFactory = $factory; @@ -583,9 +556,8 @@ protected function setModelFactory(FactoryInterface $factory) * Set a model collection loader. * * @param CollectionLoader $loader The collection loader. - * @return self */ - public function setCollectionLoader(CollectionLoader $loader) + public function setCollectionLoader(CollectionLoader $loader): static { $this->collectionLoader = $loader; @@ -598,7 +570,7 @@ public function setCollectionLoader(CollectionLoader $loader) * @param string $langCode The locale's language code. * @return void */ - protected function setLocale($langCode) + protected function setLocale(string $langCode) { $translator = $this->translator(); $translator->setLocale($langCode); @@ -617,14 +589,14 @@ protected function setLocale($langCode) $choices = (array)$locale['locales']; array_push($locales, ...$choices); } elseif (isset($locale['locale'])) { - array_push($locales, $locale['locale']); + $locales[] = $locale['locale']; } } } $locales = array_unique($locales); - if ($locales) { + if ($locales !== []) { setlocale(LC_ALL, $locales); } } @@ -647,13 +619,12 @@ protected function path() * Retrieve the object model factory. * * @throws RuntimeException If the model factory was not previously set. - * @return FactoryInterface */ - public function modelFactory() + public function modelFactory(): \Charcoal\Factory\FactoryInterface { - if (!isset($this->modelFactory)) { + if (!$this->modelFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException( - sprintf('Model Factory is not defined for "%s"', get_class($this)) + sprintf('Model Factory is not defined for "%s"', static::class) ); } @@ -664,13 +635,12 @@ public function modelFactory() * Retrieve the model collection loader. * * @throws RuntimeException If the collection loader was not previously set. - * @return CollectionLoader */ - protected function collectionLoader() + protected function collectionLoader(): \Charcoal\Loader\CollectionLoader { - if (!isset($this->collectionLoader)) { + if (!$this->collectionLoader instanceof \Charcoal\Loader\CollectionLoader) { throw new RuntimeException( - sprintf('Collection Loader is not defined for "%s"', get_class($this)) + sprintf('Collection Loader is not defined for "%s"', static::class) ); } @@ -680,6 +650,7 @@ protected function collectionLoader() /** * @return boolean */ + #[\Override] protected function cacheEnabled() { $obj = $this->getContextObject(); @@ -689,16 +660,15 @@ protected function cacheEnabled() /** * @return integer */ + #[\Override] protected function cacheTtl() { $obj = $this->getContextObject(); return $obj['cache_ttl'] ?: 0; } - /** - * @return string - */ - protected function cacheIdent() + #[\Override] + protected function cacheIdent(): string { $obj = $this->getContextObject(); return $obj->objType() . '.' . $obj->id(); diff --git a/packages/cms/src/Charcoal/Cms/Route/NewsRoute.php b/packages/cms/src/Charcoal/Cms/Route/NewsRoute.php index dc33433e5..146a7c2af 100644 --- a/packages/cms/src/Charcoal/Cms/Route/NewsRoute.php +++ b/packages/cms/src/Charcoal/Cms/Route/NewsRoute.php @@ -26,10 +26,8 @@ class NewsRoute extends TemplateRoute /** * URI path. - * - * @var string */ - private $path; + private string $path; /** * The news entry matching the URI path. @@ -40,10 +38,8 @@ class NewsRoute extends TemplateRoute /** * The news entry model. - * - * @var string */ - private $objType = 'charcoal/cms/news'; + private string $objType = 'charcoal/cms/news'; /** * @param array $data Class depdendencies. @@ -51,16 +47,15 @@ class NewsRoute extends TemplateRoute public function __construct(array $data) { parent::__construct($data); - $this->path = ltrim($data['path'], '/'); + $this->path = ltrim((string)$data['path'], '/'); } /** * Determine if the URI path resolves to an object. * * @param Container $container A DI (Pimple) container. - * @return boolean */ - public function pathResolvable(Container $container) + public function pathResolvable(Container $container): bool { $news = $this->loadNewsFromPath($container); return ($news instanceof NewsInterface) && $news->id(); @@ -72,6 +67,7 @@ public function pathResolvable(Container $container) * @param ResponseInterface $response A PSR-7 compatible Response instance. * @return ResponseInterface */ + #[\Override] public function __invoke( Container $container, RequestInterface $request, @@ -87,11 +83,11 @@ public function __invoke( $templateIdent = (string)$news['templateIdent']; $templateController = (string)$news['templateIdent']; - if (!$templateController) { + if ($templateController === '' || $templateController === '0') { $container['logger']->warning(sprintf( '[%s] Missing template controller on model [%s] for ID [%s]', - get_class($this), - get_class($news), + static::class, + $news::class, $news['id'] )); return $response->withStatus(500); @@ -110,8 +106,8 @@ public function __invoke( if ($templateContent === $templateIdent || $templateContent === '') { $container['logger']->warning(sprintf( '[%s] Missing or bad template identifier on model [%s] for ID [%s]', - get_class($this), - get_class($news), + static::class, + $news::class, $templateIdent )); return $response->withStatus(500); @@ -131,7 +127,7 @@ protected function loadNewsFromPath(Container $container) { if ($this->news === null) { $config = $this->config(); - $objType = (isset($config['obj_type']) ? $config['obj_type'] : $this->objType); + $objType = ($config['obj_type'] ?? $this->objType); try { $model = $container['model/factory']->create($objType); @@ -146,11 +142,11 @@ protected function loadNewsFromPath(Container $container) $this->news = $model; return $model; } - } catch (Exception $e) { + } catch (Exception) { $container['logger']->debug(sprintf( '[%s] Unable to load model [%s] for path [%s]', - get_class($this), - get_class($model), + static::class, + $model::class, $this->path )); } diff --git a/packages/cms/src/Charcoal/Cms/Route/SectionRoute.php b/packages/cms/src/Charcoal/Cms/Route/SectionRoute.php index 797233234..1abc3a768 100644 --- a/packages/cms/src/Charcoal/Cms/Route/SectionRoute.php +++ b/packages/cms/src/Charcoal/Cms/Route/SectionRoute.php @@ -26,10 +26,8 @@ class SectionRoute extends TemplateRoute /** * URI path. - * - * @var string */ - private $path; + private string $path; /** * The section object matching the URI path. @@ -40,10 +38,8 @@ class SectionRoute extends TemplateRoute /** * The section model. - * - * @var string */ - private $objType = 'charcoal/cms/section'; + private string $objType = 'charcoal/cms/section'; /** * @param array $data Class depdendencies. @@ -52,16 +48,15 @@ public function __construct(array $data) { parent::__construct($data); - $this->path = ltrim($data['path'], '/'); + $this->path = ltrim((string)$data['path'], '/'); } /** * Determine if the URI path resolves to an object. * * @param Container $container A DI (Pimple) container. - * @return boolean */ - public function pathResolvable(Container $container) + public function pathResolvable(Container $container): bool { $section = $this->loadSectionFromPath($container); return ($section instanceof SectionInterface) && $section->id(); @@ -73,6 +68,7 @@ public function pathResolvable(Container $container) * @param ResponseInterface $response A PSR-7 compatible Response instance. * @return ResponseInterface */ + #[\Override] public function __invoke( Container $container, RequestInterface $request, @@ -88,11 +84,11 @@ public function __invoke( $templateIdent = (string)$section['templateIdent']; $templateController = (string)$section['templateIdent']; - if (!$templateController) { + if ($templateController === '' || $templateController === '0') { $container['logger']->warning(sprintf( '[%s] Missing template controller on model [%s] for ID [%s]', - get_class($this), - get_class($section), + static::class, + $section::class, $section['id'] )); return $response->withStatus(500); @@ -112,8 +108,8 @@ public function __invoke( if ($templateContent === $templateIdent || $templateContent === '') { $container['logger']->warning(sprintf( '[%s] Missing or bad template identifier on model [%s] for ID [%s]', - get_class($this), - get_class($section), + static::class, + $section::class, $templateIdent )); return $response->withStatus(500); @@ -133,7 +129,7 @@ protected function loadSectionFromPath(Container $container) { if ($this->section === null) { $config = $this->config(); - $objType = (isset($config['obj_type']) ? $config['obj_type'] : $this->objType); + $objType = ($config['obj_type'] ?? $this->objType); try { $model = $container['model/factory']->create($objType); @@ -148,11 +144,11 @@ protected function loadSectionFromPath(Container $container) $this->section = $model; return $model; } - } catch (Exception $e) { + } catch (Exception) { $container['logger']->debug(sprintf( '[%s] Unable to load model [%s] for path [%s]', - get_class($this), - get_class($model), + static::class, + $model::class, $this->path )); } diff --git a/packages/cms/src/Charcoal/Cms/SearchableInterface.php b/packages/cms/src/Charcoal/Cms/SearchableInterface.php index 89c794a6e..57aa639c9 100644 --- a/packages/cms/src/Charcoal/Cms/SearchableInterface.php +++ b/packages/cms/src/Charcoal/Cms/SearchableInterface.php @@ -1,5 +1,7 @@ externalUrl = $this->translator()->translation($url); @@ -31,6 +33,7 @@ public function setExternalUrl($url) /** * @return Translation|string|null */ + #[\Override] public function externalUrl() { return $this->externalUrl; diff --git a/packages/cms/src/Charcoal/Cms/SectionInterface.php b/packages/cms/src/Charcoal/Cms/SectionInterface.php index e4a924d5b..982de3435 100644 --- a/packages/cms/src/Charcoal/Cms/SectionInterface.php +++ b/packages/cms/src/Charcoal/Cms/SectionInterface.php @@ -1,5 +1,7 @@ modelFactory = $factory; @@ -85,9 +84,9 @@ protected function setModelFactory(FactoryInterface $factory) */ public function modelFactory() { - if (!isset($this->modelFactory)) { + if ($this->modelFactory === null) { throw new RuntimeException( - sprintf('Model Factory is not defined for "%s"', get_class($this)) + sprintf('Model Factory is not defined for "%s"', static::class) ); } @@ -98,9 +97,8 @@ public function modelFactory() * Set a model collection loader. * * @param CollectionLoader $loader The collection loader. - * @return self */ - protected function setCollectionLoader(CollectionLoader $loader) + protected function setCollectionLoader(CollectionLoader $loader): static { $this->collectionLoader = $loader; @@ -115,9 +113,9 @@ protected function setCollectionLoader(CollectionLoader $loader) */ public function collectionLoader() { - if (!isset($this->collectionLoader)) { + if ($this->collectionLoader === null) { throw new RuntimeException( - sprintf('Collection Loader is not defined for "%s"', get_class($this)) + sprintf('Collection Loader is not defined for "%s"', static::class) ); } diff --git a/packages/cms/src/Charcoal/Cms/Service/Loader/EventLoader.php b/packages/cms/src/Charcoal/Cms/Service/Loader/EventLoader.php index c536ab4e2..730a04a85 100644 --- a/packages/cms/src/Charcoal/Cms/Service/Loader/EventLoader.php +++ b/packages/cms/src/Charcoal/Cms/Service/Loader/EventLoader.php @@ -137,7 +137,7 @@ public function objType() * @param string $lifespan The lifespan of events. * @return self Chainable */ - public function setLifespan($lifespan) + public function setLifespan($lifespan): static { $this->lifespan = $lifespan; @@ -148,7 +148,7 @@ public function setLifespan($lifespan) * @param object $objType The object type. * @return self Chainable */ - public function setObjType($objType) + public function setObjType($objType): static { $this->objType = $objType; @@ -159,7 +159,7 @@ public function setObjType($objType) * @param mixed $date The date to convert. * @return DateTime */ - private function parseAsDate($date) + private function parseAsDate($date): \DateTimeInterface|\DateTime { if ($date instanceof DateTimeInterface) { return $date; diff --git a/packages/cms/src/Charcoal/Cms/Service/Loader/NewsLoader.php b/packages/cms/src/Charcoal/Cms/Service/Loader/NewsLoader.php index 11a21edda..266876b06 100644 --- a/packages/cms/src/Charcoal/Cms/Service/Loader/NewsLoader.php +++ b/packages/cms/src/Charcoal/Cms/Service/Loader/NewsLoader.php @@ -75,9 +75,7 @@ public function expired() */ public function upcoming() { - $loader = $this->published(); - - return $loader; + return $this->published(); } /** @@ -86,9 +84,7 @@ public function upcoming() */ public function archive() { - $loader = $this->expired(); - - return $loader; + return $this->expired(); } /** @@ -109,9 +105,8 @@ public function objType() /** * @param string $median The median between upcoming and archive. - * @return self */ - public function setMedian($median) + public function setMedian($median): static { $this->median = $median; @@ -120,9 +115,8 @@ public function setMedian($median) /** * @param object $objType The object type. - * @return self */ - public function setObjType($objType) + public function setObjType($objType): static { $this->objType = $objType; diff --git a/packages/cms/src/Charcoal/Cms/Service/Loader/SectionLoader.php b/packages/cms/src/Charcoal/Cms/Service/Loader/SectionLoader.php index 47c67e1e8..5b78d2aae 100644 --- a/packages/cms/src/Charcoal/Cms/Service/Loader/SectionLoader.php +++ b/packages/cms/src/Charcoal/Cms/Service/Loader/SectionLoader.php @@ -77,7 +77,7 @@ public function all() /** * @return \ArrayAccess|\Traversable */ - public function masters() + public function masters(): \ArrayAccess|array { $loader = $this->all(); $operator = []; @@ -92,7 +92,7 @@ public function masters() /** * @return \ArrayAccess|\Traversable */ - public function children() + public function children(): array { $masters = $this->masters(); @@ -144,7 +144,7 @@ public function sectionRoutes() $loader->setModel($proto); $filters = []; - foreach ($sectionTypes as $key => $val) { + foreach ($sectionTypes as $val) { $filters[] = 'route_obj_type = \'' . $val . '\''; } $q = 'SELECT * FROM `' . $proto->source()->table() . '` @@ -213,9 +213,7 @@ public function resolveSectionId($route) return ''; } - $sId = $routes['routes'][$route]; - - return $sId; + return $routes['routes'][$route]; } /** @@ -244,9 +242,8 @@ public function sectionTypes() /** * @param object $objType The object type. - * @return self */ - public function setObjType($objType) + public function setObjType($objType): static { $this->objType = $objType; @@ -255,9 +252,8 @@ public function setObjType($objType) /** * @param integer $baseSection The base section id. - * @return self */ - public function setBaseSection($baseSection) + public function setBaseSection($baseSection): static { $this->baseSection = $baseSection; @@ -266,9 +262,8 @@ public function setBaseSection($baseSection) /** * @param array|null $sectionTypes Available section types. - * @return self */ - public function setSectionTypes(array $sectionTypes = null) + public function setSectionTypes(?array $sectionTypes = null): static { $this->sectionTypes = $sectionTypes; @@ -282,7 +277,7 @@ public function setSectionTypes(array $sectionTypes = null) * @param string $delimiter The word delimiter. * @return string */ - public static function snake($value, $delimiter = '-') + public static function snake($value, string $delimiter = '-') { $key = $value; if (isset(static::$snakeCache[$key][$delimiter])) { @@ -290,7 +285,7 @@ public static function snake($value, $delimiter = '-') } if (!ctype_lower($value)) { $value = preg_replace('/\s+/u', '', $value); - $value = mb_strtolower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value), 'UTF-8'); + $value = mb_strtolower((string)preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, (string)$value), 'UTF-8'); } static::$snakeCache[$key][$delimiter] = $value; diff --git a/packages/cms/src/Charcoal/Cms/Service/Manager/AbstractManager.php b/packages/cms/src/Charcoal/Cms/Service/Manager/AbstractManager.php index daaac2faf..1a20fb22a 100644 --- a/packages/cms/src/Charcoal/Cms/Service/Manager/AbstractManager.php +++ b/packages/cms/src/Charcoal/Cms/Service/Manager/AbstractManager.php @@ -47,13 +47,13 @@ public function __construct(array $data) if (!isset($data['factory'])) { throw new Exception(sprintf( 'Model Factory must be defined in the %s constructor.', - get_called_class() + static::class )); } if (!isset($data['loader'])) { throw new Exception(sprintf( 'CollectionLoader must be defined in the %s constructor.', - get_called_class() + static::class )); } if (!isset($data['cms/config'])) { @@ -73,9 +73,8 @@ public function __construct(array $data) * Set an object model factory. * * @param FactoryInterface $factory The model factory, to create objects. - * @return self */ - protected function setModelFactory(FactoryInterface $factory) + protected function setModelFactory(FactoryInterface $factory): static { $this->modelFactory = $factory; @@ -90,9 +89,9 @@ protected function setModelFactory(FactoryInterface $factory) */ public function modelFactory() { - if (!isset($this->modelFactory)) { + if ($this->modelFactory === null) { throw new RuntimeException( - sprintf('Model Factory is not defined for "%s"', get_class($this)) + sprintf('Model Factory is not defined for "%s"', static::class) ); } @@ -103,9 +102,8 @@ public function modelFactory() * Set a model collection loader. * * @param CollectionLoader $loader The collection loader. - * @return self */ - protected function setCollectionLoader(CollectionLoader $loader) + protected function setCollectionLoader(CollectionLoader $loader): static { $this->collectionLoader = $loader; @@ -120,9 +118,9 @@ protected function setCollectionLoader(CollectionLoader $loader) */ public function collectionLoader() { - if (!isset($this->collectionLoader)) { + if ($this->collectionLoader === null) { throw new RuntimeException( - sprintf('Collection Loader is not defined for "%s"', get_class($this)) + sprintf('Collection Loader is not defined for "%s"', static::class) ); } @@ -131,9 +129,8 @@ public function collectionLoader() /** * @param mixed $adminConfig The admin configuration. - * @return self */ - public function setAdminConfig($adminConfig) + public function setAdminConfig($adminConfig): static { $this->adminConfig = $adminConfig; diff --git a/packages/cms/src/Charcoal/Cms/Service/Manager/EventManager.php b/packages/cms/src/Charcoal/Cms/Service/Manager/EventManager.php index c6442b579..12365277a 100644 --- a/packages/cms/src/Charcoal/Cms/Service/Manager/EventManager.php +++ b/packages/cms/src/Charcoal/Cms/Service/Manager/EventManager.php @@ -28,13 +28,13 @@ class EventManager extends AbstractManager private $currentEvent; /** @var integer $currentPage The current Page. */ - private $currentPage; + private int|float|null $currentPage = null; /** @var integer $numPerPage Events by page. */ private $numPerPage = 0; /** @var integer $numPage How many pages. */ - private $numPage; + private float|int|null $numPage = null; /** @var boolean $entryCycle Does the pager can cycle indefinitely. */ private $entryCycle = false; @@ -55,13 +55,13 @@ class EventManager extends AbstractManager private $all = []; /** @var EventInterface[] $entries The event collection. */ - private $entries = []; + private array $entries = []; /** @var EventInterface[] $archive The archive events collection. */ - private $archive = []; + private array $archive = []; /** @var EventInterface $entry An event. */ - private $entry; + private ?array $entry = null; /** @var object $objType The event object model. */ private $objType; @@ -76,19 +76,19 @@ class EventManager extends AbstractManager private $loader; /** @var array $mapEvents The events mapped per [year][month][date]. */ - private $mapEvents = []; + private array $mapEvents = []; /** @var datetime $date Datetime filter */ - private $date; + private ?\DateTime $date = null; /** @var mixed $year Year filter. */ - private $year; + private int|float|string|bool|null $year = null; /** @var mixed $month Month filter. */ - private $month; + private int|float|string|bool|null $month = null; /** @var mixed $day Day filter. */ - private $day; + private int|float|string|bool|null $day = null; /** * EventManager constructor. @@ -149,7 +149,7 @@ public function entries() } // Get event from specific date. - if ($date) { + if ($date instanceof \DateTime) { $loader = $this->loader()->all(); $proto = $this->loader()->proto(); $table = $proto->source()->table(); @@ -161,9 +161,7 @@ public function entries() AND active = 1' . $extraSql; - $collection = $loader->loadFromQuery($q); - - return $collection; + return $loader->loadFromQuery($q); } // YEAR only filter. @@ -179,9 +177,7 @@ public function entries() AND active = 1' . $extraSql; - $collection = $loader->loadFromQuery($q); - - return $collection; + return $loader->loadFromQuery($q); } // Year AND month filter. @@ -200,15 +196,11 @@ public function entries() AND active = 1' . $extraSql; - $collection = $loader->loadFromQuery($q); - - return $collection; + return $loader->loadFromQuery($q); } - if (isset($this->entries[$cat])) { - if (isset($this->entries[$cat][$page])) { - return $this->entries[$cat][$page]; - } + if (isset($this->entries[$cat]) && isset($this->entries[$cat][$page])) { + return $this->entries[$cat][$page]; } if ($this->category()) { @@ -264,7 +256,7 @@ public function all() /** * @return CategoryInterface[]|Collection The category collection. */ - public function loadCategoryItems() + public function loadCategoryItems(): \ArrayAccess|array { /** @var Model $model */ $model = $this->modelFactory(); @@ -306,7 +298,7 @@ public function featList(array $options = []) throw new Exception(sprintf( 'The featured news ident "%s" doesn\'t exist the class "%s"', $ident, - get_class($config) + $config::class )); } $ids = $config->{$ident}(); @@ -315,32 +307,30 @@ public function featList(array $options = []) return null; } - $ids = explode(',', $ids); + $ids = explode(',', (string)$ids); $loader->addFilter('id', $ids, [ 'operator' => 'in' ]) ->addOrder('id', 'values', [ 'values' => $ids ]); - if (count($options) > 0) { - foreach ($options as $key => $option) { - switch ($key) { - case 'filters': - $filters = $option; - foreach ($filters as $f) { - $filter[] = $f['property'] ?: ''; - $filter[] = $f['value'] ?: ''; - $filter[] = $f['options'] ?: ''; - $filter = join(',', $filter); - - $loader->addFilter($filter); - } - break; - case 'page': - $loader->setPage($option); - break; - case 'numPerPage': - $loader->setNumPerPage($option); - break; - } + foreach ($options as $key => $option) { + switch ($key) { + case 'filters': + $filters = $option; + foreach ($filters as $f) { + $filter[] = $f['property'] ?: ''; + $filter[] = $f['value'] ?: ''; + $filter[] = $f['options'] ?: ''; + $filter = implode(',', $filter); + + $loader->addFilter($filter); + } + break; + case 'page': + $loader->setPage($option); + break; + case 'numPerPage': + $loader->setNumPerPage($option); + break; } } @@ -356,10 +346,8 @@ public function archive() { $page = $this->page(); $cat = $this->category(); - if (isset($this->archive[$cat])) { - if (isset($this->archive[$cat][$page])) { - return $this->archive[$cat][$page]; - } + if (isset($this->archive[$cat]) && isset($this->archive[$cat][$page])) { + return $this->archive[$cat][$page]; } $loader = $this->loader()->archive(); @@ -420,7 +408,7 @@ public function next() /** * @return float|integer The current event index page ident. */ - public function currentPage() + public function currentPage(): float|int { if ($this->currentPage) { return $this->currentPage; @@ -459,11 +447,7 @@ public function getEventsByDate($date) $month = $date->format('m'); $day = $date->format('d'); - if (isset($map[$year][$month][$day])) { - return $map[$year][$month][$day]; - } - - return []; + return ($map[$year][$month][$day] ?? []); } /** @@ -498,38 +482,29 @@ public function entryCycle() * Amount of event (total) * @return integer How many event? */ - public function numEvent() + public function numEvent(): bool { - return !!(count($this->entries())); + return (bool)count($this->entries()); } /** * The total amount of pages. * @return float */ - public function numPages() + public function numPages(): float|int { - if ($this->numPage) { - $this->numPage; - }; - $entries = $this->entries(); $count = count($entries); - if ($this->numPerPage()) { - $this->numPage = ceil($count / $this->numPerPage()); - } else { - $this->numPage = 1; - } + $this->numPage = $this->numPerPage() ? ceil($count / $this->numPerPage()) : 1; return $this->numPage; } /** * Is there a pager. - * @return boolean */ - public function hasPager() + public function hasPager(): bool { return ($this->numPages() > 1); } @@ -578,7 +553,7 @@ public function loader() * Datetime object OR null. * @return mixed Datetime or null. */ - public function date() + public function date(): ?\DateTime { return $this->date; } @@ -587,7 +562,7 @@ public function date() * Full year * @return integer Full year. */ - public function year() + public function year(): int|float|string|bool|null { return $this->year; } @@ -596,7 +571,7 @@ public function year() * Month * @return mixed month. */ - public function month() + public function month(): int|float|string|bool|null { return $this->month; } @@ -605,16 +580,15 @@ public function month() * Day * @return mixed day. */ - public function day() + public function day(): int|float|string|bool|null { return $this->day; } /** * @param mixed $currentEvent The current event context. - * @return self */ - public function setCurrentEvent($currentEvent) + public function setCurrentEvent($currentEvent): static { $this->currentEvent = $currentEvent; @@ -623,9 +597,8 @@ public function setCurrentEvent($currentEvent) /** * @param integer $numPerPage The number of event per page. - * @return self */ - public function setNumPerPage($numPerPage) + public function setNumPerPage($numPerPage): static { $this->numPerPage = $numPerPage; @@ -634,9 +607,8 @@ public function setNumPerPage($numPerPage) /** * @param boolean $entryCycle Next and Prev cycles indefinitely. - * @return self */ - public function setEntryCycle($entryCycle) + public function setEntryCycle($entryCycle): static { $this->entryCycle = $entryCycle; @@ -645,9 +617,8 @@ public function setEntryCycle($entryCycle) /** * @param integer $page The page number to load. - * @return self */ - public function setPage($page) + public function setPage($page): static { $this->page = $page; @@ -656,9 +627,8 @@ public function setPage($page) /** * @param integer $category The current entry category. - * @return self */ - public function setCategory($category) + public function setCategory($category): static { $this->category = $category; @@ -667,9 +637,8 @@ public function setCategory($category) /** * @param mixed $objType The object type. - * @return self */ - public function setObjType($objType) + public function setObjType($objType): static { $this->objType = $objType; @@ -678,9 +647,8 @@ public function setObjType($objType) /** * @param mixed $featIdent The featured list ident. - * @return self */ - public function setFeatIdent($featIdent) + public function setFeatIdent($featIdent): static { $this->featIdent = $featIdent; @@ -689,9 +657,8 @@ public function setFeatIdent($featIdent) /** * @param EventLoader|null $loader The event loader provider. - * @return self */ - public function setLoader($loader) + public function setLoader($loader): static { $this->loader = $loader; @@ -701,9 +668,8 @@ public function setLoader($loader) /** * Set date filter. * @param DateTime $date Date filter. - * @return self */ - public function setDate(DateTime $date) + public function setDate(DateTime $date): static { $this->date = $date; @@ -716,7 +682,7 @@ public function setDate(DateTime $date) * @throws Exception If argument is not scalar. * @return EventManager */ - public function setYear($year) + public function setYear($year): int|float|string|bool { if (!is_scalar($year)) { throw new Exception('Year must be a string or an integer in EventManager setYear method.'); @@ -730,9 +696,8 @@ public function setYear($year) * Month. * @param mixed $month Specific month. * @throws Exception If argument is not scalar. - * @return EventManager */ - public function setMonth($month) + public function setMonth($month): static { if (!is_scalar($month)) { throw new Exception('Month must be a string or an integer in EventManager setMonth method.'); @@ -746,9 +711,8 @@ public function setMonth($month) * Day. * @param mixed $day Specific day. * @throws Exception If argument is not scalar. - * @return EventManager */ - public function setDay($day) + public function setDay($day): static { if (!is_scalar($day)) { throw new Exception('Day must be a string or an integer in EventManager setDay method.'); @@ -762,7 +726,7 @@ public function setDay($day) * Set the Prev and Next event * @return $this */ - public function setPrevNext() + public function setPrevNext(): static { if ($this->prevEvent && $this->nextEvent) { return $this; @@ -815,7 +779,7 @@ public function setPrevNext() * Mapping between events and dates * @return array The array containing events stored as [$year][$month][$day][event] */ - public function mapEvents() + public function mapEvents(): array { if ($this->mapEvents) { return $this->mapEvents; diff --git a/packages/cms/src/Charcoal/Cms/Service/Manager/NewsManager.php b/packages/cms/src/Charcoal/Cms/Service/Manager/NewsManager.php index 09c86071d..91bc358f3 100644 --- a/packages/cms/src/Charcoal/Cms/Service/Manager/NewsManager.php +++ b/packages/cms/src/Charcoal/Cms/Service/Manager/NewsManager.php @@ -109,10 +109,8 @@ public function entries() { $page = $this->page(); $cat = $this->category(); - if (isset($this->entries[$cat])) { - if (isset($this->entries[$cat][$page])) { - return $this->entries[$cat][$page]; - } + if (isset($this->entries[$cat]) && isset($this->entries[$cat][$page])) { + return $this->entries[$cat][$page]; } $loader = $this->entriesLoader(); @@ -136,7 +134,7 @@ public function entriesLoader() if ($this->numPerPage()) { $loader->setPage($this->page()); - $numPerPage = !!($this->page()) ? $this->numPerPage() : 0; + $numPerPage = $this->page() ? $this->numPerPage() : 0; $loader->setNumPerPage($numPerPage); } @@ -179,7 +177,7 @@ public function all() /** * @return CategoryInterface[]|Collection The category collection. */ - public function loadCategoryItems() + public function loadCategoryItems(): \ArrayAccess|array { $proto = $this->modelFactory()->create($this->categoryItemType()); $loader = $this->collectionLoader()->setModel($proto); @@ -223,7 +221,7 @@ public function featList(array $options = []) throw new Exception(sprintf( 'The featured news ident "%s" doesn\'t exist the class "%s"', $ident, - get_class($config) + $config::class )); } $ids = $config->{$ident}(); @@ -232,32 +230,30 @@ public function featList(array $options = []) return null; } - $ids = explode(',', $ids); + $ids = explode(',', (string)$ids); $loader->addFilter('id', $ids, [ 'operator' => 'in' ]) ->addOrder('id', 'values', [ 'values' => $ids ]); - if (count($options) > 0) { - foreach ($options as $key => $option) { - switch ($key) { - case 'filters': - $filters = $option; - foreach ($filters as $f) { - $filter[] = $f['property'] ?: ''; - $filter[] = $f['value'] ?: ''; - $filter[] = $f['options'] ?: ''; - $filter = join(',', $filter); - - $loader->addFilter($filter); - } - break; - case 'page': - $loader->setPage($option); - break; - case 'numPerPage': - $loader->setNumPerPage($option); - break; - } + foreach ($options as $key => $option) { + switch ($key) { + case 'filters': + $filters = $option; + foreach ($filters as $f) { + $filter[] = $f['property'] ?: ''; + $filter[] = $f['value'] ?: ''; + $filter[] = $f['options'] ?: ''; + $filter = implode(',', $filter); + + $loader->addFilter($filter); + } + break; + case 'page': + $loader->setPage($option); + break; + case 'numPerPage': + $loader->setNumPerPage($option); + break; } } @@ -273,10 +269,8 @@ public function archive() { $page = $this->page(); $cat = $this->category(); - if (isset($this->archive[$cat])) { - if (isset($this->archive[$cat][$page])) { - return $this->archive[$cat][$page]; - } + if (isset($this->archive[$cat]) && isset($this->archive[$cat][$page])) { + return $this->archive[$cat][$page]; } $loader = $this->loader()->archive(); @@ -394,25 +388,23 @@ public function entryCycle() * Amount of news (total) * @return integer How many news? */ - public function numNews() + public function numNews(): bool { - return !!(count($this->entries())); + return (bool)count($this->entries()); } /** * The total amount of pages. - * @return float */ - public function numPages() + public function numPages(): float { return ceil($this->entriesLoader()->loadCount() / $this->numPerPage()); } /** * Is there a pager. - * @return boolean */ - public function hasPager() + public function hasPager(): bool { return ($this->numPages() > 1); } @@ -461,7 +453,7 @@ public function loader() * @param mixed $currentNews The current news context. * @return self . */ - public function setCurrentNews($currentNews) + public function setCurrentNews($currentNews): static { $this->currentNews = $currentNews; @@ -470,9 +462,8 @@ public function setCurrentNews($currentNews) /** * @param integer $numPerPage The number of news per page. - * @return self */ - public function setNumPerPage($numPerPage) + public function setNumPerPage($numPerPage): static { $this->numPerPage = $numPerPage; @@ -481,9 +472,8 @@ public function setNumPerPage($numPerPage) /** * @param boolean $entryCycle Next and Prev cycles indefinitely. - * @return self */ - public function setEntryCycle($entryCycle) + public function setEntryCycle($entryCycle): static { $this->entryCycle = $entryCycle; @@ -492,9 +482,8 @@ public function setEntryCycle($entryCycle) /** * @param integer $page The page number to load. - * @return self */ - public function setPage($page) + public function setPage($page): static { $this->page = $page; @@ -503,9 +492,8 @@ public function setPage($page) /** * @param integer $category The current news category. - * @return self */ - public function setCategory($category) + public function setCategory($category): static { $this->category = $category; @@ -514,9 +502,8 @@ public function setCategory($category) /** * @param mixed $objType The object type. - * @return self */ - public function setObjType($objType) + public function setObjType($objType): static { $this->objType = $objType; @@ -525,9 +512,8 @@ public function setObjType($objType) /** * @param mixed $featIdent The featured list ident. - * @return self */ - public function setFeatIdent($featIdent) + public function setFeatIdent($featIdent): static { $this->featIdent = $featIdent; @@ -536,9 +522,8 @@ public function setFeatIdent($featIdent) /** * @param NewsLoader $loader The news loader provider. - * @return self */ - public function setLoader(NewsLoader $loader) + public function setLoader(NewsLoader $loader): static { $this->loader = $loader; @@ -549,7 +534,7 @@ public function setLoader(NewsLoader $loader) * Set the Prev and Next news * @return $this */ - public function setPrevNext() + public function setPrevNext(): static { if ($this->nextNews && $this->prevNews) { return $this; diff --git a/packages/cms/src/Charcoal/Cms/ServiceProvider/CmsServiceProvider.php b/packages/cms/src/Charcoal/Cms/ServiceProvider/CmsServiceProvider.php index d5dd3ef4d..e9633ecec 100644 --- a/packages/cms/src/Charcoal/Cms/ServiceProvider/CmsServiceProvider.php +++ b/packages/cms/src/Charcoal/Cms/ServiceProvider/CmsServiceProvider.php @@ -36,9 +36,8 @@ class CmsServiceProvider implements ServiceProviderInterface * It should not get services. * * @param \Pimple\Container $container Pimple DI Container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { $this->registerConfig($container); $this->reggisterDateHelper($container); @@ -49,15 +48,14 @@ public function register(Container $container) /** * @param Container $container Pimple DI Container. - * @return void */ - private function registerConfig(Container $container) + private function registerConfig(Container $container): void { /** * @param Container $container Pimple DI Container. * @return CmsConfig Website configurations (from cms.json). */ - $container['cms/config'] = function (Container $container) { + $container['cms/config'] = function (Container $container): \Charcoal\Cms\Config\CmsConfig { $appConfig = $container['config']; $cms = $appConfig->get('cms'); @@ -73,7 +71,7 @@ private function registerConfig(Container $container) $model = $container['model/factory']->create($configType); $model->load($configId); - if (!!$model->id()) { + if ((bool)$model->id()) { $cmsConfig->addModel($model); } } @@ -84,21 +82,18 @@ private function registerConfig(Container $container) /** * @param Container $container Pimple DI Container. - * @return void */ - private function reggisterDateHelper(Container $container) + private function reggisterDateHelper(Container $container): void { /** * @param Container $container Pimple DI Container. * @return DateHelper */ - $container['cms/date/helper'] = function (Container $container) { - return new DateHelper([ - 'date_formats' => $container['cms/config']->get('date_formats'), - 'time_formats' => $container['cms/config']->get('time_formats'), - 'translator' => $container['translator'] - ]); - }; + $container['cms/date/helper'] = (fn(Container $container): \Charcoal\Cms\Support\Helpers\DateHelper => new DateHelper([ + 'date_formats' => $container['cms/config']->get('date_formats'), + 'time_formats' => $container['cms/config']->get('time_formats'), + 'translator' => $container['translator'] + ])); /** * @param Container $container Pimple DI Container. @@ -117,29 +112,26 @@ private function reggisterDateHelper(Container $container) /** * @param Container $container Pimple DI Container. - * @return void */ - private function registerSectionServices(Container $container) + private function registerSectionServices(Container $container): void { /** * @param Container $container Pimple DI Container. * @return Factory */ - $container['cms/section/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => SectionInterface::class, - 'arguments' => $container['model/factory']->arguments(), - 'resolver_options' => [ - 'suffix' => 'Section' - ] - ]); - }; + $container['cms/section/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => SectionInterface::class, + 'arguments' => $container['model/factory']->arguments(), + 'resolver_options' => [ + 'suffix' => 'Section' + ] + ])); /** * @param Container $container Pimple DI Container. * @return SectionLoader */ - $container['cms/section/loader'] = function (Container $container) { + $container['cms/section/loader'] = function (Container $container): \Charcoal\Cms\Service\Loader\SectionLoader { $sectionLoader = new SectionLoader([ 'loader' => $container['model/collection/loader'], 'factory' => $container['model/factory'], @@ -160,15 +152,14 @@ private function registerSectionServices(Container $container) /** * @param Container $container Pimple DI Container. - * @return void */ - private function registerNewsServices(Container $container) + private function registerNewsServices(Container $container): void { /** * @param Container $container Pimple DI Container. * @return NewsLoader */ - $container['cms/news/loader'] = function (Container $container) { + $container['cms/news/loader'] = function (Container $container): \Charcoal\Cms\Service\Loader\NewsLoader { $newsLoader = new NewsLoader([ 'loader' => $container['model/collection/loader'], 'factory' => $container['model/factory'], @@ -189,32 +180,26 @@ private function registerNewsServices(Container $container) * @param Container $container * @return NewsManager */ - $container['cms/news/manager'] = function (Container $container) { - - $newsManager = new NewsManager([ - 'loader' => $container['model/collection/loader'], - 'factory' => $container['model/factory'], - 'news/loader' => $container['cms/news/loader'], - 'cache' => $container['cache'], - 'cms/config' => $container['cms/config'], - 'translator' => $container['translator'] - ]); - - return $newsManager; - }; + $container['cms/news/manager'] = (fn(Container $container): \Charcoal\Cms\Service\Manager\NewsManager => new NewsManager([ + 'loader' => $container['model/collection/loader'], + 'factory' => $container['model/factory'], + 'news/loader' => $container['cms/news/loader'], + 'cache' => $container['cache'], + 'cms/config' => $container['cms/config'], + 'translator' => $container['translator'] + ])); } /** * @param Container $container Pimple DI Container. - * @return void */ - private function registerEventServices(Container $container) + private function registerEventServices(Container $container): void { /** * @param Container $container Pimple DI Container. * @return EventLoader */ - $container['cms/event/loader'] = function (Container $container) { + $container['cms/event/loader'] = function (Container $container): \Charcoal\Cms\Service\Loader\EventLoader { $eventLoader = new EventLoader([ 'loader' => $container['model/collection/loader'], 'factory' => $container['model/factory'], @@ -238,18 +223,13 @@ private function registerEventServices(Container $container) * @param Container $container * @return EventManager */ - $container['cms/event/manager'] = function (Container $container) { - - $eventManager = new EventManager([ - 'loader' => $container['model/collection/loader'], - 'factory' => $container['model/factory'], - 'event/loader' => $container['cms/event/loader'], - 'cache' => $container['cache'], - 'cms/config' => $container['cms/config'], - 'translator' => $container['translator'] - ]); - - return $eventManager; - }; + $container['cms/event/manager'] = (fn(Container $container): \Charcoal\Cms\Service\Manager\EventManager => new EventManager([ + 'loader' => $container['model/collection/loader'], + 'factory' => $container['model/factory'], + 'event/loader' => $container['cms/event/loader'], + 'cache' => $container['cache'], + 'cms/config' => $container['cms/config'], + 'translator' => $container['translator'] + ])); } } diff --git a/packages/cms/src/Charcoal/Cms/Support/ContextualTemplateTrait.php b/packages/cms/src/Charcoal/Cms/Support/ContextualTemplateTrait.php index 02e23d9b3..413bce5d9 100644 --- a/packages/cms/src/Charcoal/Cms/Support/ContextualTemplateTrait.php +++ b/packages/cms/src/Charcoal/Cms/Support/ContextualTemplateTrait.php @@ -138,7 +138,7 @@ protected function createGenericContext() $base = $uri->getBasePath(); $path = $uri->getPath(); - $path = $base . '/' . ltrim($path, '/'); + $path = $base . '/' . ltrim((string)$path, '/'); $endpoint[$lang] = $path; } @@ -181,7 +181,7 @@ public function setRouteGroup($path) $group = $this->translator()->translation($path); foreach ($this->translator()->availableLocales() as $lang) { - $group[$lang] = trim($group[$lang], '/'); + $group[$lang] = trim((string)$group[$lang], '/'); } $this->routeGroup = $group; @@ -200,7 +200,7 @@ public function setRouteEndpoint($path) $endpoint = $this->translator()->translation($path); foreach ($this->translator()->availableLocales() as $lang) { - $endpoint[$lang] = trim($endpoint[$lang], '/'); + $endpoint[$lang] = trim((string)$endpoint[$lang], '/'); } $this->routeEndpoint = $endpoint; diff --git a/packages/cms/src/Charcoal/Cms/Support/DocumentTrait.php b/packages/cms/src/Charcoal/Cms/Support/DocumentTrait.php index 0779daec5..56556f458 100644 --- a/packages/cms/src/Charcoal/Cms/Support/DocumentTrait.php +++ b/packages/cms/src/Charcoal/Cms/Support/DocumentTrait.php @@ -14,7 +14,7 @@ trait DocumentTrait * * @return string[] */ - protected function documentTitleParts() + protected function documentTitleParts(): array { return [ 'title' => $this->title(), @@ -24,23 +24,19 @@ protected function documentTitleParts() /** * Retrieve the document title separator. - * - * @return string */ - protected function documentTitleSeparator() + protected function documentTitleSeparator(): string { return '—'; } /** * Parse the document title separator. - * - * @return string */ - protected function parseDocumentTitleSeparator() + protected function parseDocumentTitleSeparator(): string { $delim = trim($this->documentTitleSeparator()); - if (empty($delim)) { + if ($delim === '' || $delim === '0') { return ''; } @@ -53,13 +49,12 @@ protected function parseDocumentTitleSeparator() * @param array $parts The document title parts. * @return string The concatenated title. */ - protected function parseDocumentTitle(array $parts) + protected function parseDocumentTitle(array $parts): string { $parts = $this->parseDocumentTitleParts($parts); $delim = $this->parseDocumentTitleSeparator(); - $title = implode($delim, $parts); - return $title; + return implode($delim, $parts); } /** @@ -73,7 +68,7 @@ protected function parseDocumentTitle(array $parts) * @param array $parts The document title parts. * @return array The parsed and filtered segments. */ - protected function parseDocumentTitleParts(array $parts) + protected function parseDocumentTitleParts(array $parts): array { $segments = []; foreach ($parts as $key => $value) { diff --git a/packages/cms/src/Charcoal/Cms/Support/Helpers/DateHelper.php b/packages/cms/src/Charcoal/Cms/Support/Helpers/DateHelper.php index 35a0f6877..48ed9ae82 100644 --- a/packages/cms/src/Charcoal/Cms/Support/Helpers/DateHelper.php +++ b/packages/cms/src/Charcoal/Cms/Support/Helpers/DateHelper.php @@ -4,6 +4,7 @@ use DateTime; use Exception; +use IntlDateFormatter; // From 'charcoal-translator' use Charcoal\Translator\TranslatorAwareTrait; @@ -44,6 +45,11 @@ class DateHelper */ protected $timeFormat; + /** + * @var string $locale The current locale for date formatting + */ + protected $locale; + /** * DateHelper constructor. * @param array $data DateHelper data. @@ -64,6 +70,7 @@ public function __construct(array $data) $this->setTranslator($data['translator']); $this->dateFormats = $data['date_formats']; $this->timeFormats = $data['time_formats']; + $this->locale = $this->translator()->getLocale(); } /** @@ -72,21 +79,20 @@ public function __construct(array $data) * DateTimeInterface * string. * @param string $format The format to use. - * @return string */ - public function formatDate($date, $format = 'default') + public function formatDate($date, $format = 'default'): string { $this->dateFormat = $format; if (is_array($date)) { $this->from = $this->parseAsDate($date[0]); - $this->to = !!($date[1]) ? $this->parseAsDate($date[1]) : null; + $this->to = $date[1] ? $this->parseAsDate($date[1]) : null; } else { $this->from = $this->parseAsDate($date); $this->to = null; } - return (string)$this->formatDateFromCase($this->getDateCase()); + return $this->formatDateFromCase($this->getDateCase()); } /** @@ -95,9 +101,8 @@ public function formatDate($date, $format = 'default') * DateTimeInterface * string. * @param string $format The format to use. - * @return string */ - public function formatTime($date, $format = 'default') + public function formatTime($date, $format = 'default'): string { $this->timeFormat = $format; @@ -116,7 +121,7 @@ public function formatTime($date, $format = 'default') * Get the usage case by comparing two dates. * @return string */ - private function getDateCase() + private function getDateCase(): ?string { $from = $this->from; $to = $this->to; @@ -141,16 +146,15 @@ private function getDateCase() $case = null; $case = $fromDate['day'] !== $toDate['day'] ? 'different_day' : $case; $case = $fromDate['month'] !== $toDate['month'] ? 'different_month' : $case; - $case = $fromDate['year'] !== $toDate['year'] ? 'different_year' : $case; - return $case; + return $fromDate['year'] !== $toDate['year'] ? 'different_year' : $case; } /** * Get the usage case by comparing two hours. * @return string */ - private function getTimeCase() + private function getTimeCase(): ?string { $from = $this->from; $to = $this->to; @@ -177,16 +181,14 @@ private function getTimeCase() $case = null; $case = $fromTime['hour'] !== $toTime['hour'] ? 'different_time' : $case; $case = $fromTime['minute'] == 0 ? 'different_time_round' : $case; - $case = $fromTime['minute'] != $toTime['minute'] ? 'different_time' : $case; - return $case; + return $fromTime['minute'] != $toTime['minute'] ? 'different_time' : $case; } /** * @param string $case The use case. - * @return string */ - private function formatDateFromCase($case) + private function formatDateFromCase(array $case): string { $dateFormats = $this->dateFormats; $case = $dateFormats[$this->dateFormat][$case]; @@ -202,24 +204,47 @@ private function formatDateFromCase($case) $formats['to'] = $this->crossPlatformFormat((string)$formats['to']); if (!$this->to || !$formats['to']) { + $formatter = new IntlDateFormatter( + $this->locale, + IntlDateFormatter::FULL, + IntlDateFormatter::FULL, + null, + null, + $formats['from'] + ); return sprintf( (string)$content, - strftime($formats['from'], $this->from->getTimestamp()) + $formatter->format($this->from) ); } + $formatterFrom = new IntlDateFormatter( + $this->locale, + IntlDateFormatter::FULL, + IntlDateFormatter::FULL, + null, + null, + $formats['from'] + ); + $formatterTo = new IntlDateFormatter( + $this->locale, + IntlDateFormatter::FULL, + IntlDateFormatter::FULL, + null, + null, + $formats['to'] + ); return sprintf( (string)$content, - strftime($formats['from'], $this->from->getTimestamp()), - strftime($formats['to'], $this->to->getTimestamp()) + $formatterFrom->format($this->from), + $formatterTo->format($this->to) ); } /** * @param string $case The use case. - * @return string */ - private function formatTimeFromCase($case) + private function formatTimeFromCase(array $case): string { $timeFormats = $this->timeFormats; $case = $timeFormats[$this->timeFormat][$case]; @@ -227,22 +252,46 @@ private function formatTimeFromCase($case) $content = $this->translator()->translation($case['content']); $formats['from'] = $case['formats']['from']; - $formats['to'] = isset($case['formats']['to']) ? $case['formats']['to'] : null; + $formats['to'] = ($case['formats']['to'] ?? null); $formats['from'] = $this->translator()->translation($formats['from']); $formats['to'] = $this->translator()->translation($formats['to']); if (!$this->to || !$formats['to']) { + $formatter = new IntlDateFormatter( + $this->locale, + IntlDateFormatter::FULL, + IntlDateFormatter::FULL, + null, + null, + $formats['from'] + ); return sprintf( (string)$content, - strftime($formats['from'], $this->from->getTimestamp()) + $formatter->format($this->from) ); } + $formatterFrom = new IntlDateFormatter( + $this->locale, + IntlDateFormatter::FULL, + IntlDateFormatter::FULL, + null, + null, + $formats['from'] + ); + $formatterTo = new IntlDateFormatter( + $this->locale, + IntlDateFormatter::FULL, + IntlDateFormatter::FULL, + null, + null, + $formats['to'] + ); return sprintf( (string)$content, - strftime($formats['from'], $this->from->getTimestamp()), - strftime($formats['to'], $this->to->getTimestamp()) + $formatterFrom->format($this->from), + $formatterTo->format($this->to) ); } @@ -250,7 +299,7 @@ private function formatTimeFromCase($case) * @param mixed $date The date to convert. * @return DateTime */ - private function parseAsDate($date) + private function parseAsDate($date): \DateTimeInterface|\DateTime { if ($date instanceof \DateTimeInterface) { return $date; @@ -258,17 +307,4 @@ private function parseAsDate($date) return new DateTime($date); } - - /** - * @param mixed $format DateTime to be formatted. - * @return mixed - */ - private function crossPlatformFormat($format) - { - if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { - $format = preg_replace('#(?locales()); } @@ -117,10 +114,8 @@ protected function availableLanguages() * Build the alternate translations associated with the current route. * * This method _excludes_ the current route's canonical URI. - * - * @return array */ - protected function buildAlternateTranslations() + protected function buildAlternateTranslations(): array { $translations = []; @@ -171,7 +166,7 @@ protected function getAlternateTranslations() * @param array $localeStruct The currently iterated language. * @return array Returns a link structure. */ - protected function formatAlternateTranslation($context, array $localeStruct) + protected function formatAlternateTranslation(\ArrayAccess|array $context, array $localeStruct): array { return [ 'id' => ($context['id']) ? : $this->templateName(), @@ -222,10 +217,8 @@ public function alternateTranslations() /** * Determine if there exists alternate translations associated with the current route. - * - * @return boolean */ - public function hasAlternateTranslations() + public function hasAlternateTranslations(): bool { return !empty($this->getAlternateTranslations()); } diff --git a/packages/cms/src/Charcoal/Cms/Support/Traits/DateHelperAwareTrait.php b/packages/cms/src/Charcoal/Cms/Support/Traits/DateHelperAwareTrait.php index f4a657ab4..0fe5cd202 100644 --- a/packages/cms/src/Charcoal/Cms/Support/Traits/DateHelperAwareTrait.php +++ b/packages/cms/src/Charcoal/Cms/Support/Traits/DateHelperAwareTrait.php @@ -26,7 +26,7 @@ protected function dateHelper() if (!$this->dateHelper instanceof DateHelper) { throw new ContainerException(sprintf( 'Missing dependency for %s: %s', - get_called_class(), + static::class, DateHelper::class )); } diff --git a/packages/cms/src/Charcoal/Cms/Support/Traits/EventManagerAwareTrait.php b/packages/cms/src/Charcoal/Cms/Support/Traits/EventManagerAwareTrait.php index c29b95372..e53e3dde2 100644 --- a/packages/cms/src/Charcoal/Cms/Support/Traits/EventManagerAwareTrait.php +++ b/packages/cms/src/Charcoal/Cms/Support/Traits/EventManagerAwareTrait.php @@ -231,7 +231,7 @@ protected function getEventTimeFormat(EventInterface $event) * @param EventInterface $event Charcoal\Cms\EventInterface. * @return array The needed event properties. */ - protected function eventFormatShort(EventInterface $event) + protected function eventFormatShort(EventInterface $event): array { return [ 'title' => (string)$event->title(), @@ -251,7 +251,7 @@ protected function eventFormatShort(EventInterface $event) * @param EventInterface $event Charcoal\Cms\EventInterface. * @return array The needed event properties. */ - protected function eventFormatNav(EventInterface $event) + protected function eventFormatNav(EventInterface $event): array { return [ 'startDate' => $this->getEventStartDateFormat($event), @@ -269,7 +269,7 @@ protected function eventFormatNav(EventInterface $event) * @param EventInterface $event The current event. * @return array The needed properties. */ - protected function eventFormatFull(EventInterface $event) + protected function eventFormatFull(EventInterface $event): array { $contentBlocks = $event->getAttachments('content-blocks'); $gallery = $event->getAttachments('image-gallery'); @@ -288,11 +288,11 @@ protected function eventFormatFull(EventInterface $event) 'date' => $this->getEventDateFormat($event), 'time' => $this->getEventTimeFormat($event), 'contentBlocks' => $contentBlocks, - 'hasContentBlocks' => !!(count($contentBlocks)), + 'hasContentBlocks' => (bool)count($contentBlocks), 'documents' => $documents, - 'hasDocuments' => !!(count($documents)), + 'hasDocuments' => (bool)count($documents), 'gallery' => $gallery, - 'hasGallery' => !!(count($gallery)), + 'hasGallery' => (bool)count($gallery), 'url' => $event->url(), 'metaTitle' => (string)$event->metaTitle(), 'locationName' => (string)$event->locationName(), @@ -305,7 +305,7 @@ protected function eventFormatFull(EventInterface $event) * @param CategoryInterface $category The category item. * @return array The formatted category item. */ - protected function eventFormatCategory(CategoryInterface $category) + protected function eventFormatCategory(CategoryInterface $category): array { return [ 'id' => $category->id(), @@ -326,7 +326,7 @@ protected function eventManager() if (!$this->eventManager instanceof EventManager) { throw new ContainerException(sprintf( 'Missing dependency for %s: %s', - get_called_class(), + static::class, EventManager::class )); } diff --git a/packages/cms/src/Charcoal/Cms/Support/Traits/NewsManagerAwareTrait.php b/packages/cms/src/Charcoal/Cms/Support/Traits/NewsManagerAwareTrait.php index 92cb9c80f..a9f02b93a 100644 --- a/packages/cms/src/Charcoal/Cms/Support/Traits/NewsManagerAwareTrait.php +++ b/packages/cms/src/Charcoal/Cms/Support/Traits/NewsManagerAwareTrait.php @@ -190,7 +190,7 @@ protected function getNewsDateFormat(NewsInterface $news) * @param NewsInterface $news A single news. * @return array The needed news properties. */ - protected function newsFormatShort(NewsInterface $news) + protected function newsFormatShort(NewsInterface $news): array { return [ 'title' => (string)$news->title(), @@ -208,7 +208,7 @@ protected function newsFormatShort(NewsInterface $news) * @param NewsInterface $news A single news. * @return array The needed news properties. */ - protected function newsFormatNav(NewsInterface $news) + protected function newsFormatNav(NewsInterface $news): array { return [ 'date' => $this->getNewsDateFormat($news), @@ -224,7 +224,7 @@ protected function newsFormatNav(NewsInterface $news) * @param NewsInterface $news The current news. * @return array The needed properties. */ - protected function newsFormatFull(NewsInterface $news) + protected function newsFormatFull(NewsInterface $news): array { $contentBlocks = $news->getAttachments('content-blocks'); $gallery = $news->getAttachments('image-gallery'); @@ -239,11 +239,11 @@ protected function newsFormatFull(NewsInterface $news) 'date' => $this->getNewsDateFormat($news), 'dateTime' => $news->newsDate()->format('Y-m-d h:i'), 'contentBlocks' => $contentBlocks, - 'hasContentBlocks' => !!(count($contentBlocks)), + 'hasContentBlocks' => (bool)count($contentBlocks), 'documents' => $documents, - 'hasDocuments' => !!(count($documents)), + 'hasDocuments' => (bool)count($documents), 'gallery' => $gallery, - 'hasGallery' => !!(count($gallery)), + 'hasGallery' => (bool)count($gallery), 'url' => $news->url(), 'metaTitle' => (string)$news->metaTitle(), 'category' => $news->category(), @@ -255,7 +255,7 @@ protected function newsFormatFull(NewsInterface $news) * @param CategoryInterface $category The category item. * @return array The formatted category item. */ - protected function newsFormatCategory(CategoryInterface $category) + protected function newsFormatCategory(CategoryInterface $category): array { return [ 'id' => $category->id(), @@ -276,7 +276,7 @@ protected function newsManager() if (!$this->newsManager instanceof NewsManager) { throw new ContainerException(sprintf( 'Missing dependency for %s: %s', - get_called_class(), + static::class, NewsManager::class )); } diff --git a/packages/cms/src/Charcoal/Cms/Support/Traits/SectionLoaderAwareTrait.php b/packages/cms/src/Charcoal/Cms/Support/Traits/SectionLoaderAwareTrait.php index bf6aa89ae..3ed31cafd 100644 --- a/packages/cms/src/Charcoal/Cms/Support/Traits/SectionLoaderAwareTrait.php +++ b/packages/cms/src/Charcoal/Cms/Support/Traits/SectionLoaderAwareTrait.php @@ -81,9 +81,7 @@ public function childrenSections() */ public function routes() { - return function ($arg) { - return $this->sectionLoader()->resolveRoute($arg); - }; + return fn($arg) => $this->sectionLoader()->resolveRoute($arg); } /** @@ -149,7 +147,7 @@ protected function sectionLoader() if (!$this->sectionLoader instanceof SectionLoader) { throw new ContainerException(sprintf( 'Missing dependency for %s: %s', - get_called_class(), + static::class, SectionLoader::class )); } @@ -171,12 +169,10 @@ protected function setSectionLoader(SectionLoader $loader) // ========================================================================== // FORMATTER // ========================================================================== - /** * @param SectionInterface $section The section to format. - * @return array */ - protected function formatSection(SectionInterface $section) + protected function formatSection(SectionInterface $section): array { $contentBlocks = $section->getAttachments('content-blocks'); $gallery = $section->getAttachments('image-gallery'); diff --git a/packages/cms/src/Charcoal/Cms/Support/Traits/SocialNetworksAwareTrait.php b/packages/cms/src/Charcoal/Cms/Support/Traits/SocialNetworksAwareTrait.php index 4735e1257..e2e2724fa 100644 --- a/packages/cms/src/Charcoal/Cms/Support/Traits/SocialNetworksAwareTrait.php +++ b/packages/cms/src/Charcoal/Cms/Support/Traits/SocialNetworksAwareTrait.php @@ -21,10 +21,8 @@ trait SocialNetworksAwareTrait /** * Determine if the website has a social presence. - * - * @return integer|boolean */ - public function hasSocialNetworks() + public function hasSocialNetworks(): int { return count($this->socialNetworks()); } @@ -41,7 +39,7 @@ public function socialNetworks() return $this->socialNetworks; } - $socials = json_decode($this->cmsConfig()['social_medias'], true); + $socials = json_decode((string)$this->cmsConfig()['social_medias'], true); $configMeta = $this->configModel()->p('social_medias')->structureMetadata(); foreach ($socials as $ident => $account) { diff --git a/packages/cms/src/Charcoal/Cms/Tag.php b/packages/cms/src/Charcoal/Cms/Tag.php index 670e0ea09..30e2ef6b1 100644 --- a/packages/cms/src/Charcoal/Cms/Tag.php +++ b/packages/cms/src/Charcoal/Cms/Tag.php @@ -1,5 +1,7 @@ property($key); $val = $this->propertyValue($key); - $obj = $prop->structureVal($val, $this->templateOptionsMetadata()); - return $obj; + return $prop->structureVal($val, $this->templateOptionsMetadata()); } /** @@ -238,7 +235,7 @@ final protected function assertValidTemplateStructureDependencies() if (!$this instanceof TemplateableInterface) { throw new RuntimeException(sprintf( 'Class [%s] must implement [%s]', - get_class($this), + $this::class, TemplateableInterface::class )); } @@ -260,7 +257,7 @@ final protected function assertValidTemplateStructureDependencies() * @param boolean $recursive Whether we should traverse structure properties. * @return ModelInterface The localized object. */ - protected function translateTemplateOptionsModel(ModelInterface $obj, $recursive = false) + protected function translateTemplateOptionsModel(ModelInterface $obj, $recursive = false): ModelInterface { unset($recursive); foreach ($obj->properties() as $propertyIdent => $property) { @@ -271,7 +268,7 @@ protected function translateTemplateOptionsModel(ModelInterface $obj, $recursive $struct = $property->structureVal($obj[$propertyIdent]); /** Provide support for dynamically wrapping translation sets. */ - if (in_array(get_class($struct), [ Model::class, StructureModel::class ])) { + if (in_array($struct::class, [ Model::class, StructureModel::class ])) { $struct = $this->translateTemplateOptionsModel($struct); } @@ -287,7 +284,7 @@ protected function translateTemplateOptionsModel(ModelInterface $obj, $recursive * * @return string[] */ - protected function defaultTemplateProperties() + protected function defaultTemplateProperties(): array { return [ 'template_ident' @@ -303,7 +300,7 @@ protected function defaultTemplateProperties() * @param PropertyInterface|string ...$properties The properties to lookup. * @return string[]|null */ - protected function extractTemplateInterfacesFrom(...$properties) + protected function extractTemplateInterfacesFrom(...$properties): array { $interfaces = []; foreach ($properties as $property) { @@ -321,10 +318,8 @@ protected function extractTemplateInterfacesFrom(...$properties) if (isset($choice[$key])) { $interface = $choice[$key]; - if ($key === 'template' || $key === 'controller') { - if (substr($interface, -9) !== '-template') { - $interface .= '-template'; - } + if (($key === 'template' || $key === 'controller') && !str_ends_with((string)$interface, '-template')) { + $interface .= '-template'; } $interfaces[] = $interface; @@ -345,9 +340,8 @@ protected function extractTemplateInterfacesFrom(...$properties) * * @uses self::assertValidTemplateStructureDependencies() Validates that the model meets requirements. * @param (PropertyInterface|string)[]|null $templateIdentProperties The template key properties to parse. - * @return boolean */ - protected function prepareTemplateOptions(array $templateIdentProperties = null) + protected function prepareTemplateOptions(?array $templateIdentProperties = null): bool { $this->assertValidTemplateStructureDependencies(); @@ -384,7 +378,7 @@ protected function prepareTemplateOptions(array $templateIdentProperties = null) * @param (PropertyInterface|string)[]|null $properties The template properties to parse. * @return void */ - protected function saveTemplateOptions(array $properties = null) + protected function saveTemplateOptions(?array $properties = null) { if ($properties === null) { $properties = $this->defaultTemplateProperties(); diff --git a/packages/cms/src/Charcoal/Property/TemplateOptionsProperty.php b/packages/cms/src/Charcoal/Property/TemplateOptionsProperty.php index f9346e6df..7eef161ac 100644 --- a/packages/cms/src/Charcoal/Property/TemplateOptionsProperty.php +++ b/packages/cms/src/Charcoal/Property/TemplateOptionsProperty.php @@ -14,10 +14,9 @@ class TemplateOptionsProperty extends ModelStructureProperty { /** * Retrieve the property's type identifier. - * - * @return string */ - public function type() + #[\Override] + public function type(): string { return 'template-options'; } @@ -28,9 +27,9 @@ public function type() * @see StructureProperty::addStructureInterface() * @param string $interface A metadata interface to use. * @throws InvalidArgumentException If the template property value is invalid. - * @return TemplateOptionsProperty */ - public function addStructureInterface($interface) + #[\Override] + public function addStructureInterface($interface): static { if ($interface instanceof TemplateProperty) { $interface = (string)$interface; diff --git a/packages/cms/src/Charcoal/Property/TemplateProperty.php b/packages/cms/src/Charcoal/Property/TemplateProperty.php index fbdb492ea..ce2c3bdb8 100644 --- a/packages/cms/src/Charcoal/Property/TemplateProperty.php +++ b/packages/cms/src/Charcoal/Property/TemplateProperty.php @@ -23,15 +23,10 @@ class TemplateProperty extends AbstractProperty implements SelectablePropertyInt /** * The available selectable templates. - * - * @var array|null */ - private $availableTemplates; + private ?array $availableTemplates = null; - /** - * @return string - */ - public function type() + public function type(): string { return 'template'; } @@ -41,9 +36,8 @@ public function type() * * @param string $choiceIdent The choice identifier (will be key / default ident). * @param string|array $choice A string representing the choice label or a structure. - * @return self */ - public function addChoice($choiceIdent, $choice) + public function addChoice($choiceIdent, $choice): static { $choice = $this->parseTemplateChoice($choice, strval($choiceIdent)); @@ -79,7 +73,7 @@ protected function parseTemplateChoice($choice, $choiceIdent) $choice )); } - } elseif (is_bool($choice) && $choice === true) { + } elseif (is_bool($choice) && $choice) { if (isset($this->availableTemplates[$choiceIdent])) { return $this->availableTemplates[$choiceIdent]; } else { @@ -120,9 +114,9 @@ protected function parseTemplateChoice($choice, $choiceIdent) * * @param mixed $val The value to to convert for display. * @param array $options Optional display options. - * @return string */ - public function displayVal($val, array $options = []) + #[\Override] + public function displayVal($val, array $options = []): string { if ($val === null || $val === '') { return ''; @@ -143,10 +137,8 @@ public function displayVal($val, array $options = []) $separator = $this->multipleSeparator(); /** Parse multiple values / ensure they are of array type. */ - if ($this['multiple']) { - if (!is_array($propertyValue)) { - $propertyValue = explode($separator, $propertyValue); - } + if ($this['multiple'] && !is_array($propertyValue)) { + $propertyValue = explode($separator, (string)$propertyValue); } if ($separator === ',') { @@ -175,10 +167,9 @@ public function displayVal($val, array $options = []) /** * Retrieve the selected template's FQCN. - * - * @return string */ - public function __toString() + #[\Override] + public function __toString(): string { $val = $this->val(); if ($this->hasChoice($val)) { @@ -186,7 +177,7 @@ public function __toString() $keys = [ 'controller', 'template', 'class' ]; foreach ($keys as $key) { if (isset($choice[$key])) { - return $choice[$key]; + return (string)$choice[$key]; } } } @@ -194,10 +185,7 @@ public function __toString() return ''; } - /** - * @return string - */ - public function sqlExtra() + public function sqlExtra(): ?string { return ''; } @@ -207,7 +195,7 @@ public function sqlExtra() * * @return string The SQL type */ - public function sqlType() + public function sqlType(): string { if ($this['multiple']) { return 'TEXT'; @@ -216,10 +204,7 @@ public function sqlType() return 'VARCHAR(255)'; } - /** - * @return integer - */ - public function sqlPdoType() + public function sqlPdoType(): int { return PDO::PARAM_STR; } @@ -230,6 +215,7 @@ public function sqlPdoType() * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/cms/tests/Charcoal/AbstractTestCase.php b/packages/cms/tests/Charcoal/AbstractTestCase.php index 59ba12ea0..80f1772c4 100644 --- a/packages/cms/tests/Charcoal/AbstractTestCase.php +++ b/packages/cms/tests/Charcoal/AbstractTestCase.php @@ -1,5 +1,7 @@ getContainer(); @@ -56,10 +54,8 @@ protected function getModelDependenciesWithContainer() /** * Retrieve the property's mock dependencies with the service locator. - * - * @return array */ - protected function getPropertyDependenciesWithContainer() + protected function getPropertyDependenciesWithContainer(): array { $container = $this->getContainer(); @@ -97,9 +93,8 @@ protected function getContainerProvider() /** * @see ContainerProvider - * @return void */ - private function setupContainer() + private function setupContainer(): void { $provider = new ContainerProvider(); $container = new Container(); diff --git a/packages/cms/tests/Charcoal/Cms/ContainerProvider.php b/packages/cms/tests/Charcoal/Cms/ContainerProvider.php index a5d9c3930..61739d673 100644 --- a/packages/cms/tests/Charcoal/Cms/ContainerProvider.php +++ b/packages/cms/tests/Charcoal/Cms/ContainerProvider.php @@ -45,9 +45,8 @@ class ContainerProvider { /** * @param Container $container A DI container. - * @return void */ - public function registerBaseServices(Container $container) + public function registerBaseServices(Container $container): void { $this->registerLogger($container); $this->registerCache($container); @@ -59,9 +58,8 @@ public function registerBaseServices(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerModelDependencies(Container $container) + public function registerModelDependencies(Container $container): void { $this->registerDatabase($container); $this->registerViewServices($container); @@ -70,44 +68,40 @@ public function registerModelDependencies(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerConfig(Container $container) + public function registerConfig(Container $container): void { - $container['config'] = function () { - return new AppConfig([ - 'base_path' => realpath(__DIR__ . '/../../..'), - 'templates' => [], - 'metadata' => [ - 'paths' => [ - 'metadata', - 'tests/Charcoal/Cms/Fixture/metadata', - // Standalone - 'vendor/charcoal/object/metadata', - // Monorepo - '/../object/metadata', - ], + $container['config'] = (fn(): \Charcoal\App\AppConfig => new AppConfig([ + 'base_path' => realpath(__DIR__ . '/../../..'), + 'templates' => [], + 'metadata' => [ + 'paths' => [ + 'metadata', + 'tests/Charcoal/Cms/Fixture/metadata', + // Standalone + 'vendor/charcoal/object/metadata', + // Monorepo + '/../object/metadata', ], - 'view' => [ - 'paths' => [ - 'views', - 'tests/Charcoal/Cms/Fixture/views', - ], - 'default_controller' => GenericTemplate::class, + ], + 'view' => [ + 'paths' => [ + 'views', + 'tests/Charcoal/Cms/Fixture/views', ], - ]); - }; + 'default_controller' => GenericTemplate::class, + ], + ])); } /** * Extend the application configset for a unilingual setup. * * @param Container $container A DI container. - * @return void */ - public function withUnilingualConfig(Container $container) + public function withUnilingualConfig(Container $container): void { - $container->extend('config', function (AppConfig $config) { + $container->extend('config', function (AppConfig $config): \Charcoal\App\AppConfig { $config['locales'] = [ 'languages' => [ 'en' => [ @@ -133,11 +127,10 @@ public function withUnilingualConfig(Container $container) * Extend the application configset for a multilingual setup. * * @param Container $container A DI container. - * @return void */ - public function withMultilingualConfig(Container $container) + public function withMultilingualConfig(Container $container): void { - $container->extend('config', function (AppConfig $config) { + $container->extend('config', function (AppConfig $config): \Charcoal\App\AppConfig { $config['locales'] = [ 'languages' => [ 'en' => [ @@ -194,11 +187,10 @@ public function withMultilingualConfig(Container $container) * Extend the application configset with templates. * * @param Container $container A DI container. - * @return void */ - public function withTemplatesConfig(Container $container) + public function withTemplatesConfig(Container $container): void { - $container->extend('config', function (AppConfig $config) { + $container->extend('config', function (AppConfig $config): \Charcoal\App\AppConfig { $config['templates'] = [ [ 'value' => 'foo', @@ -239,11 +231,10 @@ public function withTemplatesConfig(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerDatabase(Container $container) + public function registerDatabase(Container $container): void { - $container['database'] = function () { + $container['database'] = function (): \PDO { $pdo = new PDO('sqlite::memory:'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); @@ -253,33 +244,26 @@ public function registerDatabase(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerLogger(Container $container) + public function registerLogger(Container $container): void { - $container['logger'] = function () { - return new NullLogger(); - }; + $container['logger'] = (fn(): \Psr\Log\NullLogger => new NullLogger()); } /** * @param Container $container A DI container. - * @return void */ - public function registerCache(Container $container) + public function registerCache(Container $container): void { - $container['cache'] = function () { - return new Pool(); - }; + $container['cache'] = (fn(): \Stash\Pool => new Pool()); } /** * Register the admin services. * * @param Container $container A DI container. - * @return void */ - public function registerModelServices(Container $container) + public function registerModelServices(Container $container): void { static $provider = null; @@ -294,9 +278,8 @@ public function registerModelServices(Container $container) * Register the admin services. * * @param Container $container A DI container. - * @return void */ - public function registerAuthServices(Container $container) + public function registerAuthServices(Container $container): void { static $provider = null; @@ -311,9 +294,8 @@ public function registerAuthServices(Container $container) * Setup the application's translator service. * * @param Container $container A DI container. - * @return void */ - public function registerTranslatorServices(Container $container) + public function registerTranslatorServices(Container $container): void { static $provider = null; @@ -328,9 +310,8 @@ public function registerTranslatorServices(Container $container) * Setup the framework's view renderer. * * @param Container $container A DI container. - * @return void */ - public function registerViewServices(Container $container) + public function registerViewServices(Container $container): void { static $provider = null; @@ -343,48 +324,39 @@ public function registerViewServices(Container $container) /** * @param Container $container A DI container. - * @return void */ - public function registerCmsConfig(Container $container) + public function registerCmsConfig(Container $container): void { - $container['cms/config'] = function () { - return new CmsConfig(); - }; + $container['cms/config'] = (fn(): \Charcoal\Cms\Config\CmsConfig => new CmsConfig()); } /** * @param Container $container A DI container. - * @return void */ - public function registerDateHelper(Container $container) + public function registerDateHelper(Container $container): void { - $container['date/helper'] = function () { - return new DateHelper([ - 'date_formats' => '', - 'time_formats' => '', - ]); - }; + $container['date/helper'] = (fn(): \Charcoal\Cms\Support\Helpers\DateHelper => new DateHelper([ + 'date_formats' => '', + 'time_formats' => '', + ])); } /** * @param Container $container A DI container. - * @return void */ - public function registerTemplateFactory(Container $container) + public function registerTemplateFactory(Container $container): void { - $container['template/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => TemplateInterface::class, - 'resolver_options' => [ - 'suffix' => 'Template', - ], - 'arguments' => [ - [ - 'container' => $container, - 'logger' => $container['logger'], - ], + $container['template/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => TemplateInterface::class, + 'resolver_options' => [ + 'suffix' => 'Template', + ], + 'arguments' => [ + [ + 'container' => $container, + 'logger' => $container['logger'], ], - ]); - }; + ], + ])); } } diff --git a/packages/cms/tests/Charcoal/Cms/EventCategoryTest.php b/packages/cms/tests/Charcoal/Cms/EventCategoryTest.php index cc74529db..856d5e933 100644 --- a/packages/cms/tests/Charcoal/Cms/EventCategoryTest.php +++ b/packages/cms/tests/Charcoal/Cms/EventCategoryTest.php @@ -17,15 +17,11 @@ class EventCategoryTest extends AbstractTestCase /** * Tested Class. - * - * @var EventCategory */ - private $obj; + private \Charcoal\Cms\EventCategory $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -34,18 +30,12 @@ protected function setUp(): void $this->obj = new EventCategory($dependencies); } - /** - * @return void - */ - public function testItemType() + public function testItemType(): void { $this->assertEquals(Event::class, $this->obj->itemType()); } - /** - * @return void - */ - public function testValidate() + public function testValidate(): void { $this->assertFalse($this->obj->validate()); $this->obj->setName([ 'fr' => 'Titre' ]); diff --git a/packages/cms/tests/Charcoal/Cms/EventTest.php b/packages/cms/tests/Charcoal/Cms/EventTest.php index 86178a2eb..a03c935c9 100644 --- a/packages/cms/tests/Charcoal/Cms/EventTest.php +++ b/packages/cms/tests/Charcoal/Cms/EventTest.php @@ -22,15 +22,11 @@ class EventTest extends AbstractTestCase /** * Tested Class. - * - * @var Event */ - private $obj; + private \Charcoal\Cms\Event|array $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -46,10 +42,7 @@ protected function setUp(): void $this->obj = new Event($dependencies); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $ret = $this->obj->setData([ 'title' => 'Example title', @@ -80,10 +73,7 @@ public function testSetData() $this->assertEquals(50, $this->obj->ticketPriceMax()); } - /** - * @return void - */ - public function testSetTitle() + public function testSetTitle(): void { $this->assertEquals('', (string)$this->obj->title()); $ret = $this->obj->setTitle('Foo bar'); @@ -97,10 +87,7 @@ public function testSetTitle() $this->assertEquals('Hello', (string)$this->obj['title']); } - /** - * @return void - */ - public function testSetSubtitle() + public function testSetSubtitle(): void { $this->assertEquals('', (string)$this->obj->subtitle()); $ret = $this->obj->setSubtitle('Bar foo'); @@ -114,10 +101,7 @@ public function testSetSubtitle() $this->assertEquals('foo', (string)$this->obj['subtitle']); } - /** - * @return void - */ - public function testSetSummary() + public function testSetSummary(): void { $this->assertEquals('', (string)$this->obj->summary()); $ret = $this->obj->setSummary('Bar foo baz'); @@ -131,10 +115,7 @@ public function testSetSummary() $this->assertEquals('foo', (string)$this->obj['summary']); } - /** - * @return void - */ - public function testSetContent() + public function testSetContent(): void { $this->assertEquals('', (string)$this->obj->content()); $ret = $this->obj->setContent('Bar foo'); @@ -148,10 +129,7 @@ public function testSetContent() $this->assertEquals('foo', (string)$this->obj['content']); } - /** - * @return void - */ - public function testSetStartDate() + public function testSetStartDate(): void { $this->assertEquals(null, $this->obj->startDate()); $ret = $this->obj->setStartDate('2016-02-02'); @@ -165,19 +143,13 @@ public function testSetStartDate() $this->obj->setStartDate([]); } - /** - * @return void - */ - public function testSetStartDateInvalidString() + public function testSetStartDateInvalidString(): void { $this->expectException('\Exception'); $this->obj->setStartDate('foo.bar'); } - /** - * @return void - */ - public function testSetEndDate() + public function testSetEndDate(): void { $this->assertEquals(null, $this->obj->endDate()); $ret = $this->obj->setEndDate('2016-02-02'); @@ -191,27 +163,18 @@ public function testSetEndDate() $this->obj->setEndDate([]); } - /** - * @return void - */ - public function testSetEndDateInvalidString() + public function testSetEndDateInvalidString(): void { $this->expectException('\Exception'); $this->obj->setEndDate('foo.bar'); } - /** - * @return void - */ - public function testCategoryType() + public function testCategoryType(): void { $this->assertEquals(EventCategory::class, $this->obj->categoryType()); } - /** - * @return void - */ - public function testMetaTitleDefaultsToTitle() + public function testMetaTitleDefaultsToTitle(): void { $this->assertEquals('', (string)$this->obj->metaTitle()); @@ -223,10 +186,7 @@ public function testMetaTitleDefaultsToTitle() $this->assertEquals('Barfoo', (string)$this->obj->metaTitle()); } - /** - * @return void - */ - public function testMetaDescriptionDefaultsToDescription() + public function testMetaDescriptionDefaultsToDescription(): void { $this->assertEquals('', (string)$this->obj->metaDescription()); @@ -238,27 +198,20 @@ public function testMetaDescriptionDefaultsToDescription() $this->assertEquals('Barfoo', (string)$this->obj->metaDescription()); } - /** - * @return void - */ /* public function testMetaImageDefaultsToImage() { $this->assertEquals('', (string)$this->obj->metaImage()); - + $this->obj->setImage('Foo.png'); $this->assertSame($this->obj->image(), $this->obj->metaImage()); $this->assertEquals('Foo.png', (string)$this->obj->metaImage()); - + $this->obj->setMetaImage('Bar.jpg'); $this->assertEquals('Bar.jpg', (string)$this->obj->metaImage()); } */ - - /** - * @return void - */ - public function testSaveGeneratesSlug() + public function testSaveGeneratesSlug(): void { $this->assertEquals('', $this->obj['slug']); $this->obj->setData([ @@ -269,10 +222,7 @@ public function testSaveGeneratesSlug() $this->assertEquals('en/events/foo', (string)$this->obj['slug']); } - /** - * @return void - */ - public function testUpdateGeneratesSlug() + public function testUpdateGeneratesSlug(): void { $this->assertEquals('', $this->obj['slug']); $this->obj->setData([ diff --git a/packages/cms/tests/Charcoal/Cms/FaqCategoryTest.php b/packages/cms/tests/Charcoal/Cms/FaqCategoryTest.php index a7e5a54c7..ccfebb70e 100644 --- a/packages/cms/tests/Charcoal/Cms/FaqCategoryTest.php +++ b/packages/cms/tests/Charcoal/Cms/FaqCategoryTest.php @@ -17,15 +17,11 @@ class FaqCategoryTest extends AbstractTestCase /** * Tested Class. - * - * @var FaqCategory */ - private $obj; + private \Charcoal\Cms\FaqCategory $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -34,10 +30,7 @@ protected function setUp(): void $this->obj = new FaqCategory($dependencies); } - /** - * @return void - */ - public function testItemType() + public function testItemType(): void { $this->assertEquals(Faq::class, $this->obj->itemType()); } diff --git a/packages/cms/tests/Charcoal/Cms/FaqTest.php b/packages/cms/tests/Charcoal/Cms/FaqTest.php index 95422a5ac..95cfa2c83 100644 --- a/packages/cms/tests/Charcoal/Cms/FaqTest.php +++ b/packages/cms/tests/Charcoal/Cms/FaqTest.php @@ -17,15 +17,11 @@ class FaqTest extends AbstractTestCase /** * Tested Class. - * - * @var Faq */ - private $obj; + private \Charcoal\Cms\Faq $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -34,10 +30,7 @@ protected function setUp(): void $this->obj = new Faq($dependencies); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $ret = $this->obj->setData([ 'question' => 'Foo?', @@ -48,30 +41,21 @@ public function testSetData() $this->assertEquals('Bar', (string)$this->obj->answer()); } - /** - * @return void - */ - public function testSetQuestion() + public function testSetQuestion(): void { $ret = $this->obj->setQuestion('Foo?'); $this->assertSame($ret, $this->obj); $this->assertEquals('Foo?', $this->obj->question()); } - /** - * @return void - */ - public function testSetAnswer() + public function testSetAnswer(): void { $ret = $this->obj->setAnswer('Bar'); $this->assertSame($ret, $this->obj); $this->assertEquals('Bar', $this->obj->answer()); } - /** - * @return void - */ - public function testCategoryType() + public function testCategoryType(): void { $this->assertEquals(FaqCategory::class, $this->obj->categoryType()); } diff --git a/packages/cms/tests/Charcoal/Cms/MetatagTraitTest.php b/packages/cms/tests/Charcoal/Cms/MetatagTraitTest.php index f66380b25..1762f4695 100644 --- a/packages/cms/tests/Charcoal/Cms/MetatagTraitTest.php +++ b/packages/cms/tests/Charcoal/Cms/MetatagTraitTest.php @@ -23,9 +23,6 @@ class MetatagTraitTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -42,19 +39,14 @@ protected function setUp(): void /** * Asserts that the object implements MetatagInterface. - * - * @coversNothing - * @return void */ - public function testMetatagInterface() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testMetatagInterface(): void { $this->assertInstanceOf(MetatagInterface::class, $this->obj); } - /** - * @return void - */ - public function testSaveGeneratesMetaTags() + public function testSaveGeneratesMetaTags(): void { $this->assertEquals('', (string)$this->obj->metaTitle()); $this->assertEquals('', (string)$this->obj->metaDescription()); @@ -72,10 +64,7 @@ public function testSaveGeneratesMetaTags() $this->assertEquals('x.jpg', (string)$this->obj->metaImage()); } - /** - * @return void - */ - public function testUpdateGeneratesMetaTags() + public function testUpdateGeneratesMetaTags(): void { $this->assertEquals('', (string)$this->obj->metaTitle()); $this->assertEquals('', (string)$this->obj->metaDescription()); diff --git a/packages/cms/tests/Charcoal/Cms/Mock/BrokenTemplate.php b/packages/cms/tests/Charcoal/Cms/Mock/BrokenTemplate.php index f04e6ae62..be6c9c688 100644 --- a/packages/cms/tests/Charcoal/Cms/Mock/BrokenTemplate.php +++ b/packages/cms/tests/Charcoal/Cms/Mock/BrokenTemplate.php @@ -1,5 +1,7 @@ event; } /** * @param EventInterface $event The current event. - * @return self */ - public function setEvent(EventInterface $event) + public function setEvent(EventInterface $event): static { $this->event = $event; @@ -52,16 +44,15 @@ public function setEvent(EventInterface $event) /** * @return NewsInterface */ - public function news() + public function news(): ?\Charcoal\Cms\NewsInterface { return $this->news; } /** * @param NewsInterface $news The current news. - * @return self */ - public function setNews(NewsInterface $news) + public function setNews(NewsInterface $news): static { $this->news = $news; @@ -71,16 +62,15 @@ public function setNews(NewsInterface $news) /** * @return SectionInterface */ - public function section() + public function section(): ?\Charcoal\Cms\SectionInterface { return $this->section; } /** * @param SectionInterface $section The current section. - * @return self */ - public function setSection(SectionInterface $section) + public function setSection(SectionInterface $section): static { $this->section = $section; diff --git a/packages/cms/tests/Charcoal/Cms/Mock/EventTemplate.php b/packages/cms/tests/Charcoal/Cms/Mock/EventTemplate.php index d99e5b990..3d2a94c9c 100644 --- a/packages/cms/tests/Charcoal/Cms/Mock/EventTemplate.php +++ b/packages/cms/tests/Charcoal/Cms/Mock/EventTemplate.php @@ -1,5 +1,7 @@ event; } /** * @param EventInterface $event The current event. - * @return self */ - public function setEvent(EventInterface $event) + public function setEvent(EventInterface $event): static { $this->event = $event; diff --git a/packages/cms/tests/Charcoal/Cms/Mock/GenericTemplate.php b/packages/cms/tests/Charcoal/Cms/Mock/GenericTemplate.php index 16b7ae678..dccd43c7c 100644 --- a/packages/cms/tests/Charcoal/Cms/Mock/GenericTemplate.php +++ b/packages/cms/tests/Charcoal/Cms/Mock/GenericTemplate.php @@ -1,5 +1,7 @@ section; } /** * @param SectionInterface $section The current section. - * @return self */ - public function setSection(SectionInterface $section) + public function setSection(SectionInterface $section): static { $this->section = $section; diff --git a/packages/cms/tests/Charcoal/Cms/Mock/HomeTemplate.php b/packages/cms/tests/Charcoal/Cms/Mock/HomeTemplate.php index cabc511b1..3c8969c04 100644 --- a/packages/cms/tests/Charcoal/Cms/Mock/HomeTemplate.php +++ b/packages/cms/tests/Charcoal/Cms/Mock/HomeTemplate.php @@ -1,5 +1,7 @@ section; } /** * @param SectionInterface $section The current section. - * @return self */ - public function setSection(SectionInterface $section) + public function setSection(SectionInterface $section): static { $this->section = $section; diff --git a/packages/cms/tests/Charcoal/Cms/Mock/NewsTemplate.php b/packages/cms/tests/Charcoal/Cms/Mock/NewsTemplate.php index cab71e68f..ea2114d92 100644 --- a/packages/cms/tests/Charcoal/Cms/Mock/NewsTemplate.php +++ b/packages/cms/tests/Charcoal/Cms/Mock/NewsTemplate.php @@ -1,5 +1,7 @@ news; } /** * @param NewsInterface $news The current news. - * @return self */ - public function setNews(NewsInterface $news) + public function setNews(NewsInterface $news): static { $this->news = $news; diff --git a/packages/cms/tests/Charcoal/Cms/Mock/TemplateableModel.php b/packages/cms/tests/Charcoal/Cms/Mock/TemplateableModel.php index c32909ae1..90dde6fa6 100644 --- a/packages/cms/tests/Charcoal/Cms/Mock/TemplateableModel.php +++ b/packages/cms/tests/Charcoal/Cms/Mock/TemplateableModel.php @@ -1,5 +1,7 @@ saveTemplateOptions(); @@ -36,7 +39,8 @@ public function preSave() * @param array $properties Optional. The list of properties to update. * @return boolean */ - public function preUpdate(array $properties = null) + #[\Override] + public function preUpdate(?array $properties = null) { if ($properties === null || array_search('template_options', $properties)) { $this->saveTemplateOptions(); diff --git a/packages/cms/tests/Charcoal/Cms/Mock/WebPage.php b/packages/cms/tests/Charcoal/Cms/Mock/WebPage.php index efba18a59..f7a18c6ab 100644 --- a/packages/cms/tests/Charcoal/Cms/Mock/WebPage.php +++ b/packages/cms/tests/Charcoal/Cms/Mock/WebPage.php @@ -1,5 +1,7 @@ generateDefaultMetaTags(); @@ -26,9 +27,9 @@ public function preSave() * Update object in storage. * * @param array $properties Optional. The list of properties to update. - * @return boolean */ - public function preUpdate(array $properties = null) + #[\Override] + public function preUpdate(?array $properties = null): bool { $this->generateDefaultMetaTags(); diff --git a/packages/cms/tests/Charcoal/Cms/NewsCategoryTest.php b/packages/cms/tests/Charcoal/Cms/NewsCategoryTest.php index ce606199d..0632a25b9 100644 --- a/packages/cms/tests/Charcoal/Cms/NewsCategoryTest.php +++ b/packages/cms/tests/Charcoal/Cms/NewsCategoryTest.php @@ -17,15 +17,11 @@ class NewsCategoryTest extends AbstractTestCase /** * Tested Class. - * - * @var NewsCategory */ - private $obj; + private \Charcoal\Cms\NewsCategory $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -34,10 +30,7 @@ protected function setUp(): void $this->obj = new NewsCategory($dependencies); } - /** - * @return void - */ - public function testItemType() + public function testItemType(): void { $this->assertEquals(News::class, $this->obj->itemType()); } diff --git a/packages/cms/tests/Charcoal/Cms/NewsTest.php b/packages/cms/tests/Charcoal/Cms/NewsTest.php index 89b992c62..bbad38b48 100644 --- a/packages/cms/tests/Charcoal/Cms/NewsTest.php +++ b/packages/cms/tests/Charcoal/Cms/NewsTest.php @@ -22,15 +22,11 @@ class NewsTest extends AbstractTestCase /** * Tested Class. - * - * @var News */ - private $obj; + private \Charcoal\Cms\News|array $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -46,10 +42,7 @@ protected function setUp(): void $this->obj = new News($dependencies); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $ret = $this->obj->setData([ 'title' => 'Example title', @@ -65,10 +58,7 @@ public function testSetData() $this->assertEquals(new DateTime('2015-01-01 20:00:00'), $this->obj->newsDate()); } - /** - * @return void - */ - public function testSetTitle() + public function testSetTitle(): void { $this->assertEquals('', (string)$this->obj->title()); $ret = $this->obj->setTitle('Foo bar'); @@ -82,10 +72,7 @@ public function testSetTitle() $this->assertEquals('Hello', (string)$this->obj['title']); } - /** - * @return void - */ - public function testSetSubtitle() + public function testSetSubtitle(): void { $this->assertEquals('', (string)$this->obj->subtitle()); $ret = $this->obj->setSubtitle('Bar foo'); @@ -99,10 +86,7 @@ public function testSetSubtitle() $this->assertEquals('foo', (string)$this->obj['subtitle']); } - /** - * @return void - */ - public function testSetSummary() + public function testSetSummary(): void { $this->assertEquals('', (string)$this->obj->summary()); $ret = $this->obj->setSummary('Bar foo'); @@ -116,10 +100,7 @@ public function testSetSummary() $this->assertEquals('foo', (string)$this->obj['summary']); } - /** - * @return void - */ - public function testSetContent() + public function testSetContent(): void { $this->assertEquals('', (string)$this->obj->content()); $ret = $this->obj->setContent('Bar foo'); @@ -133,10 +114,7 @@ public function testSetContent() $this->assertEquals('foo', (string)$this->obj['content']); } - /** - * @return void - */ - public function testSetNewsDate() + public function testSetNewsDate(): void { $this->assertEquals(null, $this->obj->newsDate()); $ret = $this->obj->setNewsDate('2016-02-02'); @@ -150,19 +128,13 @@ public function testSetNewsDate() $this->obj->setNewsDate([]); } - /** - * @return void - */ - public function testSetNewsDateInvalidString() + public function testSetNewsDateInvalidString(): void { $this->expectException('\Exception'); $this->obj->setNewsDate('foo.bar'); } - /** - * @return void - */ - public function testMetaTitleDefaultsToTitle() + public function testMetaTitleDefaultsToTitle(): void { $this->assertEquals('', (string)$this->obj->metaTitle()); @@ -174,10 +146,7 @@ public function testMetaTitleDefaultsToTitle() $this->assertEquals('Barfoo', (string)$this->obj->metaTitle()); } - /** - * @return void - */ - public function testMetaDescriptionDefaultsToDescription() + public function testMetaDescriptionDefaultsToDescription(): void { $this->assertEquals('', (string)$this->obj->metaDescription()); @@ -189,45 +158,31 @@ public function testMetaDescriptionDefaultsToDescription() $this->assertEquals('Barfoo', (string)$this->obj->metaDescription()); } - /** - * @return void - */ /* public function testMetaImageDefaultsToImage() { $this->assertEquals('', (string)$this->obj->metaImage()); - + $this->obj->setImage('Foo.png'); $this->assertSame($this->obj->image(), $this->obj->metaImage()); $this->assertEquals('Foo.png', (string)$this->obj->metaImage()); - + $this->obj->setMetaImage('Bar.jpg'); $this->assertEquals('Bar.jpg', (string)$this->obj->metaImage()); } */ - - /** - * @return void - */ - public function testCategoryType() + public function testCategoryType(): void { $this->assertEquals(NewsCategory::class, $this->obj->categoryType()); } - /** - * @return void - */ /* public function testSave() { $this->obj->save(); } */ - - /** - * @return void - */ - public function testSaveGeneratesSlug() + public function testSaveGeneratesSlug(): void { $this->assertEquals('', $this->obj['slug']); $this->obj->setData([ @@ -238,10 +193,7 @@ public function testSaveGeneratesSlug() $this->assertEquals('en/news/foo', (string)$this->obj['slug']); } - /** - * @return void - */ - public function testUpdateGeneratesSlug() + public function testUpdateGeneratesSlug(): void { $this->assertEquals('', $this->obj['slug']); $this->obj->setData([ diff --git a/packages/cms/tests/Charcoal/Cms/Route/AbstractRouteTestCase.php b/packages/cms/tests/Charcoal/Cms/Route/AbstractRouteTestCase.php index 9c541127b..d53c97813 100644 --- a/packages/cms/tests/Charcoal/Cms/Route/AbstractRouteTestCase.php +++ b/packages/cms/tests/Charcoal/Cms/Route/AbstractRouteTestCase.php @@ -3,6 +3,7 @@ namespace Charcoal\Tests\Cms\Route; // From PSR-7 +use Charcoal\App\Route\RouteInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; @@ -26,8 +27,6 @@ abstract class AbstractRouteTestCase extends AbstractTestCase /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -86,10 +85,8 @@ protected function createHttpResponse() /** * Assertion when given an empty path. - * - * @return void */ - public function testPathResolvableOnEmptyPath() + public function testPathResolvableOnEmptyPath(): void { $container = $this->getContainer(); $router = $this->createRouter([ @@ -149,9 +146,8 @@ abstract public function testInvokeOnExistingModelWithTemplateIdent(); * Create the dynamic route to test. * * @param array $data The dynamic route dependencies. - * @return \Charcoal\App\Route\RouteInterface */ - abstract protected function createRouter(array $data = []); + abstract protected function createRouter(array $data = []): RouteInterface; /** * Create the model's database table to test lookup. diff --git a/packages/cms/tests/Charcoal/Cms/Route/EventRouteTest.php b/packages/cms/tests/Charcoal/Cms/Route/EventRouteTest.php index dbf5924d3..45015660a 100644 --- a/packages/cms/tests/Charcoal/Cms/Route/EventRouteTest.php +++ b/packages/cms/tests/Charcoal/Cms/Route/EventRouteTest.php @@ -16,10 +16,8 @@ class EventRouteTest extends AbstractRouteTestCase /** * Asserts that `EventRoute::__invoke()` method returns an HTTP Response object * with a 404 status code if the path does not resolve to any routable model. - * - * @return void */ - public function testInvokeOnNonexistentModel() + public function testInvokeOnNonexistentModel(): void { $container = $this->getContainer(); $router = $this->createRouter([ @@ -41,10 +39,8 @@ public function testInvokeOnNonexistentModel() * if the resolved model has a nonexistent template controller. * * The "template/factory" service throws an Exception when a model's template controller can not be found. - * - * @return void */ - public function testInvokeOnExistingModelWithMissingTemplateController() + public function testInvokeOnExistingModelWithMissingTemplateController(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => 'nonexistent', @@ -62,16 +58,14 @@ public function testInvokeOnExistingModelWithMissingTemplateController() $response = $this->createHttpResponse(); $this->expectException(InvalidArgumentException::class); - $response = $router($container, $request, $response); + $router($container, $request, $response); } /** * Asserts that `EventRoute::__invoke()` method returns an HTTP Response object * with a 500 status code if the resolved model does not have a template identifier. - * - * @return void */ - public function testInvokeOnExistingModelWithoutTemplateIdent() + public function testInvokeOnExistingModelWithoutTemplateIdent(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => '', @@ -95,10 +89,8 @@ public function testInvokeOnExistingModelWithoutTemplateIdent() /** * Asserts that `EventRoute::__invoke()` method returns an HTTP Response object * with a 500 status code if the resolved model does not have a rendered template view. - * - * @return void */ - public function testInvokeOnExistingModelWithBadTemplateIdent() + public function testInvokeOnExistingModelWithBadTemplateIdent(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => 'charcoal/tests/cms/mock/broken', @@ -122,10 +114,8 @@ public function testInvokeOnExistingModelWithBadTemplateIdent() /** * Asserts that `EventRoute::__invoke()` method returns an HTTP Response object * with a 2XX status code if the path does resolve to a specific routable model. - * - * @return void */ - public function testInvokeOnExistingModelWithTemplateIdent() + public function testInvokeOnExistingModelWithTemplateIdent(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => 'charcoal/tests/cms/mock/event', @@ -151,9 +141,8 @@ public function testInvokeOnExistingModelWithTemplateIdent() * Create the dynamic route to test. * * @param array $data The dynamic route dependencies. - * @return EventRoute */ - protected function createRouter(array $data = []) + protected function createRouter(array $data = []): \Charcoal\Cms\Route\EventRoute { return new EventRoute($data + [ 'config' => [], diff --git a/packages/cms/tests/Charcoal/Cms/Route/GenericRouteTest.php b/packages/cms/tests/Charcoal/Cms/Route/GenericRouteTest.php index 160ece978..9cff3b738 100644 --- a/packages/cms/tests/Charcoal/Cms/Route/GenericRouteTest.php +++ b/packages/cms/tests/Charcoal/Cms/Route/GenericRouteTest.php @@ -2,6 +2,7 @@ namespace Charcoal\Tests\Cms\Route; +use Charcoal\App\Route\RouteInterface; use InvalidArgumentException; // From 'charcoal-object' @@ -21,10 +22,9 @@ class GenericRouteTest extends SectionRouteTest * with a 500 status code if the resolved model does not have a template identifier. * * The route's config throws an Exception when a model's template controller is invalid. - * - * @return void */ - public function testInvokeOnExistingModelWithoutTemplateIdent() + #[\Override] + public function testInvokeOnExistingModelWithoutTemplateIdent(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => '', @@ -43,16 +43,14 @@ public function testInvokeOnExistingModelWithoutTemplateIdent() $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Route view controller must be a string.'); - $response = $router($container, $request, $response); + $router($container, $request, $response); } /** * Asserts that `SectionRoute::__invoke()` method returns an HTTP Response object * with a 404 status code if the path does resolve but the routable model does not. - * - * @return void */ - public function testInvokeOnExistingObjectRouteWithMissingModel() + public function testInvokeOnExistingObjectRouteWithMissingModel(): void { $container = $this->getContainer(); @@ -83,9 +81,9 @@ public function testInvokeOnExistingObjectRouteWithMissingModel() * Create the dynamic route to test. * * @param array $data The dynamic route dependencies. - * @return GenericRoute */ - protected function createRouter(array $data = []) + #[\Override] + protected function createRouter(array $data = []): RouteInterface { return new GenericRoute($data + [ 'config' => [], diff --git a/packages/cms/tests/Charcoal/Cms/Route/NewsRouteTest.php b/packages/cms/tests/Charcoal/Cms/Route/NewsRouteTest.php index 3448d8f52..31675ca68 100644 --- a/packages/cms/tests/Charcoal/Cms/Route/NewsRouteTest.php +++ b/packages/cms/tests/Charcoal/Cms/Route/NewsRouteTest.php @@ -16,10 +16,8 @@ class NewsRouteTest extends AbstractRouteTestCase /** * Asserts that `NewsRoute::__invoke()` method returns an HTTP Response object * with a 404 status code if the path does not resolve to any routable model. - * - * @return void */ - public function testInvokeOnNonexistentModel() + public function testInvokeOnNonexistentModel(): void { $container = $this->getContainer(); $router = $this->createRouter([ @@ -41,10 +39,8 @@ public function testInvokeOnNonexistentModel() * if the resolved model has a nonexistent template controller. * * The "template/factory" service throws an Exception when a model's template controller can not be found. - * - * @return void */ - public function testInvokeOnExistingModelWithMissingTemplateController() + public function testInvokeOnExistingModelWithMissingTemplateController(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => 'nonexistent', @@ -62,16 +58,14 @@ public function testInvokeOnExistingModelWithMissingTemplateController() $response = $this->createHttpResponse(); $this->expectException(InvalidArgumentException::class); - $response = $router($container, $request, $response); + $router($container, $request, $response); } /** * Asserts that `NewsRoute::__invoke()` method returns an HTTP Response object * with a 500 status code if the resolved model does not have a template identifier. - * - * @return void */ - public function testInvokeOnExistingModelWithoutTemplateIdent() + public function testInvokeOnExistingModelWithoutTemplateIdent(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => '', @@ -95,10 +89,8 @@ public function testInvokeOnExistingModelWithoutTemplateIdent() /** * Asserts that `NewsRoute::__invoke()` method returns an HTTP Response object * with a 500 status code if the resolved model does not have a rendered template view. - * - * @return void */ - public function testInvokeOnExistingModelWithBadTemplateIdent() + public function testInvokeOnExistingModelWithBadTemplateIdent(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => 'charcoal/tests/cms/mock/broken', @@ -122,10 +114,8 @@ public function testInvokeOnExistingModelWithBadTemplateIdent() /** * Asserts that `NewsRoute::__invoke()` method returns an HTTP Response object * with a 2XX status code if the path does resolve to a specific routable model. - * - * @return void */ - public function testInvokeOnExistingModelWithTemplateIdent() + public function testInvokeOnExistingModelWithTemplateIdent(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => 'charcoal/tests/cms/mock/news', @@ -151,9 +141,8 @@ public function testInvokeOnExistingModelWithTemplateIdent() * Create the dynamic route to test. * * @param array $data The dynamic route dependencies. - * @return NewsRoute */ - protected function createRouter(array $data = []) + protected function createRouter(array $data = []): \Charcoal\Cms\Route\NewsRoute { return new NewsRoute($data + [ 'config' => [], diff --git a/packages/cms/tests/Charcoal/Cms/Route/SectionRouteTest.php b/packages/cms/tests/Charcoal/Cms/Route/SectionRouteTest.php index 1c79b174a..d3062c795 100644 --- a/packages/cms/tests/Charcoal/Cms/Route/SectionRouteTest.php +++ b/packages/cms/tests/Charcoal/Cms/Route/SectionRouteTest.php @@ -2,6 +2,7 @@ namespace Charcoal\Tests\Cms\Route; +use Charcoal\App\Route\RouteInterface; use InvalidArgumentException; // From 'charcoal-cms' @@ -16,10 +17,8 @@ class SectionRouteTest extends AbstractRouteTestCase /** * Asserts that `SectionRoute::__invoke()` method returns an HTTP Response object * with a 404 status code if the path does not resolve to any routable model. - * - * @return void */ - public function testInvokeOnNonexistentModel() + public function testInvokeOnNonexistentModel(): void { $container = $this->getContainer(); $router = $this->createRouter([ @@ -43,10 +42,8 @@ public function testInvokeOnNonexistentModel() * * The "config.view.defaultController" option ensures the "template/factory" service * does not throw an Exception when a model's template controller can not be found. - * - * @return void */ - public function testInvokeOnExistingModelWithMissingTemplateController() + public function testInvokeOnExistingModelWithMissingTemplateController(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => 'nonexistent', @@ -70,10 +67,8 @@ public function testInvokeOnExistingModelWithMissingTemplateController() /** * Asserts that `SectionRoute::__invoke()` method returns an HTTP Response object * with a 500 status code if the resolved model does not have a template identifier. - * - * @return void */ - public function testInvokeOnExistingModelWithoutTemplateIdent() + public function testInvokeOnExistingModelWithoutTemplateIdent(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => '', @@ -97,10 +92,8 @@ public function testInvokeOnExistingModelWithoutTemplateIdent() /** * Asserts that `SectionRoute::__invoke()` method returns an HTTP Response object * with a 500 status code if the resolved model does not have a rendered template view. - * - * @return void */ - public function testInvokeOnExistingModelWithBadTemplateIdent() + public function testInvokeOnExistingModelWithBadTemplateIdent(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => 'charcoal/tests/cms/mock/broken', @@ -124,10 +117,8 @@ public function testInvokeOnExistingModelWithBadTemplateIdent() /** * Asserts that `SectionRoute::__invoke()` method returns an HTTP Response object * with a 2XX status code if the path does resolve to a specific routable model. - * - * @return void */ - public function testInvokeOnExistingModelWithTemplateIdent() + public function testInvokeOnExistingModelWithTemplateIdent(): void { $this->insertMockRoutableContextObjects([ 'templateIdent' => 'charcoal/tests/cms/mock/home', @@ -153,9 +144,8 @@ public function testInvokeOnExistingModelWithTemplateIdent() * Create the dynamic route to test. * * @param array $data The dynamic route dependencies. - * @return SectionRoute */ - protected function createRouter(array $data = []) + protected function createRouter(array $data = []): RouteInterface { return new SectionRoute($data + [ 'config' => [], diff --git a/packages/cms/tests/Charcoal/Cms/SectionTest.php b/packages/cms/tests/Charcoal/Cms/SectionTest.php index 24dfe7aca..e9043194c 100644 --- a/packages/cms/tests/Charcoal/Cms/SectionTest.php +++ b/packages/cms/tests/Charcoal/Cms/SectionTest.php @@ -19,15 +19,11 @@ class SectionTest extends AbstractTestCase /** * Tested Class. - * - * @var Section */ - private $obj; + private \Charcoal\Cms\Section|array $obj; /** * Set up the test. - * - * @return void */ protected function setUp():void { @@ -43,10 +39,7 @@ protected function setUp():void $this->obj = new Section($dependencies); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ @@ -71,10 +64,7 @@ public function testSetData() $this->assertEquals([ 'x' => 'y' ], $obj->templateOptions()); } - /** - * @return void - */ - public function testSetSectionType() + public function testSetSectionType(): void { $ret = $this->obj->setSectionType(Section::TYPE_EMPTY); $this->assertSame($ret, $this->obj); @@ -84,10 +74,7 @@ public function testSetSectionType() $this->obj->setSectionType(false); } - /** - * @return void - */ - public function testSetTitle() + public function testSetTitle(): void { $this->assertEquals('', (string)$this->obj->title()); $ret = $this->obj->setTitle('Foo bar'); @@ -101,10 +88,7 @@ public function testSetTitle() $this->assertEquals('Hello', (string)$this->obj['title']); } - /** - * @return void - */ - public function testSetSubtitle() + public function testSetSubtitle(): void { $this->assertEquals('', (string)$this->obj->subtitle()); $ret = $this->obj->setSubtitle('Bar foo'); @@ -118,10 +102,7 @@ public function testSetSubtitle() $this->assertEquals('foo', (string)$this->obj['subtitle']); } - /** - * @return void - */ - public function testSetContent() + public function testSetContent(): void { $this->assertEquals('', (string)$this->obj->content()); $ret = $this->obj->setContent('Bar foo'); @@ -135,10 +116,7 @@ public function testSetContent() $this->assertEquals('foo', (string)$this->obj['content']); } - /** - * @return void - */ - public function testSetImage() + public function testSetImage(): void { $this->assertEquals('', (string)$this->obj->image()); $ret = $this->obj->setImage('foo.png'); @@ -152,10 +130,7 @@ public function testSetImage() $this->assertEquals('foo.webp', $this->obj['image']); } - /** - * @return void - */ - public function testMetaTitleDefaultsToTitle() + public function testMetaTitleDefaultsToTitle(): void { $this->assertEquals('', (string)$this->obj->metaTitle()); @@ -167,10 +142,7 @@ public function testMetaTitleDefaultsToTitle() $this->assertEquals('Barfoo', (string)$this->obj->metaTitle()); } - /** - * @return void - */ - public function testMetaDescriptionDefaultsToDescription() + public function testMetaDescriptionDefaultsToDescription(): void { $this->assertEquals('', (string)$this->obj->metaDescription()); @@ -182,10 +154,7 @@ public function testMetaDescriptionDefaultsToDescription() $this->assertEquals('Barfoo', (string)$this->obj->metaDescription()); } - /** - * @return void - */ - public function testMetaImageDefaultsToImage() + public function testMetaImageDefaultsToImage(): void { $this->assertEquals('', (string)$this->obj->metaImage()); @@ -197,10 +166,7 @@ public function testMetaImageDefaultsToImage() $this->assertEquals('Bar.jpg', (string)$this->obj->metaImage()); } - /** - * @return void - */ - public function testSaveGeneratesSlug() + public function testSaveGeneratesSlug(): void { $this->assertEquals('', $this->obj['slug']); $this->obj->setData([ @@ -211,10 +177,7 @@ public function testSaveGeneratesSlug() $this->assertEquals('en/foo', (string)$this->obj['slug']); } - /** - * @return void - */ - public function testUpdateGeneratesSlug() + public function testUpdateGeneratesSlug(): void { $this->assertEquals('', $this->obj['slug']); $this->obj->setData([ diff --git a/packages/cms/tests/Charcoal/Cms/TagTest.php b/packages/cms/tests/Charcoal/Cms/TagTest.php index 7b57b57b8..7fb77c686 100644 --- a/packages/cms/tests/Charcoal/Cms/TagTest.php +++ b/packages/cms/tests/Charcoal/Cms/TagTest.php @@ -17,15 +17,11 @@ class TagTest extends AbstractTestCase /** * Tested Class. - * - * @var Tag */ - private $obj; + private \Charcoal\Cms\Tag $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -34,10 +30,7 @@ protected function setUp(): void $this->obj = new Tag($dependencies); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $ret = $this->obj->setData([ 'name' => 'Foo?', @@ -54,34 +47,28 @@ public function testSetData() $this->assertEquals(42, $this->obj->searchWeight()); } - /** - * @return void - */ - public function testSetName() + public function testSetName(): void { $ret = $this->obj->setName('Foo?'); $this->assertSame($ret, $this->obj); $this->assertEquals('Foo?', $this->obj->name()); } - /** - * @return void - */ - public function testSetColor() + public function testSetColor(): void { $ret = $this->obj->setColor('Bar'); $this->assertSame($ret, $this->obj); $this->assertEquals('Bar', $this->obj->color()); } - public function testSetVariations() + public function testSetVariations(): void { $ret = $this->obj->setVariations('foo,bar,baz'); $this->assertSame($ret, $this->obj); $this->assertEquals('foo,bar,baz', $this->obj->variations()); } - public function testSetSearchWeight() + public function testSetSearchWeight(): void { $ret = $this->obj->setSearchWeight(1984); $this->assertSame($ret, $this->obj); diff --git a/packages/cms/tests/Charcoal/Cms/TemplateableTraitTest.php b/packages/cms/tests/Charcoal/Cms/TemplateableTraitTest.php index a53c7aaad..3ed508874 100644 --- a/packages/cms/tests/Charcoal/Cms/TemplateableTraitTest.php +++ b/packages/cms/tests/Charcoal/Cms/TemplateableTraitTest.php @@ -29,8 +29,6 @@ class TemplateableTraitTest extends AbstractTestCase /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -58,8 +56,6 @@ protected function setUp(): void * Tear down the test. * * Drop any existing SQL table. - * - * @return void */ protected function tearDown(): void { @@ -68,10 +64,8 @@ protected function tearDown(): void /** * Drop the SQL table. - * - * @return void */ - private function dropTable() + private function dropTable(): void { $container = $this->getContainer(); @@ -80,10 +74,8 @@ private function dropTable() /** * Retrieve the model's mock metadata. - * - * @return array */ - public function getModelMetadata() + public function getModelMetadata(): array { return [ 'properties' => [ @@ -124,30 +116,23 @@ public function getModelMetadata() ]; } - /** - * @return void - */ - public function testMissingPropertyDependency() + public function testMissingPropertyDependency(): void { $this->expectException(RuntimeException::class); $obj = new TemplateableModel($this->getModelDependencies()); $obj->templateOptionsStructure(); } - /** - * @return void - */ - public function testMissingInterfaceDependency() + public function testMissingInterfaceDependency(): void { $this->expectException(RuntimeException::class); - $obj = $this->getMockForTrait(TemplateableTrait::class); + $obj = new class { + use TemplateableTrait; + }; $obj->templateOptionsStructure(); } - /** - * @return void - */ - public function testTemplateIdent() + public function testTemplateIdent(): void { $this->assertEmpty($this->obj->templateIdent()); @@ -155,10 +140,7 @@ public function testTemplateIdent() $this->assertEquals('foobar', $this->obj->templateIdent()); } - /** - * @return void - */ - public function testControllerIdent() + public function testControllerIdent(): void { $this->assertNull($this->obj->controllerIdent()); @@ -166,10 +148,7 @@ public function testControllerIdent() $this->assertEquals('foobar', $this->obj->controllerIdent()); } - /** - * @return void - */ - public function testTemplateOptions() + public function testTemplateOptions(): void { $this->assertIsArray($this->obj->templateOptions()); $this->assertEmpty($this->obj->templateOptions()); @@ -194,10 +173,7 @@ public function testTemplateOptions() $this->assertEquals($obj, $this->obj->templateOptions()); } - /** - * @return void - */ - public function testSavingTemplateOptions() + public function testSavingTemplateOptions(): void { $obj = $this->obj; $obj->setTemplateIdent('foo'); @@ -214,10 +190,7 @@ public function testSavingTemplateOptions() $this->assertTrue($result); } - /** - * @return void - */ - public function testTemplateOptionsStructure() + public function testTemplateOptionsStructure(): void { $templateData = [ 'foo' => 'Huxley' ]; $basePath = $this->getContainer()['config']['base_path']; diff --git a/packages/cms/tests/Charcoal/Property/TemplateOptionsPropertyTest.php b/packages/cms/tests/Charcoal/Property/TemplateOptionsPropertyTest.php index cc33465de..7154d21fd 100644 --- a/packages/cms/tests/Charcoal/Property/TemplateOptionsPropertyTest.php +++ b/packages/cms/tests/Charcoal/Property/TemplateOptionsPropertyTest.php @@ -26,8 +26,6 @@ class TemplateOptionsPropertyTest extends AbstractTestCase /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -52,18 +50,12 @@ protected function setUp(): void $this->obj = new TemplateOptionsProperty($dependencies); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('template-options', $this->obj->type()); } - /** - * @return void - */ - public function testAddStructureInterface() + public function testAddStructureInterface(): void { $container = $this->getContainer(); $property = $container['property/factory']->create(TemplateProperty::class); @@ -76,10 +68,7 @@ public function testAddStructureInterface() $this->assertEquals([ 'charcoal/tests/cms/mock/generic' ], $interfaces); } - /** - * @return void - */ - public function testAddStructureInterfaceException() + public function testAddStructureInterfaceException(): void { $container = $this->getContainer(); $property = $container['property/factory']->create(TemplateProperty::class); diff --git a/packages/cms/tests/Charcoal/Property/TemplatePropertyTest.php b/packages/cms/tests/Charcoal/Property/TemplatePropertyTest.php index 79ed83b9e..7b45bbb3d 100644 --- a/packages/cms/tests/Charcoal/Property/TemplatePropertyTest.php +++ b/packages/cms/tests/Charcoal/Property/TemplatePropertyTest.php @@ -27,8 +27,6 @@ class TemplatePropertyTest extends AbstractTestCase /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -43,26 +41,17 @@ protected function setUp(): void $this->obj = new TemplateProperty($dependencies); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('template', $this->obj->type()); } - /** - * @return void - */ - public function testSqlExtra() + public function testSqlExtra(): void { $this->assertEquals('', $this->obj->sqlExtra()); } - /** - * @return void - */ - public function testSqlType() + public function testSqlType(): void { $this->obj->setMultiple(false); $this->assertEquals('VARCHAR(255)', $this->obj->sqlType()); @@ -71,18 +60,12 @@ public function testSqlType() $this->assertEquals('TEXT', $this->obj->sqlType()); } - /** - * @return void - */ - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->assertEquals(PDO::PARAM_STR, $this->obj->sqlPdoType()); } - /** - * @return void - */ - public function testChoices() + public function testChoices(): void { $container = $this->getContainer(); $templates = $container['config']['templates']; @@ -109,59 +92,40 @@ public function testChoices() $this->assertArrayHasKey('zyx', $this->obj->choices()); } - /** - * @return void - */ - public function testChoicesInvalidKey() + public function testChoicesInvalidKey(): void { $this->expectException(InvalidArgumentException::class); $this->obj->addChoice(3, 'boo'); } - /** - * @return void - */ - public function testChoicesInvalidString() + public function testChoicesInvalidString(): void { $this->expectException(InvalidArgumentException::class); $this->obj->addChoice('boo', 'boo'); } - /** - * @return void - */ - public function testChoicesInvalidBoolean() + public function testChoicesInvalidBoolean(): void { $this->expectException(InvalidArgumentException::class); $this->obj->addChoice('boo', true); } - /** - * @return void - */ - public function testChoicesInvalidArray() + public function testChoicesInvalidArray(): void { $this->expectException(InvalidArgumentException::class); $this->obj->addChoice('boo', [ 'foo' => 'boo' ]); } - /** - * @return void - */ - public function testChoicesInvalidType() + public function testChoicesInvalidType(): void { $this->expectException(InvalidArgumentException::class); $this->obj->addChoice('xyz', null); } - /** - * @return void - */ - public function testDisplayVal() + public function testDisplayVal(): void { $container = $this->getContainer(); $translator = $container['translator']; - $templates = $container['config']['templates']; $this->assertEquals('', $this->obj->displayVal(null)); $this->assertEquals('', $this->obj->displayVal('')); @@ -189,10 +153,7 @@ public function testDisplayVal() $this->assertEquals('Oofoof, Zabzab, Xuqxuq', $this->obj->displayVal('foo,baz,qux', [ 'lang' => 'fr' ])); } - /** - * @return void - */ - public function testToString() + public function testToString(): void { $this->assertEquals('', (string)$this->obj); diff --git a/packages/cms/tests/bootstrap.php b/packages/cms/tests/bootstrap.php new file mode 100644 index 000000000..90929e3b5 --- /dev/null +++ b/packages/cms/tests/bootstrap.php @@ -0,0 +1,14 @@ + - -> + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal @@ -18,17 +19,19 @@ - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/config/src/Charcoal/Config/AbstractConfig.php b/packages/config/src/Charcoal/Config/AbstractConfig.php index d9a33d9e8..cea8098f8 100644 --- a/packages/config/src/Charcoal/Config/AbstractConfig.php +++ b/packages/config/src/Charcoal/Config/AbstractConfig.php @@ -41,7 +41,7 @@ abstract class AbstractConfig extends AbstractEntity implements * @param EntityInterface[] $delegates An array of delegates (config) to set. * @throws InvalidArgumentException If $data is invalid. */ - final public function __construct($data = null, array $delegates = null) + final public function __construct($data = null, ?array $delegates = null) { // Always set the default chaining notation $this->setSeparator(self::DEFAULT_SEPARATOR); @@ -108,9 +108,8 @@ public function merge($data) * Create a new iterator from the configuration instance. * * @see IteratorAggregate - * @return ArrayIterator */ - public function getIterator() + public function getIterator(): ArrayIterator { return new ArrayIterator($this->data()); } @@ -131,7 +130,8 @@ public function getIterator() * @throws InvalidArgumentException If the $key is not a string or is a numeric value. * @return boolean TRUE if $key exists and has a value other than NULL, FALSE otherwise. */ - public function offsetExists($key) + #[\Override] + public function offsetExists($key): bool { if (is_numeric($key)) { throw new InvalidArgumentException( @@ -192,7 +192,8 @@ public function offsetExists($key) * @throws InvalidArgumentException If the $key is not a string or is a numeric value. * @return mixed Value of the requested $key on success, NULL if the $key is not set. */ - public function offsetGet($key) + #[\Override] + public function offsetGet($key): mixed { if (is_numeric($key)) { throw new InvalidArgumentException( @@ -228,13 +229,8 @@ public function offsetGet($key) if ($this->mutatorCache[$key]) { return $this->{$key}(); } - // -- END DEPRECATED - - if (isset($this->{$key})) { - return $this->{$key}; - } - return $this->getInDelegates($key); + return ($this->{$key} ?? $this->getInDelegates($key)); } /** @@ -249,9 +245,9 @@ public function offsetGet($key) * @param string $key The data key to assign $value to. * @param mixed $value The data value to assign to $key. * @throws InvalidArgumentException If the $key is not a string or is a numeric value. - * @return void */ - public function offsetSet($key, $value) + #[\Override] + public function offsetSet($key, $value): void { if (is_numeric($key)) { throw new InvalidArgumentException( @@ -298,9 +294,8 @@ public function offsetSet($key, $value) * @param string $key The data key to assign or merge $value to. * @param mixed $value The data value to assign to or merge with $key. * @throws InvalidArgumentException If the $key is not a string or is a numeric value. - * @return void */ - public function offsetReplace($key, $value) + public function offsetReplace($key, $value): void { if (is_numeric($key)) { throw new InvalidArgumentException( diff --git a/packages/config/src/Charcoal/Config/AbstractEntity.php b/packages/config/src/Charcoal/Config/AbstractEntity.php index d14fab59e..1c59dce18 100644 --- a/packages/config/src/Charcoal/Config/AbstractEntity.php +++ b/packages/config/src/Charcoal/Config/AbstractEntity.php @@ -2,6 +2,7 @@ namespace Charcoal\Config; +use AllowDynamicProperties; use ArrayAccess; use InvalidArgumentException; @@ -17,6 +18,7 @@ * - A key-value pair is internally passed to a (non-private / non-static) setter method (if present) * or assigned to a (non-private / non-static) property (declared or not) and tracks affected keys. */ +#[AllowDynamicProperties] abstract class AbstractEntity implements EntityInterface { /** @@ -58,7 +60,7 @@ public function keys() * @param string[] $keys Optional. Extracts only the requested data. * @return array Key-value array of data, excluding pairs with NULL values. */ - public function data(array $keys = null) + public function data(?array $keys = null) { if ($keys === null) { $keys = $this->keys(); @@ -66,7 +68,7 @@ public function data(array $keys = null) $data = []; foreach ($keys as $key) { - if (strtolower($key) === 'data') { + if (strtolower((string)$key) === 'data') { /** @internal Edge Case: Avoid recursive call */ continue; } @@ -88,7 +90,7 @@ public function data(array $keys = null) public function setData(array $data) { foreach ($data as $key => $value) { - if (strtolower($key) === 'data') { + if (strtolower((string)$key) === 'data') { /** @internal Edge Case: Avoid recursive call */ continue; } @@ -150,7 +152,7 @@ public function set($key, $value) * @throws InvalidArgumentException If the $key is not a string or is a numeric value. * @return boolean TRUE if $key exists and has a value other than NULL, FALSE otherwise. */ - public function offsetExists($key) + public function offsetExists($key): bool { if (is_numeric($key)) { throw new InvalidArgumentException( @@ -183,12 +185,7 @@ public function offsetExists($key) return ($this->{$key}() !== null); } // -- END DEPRECATED - - if (isset($this->{$key})) { - return true; - } - - return false; + return isset($this->{$key}); } /** @@ -205,7 +202,7 @@ public function offsetExists($key) * @throws InvalidArgumentException If the $key is not a string or is a numeric value. * @return mixed Value of the requested $key on success, NULL if the $key is not set. */ - public function offsetGet($key) + public function offsetGet($key): mixed { if (is_numeric($key)) { throw new InvalidArgumentException( @@ -237,13 +234,8 @@ public function offsetGet($key) if ($this->mutatorCache[$key]) { return $this->{$key}(); } - // -- END DEPRECATED - if (isset($this->{$key})) { - return $this->{$key}; - } - - return null; + return ($this->{$key} ?? null); } /** @@ -259,9 +251,8 @@ public function offsetGet($key) * @param string $key The data key to assign $value to. * @param mixed $value The data value to assign to $key. * @throws InvalidArgumentException If the $key is not a string or is a numeric value. - * @return void */ - public function offsetSet($key, $value) + public function offsetSet($key, $value): void { if (is_numeric($key)) { throw new InvalidArgumentException( @@ -301,9 +292,8 @@ public function offsetSet($key, $value) * @uses self::offsetSet() * @param string $key The data key to remove. * @throws InvalidArgumentException If the $key is not a string or is a numeric value. - * @return void */ - public function offsetUnset($key) + public function offsetUnset($key): void { if (is_numeric($key)) { throw new InvalidArgumentException( @@ -328,32 +318,18 @@ public function offsetUnset($key) * @see \JsonSerializable * @return array Key-value array of data. */ - public function jsonSerialize() + public function jsonSerialize(): mixed { return $this->data(); } - /** - * Serializes the data on this entity. - * - * @see \Serializable - * @return string Returns a string containing a byte-stream representation of the object. - */ - public function serialize() + public function __serialize(): array { - return serialize($this->data()); + return $this->data(); } - /** - * Applies the serialized data to this entity. - * - * @see \Serializable - * @param string $data The serialized data to extract. - * @return void - */ - public function unserialize($data) + public function __unserialize(array $data): void { - $data = unserialize($data); $this->setData($data); } @@ -371,8 +347,8 @@ final protected function camelize($value) return static::$camelCache[$key]; } - if (strpos($value, '_') !== false) { - $value = implode('', array_map('ucfirst', explode('_', $value))); + if (str_contains($value, '_')) { + $value = implode('', array_map(ucfirst(...), explode('_', $value))); } static::$camelCache[$key] = lcfirst($value); diff --git a/packages/config/src/Charcoal/Config/ConfigInterface.php b/packages/config/src/Charcoal/Config/ConfigInterface.php index 780dcd384..8d1d19dba 100644 --- a/packages/config/src/Charcoal/Config/ConfigInterface.php +++ b/packages/config/src/Charcoal/Config/ConfigInterface.php @@ -1,5 +1,7 @@ delegates as $delegate) { if (isset($delegate[$key])) { diff --git a/packages/config/src/Charcoal/Config/EntityInterface.php b/packages/config/src/Charcoal/Config/EntityInterface.php index b64045c0a..66ec2161c 100644 --- a/packages/config/src/Charcoal/Config/EntityInterface.php +++ b/packages/config/src/Charcoal/Config/EntityInterface.php @@ -1,5 +1,7 @@ getMessage()); - throw new UnexpectedValueException($message, 0, $e); - } catch (Throwable $e) { + } catch (Exception | Throwable $e) { $message = sprintf('PHP file "%s" could not be parsed: %s', $path, $e->getMessage()); throw new UnexpectedValueException($message, 0, $e); } - if (is_array($data) || ($data instanceof Traversable)) { + if (is_iterable($data)) { return $data; } @@ -156,9 +153,9 @@ private function loadPhpFile($path) * @return array An array on success. * If the file is parsed as any other type, an empty array is returned. */ - private function loadYamlFile($path) + private function loadYamlFile(string $path): array { - if (!class_exists('Symfony\Component\Yaml\Parser')) { + if (!class_exists(\Symfony\Component\Yaml\Parser::class)) { throw new LogicException('YAML format requires the Symfony YAML component'); } diff --git a/packages/config/src/Charcoal/Config/GenericConfig.php b/packages/config/src/Charcoal/Config/GenericConfig.php index 6be9b26eb..cb9a17927 100644 --- a/packages/config/src/Charcoal/Config/GenericConfig.php +++ b/packages/config/src/Charcoal/Config/GenericConfig.php @@ -1,5 +1,7 @@ separator, $key); diff --git a/packages/config/tests/Charcoal/AbstractTestCase.php b/packages/config/tests/Charcoal/AbstractTestCase.php index 3fdbb598d..a382decca 100644 --- a/packages/config/tests/Charcoal/AbstractTestCase.php +++ b/packages/config/tests/Charcoal/AbstractTestCase.php @@ -1,5 +1,7 @@ assertCount(count($expected), $haystack, $message); $this->assertEquals($expected, $haystack, $message); @@ -27,9 +26,8 @@ public function assertArrayEquals(array $expected, array $haystack, $message = ' * @param array $expected The expected haystack. * @param array $haystack The actual haystack. * @param string $message The error to report. - * @return void */ - public function assertArrayContains(array $expected, array $haystack, $message = '') + public function assertArrayContains(array $expected, array $haystack, $message = ''): void { foreach ($expected as $item) { $this->assertContains($item, $haystack, $message); @@ -42,9 +40,8 @@ public function assertArrayContains(array $expected, array $haystack, $message = * @param array $expected The expected haystack. * @param array $haystack The actual haystack. * @param string $message The error to report. - * @return void */ - public function assertArrayHasKeys(array $expected, array $haystack, $message = '') + public function assertArrayHasKeys(array $expected, array $haystack, $message = ''): void { foreach ($expected as $item) { $this->assertArrayHasKey($item, $haystack, $message); @@ -58,14 +55,13 @@ public function assertArrayHasKeys(array $expected, array $haystack, $message = * @param array $haystack The actual haystack. * @param boolean $strict Whether to check for object identity. * @param string $message The error to report. - * @return void */ public function assertArraySubsets( array $expected, array $haystack, $strict = false, $message = '' - ) { + ): void { foreach ($expected as $key => $val) { $this->assertArraySubset([ $key => $val ], $haystack, $strict, $message); } diff --git a/packages/config/tests/Charcoal/Config/Config/AbstractConfigTestCase.php b/packages/config/tests/Charcoal/Config/Config/AbstractConfigTestCase.php index 427c6edf8..812d5ad6c 100644 --- a/packages/config/tests/Charcoal/Config/Config/AbstractConfigTestCase.php +++ b/packages/config/tests/Charcoal/Config/Config/AbstractConfigTestCase.php @@ -22,7 +22,7 @@ abstract class AbstractConfigTestCase extends AbstractTestCase * @param array $delegates Delegates to pre-populate the object. * @return MacroConfig */ - public function createConfig($data = null, array $delegates = null) + public function createConfig($data = null, ?array $delegates = null) { return new MacroConfig($data, $delegates); } @@ -36,6 +36,6 @@ public function createConfig($data = null, array $delegates = null) */ public function mockConfig($data = null, $delegates = null) { - return $this->getMockForAbstractClass(AbstractConfig::class, [ $data, $delegates ]); + return new class($data, $delegates) extends AbstractConfig {}; } } diff --git a/packages/config/tests/Charcoal/Config/Config/ConfigArrayAccessTest.php b/packages/config/tests/Charcoal/Config/Config/ConfigArrayAccessTest.php index 1b957e0ac..7a72d9325 100644 --- a/packages/config/tests/Charcoal/Config/Config/ConfigArrayAccessTest.php +++ b/packages/config/tests/Charcoal/Config/Config/ConfigArrayAccessTest.php @@ -12,9 +12,14 @@ /** * Test ArrayAccess implementation in AbstractConfig - * - * @coversDefaultClass \Charcoal\Config\AbstractConfig */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Config\AbstractConfig::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'offsetExists()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'offsetGet()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'offsetSet()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'offsetUnset()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Tests\Config\Mock\MacroConfig::class, 'foo()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Tests\Config\Mock\MacroConfig::class, 'setFoo()')] class ConfigArrayAccessTest extends AbstractConfigTestCase { use ArrayAccessTestTrait; @@ -26,8 +31,6 @@ class ConfigArrayAccessTest extends AbstractConfigTestCase /** * Create a concrete MacroConfig instance. - * - * @return void */ protected function setUp(): void { @@ -41,9 +44,9 @@ protected function setUp(): void /** * Asserts that the object implements ArrayAccess. * - * @coversNothing * @return MacroConfig */ + #[\PHPUnit\Framework\Attributes\CoversNothing] public function testArrayAccess() { $this->assertInstanceOf(ArrayAccess::class, $this->cfg); @@ -54,17 +57,12 @@ public function testArrayAccess() // Test ArrayAccess on non-private properties // ========================================================================= - - /** - * @covers ::offsetExists() - * @return void - */ - public function testOffsetExists() + public function testOffsetExists(): void { $cfg = $this->cfg; // MacroConfig::$name - $this->assertObjectHasAttribute('name', $cfg); + $this->assertTrue(property_exists($cfg, 'name')); $this->assertTrue(isset($cfg['name'])); // MacroConfig::foo() @@ -74,11 +72,7 @@ public function testOffsetExists() $this->assertTrue(isset($cfg['erd'])); } - /** - * @covers ::offsetGet() - * @return void - */ - public function testOffsetGet() + public function testOffsetGet(): void { $cfg = $this->cfg; @@ -92,29 +86,21 @@ public function testOffsetGet() $this->assertEquals(true, $cfg['erd']); } - /** - * @covers ::offsetSet() - * @return void - */ - public function testOffsetSet() + public function testOffsetSet(): void { $cfg = $this->cfg; $cfg['baz'] = 'waldo'; - $this->assertObjectHasAttribute('baz', $cfg); + $this->assertTrue(property_exists($cfg, 'baz')); $this->assertEquals('waldo', $cfg['baz']); } - /** - * @covers ::offsetUnset() - * @return void - */ - public function testOffsetUnset() + public function testOffsetUnset(): void { $cfg = $this->cfg; unset($cfg['name']); - $this->assertObjectHasAttribute('name', $cfg); + $this->assertTrue(property_exists($cfg, 'name')); $this->assertNull($cfg['name']); } @@ -122,38 +108,22 @@ public function testOffsetUnset() // Test ArrayAccess on encapsulated properties // ========================================================================= - - /** - * @covers \Charcoal\Tests\Config\Mock\MacroConfig::foo() - * @covers ::offsetExists() - * @return void - */ - public function testOffsetExistsOnEncapsulatedMethod() + public function testOffsetExistsOnEncapsulatedMethod(): void { $cfg = $this->cfg; - $this->assertObjectHasAttribute('foo', $cfg); + $this->assertTrue(property_exists($cfg, 'foo')); $this->assertTrue(isset($cfg['foo'])); } - /** - * @covers \Charcoal\Tests\Config\Mock\MacroConfig::foo() - * @covers ::offsetGet() - * @return void - */ - public function testOffsetGetOnEncapsulatedMethod() + public function testOffsetGetOnEncapsulatedMethod(): void { $cfg = $this->cfg; $this->assertEquals('foo is 20', $cfg['foo']); } - /** - * @covers \Charcoal\Tests\Config\Mock\MacroConfig::setFoo() - * @covers ::offsetSet() - * @return void - */ - public function testOffsetSetOnEncapsulatedMethod() + public function testOffsetSetOnEncapsulatedMethod(): void { $cfg = $this->cfg; @@ -161,17 +131,12 @@ public function testOffsetSetOnEncapsulatedMethod() $this->assertEquals('foo is 42', $cfg['foo']); } - /** - * @covers \Charcoal\Tests\Config\Mock\MacroConfig::setFoo() - * @covers ::offsetUnset() - * @return void - */ - public function testOffsetUnsetOnEncapsulatedMethod() + public function testOffsetUnsetOnEncapsulatedMethod(): void { $cfg = $this->cfg; unset($cfg['foo']); - $this->assertObjectHasAttribute('foo', $cfg); + $this->assertTrue(property_exists($cfg, 'foo')); $this->assertEquals('foo is 10', $cfg['foo']); } } diff --git a/packages/config/tests/Charcoal/Config/Config/ConfigArrayMergeTest.php b/packages/config/tests/Charcoal/Config/Config/ConfigArrayMergeTest.php index f286d35e1..d5eabb354 100644 --- a/packages/config/tests/Charcoal/Config/Config/ConfigArrayMergeTest.php +++ b/packages/config/tests/Charcoal/Config/Config/ConfigArrayMergeTest.php @@ -14,9 +14,10 @@ /** * Test data merging in AbstractConfig - * - * @coversDefaultClass \Charcoal\Config\AbstractConfig */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Config\AbstractConfig::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'offsetReplace()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'merge()')] class ConfigArrayMergeTest extends AbstractConfigTestCase { use AssertionsTrait; @@ -28,8 +29,6 @@ class ConfigArrayMergeTest extends AbstractConfigTestCase /** * Create a concrete GenericConfig instance. - * - * @return void */ protected function setUp(): void { @@ -41,23 +40,18 @@ protected function setUp(): void * * @param mixed $data Data to pre-populate the object. * @param array $delegates Delegates to pre-populate the object. - * @return GenericConfig */ - public function createConfig($data = null, array $delegates = null) + #[\Override] + public function createConfig($data = null, ?array $delegates = null): \Charcoal\Config\GenericConfig { return new GenericConfig($data, $delegates); } // ========================================================================= - /** * Test {@see AbstractEntity::merge()} with array. - * - * @covers ::offsetReplace() - * @covers ::merge() - * @return void */ - public function testMergeDataWithArray() + public function testMergeDataWithArray(): void { $cfg = $this->cfg; @@ -74,12 +68,8 @@ public function testMergeDataWithArray() /** * Test {@see AbstractEntity::merge()} with another Config instance. - * - * @covers ::offsetReplace() - * @covers ::merge() - * @return void */ - public function testMergeDataWithConfigInstance() + public function testMergeDataWithConfigInstance(): void { $cfg = $this->cfg; @@ -95,10 +85,8 @@ public function testMergeDataWithConfigInstance() /** * Gets the intiial Config data. - * - * @return array */ - public function getInitialConfigData() + public function getInitialConfigData(): array { return [ 'name' => 'vendor/my-cool-app', @@ -116,10 +104,8 @@ public function getInitialConfigData() /** * Gets the mutations for the Config. - * - * @return array */ - public function getMutatedConfigData() + public function getMutatedConfigData(): array { return [ 'name' => 'vendor/my-awesome-app', @@ -138,10 +124,8 @@ public function getMutatedConfigData() /** * Gets the expected Config data. - * - * @return array */ - public function getExpectedConfigData() + public function getExpectedConfigData(): array { return [ 'name' => 'vendor/my-awesome-app', @@ -159,15 +143,11 @@ public function getExpectedConfigData() } // ========================================================================= - /** * Asserts that the container assigns a value to the endpoint * {@see SeparatorAwareTrait::setWithSeparator() of the keypath}. - * - * @covers ::offsetReplace() - * @return void */ - public function testOffsetMergeOnEndKeyPath() + public function testOffsetMergeOnEndKeyPath(): void { $cfg = $this->cfg; @@ -185,11 +165,8 @@ public function testOffsetMergeOnEndKeyPath() /** * Asserts that the container assigns a value to the endpoint of a nonexistent midpoint * {@see SeparatorAwareTrait::setWithSeparator() in the keypath}. - * - * @covers ::offsetReplace() - * @return void */ - public function testOffsetMergeOnNonexistentMidKeyPath() + public function testOffsetMergeOnNonexistentMidKeyPath(): void { $cfg = $this->cfg; @@ -206,22 +183,13 @@ public function testOffsetMergeOnNonexistentMidKeyPath() } // ========================================================================= - - /** - * @covers ::offsetReplace() - * @return void - */ - public function testOffsetMergeIgnoredOnZeroLengthKey() + public function testOffsetMergeIgnoredOnZeroLengthKey(): void { $this->cfg->offsetReplace('', 'waldo'); $this->assertNull($this->cfg['']); } - /** - * @covers ::offsetReplace() - * @return void - */ - public function testOffsetMergeIgnoredOnUnderscoreKey() + public function testOffsetMergeIgnoredOnUnderscoreKey(): void { $this->cfg->offsetReplace('_', 'waldo'); $this->assertNull($this->cfg['_']); @@ -229,11 +197,8 @@ public function testOffsetMergeIgnoredOnUnderscoreKey() /** * Asserts that a numeric key throws an exception, when merging a value. - * - * @covers ::offsetReplace() - * @return void */ - public function testOffsetMergeThrowsExceptionOnNumericKey() + public function testOffsetMergeThrowsExceptionOnNumericKey(): void { $this->expectExceptionMessage("Entity array access only supports non-numeric keys"); $this->expectException(InvalidArgumentException::class); diff --git a/packages/config/tests/Charcoal/Config/Config/ConfigDelegatesAwareTest.php b/packages/config/tests/Charcoal/Config/Config/ConfigDelegatesAwareTest.php index b777d94b7..058a28bbf 100644 --- a/packages/config/tests/Charcoal/Config/Config/ConfigDelegatesAwareTest.php +++ b/packages/config/tests/Charcoal/Config/Config/ConfigDelegatesAwareTest.php @@ -10,9 +10,14 @@ /** * Test DelegatesAwareTrait implementation in AbstractConfig - * - * @coversDefaultClass \Charcoal\Config\AbstractConfig */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Config\AbstractConfig::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, '__construct()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'setDelegates()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'addDelegate()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'prependDelegate()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'offsetExists()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'offsetGet()')] class ConfigDelegatesAwareTest extends AbstractConfigTestCase { /** @@ -27,8 +32,6 @@ class ConfigDelegatesAwareTest extends AbstractConfigTestCase /** * Create a concrete MacroConfig instance. - * - * @return void */ protected function setUp(): void { @@ -62,11 +65,9 @@ protected function setUp(): void /** * Asserts that the object implements DelegatesAwareInterface. - * - * @coversNothing - * @return void */ - public function testDelegatesAwareInterface() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testDelegatesAwareInterface(): void { $this->assertInstanceOf(DelegatesAwareInterface::class, $this->cfg); } @@ -75,15 +76,7 @@ public function testDelegatesAwareInterface() // Test Delegate Collecting // ========================================================================= - - /** - * @covers ::__construct() - * @covers ::setDelegates() - * @covers ::addDelegate() - * @covers ::prependDelegate() - * @return void - */ - public function testSetDelegates() + public function testSetDelegates(): void { $cfg = $this->createConfig(null, [ $this->delegates[0] ]); $this->assertEquals(0, $cfg['bop']); @@ -99,100 +92,83 @@ public function testSetDelegates() // Test ArrayAccess on delegated properties // ========================================================================= - /** * Asserts that the delegate container returns TRUE if a data key is found * {@see DelegatesAwareTrait::hasInDelegates() among its delegates}. - * - * @covers ::offsetExists() - * @return void */ - public function testOffsetExistsInDelegates() + public function testOffsetExistsInDelegates(): void { $cfg = $this->cfg; - $this->assertObjectNotHasAttribute('bar', $cfg); - $this->assertObjectHasAttribute('bar', $this->delegates[1]); + $this->assertFalse(property_exists($cfg, 'bar')); + $this->assertTrue(property_exists($this->delegates[1], 'bar')); $this->assertTrue(isset($cfg['bar'])); } /** * Asserts that the delegate container returns FALSE if a data key is nonexistent * {@see DelegatesAwareTrait::hasInDelegates() among its delegates}. - * - * @covers ::offsetExists() - * @return void */ - public function testOffsetExistsReturnsFalseOnNonexistentKeyInDelegates() + public function testOffsetExistsReturnsFalseOnNonexistentKeyInDelegates(): void { $cfg = $this->cfg; - $this->assertObjectNotHasAttribute('zyx', $cfg); + $this->assertFalse(property_exists($cfg, 'zyx')); $this->assertFalse(isset($cfg['zyx'])); } /** * Asserts that the delegate container returns the value of a data key found * {@see DelegatesAwareTrait::getInDelegates() among its delegates}. - * - * @covers ::offsetGet() - * @return void */ - public function testOffsetGetInDelegates() + public function testOffsetGetInDelegates(): void { $cfg = $this->cfg; - $this->assertObjectNotHasAttribute('qux', $cfg); - $this->assertObjectHasAttribute('qux', $this->delegates[2]); + $this->assertFalse(property_exists($cfg, 'qux')); + $this->assertTrue(property_exists($this->delegates[2], 'qux')); $this->assertEquals($this->delegates[2]['qux'], $cfg['qux']); } /** * Asserts that the delegate container returns NULL if a data key is nonexistent * {@see DelegatesAwareTrait::getInDelegates() among its delegates}. - * - * @covers ::offsetExists() - * @return void */ - public function testOffsetGetReturnsNullOnNonexistentKeyInDelegates() + public function testOffsetGetReturnsNullOnNonexistentKeyInDelegates(): void { $cfg = $this->cfg; - $this->assertObjectNotHasAttribute('xyz', $cfg); + $this->assertFalse(property_exists($cfg, 'xyz')); $this->assertNull($cfg['xyz']); } /** * Asserts that attributes in delegates cannot be mutated by the delegate container. - * - * @coversNothing - * @return void */ - public function testOffsetSetDoesNotPerformMutationsInDelegates() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testOffsetSetDoesNotPerformMutationsInDelegates(): void { $cfg = $this->cfg; - $this->assertObjectNotHasAttribute('qux', $cfg); - $this->assertObjectHasAttribute('qux', $this->delegates[2]); + $this->assertFalse(property_exists($cfg, 'qux')); + $this->assertTrue(property_exists($this->delegates[2], 'qux')); $cfg['qux'] = 'garply'; - $this->assertObjectHasAttribute('qux', $cfg); + $this->assertTrue(property_exists($cfg, 'qux')); $this->assertEquals('garply', $cfg['qux']); $this->assertEquals('xyzzy', $this->delegates[2]['qux']); } /** * Asserts that attributes in delegates cannot be removed by the delegate container. - * - * @coversNothing - * @return void */ - public function testOffsetUnsetDoesNotPerformMutationsInDelegates() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testOffsetUnsetDoesNotPerformMutationsInDelegates(): void { $cfg = $this->cfg; - $this->assertObjectNotHasAttribute('qux', $cfg); - $this->assertObjectHasAttribute('qux', $this->delegates[2]); + $this->assertFalse(property_exists($cfg, 'qux')); + $this->assertTrue(property_exists($this->delegates[2], 'qux')); unset($cfg['qux']); $this->assertEquals($this->delegates[2]['qux'], $cfg['qux']); @@ -201,15 +177,13 @@ public function testOffsetUnsetDoesNotPerformMutationsInDelegates() /** * Asserts that removing a value from the delegate container allows subsequent requests * to lookup a fallback in a delegate. - * - * @coversNothing - * @return void */ - public function testOffsetUnsetOnConfigWithFallbackInDelegates() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testOffsetUnsetOnConfigWithFallbackInDelegates(): void { $cfg = $this->cfg; - $this->assertObjectHasAttribute('hud', $cfg); + $this->assertTrue(property_exists($cfg, 'hud')); $this->assertEquals('flob', $cfg['hud']); unset($cfg['hud']); diff --git a/packages/config/tests/Charcoal/Config/Config/ConfigFileAwareTest.php b/packages/config/tests/Charcoal/Config/Config/ConfigFileAwareTest.php index 1648c8040..af45165b9 100644 --- a/packages/config/tests/Charcoal/Config/Config/ConfigFileAwareTest.php +++ b/packages/config/tests/Charcoal/Config/Config/ConfigFileAwareTest.php @@ -18,9 +18,10 @@ * @todo ::addFile() * @todo ::merge() * - * - * @coversDefaultClass \Charcoal\Config\AbstractConfig */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Config\AbstractConfig::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, '__construct()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'addFile()')] class ConfigFileAwareTest extends AbstractConfigTestCase { /** @@ -30,8 +31,6 @@ class ConfigFileAwareTest extends AbstractConfigTestCase /** * Create a concrete GenericConfig instance. - * - * @return void */ protected function setUp(): void { @@ -43,31 +42,23 @@ protected function setUp(): void * * @param mixed $data Data to pre-populate the object. * @param array $delegates Delegates to pre-populate the object. - * @return GenericConfig */ - public function createConfig($data = null, array $delegates = null) + #[\Override] + public function createConfig($data = null, ?array $delegates = null): \Charcoal\Config\GenericConfig { return new GenericConfig($data, $delegates); } /** * Asserts that the object implements FileAwareInterface. - * - * @coversNothing - * @return void */ - public function testFileAwareInterface() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testFileAwareInterface(): void { $this->assertInstanceOf(FileAwareInterface::class, $this->cfg); } - /** - * @covers ::__construct() - * @covers ::addFile() - * - * @return void - */ - public function testConstructWithSupportedFormat() + public function testConstructWithSupportedFormat(): void { $path = $this->getPathToFixture('pass/valid.json'); $cfg = $this->createConfig($path); @@ -78,14 +69,11 @@ public function testConstructWithSupportedFormat() // Test INI // ========================================================================= - /** * INI: Asserts that the Config supports INI config files. - * - * @coversNothing - * @return void */ - public function testAddIniFile() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testAddIniFile(): void { $path = $this->getPathToFixture('pass/valid1.ini'); $this->cfg->addFile($path); @@ -104,11 +92,9 @@ public function testAddIniFile() /** * INI: Asserts that the Config supports key-paths in INI config files. - * - * @coversNothing - * @return void */ - public function testAddIniFileWithDelimitedData() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testAddIniFileWithDelimitedData(): void { $path = $this->getPathToFixture('pass/valid2.ini'); $this->cfg->addFile($path); @@ -126,11 +112,8 @@ public function testAddIniFileWithDelimitedData() /** * INI: Asserts that an ordered list is NOT ignored. - * - * @covers ::addFile() - * @return void */ - public function testAddIniFileWithInvalidArray() + public function testAddIniFileWithInvalidArray(): void { $this->expectExceptionMessage('Entity array access only supports non-numeric keys'); $this->expectException(InvalidArgumentException::class); @@ -141,11 +124,8 @@ public function testAddIniFileWithInvalidArray() /** * INI: Asserts that an unparsable file is silently ignored. - * - * @covers ::addFile() - * @return void */ - public function testAddUnparsableIniFile() + public function testAddUnparsableIniFile(): void { // phpcs:disable Generic.PHP.NoSilencedErrors.Discouraged $path = $this->getPathToFixture('pass/unparsable.ini'); @@ -159,14 +139,11 @@ public function testAddUnparsableIniFile() // Test JSON // ========================================================================= - /** * JSON: Asserts that the Config supports JSON config files. - * - * @coversNothing - * @return void */ - public function testAddJsonFile() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testAddJsonFile(): void { $path = $this->getPathToFixture('pass/valid.json'); $this->cfg->addFile($path); @@ -185,11 +162,8 @@ public function testAddJsonFile() /** * JSON: Asserts that an ordered list is NOT ignored. - * - * @covers ::addFile() - * @return void */ - public function testAddJsonFileWithInvalidArray() + public function testAddJsonFileWithInvalidArray(): void { $this->expectExceptionMessage('Entity array access only supports non-numeric keys'); $this->expectException(InvalidArgumentException::class); @@ -200,11 +174,8 @@ public function testAddJsonFileWithInvalidArray() /** * JSON: Asserts that an invalid file is silently ignored. - * - * @covers ::addFile() - * @return void */ - public function testAddJsonFileWithInvalidType() + public function testAddJsonFileWithInvalidType(): void { $path = $this->getPathToFixture('pass/invalid2.json'); $this->cfg->addFile($path); @@ -216,14 +187,11 @@ public function testAddJsonFileWithInvalidType() // Test PHP // ========================================================================= - /** * PHP: Asserts that the Config supports PHP config files. - * - * @coversNothing - * @return void */ - public function testAddPhpFile() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testAddPhpFile(): void { $path = $this->getPathToFixture('pass/valid1.php'); $this->cfg->addFile($path); @@ -242,11 +210,9 @@ public function testAddPhpFile() /** * PHP: Asserts that the scope of PHP config files is bound to the Config. - * - * @coversNothing - * @return void */ - public function testAddPhpFileThatMutatesContext() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testAddPhpFileThatMutatesContext(): void { $path = $this->getPathToFixture('pass/valid2.php'); $this->cfg->addFile($path); @@ -265,11 +231,8 @@ public function testAddPhpFileThatMutatesContext() /** * PHP: Asserts that an ordered list is NOT ignored. - * - * @covers ::addFile() - * @return void */ - public function testAddPhpFileWithInvalidArray() + public function testAddPhpFileWithInvalidArray(): void { $this->expectExceptionMessage('Entity array access only supports non-numeric keys'); $this->expectException(InvalidArgumentException::class); @@ -280,11 +243,8 @@ public function testAddPhpFileWithInvalidArray() /** * PHP: Asserts that an invalid file is silently ignored. - * - * @covers ::addFile() - * @return void */ - public function testAddPhpFileWithInvalidType() + public function testAddPhpFileWithInvalidType(): void { $path = $this->getPathToFixture('pass/invalid2.php'); $this->cfg->addFile($path); @@ -296,14 +256,11 @@ public function testAddPhpFileWithInvalidType() // Test YAML // ========================================================================= - /** * YAML: Asserts that the Config supports '.yml' YAML config files. - * - * @coversNothing - * @return void */ - public function testAddYamlFile() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testAddYamlFile(): void { $path = $this->getPathToFixture('pass/valid1.yml'); $this->cfg->addFile($path); @@ -322,11 +279,8 @@ public function testAddYamlFile() /** * YAML: Asserts that an ordered list is NOT ignored. - * - * @covers ::addFile() - * @return void */ - public function testAddYamlFileWithInvalidArray() + public function testAddYamlFileWithInvalidArray(): void { $this->expectExceptionMessage('Entity array access only supports non-numeric keys'); $this->expectException(InvalidArgumentException::class); @@ -337,11 +291,8 @@ public function testAddYamlFileWithInvalidArray() /** * YAML: Asserts that an invalid file is silently ignored. - * - * @covers ::addFile() - * @return void */ - public function testAddYamlFileWithInvalidType() + public function testAddYamlFileWithInvalidType(): void { $path = $this->getPathToFixture('pass/invalid2.yml'); $this->cfg->addFile($path); diff --git a/packages/config/tests/Charcoal/Config/Config/ConfigSeparatorAwareTest.php b/packages/config/tests/Charcoal/Config/Config/ConfigSeparatorAwareTest.php index e9580b4e2..0cfd4b02d 100644 --- a/packages/config/tests/Charcoal/Config/Config/ConfigSeparatorAwareTest.php +++ b/packages/config/tests/Charcoal/Config/Config/ConfigSeparatorAwareTest.php @@ -11,9 +11,14 @@ /** * Test SeparatorAwareTrait implementation in AbstractConfig - * - * @coversDefaultClass \Charcoal\Config\AbstractConfig */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Config\AbstractConfig::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, '__construct()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'setSeparator()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'separator()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'offsetExists()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'offsetGet()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'offsetSet()')] class ConfigSeparatorAwareTest extends AbstractConfigTestCase { use AssertionsTrait; @@ -30,8 +35,6 @@ class ConfigSeparatorAwareTest extends AbstractConfigTestCase /** * Create a MacroConfig instance. - * - * @return void */ protected function setUp(): void { @@ -62,22 +65,14 @@ protected function setUp(): void /** * Asserts that the object implements SeparatorAwareInterface. - * - * @coversNothing - * @return void */ - public function testSeparatorAwareInterface() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testSeparatorAwareInterface(): void { $this->assertInstanceOf(SeparatorAwareInterface::class, $this->cfg); } - /** - * @covers ::__construct() - * @covers ::setSeparator() - * @covers ::separator() - * @return void - */ - public function testDefaultSeparator() + public function testDefaultSeparator(): void { $cfg = $this->createConfig(); $this->assertEquals(AbstractConfig::DEFAULT_SEPARATOR, $cfg->separator()); @@ -87,45 +82,35 @@ public function testDefaultSeparator() // Test ArrayAccess on nested properties // ========================================================================= - /** * Asserts that the container returns TRUE if an endpoint is found * {@see SeparatorAwareTrait::hasWithSeparator() in a keypath}. - * - * @covers ::offsetExists() - * @return void */ - public function testOffsetExistsOnEndKeyPath() + public function testOffsetExistsOnEndKeyPath(): void { $cfg = $this->cfg; - $this->assertObjectHasAttribute('connections', $cfg); + $this->assertTrue(property_exists($cfg, 'connections')); $this->assertTrue(isset($cfg['connections.default.host'])); } /** * Asserts that the container returns TRUE if a midpoint is found * {@see SeparatorAwareTrait::hasWithSeparator() in a keypath}. - * - * @covers ::offsetExists() - * @return void */ - public function testOffsetExistsOnMidKeyPath() + public function testOffsetExistsOnMidKeyPath(): void { $cfg = $this->cfg; - $this->assertObjectHasAttribute('connections', $cfg); + $this->assertTrue(property_exists($cfg, 'connections')); $this->assertTrue(isset($cfg['connections.default'])); } /** * Asserts that the container returns FALSE if an endpoint is nonexistent * {@see SeparatorAwareTrait::hasWithSeparator() in a keypath}. - * - * @covers ::offsetExists() - * @return void */ - public function testOffsetExistsReturnsFalseOnNonexistentEndKeyPath() + public function testOffsetExistsReturnsFalseOnNonexistentEndKeyPath(): void { $cfg = $this->cfg; @@ -135,11 +120,8 @@ public function testOffsetExistsReturnsFalseOnNonexistentEndKeyPath() /** * Asserts that the container returns FALSE if a midpoint is nonexistent * {@see SeparatorAwareTrait::hasWithSeparator() in a keypath}. - * - * @covers ::offsetExists() - * @return void */ - public function testOffsetExistsReturnsFalseOnNonexistentMidKeyPath() + public function testOffsetExistsReturnsFalseOnNonexistentMidKeyPath(): void { $cfg = $this->cfg; @@ -149,11 +131,8 @@ public function testOffsetExistsReturnsFalseOnNonexistentMidKeyPath() /** * Asserts that the container returns the value of the endpoint found * {@see SeparatorAwareTrait::getWithSeparator() in a keypath}. - * - * @covers ::offsetGet() - * @return void */ - public function testOffsetGetOnEndKeyPath() + public function testOffsetGetOnEndKeyPath(): void { $cfg = $this->cfg; @@ -166,11 +145,8 @@ public function testOffsetGetOnEndKeyPath() /** * Asserts that the container returns the value of the midpoint found * {@see SeparatorAwareTrait::getWithSeparator() in a keypath}. - * - * @covers ::offsetGet() - * @return void */ - public function testOffsetGetOnMidKeyPath() + public function testOffsetGetOnMidKeyPath(): void { $cfg = $this->cfg; @@ -183,11 +159,8 @@ public function testOffsetGetOnMidKeyPath() /** * Asserts that the container returns NULL if the endpoint is nonexistent * {@see SeparatorAwareTrait::getWithSeparator() in a keypath}. - * - * @covers ::offsetGet() - * @return void */ - public function testOffsetGetReturnsNullOnNonexistentEndKeyPath() + public function testOffsetGetReturnsNullOnNonexistentEndKeyPath(): void { $cfg = $this->cfg; @@ -197,11 +170,8 @@ public function testOffsetGetReturnsNullOnNonexistentEndKeyPath() /** * Asserts that the container returns NULL if the midpoint is nonexistent * {@see SeparatorAwareTrait::getWithSeparator() in a keypath}. - * - * @covers ::offsetGet() - * @return void */ - public function testOffsetGetReturnsNullOnNonexistentMidKeyPath() + public function testOffsetGetReturnsNullOnNonexistentMidKeyPath(): void { $cfg = $this->cfg; @@ -211,11 +181,8 @@ public function testOffsetGetReturnsNullOnNonexistentMidKeyPath() /** * Asserts that the container assigns a value to the endpoint * {@see SeparatorAwareTrait::setWithSeparator() of the keypath}. - * - * @covers ::offsetSet() - * @return void */ - public function testOffsetSetOnEndKeyPath() + public function testOffsetSetOnEndKeyPath(): void { $cfg = $this->cfg; @@ -226,11 +193,8 @@ public function testOffsetSetOnEndKeyPath() /** * Asserts that the container assigns a value to the endpoint of a nonexistent midpoint * {@see SeparatorAwareTrait::setWithSeparator() in the keypath}. - * - * @covers ::offsetSet() - * @return void */ - public function testOffsetSetOnNonexistentMidKeyPath() + public function testOffsetSetOnNonexistentMidKeyPath(): void { $cfg = $this->cfg; $this->assertNull($cfg['connections.analytics']); @@ -242,11 +206,9 @@ public function testOffsetSetOnNonexistentMidKeyPath() /** * Asserts that the container assigns NULL to the endpoint * {@see SeparatorAwareTrait::setWithSeparator() of the keypath} to "remove". - * - * @coversNothing - * @return void */ - public function testOffsetUnsetOnEndKeyPath() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testOffsetUnsetOnEndKeyPath(): void { $cfg = $this->cfg; @@ -257,11 +219,9 @@ public function testOffsetUnsetOnEndKeyPath() /** * Asserts that the container assigns NULL to the midpoint * {@see SeparatorAwareTrait::setWithSeparator() of the keypath} to "remove". - * - * @coversNothing - * @return void */ - public function testOffsetUnsetOnMidKeyPath() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testOffsetUnsetOnMidKeyPath(): void { $cfg = $this->cfg; diff --git a/packages/config/tests/Charcoal/Config/Config/ConfigTest.php b/packages/config/tests/Charcoal/Config/Config/ConfigTest.php index d76d7d5ae..8ac73eb39 100644 --- a/packages/config/tests/Charcoal/Config/Config/ConfigTest.php +++ b/packages/config/tests/Charcoal/Config/Config/ConfigTest.php @@ -26,9 +26,13 @@ * - ConfigSeparatorAwareTest * - ConfigFileAwareTest * - FileLoader/* - * - * @coversDefaultClass \Charcoal\Config\AbstractConfig */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Config\AbstractConfig::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'getIterator()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, '__construct')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'merge')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'setData')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractConfig::class, 'defaults')] class ConfigTest extends AbstractConfigTestCase { use AssertionsTrait; @@ -40,8 +44,6 @@ class ConfigTest extends AbstractConfigTestCase /** * Create a concrete MacroConfig instance. - * - * @return void */ protected function setUp(): void { @@ -50,33 +52,23 @@ protected function setUp(): void /** * Asserts that the object implements PSR-11. - * - * @coversNothing - * @return void */ - public function testPsr11() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testPsr11(): void { $this->assertInstanceOf(ContainerInterface::class, $this->cfg); } /** * Asserts that the object implements IteratorAggregate. - * - * @covers ::getIterator() - * @return void */ - public function testIteratorAggregate() + public function testIteratorAggregate(): void { $this->assertInstanceOf(IteratorAggregate::class, $this->cfg); $this->assertInstanceOf(ArrayIterator::class, $this->cfg->getIterator()); } - /** - * @covers ::__construct - * @covers ::merge - * @return void - */ - public function testConstructWithArray() + public function testConstructWithArray(): void { $cfg = $this->mockConfig([ 'name' => 'Charcoal' @@ -84,23 +76,13 @@ public function testConstructWithArray() $this->assertEquals('Charcoal', $cfg['name']); } - /** - * @covers ::__construct - * @covers ::merge - * @return void - */ - public function testConstructWithConfigInstance() + public function testConstructWithConfigInstance(): void { $cfg = $this->mockConfig($this->cfg); $this->assertEquals('garply', $cfg['baz']); } - /** - * @covers ::__construct - * @covers ::merge - * @return void - */ - public function testConstructWithTraversableInstance() + public function testConstructWithTraversableInstance(): void { $iter = new ArrayIterator([ 'name' => 'Charcoal' @@ -109,35 +91,23 @@ public function testConstructWithTraversableInstance() $this->assertEquals('Charcoal', $cfg['name']); } - /** - * - * @covers ::__construct - * @covers ::merge - * @return void - */ - public function testConstructWithInvalidData() + public function testConstructWithInvalidData(): void { $this->expectExceptionMessage('Data must be a config file, an associative array, or an object implementing Traversable'); $this->expectException(InvalidArgumentException::class); $std = new StdClass; - $cfg = $this->mockConfig($std); + $this->mockConfig($std); } // Test Defaults // ========================================================================= - /** * Asserts that, when defined, a Config will apply the class' default data. - * - * @covers ::__construct - * @covers ::setData - * @covers ::defaults - * @return void */ - public function testConstructWithDefaults() + public function testConstructWithDefaults(): void { /** @var array $defaults {@see \Charcoal\Tests\Config\Mock\MacroConfig::defaults()} */ $defaults = [ @@ -173,11 +143,8 @@ public function testConstructWithDefaults() /** * Asserts that, by default, a Config has no default data. - * - * @covers ::defaults - * @return void */ - public function testEmptyDefaults() + public function testEmptyDefaults(): void { $cfg = $this->mockConfig(); $this->assertEmpty($cfg->defaults()); diff --git a/packages/config/tests/Charcoal/Config/Entity/AbstractEntityTestCase.php b/packages/config/tests/Charcoal/Config/Entity/AbstractEntityTestCase.php index 85a2b9a78..0bbc42971 100644 --- a/packages/config/tests/Charcoal/Config/Entity/AbstractEntityTestCase.php +++ b/packages/config/tests/Charcoal/Config/Entity/AbstractEntityTestCase.php @@ -18,7 +18,7 @@ abstract class AbstractEntityTestCase extends AbstractTestCase * @param array $data Data to assign to the object. * @return MacroEntity */ - public function createEntity(array $data = null) + public function createEntity(?array $data = null) { return new MacroEntity($data); } @@ -29,7 +29,7 @@ public function createEntity(array $data = null) * @param array $data Data to assign to the object. * @return AbstractEntity */ - public function mockEntity(array $data = null) + public function mockEntity(?array $data = null) { $obj = $this->getMockForAbstractClass(AbstractEntity::class); diff --git a/packages/config/tests/Charcoal/Config/Entity/EntityArrayAccessTest.php b/packages/config/tests/Charcoal/Config/Entity/EntityArrayAccessTest.php index 9873e25b0..2269bdf40 100644 --- a/packages/config/tests/Charcoal/Config/Entity/EntityArrayAccessTest.php +++ b/packages/config/tests/Charcoal/Config/Entity/EntityArrayAccessTest.php @@ -12,9 +12,17 @@ /** * Test ArrayAccess implementation in AbstractEntity - * - * @coversDefaultClass \Charcoal\Config\AbstractEntity */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Config\AbstractEntity::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'offsetExists()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'offsetGet()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'offsetSet()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'offsetUnset()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Tests\Config\Mock\MacroEntity::class, 'foo()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Tests\Config\Mock\MacroEntity::class, 'setFoo()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'has()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'get()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'set()')] class EntityArrayAccessTest extends AbstractEntityTestCase { use ArrayAccessTestTrait; @@ -26,8 +34,6 @@ class EntityArrayAccessTest extends AbstractEntityTestCase /** * Create a concrete MacroEntity instance. - * - * @return void */ protected function setUp(): void { @@ -41,9 +47,9 @@ protected function setUp(): void /** * Asserts that the object implements ArrayAccess. * - * @coversNothing * @return MacroEntity */ + #[\PHPUnit\Framework\Attributes\CoversNothing] public function testArrayAccess() { $this->assertInstanceOf(ArrayAccess::class, $this->obj); @@ -54,17 +60,12 @@ public function testArrayAccess() // Test ArrayAccess on non-private properties // ========================================================================= - - /** - * @covers ::offsetExists() - * @return void - */ - public function testOffsetExists() + public function testOffsetExists(): void { $obj = $this->obj; // MacroEntity::$name - $this->assertObjectHasAttribute('name', $obj); + $this->assertTrue(property_exists($obj, 'name')); $this->assertTrue(isset($obj['name'])); // MacroEntity::foo() @@ -74,11 +75,7 @@ public function testOffsetExists() $this->assertTrue(isset($obj['erd'])); } - /** - * @covers ::offsetGet() - * @return void - */ - public function testOffsetGet() + public function testOffsetGet(): void { $obj = $this->obj; @@ -92,29 +89,21 @@ public function testOffsetGet() $this->assertEquals(true, $obj['erd']); } - /** - * @covers ::offsetSet() - * @return void - */ - public function testOffsetSet() + public function testOffsetSet(): void { $obj = $this->obj; $obj['baz'] = 'waldo'; - $this->assertObjectHasAttribute('baz', $obj); + $this->assertTrue(property_exists($obj, 'baz')); $this->assertEquals('waldo', $obj['baz']); } - /** - * @covers ::offsetUnset() - * @return void - */ - public function testOffsetUnset() + public function testOffsetUnset(): void { $obj = $this->obj; unset($obj['name']); - $this->assertObjectHasAttribute('name', $obj); + $this->assertTrue(property_exists($obj, 'name')); $this->assertNull($obj['name']); } @@ -122,38 +111,22 @@ public function testOffsetUnset() // Test ArrayAccess on encapsulated properties // ========================================================================= - - /** - * @covers \Charcoal\Tests\Config\Mock\MacroEntity::foo() - * @covers ::offsetExists() - * @return void - */ - public function testOffsetExistsOnEncapsulatedMethod() + public function testOffsetExistsOnEncapsulatedMethod(): void { $obj = $this->obj; - $this->assertObjectHasAttribute('foo', $obj); + $this->assertTrue(property_exists($obj, 'foo')); $this->assertTrue(isset($obj['foo'])); } - /** - * @covers \Charcoal\Tests\Config\Mock\MacroEntity::foo() - * @covers ::offsetGet() - * @return void - */ - public function testOffsetGetOnEncapsulatedMethod() + public function testOffsetGetOnEncapsulatedMethod(): void { $obj = $this->obj; $this->assertEquals('foo is 20', $obj['foo']); } - /** - * @covers \Charcoal\Tests\Config\Mock\MacroEntity::setFoo() - * @covers ::offsetSet() - * @return void - */ - public function testOffsetSetOnEncapsulatedMethod() + public function testOffsetSetOnEncapsulatedMethod(): void { $obj = $this->obj; @@ -161,17 +134,12 @@ public function testOffsetSetOnEncapsulatedMethod() $this->assertEquals('foo is 42', $obj['foo']); } - /** - * @covers \Charcoal\Tests\Config\Mock\MacroEntity::setFoo() - * @covers ::offsetUnset() - * @return void - */ - public function testOffsetUnsetOnEncapsulatedMethod() + public function testOffsetUnsetOnEncapsulatedMethod(): void { $obj = $this->obj; unset($obj['foo']); - $this->assertObjectHasAttribute('foo', $obj); + $this->assertTrue(property_exists($obj, 'foo')); $this->assertEquals('foo is 10', $obj['foo']); } @@ -179,44 +147,31 @@ public function testOffsetUnsetOnEncapsulatedMethod() // Test ArrayAccess via aliases // ========================================================================= - - /** - * @covers ::has() - * @return void - */ - public function testHas() + public function testHas(): void { $obj = $this->obj; - $this->assertObjectHasAttribute('name', $obj); + $this->assertTrue(property_exists($obj, 'name')); $this->assertTrue($obj->has('name')); unset($obj['name']); $this->assertFalse($obj->has('name')); } - /** - * @covers ::get() - * @return void - */ - public function testGet() + public function testGet(): void { $obj = $this->obj; $this->assertEquals('Charcoal', $obj->get('name')); } - /** - * @covers ::set() - * @return void - */ - public function testSet() + public function testSet(): void { $obj = $this->obj; $that = $obj->set('baz', 'waldo'); $this->assertEquals($obj, $that); - $this->assertObjectHasAttribute('baz', $obj); + $this->assertTrue(property_exists($obj, 'baz')); $this->assertEquals('waldo', $obj->get('baz')); } } diff --git a/packages/config/tests/Charcoal/Config/Entity/EntityTest.php b/packages/config/tests/Charcoal/Config/Entity/EntityTest.php index 4f381c79d..5fdfeabe2 100644 --- a/packages/config/tests/Charcoal/Config/Entity/EntityTest.php +++ b/packages/config/tests/Charcoal/Config/Entity/EntityTest.php @@ -10,9 +10,17 @@ /** * Test AbstractEntity - * - * @coversDefaultClass \Charcoal\Config\AbstractEntity */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Charcoal\Config\AbstractEntity::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'keys()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'setData()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'data()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'offsetSet()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'offsetGet()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'camelize()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'jsonSerialize()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'serialize()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\AbstractEntity::class, 'unserialize()')] class EntityTest extends AbstractEntityTestCase { use AssertionsTrait; @@ -24,8 +32,6 @@ class EntityTest extends AbstractEntityTestCase /** * Create a concrete MacroEntity instance. - * - * @return void */ protected function setUp(): void { @@ -39,11 +45,8 @@ protected function setUp(): void * - Keys are empty by default * - Keys are added automatically when setting a value via {@see ArrayAccess::offsetSet()} * - Keys are removed automatically when unsetting a value via {@see ArrayAccess::offsetUnset()} - * - * @covers ::keys() - * @return void */ - public function testKeys() + public function testKeys(): void { $obj = $this->obj; @@ -64,15 +67,13 @@ public function testKeys() // Test Data Methods // ========================================================================= - /** * Retrieve data for {@see AbstractEntity::setData()}. * * @used-by self::testSetData() * @used-by self::testGetDataSubset() - * @return array */ - public function getSetData() + public function getSetData(): array { return [ 'name' => 'Charcoal', @@ -96,12 +97,8 @@ public function getSetData() * - When assigning data, the entity will ignore the key "data" * to prevent recursion calls. * - The key-value pair "foo" will be passed to {@see MacroEntity::setFoo()} - * - * @covers ::setData() - * @covers ::data() - * @return void */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; @@ -129,11 +126,8 @@ public function testSetData() * - The entity will ignore "data" to prevent recursion calls * - The entity will accept "name", "type", "foo", "baz" * - The entity will pass "foo" to {@see MacroEntity::setFoo()} - * - * @covers ::data() - * @return void */ - public function testGetDataSubset() + public function testGetDataSubset(): void { $obj = $this->obj; @@ -150,14 +144,8 @@ public function testGetDataSubset() /** * Test {@see AbstractEntity::setData()} via {@see \ArrayAccess::offsetSet()}. - * - * @covers ::offsetSet() - * @covers ::offsetGet() - * @covers ::setData() - * @covers ::data() - * @return void */ - public function testSetDataViaArrayAccess() + public function testSetDataViaArrayAccess(): void { $obj = $this->obj; @@ -177,7 +165,6 @@ public function testSetDataViaArrayAccess() // Test Internals // ========================================================================= - /** * Test camelization of entity keys. * @@ -185,16 +172,13 @@ public function testSetDataViaArrayAccess() * - Keys are interchangeable between "snake_case" and "camelCase" * - Keys are converted to "camelCase" for method calls or property assignments * - Keys are memorized as "camelCase" - * - * @covers ::camelize() - * @return void */ - public function testCamelize() + public function testCamelize(): void { $obj = $this->obj; $obj->set('foo_bar', 'waldo'); - $this->assertObjectHasAttribute('fooBar', $obj); + $this->assertTrue(property_exists($obj, 'fooBar')); $this->assertEquals('waldo', $obj['fooBar']); $this->assertEquals('waldo', $obj['foo___bar']); $this->assertArrayContains([ 'fooBar' ], $obj->keys()); @@ -206,11 +190,8 @@ public function testCamelize() * Assertions: * 1. Serialization from default state * 2. Serialization from mutated state - * - * @covers ::jsonSerialize() - * @return void */ - public function testJsonSerializable() + public function testJsonSerializable(): void { $obj = $this->obj; @@ -237,18 +218,14 @@ public function testJsonSerializable() * Assertions: * 1. Serialization from default state * 2. Serialization from mutated state - * - * @covers ::serialize() - * @covers ::unserialize() - * @return void */ - public function testSerializable() + public function testSerializable(): void { $obj = $this->obj; /** 1. Serialization from default state */ $that = unserialize(serialize($obj)); - $this->assertInstanceOf(get_class($obj), $that); + $this->assertInstanceOf($obj::class, $that); $this->assertEquals($obj, $that); $this->assertEmpty($that->data()); @@ -258,7 +235,7 @@ public function testSerializable() ]; $obj->setData($mutation); $that = unserialize(serialize($obj)); - $this->assertInstanceOf(get_class($obj), $that); + $this->assertInstanceOf($obj::class, $that); $this->assertEquals($obj->data(), $that->data()); $this->assertEquals('Charcoal', $that['name']); } diff --git a/packages/config/tests/Charcoal/Config/Fixture/fail/exception.php b/packages/config/tests/Charcoal/Config/Fixture/fail/exception.php index c3a551b6d..fcba7eb8a 100644 --- a/packages/config/tests/Charcoal/Config/Fixture/fail/exception.php +++ b/packages/config/tests/Charcoal/Config/Fixture/fail/exception.php @@ -1,3 +1,5 @@ 'localhost', 'port' => 11211, diff --git a/packages/config/tests/Charcoal/Config/Mixin/ArrayAccessTestTrait.php b/packages/config/tests/Charcoal/Config/Mixin/ArrayAccessTestTrait.php index c52a67c77..e7dadadc7 100644 --- a/packages/config/tests/Charcoal/Config/Mixin/ArrayAccessTestTrait.php +++ b/packages/config/tests/Charcoal/Config/Mixin/ArrayAccessTestTrait.php @@ -15,9 +15,9 @@ trait ArrayAccessTestTrait /** * Asserts that the object implements ArrayAccess. * - * @coversNothing * @return ArrayAccess The ArrayAccess implementation to test. */ + #[\PHPUnit\Framework\Attributes\CoversNothing] abstract public function testArrayAccess(); /** @@ -48,27 +48,24 @@ abstract public function testOffsetUnset(); // Test Nonexistent Key // ========================================================================= - /** * @covers ::offsetGet() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetGetReturnsNullOnNonexistentKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetGetReturnsNullOnNonexistentKey(ArrayAccess $obj): void { $this->assertNull($obj['xyz']); } /** * @covers ::offsetExists() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetExistsReturnsFalseOnNonexistentKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetExistsReturnsFalseOnNonexistentKey(ArrayAccess $obj): void { $this->assertFalse(isset($obj['xyz'])); } @@ -77,39 +74,35 @@ public function testOffsetExistsReturnsFalseOnNonexistentKey(ArrayAccess $obj) // Test Zero-Length Key // ========================================================================= - /** * @covers ::offsetGet() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetGetReturnsNullOnZeroLengthKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetGetReturnsNullOnZeroLengthKey(ArrayAccess $obj): void { $this->assertNull($obj['']); } /** * @covers ::offsetExists() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetExistsReturnsFalseOnZeroLengthKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetExistsReturnsFalseOnZeroLengthKey(ArrayAccess $obj): void { $this->assertFalse(isset($obj[''])); } /** * @covers ::offsetSet() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetSetIgnoredOnZeroLengthKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetSetIgnoredOnZeroLengthKey(ArrayAccess $obj): void { $obj[''] = 'waldo'; $this->assertNull($obj['']); @@ -117,12 +110,11 @@ public function testOffsetSetIgnoredOnZeroLengthKey(ArrayAccess $obj) /** * @covers ::offsetUnset() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetUnsetIgnoredOnZeroLengthKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetUnsetIgnoredOnZeroLengthKey(ArrayAccess $obj): void { unset($obj['']); $this->assertNull($obj['']); @@ -132,39 +124,35 @@ public function testOffsetUnsetIgnoredOnZeroLengthKey(ArrayAccess $obj) // Test Snake-Case Delimiter Key // ========================================================================= - /** * @covers ::offsetGet() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetGetReturnsNullOnUnderscoreKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetGetReturnsNullOnUnderscoreKey(ArrayAccess $obj): void { $this->assertNull($obj['_']); } /** * @covers ::offsetExists() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetExistsReturnsFalseOnUnderscoreKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetExistsReturnsFalseOnUnderscoreKey(ArrayAccess $obj): void { $this->assertFalse(isset($obj['_'])); } /** * @covers ::offsetSet() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetSetIgnoredOnUnderscoreKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetSetIgnoredOnUnderscoreKey(ArrayAccess $obj): void { $obj['_'] = 'waldo'; $this->assertNull($obj['_']); @@ -172,12 +160,11 @@ public function testOffsetSetIgnoredOnUnderscoreKey(ArrayAccess $obj) /** * @covers ::offsetUnset() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetUnsetIgnoredOnUnderscoreKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetUnsetIgnoredOnUnderscoreKey(ArrayAccess $obj): void { unset($obj['']); $this->assertNull($obj['_']); @@ -186,17 +173,15 @@ public function testOffsetUnsetIgnoredOnUnderscoreKey(ArrayAccess $obj) // Test Numeric Key // ========================================================================= - /** * Asserts that a numeric key throws an exception, when retrieving a value. * * @covers ::offsetGet() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetGetThrowsExceptionOnNumericKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetGetThrowsExceptionOnNumericKey(ArrayAccess $obj): void { $this->expectException(InvalidArgumentException::class); $obj[0]; @@ -206,12 +191,11 @@ public function testOffsetGetThrowsExceptionOnNumericKey(ArrayAccess $obj) * Asserts that a numeric key throws an exception, when assigning a value. * * @covers ::offsetSet() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetSetThrowsExceptionOnNumericKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetSetThrowsExceptionOnNumericKey(ArrayAccess $obj): void { $this->expectException(InvalidArgumentException::class); $obj[0] = 'waldo'; @@ -221,27 +205,25 @@ public function testOffsetSetThrowsExceptionOnNumericKey(ArrayAccess $obj) * Asserts that a numeric key throws an exception, when looking up if a key/value exists. * * @covers ::offsetExists() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetExistsThrowsExceptionOnNumericKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetExistsThrowsExceptionOnNumericKey(ArrayAccess $obj): void { $this->expectException(InvalidArgumentException::class); - isset($obj[0]); + $obj[0]; } /** * Asserts that a numeric key throws an exception, when deleting a key/value. * * @covers ::offsetUnset() - * @depends testArrayAccess * * @param ArrayAccess $obj The ArrayAccess implementation to test. - * @return void */ - public function testOffsetUnsetThrowsExceptionOnNumericKey(ArrayAccess $obj) + #[\PHPUnit\Framework\Attributes\Depends('testArrayAccess')] + public function testOffsetUnsetThrowsExceptionOnNumericKey(ArrayAccess $obj): void { $this->expectException(InvalidArgumentException::class); unset($obj[0]); diff --git a/packages/config/tests/Charcoal/Config/Mixin/ConfigurableTest.php b/packages/config/tests/Charcoal/Config/Mixin/ConfigurableTest.php index 66abc36fd..d00c78ae5 100644 --- a/packages/config/tests/Charcoal/Config/Mixin/ConfigurableTest.php +++ b/packages/config/tests/Charcoal/Config/Mixin/ConfigurableTest.php @@ -15,9 +15,11 @@ /** * Test ConfigurableTrait - * - * @coversDefaultClass \Charcoal\Config\ConfigurableTrait */ +#[\PHPUnit\Framework\Attributes\CoversTrait(\Charcoal\Config\ConfigurableTrait::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\ConfigurableTrait::class, 'createConfig()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\ConfigurableTrait::class, 'setConfig()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\ConfigurableTrait::class, 'config()')] class ConfigurableTest extends AbstractTestCase { use AssertionsTrait; @@ -40,8 +42,6 @@ class ConfigurableTest extends AbstractTestCase /** * Create a ConfigurableObject instance. - * - * @return void */ protected function setUp(): void { @@ -58,10 +58,8 @@ protected function setUp(): void /** * Create a ConfigurableObject instance. - * - * @return ConfigurableObject */ - public function createObject() + public function createObject(): \Charcoal\Tests\Config\Mock\ConfigurableObject { return new ConfigurableObject(); } @@ -71,20 +69,17 @@ public function createObject() * * @param mixed $data Data to pre-populate the object. * @param array $delegates Delegates to pre-populate the object. - * @return GenericConfig */ - public function createConfig($data = null, array $delegates = null) + public function createConfig($data = null, ?array $delegates = null): \Charcoal\Config\GenericConfig { return new GenericConfig($data, $delegates); } /** * Asserts that the object implements ConfigurableInterface. - * - * @coversNothing - * @return void */ - public function testConfigurableInterface() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testConfigurableInterface(): void { $this->assertInstanceOf(ConfigurableInterface::class, $this->obj); $this->assertInstanceOf(ConfigInterface::class, $this->obj->createConfig()); @@ -93,13 +88,7 @@ public function testConfigurableInterface() // Test SetConfig // ========================================================================= - - /** - * @covers ::createConfig() - * @covers ::setConfig() - * @return void - */ - public function testSetConfigWithString() + public function testSetConfigWithString(): void { $path = $this->getPathToFixture('pass/valid.json'); $that = $this->obj->setConfig($path); @@ -111,8 +100,6 @@ public function testSetConfigWithString() } /** - * @covers ::createConfig() - * @covers ::setConfig() * @return ConfigurableInterface */ public function testSetConfigWithArray() @@ -126,12 +113,7 @@ public function testSetConfigWithArray() return $this->obj; } - /** - * @covers ::createConfig() - * @covers ::setConfig() - * @return void - */ - public function testSetConfigWithConfigInstance() + public function testSetConfigWithConfigInstance(): void { $this->obj->setConfig($this->cfg); @@ -140,11 +122,7 @@ public function testSetConfigWithConfigInstance() $this->assertArraySubsets($this->data, $cfg->data()); } - /** - * @covers ::setConfig() - * @return void - */ - public function testSetConfigWithInvalidData() + public function testSetConfigWithInvalidData(): void { $this->expectExceptionMessage('Configset must be an associative array, a file path, or an instance of Charcoal\Config\ConfigInterface'); $this->expectException(InvalidArgumentException::class); @@ -157,107 +135,79 @@ public function testSetConfigWithInvalidData() // Test GetConfig // ========================================================================= - /** * Asserts that the object will create a new Config * if one has not been assigned to object. - * - * @covers ::createConfig() - * @covers ::config() - * @return void */ - public function testGetConfigCreatesConfig() + public function testGetConfigCreatesConfig(): void { $cfg = $this->obj->config(); $this->assertInstanceOf(GenericConfig::class, $cfg); } /** - * @covers ::config() - * @depends testSetConfigWithArray - * * @param ConfigurableInterface $obj The ConfigurableInterface implementation to test. - * @return void */ - public function testGetConfigReturnsConfigOnNullKey(ConfigurableInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetConfigWithArray')] + public function testGetConfigReturnsConfigOnNullKey(ConfigurableInterface $obj): void { - $cfg = $obj->config(null); + $cfg = $obj->config(); $this->assertInstanceOf(GenericConfig::class, $cfg); } /** - * @covers ::config() - * @depends testSetConfigWithArray - * * @param ConfigurableInterface $obj The ConfigurableInterface implementation to test. - * @return void */ - public function testGetConfigReturnsValueOnKey(ConfigurableInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetConfigWithArray')] + public function testGetConfigReturnsValueOnKey(ConfigurableInterface $obj): void { $this->assertEquals($this->data['name'], $obj->config('name')); } /** - * @covers ::config() - * @depends testSetConfigWithArray - * * @param ConfigurableInterface $obj The ConfigurableInterface implementation to test. - * @return void */ - public function testGetConfigReturnsNullOnNonexistentKey(ConfigurableInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetConfigWithArray')] + public function testGetConfigReturnsNullOnNonexistentKey(ConfigurableInterface $obj): void { $this->assertNull($obj->config('charset')); } /** - * @covers ::config() - * @depends testSetConfigWithArray - * * @param ConfigurableInterface $obj The ConfigurableInterface implementation to test. - * @return void */ - public function testGetConfigReturnsDefaultValueOnNonexistentKey(ConfigurableInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetConfigWithArray')] + public function testGetConfigReturnsDefaultValueOnNonexistentKey(ConfigurableInterface $obj): void { $val = $obj->config('charset', 'utf8mb4'); $this->assertEquals('utf8mb4', $val); } /** - * @covers ::config() - * @depends testSetConfigWithArray - * * @param ConfigurableInterface $obj The ConfigurableInterface implementation to test. - * @return void */ - public function testGetConfigReturnsFallbackClosureOnNonexistentKey(ConfigurableInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetConfigWithArray')] + public function testGetConfigReturnsFallbackClosureOnNonexistentKey(ConfigurableInterface $obj): void { - $val = $obj->config('charset', function () { - return 'utf8mb4'; - }); + $val = $obj->config('charset', fn(): string => 'utf8mb4'); $this->assertEquals('utf8mb4', $val); } /** - * @covers ::config() - * @depends testSetConfigWithArray - * * @param ConfigurableInterface $obj The ConfigurableInterface implementation to test. - * @return void */ - public function testGetConfigReturnsFallbackMethodOnNonexistentKey(ConfigurableInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetConfigWithArray')] + public function testGetConfigReturnsFallbackMethodOnNonexistentKey(ConfigurableInterface $obj): void { - $val = $obj->config('charset', [ $this, 'getName' ]); + $val = $obj->config('charset', [ $this, 'name' ]); $this->assertEquals('testGetConfigReturnsFallbackMethodOnNonexistentKey', $val); } /** - * @covers ::config() - * @depends testSetConfigWithArray - * * @param ConfigurableInterface $obj The ConfigurableInterface implementation to test. - * @return void */ - public function testGetConfigReturnsFallbackFunctionOnNonexistentKey(ConfigurableInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetConfigWithArray')] + public function testGetConfigReturnsFallbackFunctionOnNonexistentKey(ConfigurableInterface $obj): void { $val = $obj->config('charset', 'getcwd'); $this->assertEquals('getcwd', $val); diff --git a/packages/config/tests/Charcoal/Config/Mixin/DelegatesAwareTest.php b/packages/config/tests/Charcoal/Config/Mixin/DelegatesAwareTest.php index 47ea0704a..af17c6939 100644 --- a/packages/config/tests/Charcoal/Config/Mixin/DelegatesAwareTest.php +++ b/packages/config/tests/Charcoal/Config/Mixin/DelegatesAwareTest.php @@ -11,9 +11,13 @@ /** * Test DelegatesAwareTrait - * - * @coversDefaultClass \Charcoal\Config\DelegatesAwareTrait */ +#[\PHPUnit\Framework\Attributes\CoversTrait(\Charcoal\Config\DelegatesAwareTrait::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\DelegatesAwareTrait::class, 'setDelegates()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\DelegatesAwareTrait::class, 'addDelegate()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\DelegatesAwareTrait::class, 'prependDelegate()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\DelegatesAwareTrait::class, 'hasInDelegates()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\DelegatesAwareTrait::class, 'getInDelegates()')] class DelegatesAwareTest extends AbstractTestCase { /** @@ -28,8 +32,6 @@ class DelegatesAwareTest extends AbstractTestCase /** * Create a DelegateEntity instance. - * - * @return void */ protected function setUp(): void { @@ -72,20 +74,17 @@ protected function setUp(): void * Create a DelegateEntity instance. * * @param array $data Data to pre-populate the object. - * @return DelegateEntity */ - public function createObject(array $data = null) + public function createObject(?array $data = null): \Charcoal\Tests\Config\Mock\DelegateEntity { return new DelegateEntity($data); } /** * Asserts that the object implements DelegatesAwareInterface. - * - * @coversNothing - * @return void */ - public function testDelegatesAwareInterface() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testDelegatesAwareInterface(): void { $this->assertInstanceOf(DelegatesAwareInterface::class, $this->obj); } @@ -94,25 +93,16 @@ public function testDelegatesAwareInterface() // Test Delegate Collecting // ========================================================================= - /** * Asserts that the separator is disabled by default. - * - * @coversNothing - * @return void */ - public function testDefaultDelegatesCollection() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testDefaultDelegatesCollection(): void { $this->assertEmpty($this->obj->delegates()); } - /** - * @covers ::setDelegates() - * @covers ::addDelegate() - * @covers ::prependDelegate() - * @return void - */ - public function testSetDelegates() + public function testSetDelegates(): void { $obj = $this->obj; @@ -134,10 +124,10 @@ public function testSetDelegates() } /** - * @coversNothing - * @doesNotPerformAssertions * @return DelegateEntity */ + #[\PHPUnit\Framework\Attributes\CoversNothing] + #[\PHPUnit\Framework\Attributes\DoesNotPerformAssertions] public function testSetNestedDelegates() { $this->delegates[4]->addDelegate($this->delegates[2]); @@ -155,28 +145,22 @@ public function testSetNestedDelegates() // Test HasInDelegates // ========================================================================= - /** - * @covers ::hasInDelegates() - * @depends testSetNestedDelegates * * @see self::$delegates[1]['bubble'] * @param DelegatesAwareInterface $obj The DelegatesAwareInterface implementation to test. - * @return void */ - public function testHasInDelegatesReturnsTrueOnDelegatedKey(DelegatesAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetNestedDelegates')] + public function testHasInDelegatesReturnsTrueOnDelegatedKey(DelegatesAwareInterface $obj): void { $this->assertTrue($obj->hasInDelegates('bubble')); } /** - * @covers ::hasInDelegates() - * @depends testSetNestedDelegates - * * @param DelegatesAwareInterface $obj The DelegatesAwareInterface implementation to test. - * @return void */ - public function testHasInDelegatesReturnsFalseOnNonexistentKey(DelegatesAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetNestedDelegates')] + public function testHasInDelegatesReturnsFalseOnNonexistentKey(DelegatesAwareInterface $obj): void { $this->assertFalse($obj->hasInDelegates('use_error_handler')); } @@ -186,16 +170,13 @@ public function testHasInDelegatesReturnsFalseOnNonexistentKey(DelegatesAwareInt // Test GetInDelegates // ========================================================================= - /** - * @covers ::getInDelegates() - * @depends testSetNestedDelegates * * @see self::$delegates[2]['level'] * @param DelegatesAwareInterface $obj The DelegatesAwareInterface implementation to test. - * @return void */ - public function testGetInDelegatesReturnsValueOnDelegatedKey(DelegatesAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetNestedDelegates')] + public function testGetInDelegatesReturnsValueOnDelegatedKey(DelegatesAwareInterface $obj): void { $this->assertEquals( $this->delegates[2]['level'], @@ -204,13 +185,10 @@ public function testGetInDelegatesReturnsValueOnDelegatedKey(DelegatesAwareInter } /** - * @covers ::getInDelegates() - * @depends testSetNestedDelegates - * * @param DelegatesAwareInterface $obj The DelegatesAwareInterface implementation to test. - * @return void */ - public function testGetInDelegatesReturnsNullOnNonexistentKey(DelegatesAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetNestedDelegates')] + public function testGetInDelegatesReturnsNullOnNonexistentKey(DelegatesAwareInterface $obj): void { $this->assertNull($obj->getInDelegates('use_error_handler')); } diff --git a/packages/config/tests/Charcoal/Config/Mixin/FileAwareTest.php b/packages/config/tests/Charcoal/Config/Mixin/FileAwareTest.php index a943300fa..196bd2e02 100644 --- a/packages/config/tests/Charcoal/Config/Mixin/FileAwareTest.php +++ b/packages/config/tests/Charcoal/Config/Mixin/FileAwareTest.php @@ -10,58 +10,44 @@ /** * Test FileAwareTrait - * - * @coversDefaultClass \Charcoal\Config\FileAwareTrait */ +#[\PHPUnit\Framework\Attributes\CoversTrait(\Charcoal\Config\FileAwareTrait::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\FileAwareTrait::class, 'loadFile()')] class FileAwareTest extends AbstractFileLoaderTestCase { /** * Asserts that the object implements FileAwareInterface. - * - * @coversNothing - * @return void */ - public function testFileAwareInterface() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testFileAwareInterface(): void { $this->assertInstanceOf(FileAwareInterface::class, $this->obj); } - /** - * @covers ::loadFile() - * @return void - */ - public function testLoadWithUnsupportedFormat() + public function testLoadWithUnsupportedFormat(): void { $this->expectExceptionMessageMatches('/^Unsupported file format for ".+?"; must be one of ".+?"$/'); $this->expectException(InvalidArgumentException::class); $path = $this->getPathToFixture('fail/unsupported.txt'); - $data = $this->obj->loadFile($path); + $this->obj->loadFile($path); } - /** - * @covers ::loadFile() - * @return void - */ - public function testLoadWithInvalidPath() + public function testLoadWithInvalidPath(): void { $this->expectExceptionMessageMatches('/^File ".+?" does not exist$/'); $this->expectException(InvalidArgumentException::class); $path = $this->getPathToFixture('fail/missing.ini'); - $data = $this->obj->loadFile($path); + $this->obj->loadFile($path); } - /** - * @covers ::loadFile() - * @return void - */ - public function testLoadWithInvalidType() + public function testLoadWithInvalidType(): void { $this->expectExceptionMessage('File must be a string'); $this->expectException(InvalidArgumentException::class); $path = null; - $data = $this->obj->loadFile($path); + $this->obj->loadFile($path); } } diff --git a/packages/config/tests/Charcoal/Config/Mixin/FileLoader/AbstractFileLoaderTestCase.php b/packages/config/tests/Charcoal/Config/Mixin/FileLoader/AbstractFileLoaderTestCase.php index 57953c525..6ac87a944 100644 --- a/packages/config/tests/Charcoal/Config/Mixin/FileLoader/AbstractFileLoaderTestCase.php +++ b/packages/config/tests/Charcoal/Config/Mixin/FileLoader/AbstractFileLoaderTestCase.php @@ -21,8 +21,6 @@ abstract class AbstractFileLoaderTestCase extends AbstractTestCase /** * Create a FileLoader instance. - * - * @return void */ protected function setUp(): void { diff --git a/packages/config/tests/Charcoal/Config/Mixin/FileLoader/IniFileLoaderTest.php b/packages/config/tests/Charcoal/Config/Mixin/FileLoader/IniFileLoaderTest.php index 37406e840..f189a37d8 100644 --- a/packages/config/tests/Charcoal/Config/Mixin/FileLoader/IniFileLoaderTest.php +++ b/packages/config/tests/Charcoal/Config/Mixin/FileLoader/IniFileLoaderTest.php @@ -1,5 +1,7 @@ getPathToFixture('pass/valid1.ini'); $data = $this->obj->loadFile($path); @@ -42,10 +41,8 @@ public function testLoadFile() * Asserts that the File Loader does NOT support key-paths in INI config files. * * @see \Charcoal\Tests\Config\Config\ConfigFileAwareTest::testLoadIniFileWithDelimitedData - * @covers ::loadIniFile() - * @return void */ - public function testLoadFileWithDelimitedData() + public function testLoadFileWithDelimitedData(): void { $path = $this->getPathToFixture('pass/valid2.ini'); $data = $this->obj->loadFile($path); @@ -64,11 +61,8 @@ public function testLoadFileWithDelimitedData() /** * Asserts that an empty file is silently ignored. - * - * @covers ::loadIniFile() - * @return void */ - public function testLoadEmptyFile() + public function testLoadEmptyFile(): void { $path = $this->getPathToFixture('pass/empty.ini'); $data = $this->obj->loadFile($path); @@ -78,28 +72,22 @@ public function testLoadEmptyFile() /** * Asserts that a broken file is NOT ignored. - * - * @covers ::loadIniFile() - * @return void */ - public function testLoadMalformedFile() + public function testLoadMalformedFile(): void { $this->expectExceptionMessageMatches('/^INI file ".+?" is empty or invalid$/'); $this->expectException(UnexpectedValueException::class); // phpcs:disable Generic.PHP.NoSilencedErrors.Discouraged $path = $this->getPathToFixture('fail/malformed.ini'); - $data = @$this->obj->loadFile($path); + @$this->obj->loadFile($path); // phpcs:enable } /** * Asserts that an unparsable file is silently ignored. - * - * @covers ::loadIniFile() - * @return void */ - public function testLoadUnparsableFile() + public function testLoadUnparsableFile(): void { // phpcs:disable Generic.PHP.NoSilencedErrors.Discouraged $path = $this->getPathToFixture('pass/unparsable.ini'); diff --git a/packages/config/tests/Charcoal/Config/Mixin/FileLoader/JsonFileLoaderTest.php b/packages/config/tests/Charcoal/Config/Mixin/FileLoader/JsonFileLoaderTest.php index 3443b4699..2376d8f71 100644 --- a/packages/config/tests/Charcoal/Config/Mixin/FileLoader/JsonFileLoaderTest.php +++ b/packages/config/tests/Charcoal/Config/Mixin/FileLoader/JsonFileLoaderTest.php @@ -1,5 +1,7 @@ getPathToFixture('pass/valid.json'); $data = $this->obj->loadFile($path); @@ -40,11 +39,8 @@ public function testLoadFile() /** * Asserts that an empty file is silently ignored. - * - * @covers ::loadJsonFile() - * @return void */ - public function testLoadEmptyFile() + public function testLoadEmptyFile(): void { $path = $this->getPathToFixture('pass/empty.json'); $data = $this->obj->loadFile($path); @@ -54,18 +50,15 @@ public function testLoadEmptyFile() /** * Asserts that a broken file is NOT ignored. - * - * @covers ::loadJsonFile() - * @return void */ - public function testLoadMalformedFile() + public function testLoadMalformedFile(): void { $this->expectExceptionMessageMatches('/^JSON file ".+?" could not be parsed: .+$/'); $this->expectException(UnexpectedValueException::class); // phpcs:disable Generic.PHP.NoSilencedErrors.Discouraged $path = $this->getPathToFixture('fail/malformed.json'); - $data = @$this->obj->loadFile($path); + @$this->obj->loadFile($path); // phpcs:enable } } diff --git a/packages/config/tests/Charcoal/Config/Mixin/FileLoader/PhpFileLoaderTest.php b/packages/config/tests/Charcoal/Config/Mixin/FileLoader/PhpFileLoaderTest.php index 0dd110db7..499a7fe35 100644 --- a/packages/config/tests/Charcoal/Config/Mixin/FileLoader/PhpFileLoaderTest.php +++ b/packages/config/tests/Charcoal/Config/Mixin/FileLoader/PhpFileLoaderTest.php @@ -1,5 +1,7 @@ getPathToFixture('pass/valid1.php'); $data = $this->obj->loadFile($path); @@ -40,11 +39,8 @@ public function testLoadFile() /** * Asserts that the scope of PHP config files is bound to the File Loader. - * - * @covers ::loadPhpFile() - * @return void */ - public function testLoadFileThatMutatesContext() + public function testLoadFileThatMutatesContext(): void { $path = $this->getPathToFixture('pass/valid3.php'); $data = $this->obj->loadFile($path); @@ -55,11 +51,8 @@ public function testLoadFileThatMutatesContext() /** * Asserts that an empty file is silently ignored. - * - * @covers ::loadPhpFile() - * @return void */ - public function testLoadEmptyFile() + public function testLoadEmptyFile(): void { $path = $this->getPathToFixture('pass/empty.php'); $data = $this->obj->loadFile($path); @@ -69,34 +62,28 @@ public function testLoadEmptyFile() /** * Asserts that a broken file is NOT ignored. - * - * @requires PHP >= 7.0 - * @covers ::loadPhpFile() - * @return void */ - public function testLoadMalformedFileInPhp7() + #[\PHPUnit\Framework\Attributes\RequiresPhp('>=8.1.0')] + public function testLoadMalformedFile(): void { $this->expectExceptionMessageMatches('/^PHP file ".+?" could not be parsed: .+$/'); $this->expectException(UnexpectedValueException::class); // phpcs:disable Generic.PHP.NoSilencedErrors.Discouraged $path = $this->getPathToFixture('fail/malformed.php'); - $data = $this->obj->loadFile($path); + $this->obj->loadFile($path); // phpcs:enable } /** * Asserts that an exception thrown within the file is caught. - * - * @covers ::loadPhpFile() - * @return void */ - public function testLoadExceptionalFile() + public function testLoadExceptionalFile(): void { $this->expectExceptionMessageMatches('/^PHP file ".+?" could not be parsed: Thrown Exception$/'); $this->expectException(UnexpectedValueException::class); $path = $this->getPathToFixture('fail/exception.php'); - $data = $this->obj->loadFile($path); + $this->obj->loadFile($path); } } diff --git a/packages/config/tests/Charcoal/Config/Mixin/FileLoader/YamlFileLoaderTest.php b/packages/config/tests/Charcoal/Config/Mixin/FileLoader/YamlFileLoaderTest.php index 9c7de1d6c..f5083a826 100644 --- a/packages/config/tests/Charcoal/Config/Mixin/FileLoader/YamlFileLoaderTest.php +++ b/packages/config/tests/Charcoal/Config/Mixin/FileLoader/YamlFileLoaderTest.php @@ -12,19 +12,16 @@ /** * Test {@see FileAwareTrait::loadYamlFile() YAML File Loading} - * - * @coversDefaultClass \Charcoal\Config\FileAwareTrait */ +#[\PHPUnit\Framework\Attributes\CoversTrait(\Charcoal\Config\FileAwareTrait::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\FileAwareTrait::class, 'loadYamlFile()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\FileAwareTrait::class, 'loadFile()')] class YamlFileLoaderTest extends AbstractFileLoaderTestCase { /** * Asserts that the File Loader supports '.yml' YAML config files. - * - * @covers ::loadYamlFile() - * @covers ::loadFile() - * @return void */ - public function testLoadFileWithYmlExtension() + public function testLoadFileWithYmlExtension(): void { $path = $this->getPathToFixture('pass/valid1.yml'); $data = $this->obj->loadFile($path); @@ -43,12 +40,8 @@ public function testLoadFileWithYmlExtension() /** * Asserts that the File Loader supports '.yaml' YAML config files. - * - * @covers ::loadYamlFile() - * @covers ::loadFile() - * @return void */ - public function testLoadFileWithYamlExtension() + public function testLoadFileWithYamlExtension(): void { $path = $this->getPathToFixture('pass/valid2.yaml'); $data = $this->obj->loadFile($path); @@ -67,19 +60,15 @@ public function testLoadFileWithYamlExtension() /** * Asserts that the File Loader throws an exception if the YAML Parser is unavailable. - * - * @runInSeparateProcess - * @preserveGlobalState disabled - * @covers ::loadYamlFile() - * @return void */ - public function testLoadFileWithNoYamlParser() + #[\PHPUnit\Framework\Attributes\PreserveGlobalState(false)] + #[\PHPUnit\Framework\Attributes\RunInSeparateProcess] + public function testLoadFileWithNoYamlParser(): void { - if (class_exists('Symfony\Component\Yaml\Parser', false)) { + if (class_exists(\Symfony\Component\Yaml\Parser::class, false)) { $this->markTestSkipped( 'The Symfony YAML component was loaded before the test could run' ); - return; } $this->expectExceptionMessage('YAML format requires the Symfony YAML component'); @@ -88,16 +77,13 @@ public function testLoadFileWithNoYamlParser() $this->disableSymfonyYamlComponent(); $path = $this->getPathToFixture('pass/valid1.yml'); - $data = $this->obj->loadFile($path); + $this->obj->loadFile($path); } /** * Asserts that an empty file is silently ignored. - * - * @covers ::loadYamlFile() - * @return void */ - public function testLoadEmptyFile() + public function testLoadEmptyFile(): void { $path = $this->getPathToFixture('pass/empty.yml'); $data = $this->obj->loadFile($path); @@ -107,25 +93,20 @@ public function testLoadEmptyFile() /** * Asserts that a broken file is NOT ignored. - * - * @covers ::loadYamlFile() - * @return void */ - public function testLoadMalformedFile() + public function testLoadMalformedFile(): void { $this->expectExceptionMessageMatches('/^YAML file ".+?" could not be parsed: .+$/'); $this->expectException(UnexpectedValueException::class); $path = $this->getPathToFixture('pass/malformed.yml'); - $data = $this->obj->loadFile($path); + $this->obj->loadFile($path); } /** * Remove the "symfony/yaml" package from Composer's search paths. - * - * @return void */ - public function disableSymfonyYamlComponent() + public function disableSymfonyYamlComponent(): void { // phpcs:disable Squiz.PHP.GlobalKeyword.NotAllowed global $autoloader; @@ -133,18 +114,16 @@ public function disableSymfonyYamlComponent() // If PSR-0/4 autoloading was optimized $classMap = $autoloader->getClassMap(); - if (isset($classMap['Symfony\\Component\\Yaml\\Parser'])) { + if (isset($classMap[\Symfony\Component\Yaml\Parser::class])) { $refClassMap = new ReflectionProperty($autoloader, 'classMap'); - $refClassMap->setAccessible(true); - unset($classMap['Symfony\\Component\\Yaml\\Parser']); + unset($classMap[\Symfony\Component\Yaml\Parser::class]); $refClassMap->setValue($autoloader, $classMap); } $prefixesPsr4 = $autoloader->getPrefixesPsr4(); if (isset($prefixesPsr4['Symfony\\Component\\Yaml\\'])) { $refPrefixesPsr4 = new ReflectionProperty($autoloader, 'prefixDirsPsr4'); - $refPrefixesPsr4->setAccessible(true); unset($prefixesPsr4['Symfony\\Component\\Yaml\\']); $refPrefixesPsr4->setValue($autoloader, $prefixesPsr4); @@ -153,10 +132,8 @@ public function disableSymfonyYamlComponent() /** * Add the "symfony/yaml" package from Composer's search paths. - * - * @return void */ - public function enableSymfonyYamlComponent() + public function enableSymfonyYamlComponent(): void { // phpcs:disable Squiz.PHP.GlobalKeyword.NotAllowed global $autoloader; @@ -164,27 +141,25 @@ public function enableSymfonyYamlComponent() // If PSR-0/4 autoloading was optimized $classMap = $autoloader->getClassMap(); - if (!isset($classMap['Symfony\\Component\\Yaml\\Parser'])) { + if (!isset($classMap[\Symfony\Component\Yaml\Parser::class])) { $refClassMap = new ReflectionProperty($autoloader, 'classMap'); - $refClassMap->setAccessible(true); $refClassLoader = $refClassMap->getDeclaringClass(); $classLoaderPath = $refClassLoader->getFileName(); - $vendorDir = dirname(dirname($classLoaderPath)); - $prefixesPsr4['Symfony\\Component\\Yaml\\Parser'] = [ $vendorDir.'/symfony/yaml/Parser.php' ]; + $vendorDir = dirname($classLoaderPath, 2); + $prefixesPsr4[\Symfony\Component\Yaml\Parser::class] = [ $vendorDir.'/symfony/yaml/Parser.php' ]; $refClassMap->setValue($autoloader, $prefixesPsr4); } $prefixesPsr4 = $autoloader->getPrefixesPsr4(); if (!isset($prefixesPsr4['Symfony\\Component\\Yaml\\'])) { $refPrefixesPsr4 = new ReflectionProperty($autoloader, 'prefixDirsPsr4'); - $refPrefixesPsr4->setAccessible(true); $refClassLoader = $refPrefixesPsr4->getDeclaringClass(); $classLoaderPath = $refClassLoader->getFileName(); - $vendorDir = dirname(dirname($classLoaderPath)); + $vendorDir = dirname($classLoaderPath, 2); $prefixesPsr4['Symfony\\Component\\Yaml\\'] = [ $vendorDir.'/symfony/yaml' ]; $refPrefixesPsr4->setValue($autoloader, $prefixesPsr4); } diff --git a/packages/config/tests/Charcoal/Config/Mixin/SeparatorAwareTest.php b/packages/config/tests/Charcoal/Config/Mixin/SeparatorAwareTest.php index 5bfce4750..31bf44b82 100644 --- a/packages/config/tests/Charcoal/Config/Mixin/SeparatorAwareTest.php +++ b/packages/config/tests/Charcoal/Config/Mixin/SeparatorAwareTest.php @@ -9,12 +9,17 @@ use Charcoal\Config\SeparatorAwareInterface; use Charcoal\Config\SeparatorAwareTrait; use InvalidArgumentException; +use ValueError; /** * Test SeparatorAwareTrait - * - * @coversDefaultClass \Charcoal\Config\SeparatorAwareTrait */ +#[\PHPUnit\Framework\Attributes\CoversTrait(\Charcoal\Config\SeparatorAwareTrait::class)] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\SeparatorAwareTrait::class, 'separator()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\SeparatorAwareTrait::class, 'setSeparator()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\SeparatorAwareTrait::class, 'hasWithSeparator()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\SeparatorAwareTrait::class, 'getWithSeparator()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Config\SeparatorAwareTrait::class, 'setWithSeparator()')] class SeparatorAwareTest extends AbstractTestCase { use AssertionsTrait; @@ -31,8 +36,6 @@ class SeparatorAwareTest extends AbstractTestCase /** * Create a TreeEntity instance. - * - * @return void */ protected function setUp(): void { @@ -66,20 +69,17 @@ protected function setUp(): void * Create a TreeEntity instance. * * @param array $data Data to pre-populate the object. - * @return TreeEntity */ - public function createObject(array $data = null) + public function createObject(?array $data = null): \Charcoal\Tests\Config\Mock\TreeEntity { return new TreeEntity($data); } /** * Asserts that the object implements SeparatorAwareInterface. - * - * @coversNothing - * @return void */ - public function testSeparatorAwareInterface() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testSeparatorAwareInterface(): void { $this->assertInstanceOf(SeparatorAwareInterface::class, $this->obj); } @@ -88,21 +88,15 @@ public function testSeparatorAwareInterface() // Test Seperator Token // ========================================================================= - /** * Asserts that the separator is disabled by default. - * - * @covers ::separator() - * @return void */ - public function testDefaultSeparatorIsEmptyString() + public function testDefaultSeparatorIsEmptyString(): void { $this->assertEmpty($this->obj->separator()); } /** - * @covers ::setSeparator() - * @covers ::separator() * @return TreeEntity */ public function testSetSeparator() @@ -116,12 +110,7 @@ public function testSetSeparator() return $obj; } - /** - * @covers ::setSeparator() - * @covers ::separator() - * @return void - */ - public function testMutatedSeparator() + public function testMutatedSeparator(): void { $obj = $this->obj; @@ -132,12 +121,7 @@ public function testMutatedSeparator() ); } - /** - * @covers ::setSeparator() - * @covers ::separator() - * @return void - */ - public function testEmptySeparator() + public function testEmptySeparator(): void { $obj = $this->obj; @@ -145,11 +129,7 @@ public function testEmptySeparator() $this->assertEquals('', $obj->separator()); } - /** - * @covers ::setSeparator() - * @return void - */ - public function testSetSeparatorWithInvalidType() + public function testSetSeparatorWithInvalidType(): void { $this->expectExceptionMessage('Separator must be a string'); $this->expectException(InvalidArgumentException::class); @@ -157,11 +137,7 @@ public function testSetSeparatorWithInvalidType() $this->obj->setSeparator(1); } - /** - * @covers ::setSeparator() - * @return void - */ - public function testSetSeparatorWithInvalidToken() + public function testSetSeparatorWithInvalidToken(): void { $this->expectExceptionMessage('Separator must be one-character, or empty'); $this->expectException(InvalidArgumentException::class); @@ -173,127 +149,83 @@ public function testSetSeparatorWithInvalidToken() // Test HasWithSeparator // ========================================================================= - /** - * @covers ::hasWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsTrueOnHasEndKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsTrueOnHasEndKeyPath(SeparatorAwareInterface $obj): void { $this->assertTrue($obj->hasWithSeparator('connections.default.driver')); } /** - * @covers ::hasWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsTrueOnHasMidKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsTrueOnHasMidKeyPath(SeparatorAwareInterface $obj): void { $this->assertTrue($obj->hasWithSeparator('connections.default')); } /** - * @covers ::hasWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsTrueOnHasBaseKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsTrueOnHasBaseKeyPath(SeparatorAwareInterface $obj): void { $this->assertTrue($obj->hasWithSeparator('connections')); } /** - * @covers ::hasWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsFalseOnHasEndKeyPathToNullValue(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsFalseOnHasEndKeyPathToNullValue(SeparatorAwareInterface $obj): void { $this->assertFalse($obj->hasWithSeparator('connections.customer.unix_socket')); } /** - * @covers ::hasWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsFalseOnHasNonexistentEndKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsFalseOnHasNonexistentEndKeyPath(SeparatorAwareInterface $obj): void { $this->assertFalse($obj->hasWithSeparator('connections.default.server_version')); } /** - * @covers ::hasWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsFalseOnHasNonexistentMidKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsFalseOnHasNonexistentMidKeyPath(SeparatorAwareInterface $obj): void { $this->assertFalse($obj->hasWithSeparator('connections.analytics.host')); } /** - * @covers ::hasWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsFalseOnHasNonexistentBaseKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsFalseOnHasNonexistentBaseKeyPath(SeparatorAwareInterface $obj): void { $this->assertFalse($obj->hasWithSeparator('logging')); } - /** - * @used-by self::testHasWithSeparatorWithoutDelimiterInPhp7() - * @used-by self::testHasWithSeparatorWithoutDelimiterInPhp5() - * - * @covers ::hasWithSeparator() - * @return void - */ - public function delegatedTestHasWithSeparatorWithoutDelimiter() + public function testHasWithSeparatorWithoutDelimiter(): void { + $this->expectException(ValueError::class); $this->obj->hasWithSeparator('connections.default.host'); } - /** - * @requires PHP >= 7.0 - * @return void - */ - public function testHasWithSeparatorWithoutDelimiterInPhp7() - { - $this->expectError(); - - $this->delegatedTestHasWithSeparatorWithoutDelimiter(); - } - - // Test GetWithSeparator // ========================================================================= - /** - * @covers ::getWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsValueOnGetEndKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsValueOnGetEndKeyPath(SeparatorAwareInterface $obj): void { $this->assertEquals( $this->connections['default']['driver'], @@ -302,13 +234,10 @@ public function testObjReturnsValueOnGetEndKeyPath(SeparatorAwareInterface $obj) } /** - * @covers ::getWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsValueOnGetMidKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsValueOnGetMidKeyPath(SeparatorAwareInterface $obj): void { $this->assertEquals( $this->connections['default'], @@ -317,13 +246,10 @@ public function testObjReturnsValueOnGetMidKeyPath(SeparatorAwareInterface $obj) } /** - * @covers ::getWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsValueOnGetBaseKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsValueOnGetBaseKeyPath(SeparatorAwareInterface $obj): void { $this->assertEquals( $this->connections, @@ -332,88 +258,54 @@ public function testObjReturnsValueOnGetBaseKeyPath(SeparatorAwareInterface $obj } /** - * @covers ::getWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsNullOnGetEndKeyPathToNullValue(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsNullOnGetEndKeyPathToNullValue(SeparatorAwareInterface $obj): void { $this->assertNull($obj->getWithSeparator('connections.customer.unix_socket')); } /** - * @covers ::getWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsNullOnGetNonexistentEndKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsNullOnGetNonexistentEndKeyPath(SeparatorAwareInterface $obj): void { $this->assertNull($obj->getWithSeparator('connections.default.server_version')); } /** - * @covers ::getWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsNullOnGetNonexistentMidKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsNullOnGetNonexistentMidKeyPath(SeparatorAwareInterface $obj): void { $this->assertNull($obj->getWithSeparator('connections.analytics.host')); } /** - * @covers ::getWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReturnsNullOnGetNonexistentBaseKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReturnsNullOnGetNonexistentBaseKeyPath(SeparatorAwareInterface $obj): void { $this->assertNull($obj->getWithSeparator('logging')); } - /** - * @used-by self::testGetWithSeparatorWithoutDelimiterInPhp7() - * @used-by self::testGetWithSeparatorWithoutDelimiterInPhp5() - * - * @covers ::getWithSeparator() - * @return void - */ - public function delegatedTestGetWithSeparatorWithoutDelimiter() + public function testGetWithSeparatorWithoutDelimiter(): void { + $this->expectException(ValueError::class); $this->obj->getWithSeparator('connections.default.host'); } - /** - * @requires PHP >= 7.0 - * @return void - */ - public function testGetWithSeparatorWithoutDelimiterInPhp7() - { - $this->expectError(); - - $this->delegatedTestGetWithSeparatorWithoutDelimiter(); - } - - // Test SetWithSeparator // ========================================================================= - /** - * @covers ::setWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReplacesValueRecursivelyOnSetKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReplacesValueRecursivelyOnSetKeyPath(SeparatorAwareInterface $obj): void { $obj->setWithSeparator('keywords', [ 'php', 'framework', 'charcoal', 'config' ]); $obj->setWithSeparator('keywords', [ 1 => 'library', 4 => 'component' ]); @@ -430,78 +322,60 @@ public function testObjReplacesValueRecursivelyOnSetKeyPath(SeparatorAwareInterf } /** - * @covers ::setWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReplacesValueOnSetEndKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReplacesValueOnSetEndKeyPath(SeparatorAwareInterface $obj): void { $obj->setWithSeparator('connections.default.driver', 'pdo_sqlite'); $this->assertEquals('pdo_sqlite', $obj->get('connections.default.driver')); } /** - * @covers ::setWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReplacesValueOnSetMidKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReplacesValueOnSetMidKeyPath(SeparatorAwareInterface $obj): void { $obj->setWithSeparator('connections.default', [ 'dbname' => 'otherdatabase' ]); $this->assertEquals('otherdatabase', $obj->get('connections.default.dbname')); } /** - * @covers ::setWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjReplacesValueOnSetBaseKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjReplacesValueOnSetBaseKeyPath(SeparatorAwareInterface $obj): void { $obj->setWithSeparator('connections', [ 'default' => [ 'host' => 'web.otherplace.tld' ] ]); $this->assertEquals('web.otherplace.tld', $obj->get('connections.default.host')); } /** - * @covers ::setWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjAddsValueOnSetNonexistentEndKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjAddsValueOnSetNonexistentEndKeyPath(SeparatorAwareInterface $obj): void { $obj->setWithSeparator('connections.default.server_version', '5.7'); $this->assertEquals('5.7', $obj->get('connections.default.server_version')); } /** - * @covers ::setWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjAddsValueOnSetNonexistentMidKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjAddsValueOnSetNonexistentMidKeyPath(SeparatorAwareInterface $obj): void { $obj->setWithSeparator('connections.analytics', [ 'driver' => 'pdo_pgsql' ]); $this->assertEquals('pdo_pgsql', $obj->get('connections.analytics.driver')); } /** - * @covers ::setWithSeparator() - * @depends testSetSeparator - * * @param SeparatorAwareInterface $obj The SeparatorAwareInterface implementation to test. - * @return void */ - public function testObjAddsValueOnSetNonexistentBaseKeyPath(SeparatorAwareInterface $obj) + #[\PHPUnit\Framework\Attributes\Depends('testSetSeparator')] + public function testObjAddsValueOnSetNonexistentBaseKeyPath(SeparatorAwareInterface $obj): void { $obj->setWithSeparator('logging', [ 'level' => 'debug' ]); $this->assertTrue($obj->has('logging.level')); @@ -511,26 +385,9 @@ public function testObjAddsValueOnSetNonexistentBaseKeyPath(SeparatorAwareInterf ); } - /** - * @used-by self::testSetWithSeparatorWithoutDelimiterInPhp7() - * @used-by self::testSetWithSeparatorWithoutDelimiterInPhp5() - * - * @covers ::setWithSeparator() - * @return void - */ - public function delegatedTestSetWithSeparatorWithoutDelimiter() + public function testSetWithSeparatorWithoutDelimiter(): void { + $this->expectException(ValueError::class); $this->obj->setWithSeparator('connections.default.server_version', '5.7'); } - - /** - * @requires PHP >= 7.0 - * @return void - */ - public function testSetWithSeparatorWithoutDelimiterInPhp7() - { - $this->expectError(); - - $this->delegatedTestSetWithSeparatorWithoutDelimiter(); - } } diff --git a/packages/config/tests/Charcoal/Config/Mock/ConfigurableObject.php b/packages/config/tests/Charcoal/Config/Mock/ConfigurableObject.php index 876aa3583..9d0d53df4 100644 --- a/packages/config/tests/Charcoal/Config/Mock/ConfigurableObject.php +++ b/packages/config/tests/Charcoal/Config/Mock/ConfigurableObject.php @@ -1,5 +1,7 @@ {$key}(); + } elseif (isset($this->{$key})) { + return $this->{$key}; } else { - if (isset($this->{$key})) { - return $this->{$key}; - } else { - return $this->getInDelegates($key); - } + return $this->getInDelegates($key); } } } diff --git a/packages/config/tests/Charcoal/Config/Mock/Entity.php b/packages/config/tests/Charcoal/Config/Mock/Entity.php index 7b84adfb9..d783597f8 100644 --- a/packages/config/tests/Charcoal/Config/Mock/Entity.php +++ b/packages/config/tests/Charcoal/Config/Mock/Entity.php @@ -1,5 +1,7 @@ setData($data); } } diff --git a/packages/config/tests/Charcoal/Config/Mock/FileLoader.php b/packages/config/tests/Charcoal/Config/Mock/FileLoader.php index 2da06b397..d6c07c419 100644 --- a/packages/config/tests/Charcoal/Config/Mock/FileLoader.php +++ b/packages/config/tests/Charcoal/Config/Mock/FileLoader.php @@ -1,5 +1,7 @@ -3, diff --git a/packages/config/tests/Charcoal/Config/Mock/MacroEntity.php b/packages/config/tests/Charcoal/Config/Mock/MacroEntity.php index e5b55cd60..24a5d29f8 100644 --- a/packages/config/tests/Charcoal/Config/Mock/MacroEntity.php +++ b/packages/config/tests/Charcoal/Config/Mock/MacroEntity.php @@ -1,5 +1,7 @@ foo; } diff --git a/packages/config/tests/Charcoal/Config/Mock/TreeEntity.php b/packages/config/tests/Charcoal/Config/Mock/TreeEntity.php index 7761a7bc6..b49aa22bf 100644 --- a/packages/config/tests/Charcoal/Config/Mock/TreeEntity.php +++ b/packages/config/tests/Charcoal/Config/Mock/TreeEntity.php @@ -26,7 +26,8 @@ class TreeEntity extends Entity implements SeparatorAwareInterface * @throws InvalidArgumentException If the $key is not a string or is a numeric value. * @return boolean TRUE if $key exists and has a value other than NULL, FALSE otherwise. */ - public function offsetExists($key) + #[\Override] + public function offsetExists($key): bool { if (is_numeric($key)) { throw new InvalidArgumentException( @@ -63,12 +64,7 @@ public function offsetExists($key) return ($this->{$key}() !== null); } // -- END DEPRECATED - - if (isset($this->{$key})) { - return true; - } - - return false; + return isset($this->{$key}); } /** @@ -78,7 +74,8 @@ public function offsetExists($key) * @throws InvalidArgumentException If the $key is not a string or is a numeric value. * @return mixed Value of the requested $key on success, NULL if the $key is not set. */ - public function offsetGet($key) + #[\Override] + public function offsetGet($key): mixed { if (is_numeric($key)) { throw new InvalidArgumentException( @@ -114,13 +111,8 @@ public function offsetGet($key) if ($this->mutatorCache[$key]) { return $this->{$key}(); } - // -- END DEPRECATED - - if (isset($this->{$key})) { - return $this->{$key}; - } - return null; + return $this->{$key} ?? null; } /** @@ -129,9 +121,9 @@ public function offsetGet($key) * @param string $key The data key to assign $value to. * @param mixed $value The data value to assign to $key. * @throws InvalidArgumentException If the $key is not a string or is a numeric value. - * @return void */ - public function offsetSet($key, $value) + #[\Override] + public function offsetSet($key, $value): void { if (is_numeric($key)) { throw new InvalidArgumentException( diff --git a/packages/config/tests/Charcoal/FixturesTrait.php b/packages/config/tests/Charcoal/FixturesTrait.php index d296ee5cf..7168625b3 100644 --- a/packages/config/tests/Charcoal/FixturesTrait.php +++ b/packages/config/tests/Charcoal/FixturesTrait.php @@ -13,7 +13,7 @@ trait FixturesTrait * @param string $file The file path relative to the Fixture directory. * @return string The file path to the fixture relative to the base directory. */ - public function getPathToFixture($file) + public function getPathToFixture($file): string { return __DIR__.'/../../tests/Charcoal/Config/Fixture/'.ltrim($file, '/'); } diff --git a/packages/config/tests/bootstrap.php b/packages/config/tests/bootstrap.php index a79f4b20d..70ded9041 100644 --- a/packages/config/tests/bootstrap.php +++ b/packages/config/tests/bootstrap.php @@ -1,6 +1,8 @@ - -> + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/core/src/Charcoal/Loader/CollectionLoader.php b/packages/core/src/Charcoal/Loader/CollectionLoader.php index 119096d59..c99909efe 100644 --- a/packages/core/src/Charcoal/Loader/CollectionLoader.php +++ b/packages/core/src/Charcoal/Loader/CollectionLoader.php @@ -26,6 +26,7 @@ /** * Object Collection Loader */ +#[\AllowDynamicProperties] class CollectionLoader implements FilterCollectionInterface, OrderCollectionInterface, @@ -107,9 +108,8 @@ public function __construct(array $data) * Set an object model factory. * * @param FactoryInterface $factory The model factory, to create objects. - * @return self */ - public function setFactory(FactoryInterface $factory) + public function setFactory(FactoryInterface $factory): static { $this->factory = $factory; @@ -126,7 +126,7 @@ protected function factory() { if ($this->factory === null) { throw new RuntimeException( - sprintf('Model Factory is not defined for "%s"', get_class($this)) + sprintf('Model Factory is not defined for "%s"', static::class) ); } @@ -140,8 +140,7 @@ protected function factory() */ public function createModel() { - $obj = $this->factory()->create($this->modelClass()); - return $obj; + return $this->factory()->create($this->modelClass()); } /** @@ -152,17 +151,15 @@ public function createModel() */ protected function createModelFromData(array $data) { - $obj = $this->factory()->create($this->dynamicModelClass($data)); - return $obj; + return $this->factory()->create($this->dynamicModelClass($data)); } /** * Set the loader settings. * * @param array $data Data to assign to the loader. - * @return self */ - public function setData(array $data) + public function setData(array $data): static { foreach ($data as $key => $val) { $setter = $this->setter($key); @@ -195,9 +192,8 @@ public function source() * Set the source to load objects from. * * @param SourceInterface $source A data source. - * @return self */ - public function setSource(SourceInterface $source) + public function setSource(SourceInterface $source): static { $source->reset(); @@ -208,10 +204,8 @@ public function setSource(SourceInterface $source) /** * Reset everything but the model. - * - * @return self */ - public function reset() + public function reset(): static { if ($this->source) { $this->source()->reset(); @@ -240,12 +234,10 @@ public function model() /** * Determine if the loader has an object model. - * - * @return boolean */ - public function hasModel() + public function hasModel(): bool { - return !!$this->model; + return (bool)$this->model; } /** @@ -253,9 +245,8 @@ public function hasModel() * * @param string|ModelInterface $model An object model. * @throws InvalidArgumentException If the given argument is not a model. - * @return self */ - public function setModel($model) + public function setModel($model): static { if (is_string($model)) { $model = $this->factory()->get($model); @@ -279,12 +270,10 @@ public function setModel($model) /** * Retrieve the model class. - * - * @return string */ - public function modelClass() + public function modelClass(): string { - return get_class($this->model()); + return $this->model()::class; } /** @@ -313,20 +302,17 @@ public function dynamicTypeField() /** * Determine if the model has a dynamic object type. - * - * @return boolean */ - public function hasDynamicTypeField() + public function hasDynamicTypeField(): bool { - return !!$this->dynamicTypeField; + return (bool)$this->dynamicTypeField; } /** * @param string $field The field to use for dynamic object type. * @throws InvalidArgumentException If the field is not a string. - * @return self */ - public function setDynamicTypeField($field) + public function setDynamicTypeField($field): static { if (!is_string($field)) { throw new InvalidArgumentException( @@ -353,9 +339,8 @@ public function properties() * Alias of {@see SourceInterface::setProperties()} * * @param array $properties An array of property identifiers. - * @return self */ - public function setProperties(array $properties) + public function setProperties(array $properties): static { $this->source()->setProperties($properties); @@ -366,9 +351,8 @@ public function setProperties(array $properties) * Alias of {@see SourceInterface::addProperty()} * * @param string $property A property identifier. - * @return self */ - public function addProperty($property) + public function addProperty($property): static { $this->source()->addProperty($property); @@ -380,9 +364,8 @@ public function addProperty($property) * * @param array $keywords An array of keywords and properties. * Expected format: `[ "search query", [ "field names…" ] ]`. - * @return self */ - public function setKeywords(array $keywords) + public function setKeywords(array $keywords): static { foreach ($keywords as $query) { $keyword = $query[0]; @@ -398,9 +381,8 @@ public function setKeywords(array $keywords) * * @param string $keyword A value to match among $properties. * @param array $properties One or more of properties to search amongst. - * @return self */ - public function addKeyword($keyword, array $properties = null) + public function addKeyword(string $keyword, ?array $properties = null): static { if ($properties === null) { $properties = []; @@ -443,9 +425,8 @@ public function hasFilters() * Alias of {@see SourceInterface::setFilters()} * * @param array $filters An array of filters. - * @return self */ - public function setFilters(array $filters) + public function setFilters(array $filters): static { $this->source()->setFilters($filters); return $this; @@ -455,9 +436,8 @@ public function setFilters(array $filters) * Alias of {@see SourceInterface::addFilters()} * * @param array $filters An array of filters. - * @return self */ - public function addFilters(array $filters) + public function addFilters(array $filters): static { foreach ($filters as $f) { $this->addFilter($f); @@ -474,9 +454,8 @@ public function addFilters(array $filters) * @param mixed $value Optional value for the property to compare against. * Only used if the first argument is a string. * @param array $options Optional extra settings to apply on the filter. - * @return self */ - public function addFilter($param, $value = null, array $options = null) + public function addFilter($param, $value = null, ?array $options = null): static { $this->source()->addFilter($param, $value, $options); return $this; @@ -506,9 +485,8 @@ public function hasOrders() * Alias of {@see SourceInterface::setOrders()} * * @param array $orders An array of orders. - * @return self */ - public function setOrders(array $orders) + public function setOrders(array $orders): static { $this->source()->setOrders($orders); return $this; @@ -518,9 +496,8 @@ public function setOrders(array $orders) * Alias of {@see SourceInterface::addOrders()} * * @param array $orders An array of orders. - * @return self */ - public function addOrders(array $orders) + public function addOrders(array $orders): static { foreach ($orders as $o) { $this->addOrder($o); @@ -537,9 +514,8 @@ public function addOrders(array $orders) * @param string $mode Optional sorting mode. * Defaults to ascending if a property is provided. * @param array $options Optional extra settings to apply on the order. - * @return self */ - public function addOrder($param, $mode = 'asc', array $options = null) + public function addOrder($param, $mode = 'asc', ?array $options = null): static { $this->source()->addOrder($param, $mode, $options); return $this; @@ -559,9 +535,8 @@ public function pagination() * Alias of {@see SourceInterface::setPagination()} * * @param mixed $param An associative array of pagination settings. - * @return self */ - public function setPagination($param) + public function setPagination($param): static { $this->source()->setPagination($param); @@ -582,9 +557,8 @@ public function page() * Alias of {@see PaginationInterface::pagination()} * * @param integer $page A page number. - * @return self */ - public function setPage($page) + public function setPage($page): static { $this->pagination()->setPage($page); @@ -605,9 +579,8 @@ public function numPerPage() * Alias of {@see PaginationInterface::setNumPerPage()} * * @param integer $num The number of items to display per page. - * @return self */ - public function setNumPerPage($num) + public function setNumPerPage($num): static { $this->pagination()->setNumPerPage($num); @@ -618,9 +591,8 @@ public function setNumPerPage($num) * Set the callback routine applied to every object added to the collection. * * @param callable $callback The callback routine. - * @return self */ - public function setCallback(callable $callback) + public function setCallback(callable $callback): static { $this->callback = $callback; @@ -647,7 +619,7 @@ public function callback() * @throws Exception If the database connection fails. * @return ModelInterface[]|ArrayAccess */ - public function load($ident = null, callable $callback = null, callable $before = null) + public function load($ident = null, ?callable $callback = null, ?callable $before = null): \ArrayAccess|array { // Unused. unset($ident); @@ -661,9 +633,8 @@ public function load($ident = null, callable $callback = null, callable $before * Get the total number of items for this collection query. * * @throws RuntimeException If the database connection fails. - * @return integer */ - public function loadCount() + public function loadCount(): int { $query = $this->source()->sqlLoadCount(); @@ -707,7 +678,7 @@ public function loadCount() * @throws InvalidArgumentException If the SQL string/set is invalid. * @return ModelInterface[]|ArrayAccess */ - public function loadFromQuery($query, callable $callback = null, callable $before = null) + public function loadFromQuery($query, ?callable $callback = null, ?callable $before = null): \ArrayAccess|array { $db = $this->source()->db(); @@ -723,14 +694,14 @@ public function loadFromQuery($query, callable $callback = null, callable $befor $sth = $db->prepare($query); $sth->execute(); } elseif (is_array($query)) { - list($query, $binds, $types) = array_pad($query, 3, []); + [$query, $binds, $types] = array_pad($query, 3, []); $sth = $this->source()->dbQuery($query, $binds, $types); } else { throw new InvalidArgumentException(sprintf( 'The SQL query must be a string or an array: ' . '[ string $query, array $binds, array $dataTypes ]; ' . 'received %s', - is_object($query) ? get_class($query) : $query + is_object($query) ? $query::class : $query )); } @@ -751,7 +722,7 @@ public function loadFromQuery($query, callable $callback = null, callable $befor * @param callable|null $after Process each entity after applying raw data. * @return ModelInterface[]|ArrayAccess */ - protected function processCollection($results, callable $before = null, callable $after = null) + protected function processCollection($results, ?callable $before = null, ?callable $after = null): \ArrayAccess|array { $collection = $this->createCollection(); foreach ($results as $objData) { @@ -773,7 +744,7 @@ protected function processCollection($results, callable $before = null, callable * @param callable|null $after Process each entity after applying raw data. * @return ModelInterface|ArrayAccess|null */ - protected function processModel($objData, callable $before = null, callable $after = null) + protected function processModel(array $objData, ?callable $before = null, ?callable $after = null) { $obj = $this->createModelFromData($objData); @@ -794,9 +765,8 @@ protected function processModel($objData, callable $before = null, callable $aft * Create a collection class or array. * * @throws RuntimeException If the collection class is invalid. - * @return array|ArrayAccess */ - public function createCollection() + public function createCollection(): array|\ArrayAccess { $collectClass = $this->collectionClass(); if ($collectClass === 'array') { @@ -817,9 +787,7 @@ public function createCollection() )); } - $collection = new $collectClass(); - - return $collection; + return new $collectClass(); } /** @@ -827,9 +795,8 @@ public function createCollection() * * @param string $className The class name of the collection. * @throws InvalidArgumentException If the class name is not a string. - * @return self */ - public function setCollectionClass($className) + public function setCollectionClass($className): static { if (!is_string($className)) { throw new InvalidArgumentException( @@ -858,7 +825,7 @@ public function collectionClass() * @param string $key The key to get the getter from. * @return string The getter method name, for a given key. */ - protected function getter($key) + protected function getter($key): string { $getter = $key; return $this->camelize($getter); @@ -870,7 +837,7 @@ protected function getter($key) * @param string $key The key to get the setter from. * @return string The setter method name, for a given key. */ - protected function setter($key) + protected function setter(string $key): string { $setter = 'set_' . $key; return $this->camelize($setter); @@ -882,8 +849,8 @@ protected function setter($key) * @param string $str The snake_case string to camelize. * @return string The camelcase'd string. */ - protected function camelize($str) + protected function camelize($str): string { - return lcfirst(implode('', array_map('ucfirst', explode('_', $str)))); + return lcfirst(implode('', array_map(ucfirst(...), explode('_', $str)))); } } diff --git a/packages/core/src/Charcoal/Loader/CollectionLoaderAwareTrait.php b/packages/core/src/Charcoal/Loader/CollectionLoaderAwareTrait.php index 770f9d5fd..989f42127 100644 --- a/packages/core/src/Charcoal/Loader/CollectionLoaderAwareTrait.php +++ b/packages/core/src/Charcoal/Loader/CollectionLoaderAwareTrait.php @@ -24,11 +24,12 @@ trait CollectionLoaderAwareTrait * Set a model collection loader. * * @param CollectionLoader $loader The model collection loader. - * @return void */ - protected function setCollectionLoader(CollectionLoader $loader) + protected function setCollectionLoader(CollectionLoader $loader): static { $this->collectionLoader = $loader; + + return $this; } /** @@ -37,12 +38,12 @@ protected function setCollectionLoader(CollectionLoader $loader) * @throws RuntimeException If the collection loader is missing. * @return CollectionLoader */ - public function collectionLoader() + public function collectionLoader(): \Charcoal\Loader\CollectionLoader { if (!isset($this->collectionLoader)) { throw new RuntimeException(sprintf( 'Collection Loader is not defined for [%s]', - get_class($this) + $this::class )); } diff --git a/packages/core/src/Charcoal/Loader/CollectionLoaderFactoryTrait.php b/packages/core/src/Charcoal/Loader/CollectionLoaderFactoryTrait.php index f256bd609..0643e1d6d 100644 --- a/packages/core/src/Charcoal/Loader/CollectionLoaderFactoryTrait.php +++ b/packages/core/src/Charcoal/Loader/CollectionLoaderFactoryTrait.php @@ -42,7 +42,7 @@ public function collectionLoaderFactory() if (!isset($this->collectionLoaderFactory)) { throw new RuntimeException(sprintf( 'Collection Loader Factory is not defined for [%s]', - get_class($this) + $this::class )); } @@ -56,7 +56,7 @@ public function collectionLoaderFactory() * @param callable|null $callback Optional. Called at creation. * @return CollectionLoader */ - public function createCollectionLoaderWith(array $args = null, callable $callback = null) + public function createCollectionLoaderWith(?array $args = null, ?callable $callback = null) { $factory = $this->collectionLoaderFactory(); diff --git a/packages/core/src/Charcoal/Loader/LazyCollectionLoader.php b/packages/core/src/Charcoal/Loader/LazyCollectionLoader.php index caa54cba7..f6696db75 100644 --- a/packages/core/src/Charcoal/Loader/LazyCollectionLoader.php +++ b/packages/core/src/Charcoal/Loader/LazyCollectionLoader.php @@ -1,5 +1,7 @@ processModel($objData, $before, $after); diff --git a/packages/core/src/Charcoal/Model/AbstractModel.php b/packages/core/src/Charcoal/Model/AbstractModel.php index 15c4e88c4..dc76a9dd6 100644 --- a/packages/core/src/Charcoal/Model/AbstractModel.php +++ b/packages/core/src/Charcoal/Model/AbstractModel.php @@ -65,7 +65,7 @@ abstract class AbstractModel extends AbstractEntity implements /** * @param array $data Dependencies. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { // LoggerAwareInterface dependencies $this->setLogger($data['logger']); @@ -107,7 +107,8 @@ public function __construct(array $data = null) * for retrieving a subset of data. * @return array */ - public function data(array $properties = null) + #[\Override] + public function data(?array $properties = null) { $data = []; $properties = $this->properties($properties); @@ -128,6 +129,7 @@ public function data(array $properties = null) * @return self * @see AbstractEntity::setData() */ + #[\Override] public function setData(array $data) { $data = $this->setIdFromData($data); @@ -183,11 +185,7 @@ public function mergeData(array $data) $property = $this->p($propIdent); if ($property['l10n'] && is_array($val)) { $currentValue = json_decode(json_encode($this[$propIdent]), true); - if (is_array($currentValue)) { - $this[$propIdent] = array_merge($currentValue, $val); - } else { - $this[$propIdent] = $val; - } + $this[$propIdent] = is_array($currentValue) ? array_merge($currentValue, $val) : $val; } else { $this[$propIdent] = $val; } @@ -238,20 +236,18 @@ public function setFlatData(array $flatData) public function setPropertyDataFromFlatData(array $flatData) { $flatData = $this->setIdFromData($flatData); - - $propData = []; $properties = $this->properties(); foreach ($properties as $propertyIdent => $property) { $fieldValues = []; $fieldNames = $property->fieldNames(); foreach ($fieldNames as $fieldName) { - if (array_key_exists($fieldName, $flatData)) { + if (array_key_exists((string)$fieldName, $flatData)) { $fieldValues[$fieldName] = $flatData[$fieldName]; unset($flatData[$fieldName]); } } - if ($fieldValues) { + if ($fieldValues !== []) { $this[$propertyIdent] = $property->parseFromFlatData($fieldValues); } } @@ -268,7 +264,7 @@ public function setPropertyDataFromFlatData(array $flatData) * for retrieving a subset of data. * @return array */ - public function flatData(array $properties = null) + public function flatData(?array $properties = null) { $flatData = []; $properties = $this->properties($properties); @@ -299,7 +295,7 @@ public function propertyValue($propertyIdent) * @param array $properties Optional array of properties to save. If null, use all object's properties. * @return boolean */ - public function saveProperties(array $properties = null) + public function saveProperties(?array $properties = null) { if ($properties === null) { $properties = array_keys($this->metadata()->properties()); @@ -335,7 +331,7 @@ public function saveProperties(array $properties = null) * @throws PDOException If the PDO query fails. * @return string The matching language. */ - public function loadFromL10n($key, $value, array $langs) + public function loadFromL10n(string $key, $value, array $langs) { $binds = [ 'ident' => $value, @@ -366,9 +362,9 @@ public function loadFromL10n($key, $value, array $langs) if ($sth === false) { throw new PDOException(sprintf( 'Could not load model [%s] for localized column "%s" [%s]', - get_class($this), + static::class, $fieldName, - (is_object($value) ? get_class($value) : (is_string($value) ? $value : gettype($value))) + (is_object($value) ? $value::class : (is_string($value) ? $value : gettype($value))) )); } @@ -376,9 +372,9 @@ public function loadFromL10n($key, $value, array $langs) if (!$data || !isset($data['_lang'])) { throw new PDOException(sprintf( 'Unable to retrieve model [%s] data for localized column "%s" [%s]', - get_class($this), + static::class, $fieldName, - (is_object($value) ? get_class($value) : (is_string($value) ? $value : gettype($value))) + (is_object($value) ? $value::class : (is_string($value) ? $value : gettype($value))) )); } @@ -446,7 +442,7 @@ protected function preSave() * @see StorableTrait::preUpdate() * @return boolean */ - protected function preUpdate(array $properties = null) + protected function preUpdate(?array $properties = null) { return $this->saveProperties($properties); } @@ -488,11 +484,11 @@ protected function createSource() if (!$sourceConfig) { throw new UnexpectedValueException(sprintf( 'Can not create source for model [%s]: Invalid metadata (can not load source\'s configuration)', - get_class($this) + static::class )); } - $type = isset($sourceConfig['type']) ? $sourceConfig['type'] : self::DEFAULT_SOURCE_TYPE; + $type = ($sourceConfig['type'] ?? self::DEFAULT_SOURCE_TYPE); $source = $this->sourceFactory()->create($type); $source->setModel($this); @@ -508,8 +504,7 @@ protected function createSource() */ protected function createValidator() { - $validator = new ModelValidator($this); - return $validator; + return new ModelValidator($this); } /** @@ -533,9 +528,8 @@ protected function setDependencies(Container $container) */ public static function objType() { - $class = get_called_class(); + $class = static::class; $ident = preg_replace('/([a-z])([A-Z])/', '$1-$2', $class); - $ident = strtolower(str_replace('\\', '/', $ident)); - return $ident; + return strtolower(str_replace('\\', '/', $ident)); } } diff --git a/packages/core/src/Charcoal/Model/Collection.php b/packages/core/src/Charcoal/Model/Collection.php index f05a22173..922843144 100644 --- a/packages/core/src/Charcoal/Model/Collection.php +++ b/packages/core/src/Charcoal/Model/Collection.php @@ -40,7 +40,6 @@ class Collection implements CollectionInterface * Create a new collection. * * @param array|Traversable|null $objs Array of objects to pre-populate this collection. - * @return void */ public function __construct($objs = null) { @@ -54,7 +53,7 @@ public function __construct($objs = null) * * @return object|null Returns the first object, or NULL if the collection is empty. */ - public function first() + public function first(): ?object { if (empty($this->objects)) { return null; @@ -68,7 +67,7 @@ public function first() * * @return object|null Returns the last object, or NULL if the collection is empty. */ - public function last() + public function last(): ?object { if (empty($this->objects)) { return null; @@ -79,15 +78,13 @@ public function last() // Satisfies CollectionInterface // ============================================================================================= - /** * Merge the collection with the given objects. * * @param array|Traversable $objs Array of objects to append to this collection. * @throws InvalidArgumentException If the given array contains an unacceptable value. - * @return self */ - public function merge($objs) + public function merge($objs): static { $objs = $this->asArray($objs); @@ -96,7 +93,7 @@ public function merge($objs) throw new InvalidArgumentException( sprintf( 'Must be an array of models, contains %s', - (is_object($obj) ? get_class($obj) : gettype($obj)) + (get_debug_type($obj)) ) ); } @@ -113,15 +110,14 @@ public function merge($objs) * * @param object $obj An acceptable object. * @throws InvalidArgumentException If the given object is not acceptable. - * @return self */ - public function add($obj) + public function add($obj): static { if (!$this->isAcceptable($obj)) { throw new InvalidArgumentException( sprintf( 'Must be a model, received %s', - (is_object($obj) ? get_class($obj) : gettype($obj)) + (get_debug_type($obj)) ) ); } @@ -155,15 +151,14 @@ public function get($key) * Determine if an object exists in the collection by key. * * @param mixed $key The primary key to lookup. - * @return boolean */ - public function has($key) + public function has($key): bool { if ($this->isAcceptable($key)) { $key = $this->modelKey($key); } - return array_key_exists($key, $this->objects); + return array_key_exists((string)$key, $this->objects); } /** @@ -171,9 +166,8 @@ public function has($key) * * @param mixed $key The object primary key to remove. * @throws InvalidArgumentException If the given key is not acceptable. - * @return self */ - public function remove($key) + public function remove($key): static { if ($this->isAcceptable($key)) { $key = $this->modelKey($key); @@ -186,10 +180,8 @@ public function remove($key) /** * Remove all objects from collection. - * - * @return self */ - public function clear() + public function clear(): static { $this->objects = []; @@ -211,7 +203,7 @@ public function all() * * @return object[] A sequential array of objects. */ - public function values() + public function values(): array { return array_values($this->objects); } @@ -221,22 +213,20 @@ public function values() * * @return array A sequential array of keys. */ - public function keys() + public function keys(): array { return array_keys($this->objects); } // Satisfies ArrayAccess // ============================================================================================= - /** * Alias of {@see CollectionInterface::has()}. * * @see \ArrayAccess * @param mixed $offset The object primary key or array offset. - * @return boolean */ - public function offsetExists($offset) + public function offsetExists($offset): bool { if (is_int($offset)) { $offset = $this->resolveOffset($offset); @@ -255,7 +245,7 @@ public function offsetExists($offset) * @param mixed $offset The object primary key or array offset. * @return mixed Returns the requested object or NULL if not in the collection. */ - public function offsetGet($offset) + public function offsetGet($offset): mixed { if (is_int($offset)) { $offset = $this->resolveOffset($offset); @@ -275,9 +265,8 @@ public function offsetGet($offset) * @param mixed $offset The object primary key or array offset. * @param mixed $value The object. * @throws LogicException Attempts to assign an offset. - * @return void */ - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { if ($offset === null) { $this->add($value); @@ -293,9 +282,8 @@ public function offsetSet($offset, $value) * * @see \ArrayAccess * @param mixed $offset The object primary key or array offset. - * @return void */ - public function offsetUnset($offset) + public function offsetUnset($offset): void { if (is_int($offset)) { $offset = $this->resolveOffset($offset); @@ -319,10 +307,8 @@ public function offsetUnset($offset) */ protected function resolveOffset($offset) { - if (is_int($offset)) { - if ($offset < 0) { - $offset = ($this->count() - abs($offset)); - } + if (is_int($offset) && $offset < 0) { + $offset = ($this->count() - abs($offset)); } return $offset; @@ -330,28 +316,24 @@ protected function resolveOffset($offset) // Satisfies Countable // ============================================================================================= - /** * Get number of objects in collection * * @see \Countable - * @return integer */ - public function count() + public function count(): int { return count($this->objects); } // Satisfies IteratorAggregate // ============================================================================================= - /** * Retrieve an external iterator. * * @see \IteratorAggregate - * @return \ArrayIterator */ - public function getIterator() + public function getIterator(): \ArrayIterator { return new ArrayIterator($this->objects); } @@ -360,24 +342,22 @@ public function getIterator() * Retrieve a cached iterator. * * @param integer $flags Bitmask of flags. - * @return \CachingIterator */ - public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING) + public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING): \CachingIterator { return new CachingIterator($this->getIterator(), $flags); } // Satisfies backwards-compatibility // ============================================================================================= - /** * Retrieve the array offset from the given key. * - * @deprecated * @param mixed $key The primary key to retrieve the offset from. * @return integer Returns an array offset. */ - public function pos($key) + #[\Deprecated] + public function pos($key): int|false { trigger_error('Collection::pos() is deprecated', E_USER_DEPRECATED); @@ -387,11 +367,11 @@ public function pos($key) /** * Alias of {@see self::values()} * - * @deprecated * @todo Trigger deprecation error. * @return object[] */ - public function objects() + #[\Deprecated] + public function objects(): array { return $this->values(); } @@ -399,26 +379,24 @@ public function objects() /** * Alias of {@see self::all()}. * - * @deprecated * @todo Trigger deprecation error. * @return object[] */ + #[\Deprecated] public function map() { return $this->all(); } // ============================================================================================= - /** * Determine if the given value is acceptable for the collection. * * Note: Practical for specialized collections extending the base collection. * * @param mixed $value The value being vetted. - * @return boolean */ - public function isAcceptable($value) + public function isAcceptable($value): bool { return ($value instanceof ModelInterface); } @@ -438,7 +416,7 @@ protected function modelKey($obj) throw new InvalidArgumentException( sprintf( 'Must be a model, received %s', - (is_object($obj) ? get_class($obj) : gettype($obj)) + (get_debug_type($obj)) ) ); } @@ -448,10 +426,8 @@ protected function modelKey($obj) /** * Determine if the collection is empty or not. - * - * @return boolean */ - public function isEmpty() + public function isEmpty(): bool { return empty($this->objects); } @@ -460,10 +436,8 @@ public function isEmpty() * Get a base collection instance from this collection. * * Note: Practical for extended classes. - * - * @return Collection */ - public function toBase() + public function toBase(): self { return new self($this); } diff --git a/packages/core/src/Charcoal/Model/CollectionInterface.php b/packages/core/src/Charcoal/Model/CollectionInterface.php index 245394c30..19b538c4f 100644 --- a/packages/core/src/Charcoal/Model/CollectionInterface.php +++ b/packages/core/src/Charcoal/Model/CollectionInterface.php @@ -1,5 +1,7 @@ metadataLoader) { throw new RuntimeException( - sprintf('Metadata loader was not set for "%s"', get_class($this)) + sprintf('Metadata loader was not set for "%s"', $this::class) ); } return $this->metadataLoader; @@ -160,13 +160,10 @@ protected function metadataLoader() * Generate a metadata identifier from this object's class name (FQN). * * Converts the short class name and converts it from camelCase to kebab-case. - * - * @return string */ - protected function generateMetadataIdent() + protected function generateMetadataIdent(): string { $ident = preg_replace('/([a-z])([A-Z])/', '$1-$2', static::class); - $ident = strtolower(str_replace('\\', '/', $ident)); - return $ident; + return strtolower(str_replace('\\', '/', $ident)); } } diff --git a/packages/core/src/Charcoal/Model/MetadataInterface.php b/packages/core/src/Charcoal/Model/MetadataInterface.php index 9f60dde0c..6e2c973f9 100644 --- a/packages/core/src/Charcoal/Model/MetadataInterface.php +++ b/packages/core/src/Charcoal/Model/MetadataInterface.php @@ -1,5 +1,7 @@ metadataLoader)) { throw new RuntimeException(sprintf( 'Metadata Loader is not defined for [%s]', - get_class($this) + $this::class )); } @@ -58,9 +58,8 @@ public function metadataLoader() protected function loadMetadata($metadataIdent) { $metadataLoader = $this->metadataLoader(); - $metadata = $metadataLoader->load($metadataIdent, $this->createMetadata()); - return $metadata; + return $metadataLoader->load($metadataIdent, $this->createMetadata()); } /** diff --git a/packages/core/src/Charcoal/Model/Model.php b/packages/core/src/Charcoal/Model/Model.php index 59dc94c17..cde44b635 100644 --- a/packages/core/src/Charcoal/Model/Model.php +++ b/packages/core/src/Charcoal/Model/Model.php @@ -7,6 +7,8 @@ * @author Mathieu Ducharme */ +declare(strict_types=1); + namespace Charcoal\Model; // From 'charcoal-core' diff --git a/packages/core/src/Charcoal/Model/ModelFactoryTrait.php b/packages/core/src/Charcoal/Model/ModelFactoryTrait.php index 78251ce21..7d0b6ef2f 100644 --- a/packages/core/src/Charcoal/Model/ModelFactoryTrait.php +++ b/packages/core/src/Charcoal/Model/ModelFactoryTrait.php @@ -43,7 +43,7 @@ public function modelFactory() if (!isset($this->modelFactory)) { throw new RuntimeException(sprintf( 'Model Factory is not defined for [%s]', - get_class($this) + $this::class )); } diff --git a/packages/core/src/Charcoal/Model/ModelInterface.php b/packages/core/src/Charcoal/Model/ModelInterface.php index 01c133a7f..f4b60f818 100644 --- a/packages/core/src/Charcoal/Model/ModelInterface.php +++ b/packages/core/src/Charcoal/Model/ModelInterface.php @@ -1,5 +1,7 @@ modelLoaderBuilder)) { throw new RuntimeException(sprintf( 'Model Factory is not defined for [%s]', - get_class($this) + $this::class )); } @@ -72,7 +72,7 @@ protected function modelLoader($objType, $objKey = null) if (!is_string($objType)) { throw new InvalidArgumentException(sprintf( 'The object type must be a string, received %s', - is_object($objType) ? get_class($objType) : gettype($objType) + get_debug_type($objType) )); } @@ -82,7 +82,7 @@ protected function modelLoader($objType, $objKey = null) } elseif (!is_string($key)) { throw new InvalidArgumentException(sprintf( 'The object property key must be a string, received %s', - is_object($key) ? get_class($key) : gettype($key) + get_debug_type($key) )); } diff --git a/packages/core/src/Charcoal/Model/ModelMetadata.php b/packages/core/src/Charcoal/Model/ModelMetadata.php index 696a22f1a..64e72e2af 100644 --- a/packages/core/src/Charcoal/Model/ModelMetadata.php +++ b/packages/core/src/Charcoal/Model/ModelMetadata.php @@ -13,10 +13,8 @@ class ModelMetadata extends AbstractMetadata { /** * The metadata identifier. - * - * @var string */ - private $ident; + private ?string $ident = null; /** * The model's sources. @@ -27,26 +25,23 @@ class ModelMetadata extends AbstractMetadata /** * The model's default source. - * - * @var string */ - private $defaultSource; + private ?string $defaultSource = null; /** * Set the metadata identifier. * * @param string $ident The metadata identifier. * @throws InvalidArgumentException If identifier is not a string. - * @return self */ - public function setIdent($ident) + public function setIdent($ident): static { if (!is_string($ident)) { throw new InvalidArgumentException( sprintf( '[%s] Identifier must be a string; received %s', - get_called_class(), - (is_object($ident) ? get_class($ident) : gettype($ident)) + static::class, + (get_debug_type($ident)) ) ); } @@ -61,16 +56,15 @@ public function setIdent($ident) * * @return string */ - public function ident() + public function ident(): ?string { return $this->ident; } /** * @param array $sources The available sources for this model. - * @return self */ - public function setSources(array $sources) + public function setSources(array $sources): static { foreach ($sources as $sourceIdent => $source) { $this->addSource($sourceIdent, $source); @@ -89,9 +83,8 @@ public function sources() /** * @param string $sourceIdent The source identifier. * @param mixed $source The source data. - * @return self */ - public function addSource($sourceIdent, $source) + public function addSource($sourceIdent, $source): static { $this->sources[$sourceIdent] = $source; return $this; @@ -113,9 +106,8 @@ public function source($sourceIdent) /** * @param string $defaultSource The default source identifier. * @throws InvalidArgumentException If the argument is not a string. - * @return self */ - public function setDefaultSource($defaultSource) + public function setDefaultSource($defaultSource): static { if (!is_string($defaultSource)) { throw new InvalidArgumentException( @@ -129,7 +121,7 @@ public function setDefaultSource($defaultSource) /** * @return string */ - public function defaultSource() + public function defaultSource(): ?string { return $this->defaultSource; } diff --git a/packages/core/src/Charcoal/Model/Service/MetadataConfig.php b/packages/core/src/Charcoal/Model/Service/MetadataConfig.php index 446dc61bf..429d2049d 100644 --- a/packages/core/src/Charcoal/Model/Service/MetadataConfig.php +++ b/packages/core/src/Charcoal/Model/Service/MetadataConfig.php @@ -15,17 +15,13 @@ class MetadataConfig extends AbstractConfig { /** * Metadata search paths. - * - * @var array */ - private $paths = []; + private array $paths = []; /** * The PSR-6 caching service or cache identifier(s) to use. - * - * @var mixed */ - private $cache = true; + private array|bool|null|object $cache = true; /** * Retrieve the default values. @@ -34,7 +30,8 @@ class MetadataConfig extends AbstractConfig * @return mixed An associative array if $key is NULL. * If $key is specified, the value of that data key if it exists, NULL on failure. */ - public function defaults($key = null) + #[\Override] + public function defaults($key = null): array|true|null { $data = [ 'paths' => [], @@ -42,7 +39,7 @@ public function defaults($key = null) ]; if ($key) { - return isset($data[$key]) ? $data[$key] : null; + return ($data[$key] ?? null); } return $data; @@ -53,9 +50,9 @@ public function defaults($key = null) * * @see \Charcoal\Config\AbstractConfig::merge() * @param array|Traversable $data The data to merge. - * @return self */ - public function merge($data) + #[\Override] + public function merge($data): static { foreach ($data as $key => $val) { if ($key === 'paths') { @@ -70,19 +67,15 @@ public function merge($data) return $this; } - /** - * @return array - */ - public function paths() + public function paths(): array { return $this->paths; } /** * @param string[] $paths One or more search paths. - * @return self */ - public function setPaths(array $paths) + public function setPaths(array $paths): static { $this->paths = []; $this->addPaths($paths); @@ -91,9 +84,8 @@ public function setPaths(array $paths) /** * @param string[] $paths One or more search paths. - * @return self */ - public function addPaths(array $paths) + public function addPaths(array $paths): static { foreach ($paths as $path) { $this->addPath($path); @@ -104,9 +96,8 @@ public function addPaths(array $paths) /** * @param string $path A directory path. * @throws InvalidArgumentException If the path is not a string. - * @return self */ - public function addPath($path) + public function addPath($path): static { if (!is_string($path)) { throw new InvalidArgumentException( @@ -117,12 +108,9 @@ public function addPath($path) return $this; } - /** - * @return mixed - */ - public function cache() + public function cache(): bool|object|array { - return isset($this->cache) ? $this->cache : false; + return ($this->cache ?? false); } /** @@ -137,9 +125,8 @@ public function cache() * - a {@see \Psr\Cache\CacheItemPoolInterface PSR-6 caching service}, * that instance will be used by the {@see \Charcoal\Model\Service\MetadataLoader}. * @throws InvalidArgumentException If the cache option is invalid. - * @return self */ - public function setCache($cache) + public function setCache($cache): static { if ($cache === null) { $this->cache = $this->defaults('cache'); diff --git a/packages/core/src/Charcoal/Model/Service/MetadataLoader.php b/packages/core/src/Charcoal/Model/Service/MetadataLoader.php index e424665ff..da23aa015 100644 --- a/packages/core/src/Charcoal/Model/Service/MetadataLoader.php +++ b/packages/core/src/Charcoal/Model/Service/MetadataLoader.php @@ -29,10 +29,8 @@ final class MetadataLoader implements LoggerAwareInterface /** * The PSR-6 caching service. - * - * @var CacheItemPoolInterface */ - private $cachePool; + private \Psr\Cache\CacheItemPoolInterface $cachePool; /** * The cache of metadata instances, indexed by metadata identifier. @@ -43,10 +41,8 @@ final class MetadataLoader implements LoggerAwareInterface /** * The cache of class/interface lineages. - * - * @var array */ - private static $lineageCache = []; + private static array $lineageCache = []; /** * The cache of snake-cased words. @@ -57,24 +53,18 @@ final class MetadataLoader implements LoggerAwareInterface /** * The cache of camel-cased words. - * - * @var array */ - private static $camelCache = []; + private static array $camelCache = []; /** * The base path to prepend to any relative paths to search in. - * - * @var string */ - private $basePath = ''; + private string $basePath = ''; /** * The paths to search in. - * - * @var array */ - private $paths = []; + private array $paths = []; /** * Return new MetadataLoader object. @@ -89,9 +79,8 @@ final class MetadataLoader implements LoggerAwareInterface * - `base_path` * * @param array $data The loader's dependencies. - * @return void */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { $this->setLogger($data['logger']); $this->setCachePool($data['cache']); @@ -121,16 +110,16 @@ public function __construct(array $data = null) * as an array or an instance of {@see MetadataInterface}. * See $metadata for more details. */ - public function load($ident, $metadata = [], array $idents = null) + public function load($ident, $metadata = [], ?array $idents = null) { if (!is_string($ident)) { throw new InvalidArgumentException(sprintf( 'Metadata identifier must be a string, received %s', - is_object($ident) ? get_class($ident) : gettype($ident) + get_debug_type($ident) )); } - if (strpos($ident, '\\') !== false) { + if (str_contains($ident, '\\')) { $ident = $this->metaKeyFromClassName($ident); } @@ -139,12 +128,12 @@ public function load($ident, $metadata = [], array $idents = null) throw new InvalidArgumentException(sprintf( 'Metadata object must be a class name or instance of %s, received %s', MetadataInterface::class, - is_object($metadata) ? get_class($metadata) : gettype($metadata) + get_debug_type($metadata) )); } - if (isset(static::$metadataCache[$ident])) { - $cachedMetadata = static::$metadataCache[$ident]; + if (isset(self::$metadataCache[$ident])) { + $cachedMetadata = self::$metadataCache[$ident]; if (is_object($targetMetadata)) { return $targetMetadata->merge($cachedMetadata); @@ -165,7 +154,7 @@ public function load($ident, $metadata = [], array $idents = null) $targetMetadata = new $metadataType(); $targetMetadata->setData($data); - static::$metadataCache[$ident] = $targetMetadata; + self::$metadataCache[$ident] = $targetMetadata; return $targetMetadata; } @@ -175,9 +164,8 @@ public function load($ident, $metadata = [], array $idents = null) * * @param string $ident The metadata identifier to load. * @throws InvalidArgumentException If the identifier is not a string. - * @return array */ - public function loadMetadataByKey($ident) + public function loadMetadataByKey($ident): array { if (!is_string($ident)) { throw new InvalidArgumentException( @@ -201,9 +189,8 @@ public function loadMetadataByKey($ident) * Fetch the metadata for the given identifiers. * * @param array $idents One or more metadata identifiers to load. - * @return array */ - public function loadMetadataByKeys(array $idents) + public function loadMetadataByKeys(array $idents): array { $metadata = []; foreach ($idents as $metaKey) { @@ -222,14 +209,14 @@ public function loadMetadataByKeys(array $idents) * @param string $ident The FQCN (in snake-case) to load the hierarchy from. * @return array */ - private function hierarchy($ident) + private function hierarchy(string $ident) { if (!is_string($ident)) { return []; } - if (isset(static::$lineageCache[$ident])) { - return static::$lineageCache[$ident]; + if (isset(self::$lineageCache[$ident])) { + return self::$lineageCache[$ident]; } $classname = $this->classNameFromMetaKey($ident); @@ -254,8 +241,8 @@ private function classLineage($class, $ident = null) $ident = $this->metaKeyFromClassName($class); } - if (isset(static::$lineageCache[$ident])) { - return static::$lineageCache[$ident]; + if (isset(self::$lineageCache[$ident])) { + return self::$lineageCache[$ident]; } $class = $this->classNameFromMetaKey($ident); @@ -280,7 +267,7 @@ private function classLineage($class, $ident = null) $hierarchy = array_keys($hierarchy); - static::$lineageCache[$ident] = $hierarchy; + self::$lineageCache[$ident] = $hierarchy; return $hierarchy; } @@ -293,7 +280,7 @@ private function classLineage($class, $ident = null) * and these metadata identifiers are loaded instead. * @return array The data associated with the metadata identifier. */ - private function loadMetadataFromCache($ident, array $idents = null) + private function loadMetadataFromCache($ident, ?array $idents = null) { $cacheKey = $this->cacheKeyFromMetaKey($ident); $cacheItem = $this->cachePool()->getItem($cacheKey); @@ -310,12 +297,7 @@ private function loadMetadataFromCache($ident, array $idents = null) return $metadata; } else { - if (empty($idents)) { - $metadata = $this->loadMetadataByKey($ident); - } else { - $metadata = $this->loadMetadataByKeys($idents); - } - + $metadata = $idents === null || $idents === [] ? $this->loadMetadataByKey($ident) : $this->loadMetadataByKeys($idents); $cacheItem->set($metadata); $this->cachePool()->save($cacheItem); } @@ -346,14 +328,14 @@ private function loadMetadataFromSource($ident) * @throws UnexpectedValueException If the file cannot be loaded. * @return array|null An associative array on success, NULL on failure. */ - private function loadFile($path) + private function loadFile(string $path) { if (file_exists($path)) { return $this->loadJsonFile($path); } $dirs = $this->paths(); - if (empty($dirs)) { + if ($dirs === []) { return null; } @@ -366,7 +348,7 @@ private function loadFile($path) } } - if (empty($data)) { + if ($data === []) { return null; } @@ -380,7 +362,7 @@ private function loadFile($path) * @throws UnexpectedValueException If the file can not correctly be parsed into an array. * @return array An associative array on success. */ - private function loadJsonFile($path) + private function loadJsonFile(string $path) { $data = json_decode(file_get_contents($path), true); if (json_last_error() !== JSON_ERROR_NONE) { @@ -403,9 +385,8 @@ private function loadJsonFile($path) * Generate a store key. * * @param string|string[] $ident The metadata identifier(s) to convert. - * @return string */ - public function serializeMetaKey($ident) + public function serializeMetaKey($ident): string { if (is_array($ident)) { sort($ident); @@ -423,8 +404,7 @@ public function serializeMetaKey($ident) */ public function cacheKeyFromMetaKey($ident) { - $cacheKey = 'metadata/' . str_replace('/', '.', $ident); - return $cacheKey; + return 'metadata/' . str_replace('/', '.', $ident); } /** @@ -436,9 +416,8 @@ public function cacheKeyFromMetaKey($ident) private function filePathFromMetaKey($ident) { $filename = str_replace('\\', '.', $ident); - $filename .= '.json'; - return $filename; + return $filename . '.json'; } /** @@ -451,15 +430,15 @@ private function classNameFromMetaKey($ident) { $key = $ident; - if (isset(static::$camelCache[$key])) { - return static::$camelCache[$key]; + if (isset(self::$camelCache[$key])) { + return self::$camelCache[$key]; } // Change "foo-bar" to "fooBar" $parts = explode('-', $ident); array_walk( $parts, - function (&$i) { + function (&$i): void { $i = ucfirst($i); } ); @@ -471,14 +450,14 @@ function (&$i) { array_walk( $parts, - function (&$i) { + function (&$i): void { $i = ucfirst($i); } ); $classname = trim(implode('\\', $parts), '\\'); - static::$camelCache[$key] = $classname; - static::$snakeCache[$classname] = $key; + self::$camelCache[$key] = $classname; + self::$snakeCache[$classname] = $key; return $classname; } @@ -493,16 +472,16 @@ private function metaKeyFromClassName($class) { $key = trim($class, '\\'); - if (isset(static::$snakeCache[$key])) { - return static::$snakeCache[$key]; + if (isset(self::$snakeCache[$key])) { + return self::$snakeCache[$key]; } - $ident = strtolower(preg_replace('/([a-z])([A-Z])/', '$1-$2', $class)); + $ident = strtolower((string)preg_replace('/([a-z])([A-Z])/', '$1-$2', $class)); $ident = str_replace('\\', '/', strtolower($ident)); $ident = ltrim($ident, '/'); - static::$snakeCache[$key] = $ident; - static::$camelCache[$ident] = $key; + self::$snakeCache[$key] = $ident; + self::$camelCache[$ident] = $key; return $ident; } @@ -515,9 +494,8 @@ private function metaKeyFromClassName($class) * @param mixed $metadata The metadata type or container to validate. * @param string|null $type If provided, then it is filled with the resolved metadata type. * @param mixed|null $bag If provided, then it is filled with the resolved metadata container. - * @return boolean */ - private function validateMetadataContainer($metadata, &$type = null, &$bag = null) + private function validateMetadataContainer($metadata, &$type = null, &$bag = null): bool { // If variables are provided, clear existing values. $type = null; @@ -531,7 +509,7 @@ private function validateMetadataContainer($metadata, &$type = null, &$bag = nul if (is_a($metadata, MetadataInterface::class, true)) { if (is_object($metadata)) { - $type = get_class($metadata); + $type = $metadata::class; $bag = $metadata; return true; } @@ -549,9 +527,8 @@ private function validateMetadataContainer($metadata, &$type = null, &$bag = nul * * @param string $basePath The base path to use. * @throws InvalidArgumentException If the base path parameter is not a string. - * @return void */ - private function setBasePath($basePath) + private function setBasePath($basePath): void { if (!is_string($basePath)) { throw new InvalidArgumentException( @@ -565,10 +542,8 @@ private function setBasePath($basePath) /** * Retrieve the base path for relative search paths. - * - * @return string */ - private function basePath() + private function basePath(): string { return $this->basePath; } @@ -577,9 +552,8 @@ private function basePath() * Assign many search paths. * * @param string[] $paths One or more search paths. - * @return void */ - private function setPaths(array $paths) + private function setPaths(array $paths): void { $this->paths = []; $this->addPaths($paths); @@ -590,7 +564,7 @@ private function setPaths(array $paths) * * @return string[] */ - private function paths() + private function paths(): array { return $this->paths; } @@ -599,9 +573,8 @@ private function paths() * Append many search paths. * * @param string[] $paths One or more search paths. - * @return self */ - private function addPaths(array $paths) + private function addPaths(array $paths): self { foreach ($paths as $path) { $this->addPath($path); @@ -614,9 +587,8 @@ private function addPaths(array $paths) * Append a search path. * * @param string $path A directory path. - * @return self */ - private function addPath($path) + private function addPath($path): self { $path = $this->resolvePath($path); @@ -632,9 +604,8 @@ private function addPath($path) * * @param string $path The path to resolve. * @throws InvalidArgumentException If the path is invalid. - * @return string */ - private function resolvePath($path) + private function resolvePath($path): string { if (!is_string($path)) { throw new InvalidArgumentException( @@ -645,7 +616,7 @@ private function resolvePath($path) $basePath = $this->basePath(); $path = trim($path, '/\\'); - if ($basePath && strpos($path, $basePath) === false) { + if ($basePath && !str_contains($path, $basePath)) { $path = $basePath . DIRECTORY_SEPARATOR . $path; } @@ -656,9 +627,8 @@ private function resolvePath($path) * Validate a resolved path. * * @param string $path The path to validate. - * @return string */ - private function validatePath($path) + private function validatePath(string $path): bool { return is_dir($path); } @@ -667,19 +637,16 @@ private function validatePath($path) * Set the cache service. * * @param CacheItemPoolInterface $cache A PSR-6 compliant cache pool instance. - * @return void */ - private function setCachePool(CacheItemPoolInterface $cache) + private function setCachePool(CacheItemPoolInterface $cache): void { $this->cachePool = $cache; } /** * Retrieve the cache service. - * - * @return CacheItemPoolInterface */ - private function cachePool() + private function cachePool(): \Psr\Cache\CacheItemPoolInterface { return $this->cachePool; } diff --git a/packages/core/src/Charcoal/Model/Service/ModelBuilder.php b/packages/core/src/Charcoal/Model/Service/ModelBuilder.php index d23fc9afc..667d238a1 100644 --- a/packages/core/src/Charcoal/Model/Service/ModelBuilder.php +++ b/packages/core/src/Charcoal/Model/Service/ModelBuilder.php @@ -14,22 +14,13 @@ */ final class ModelBuilder { - public const DEFAULT_SOURCE_TYPE = 'database'; + public const string DEFAULT_SOURCE_TYPE = 'database'; - /** - * @var FactoryInterface - */ - private $factory; + private \Charcoal\Factory\FactoryInterface $factory; - /** - * @var MetadataLoader - */ - private $metadataLoader; + private \Charcoal\Model\Service\MetadataLoader $metadataLoader; - /** - * @var FactoryInterface - */ - private $sourceFactory; + private \Charcoal\Factory\FactoryInterface $sourceFactory; /** * @param array $data Constructor dependencies. @@ -84,27 +75,24 @@ public function __invoke($objType, $metadataIdent = null, $sourceIdent = null) /** * @param FactoryInterface $factory The factory to use to create models. - * @return void */ - private function setFactory(FactoryInterface $factory) + private function setFactory(FactoryInterface $factory): void { $this->factory = $factory; } /** * @param MetadataLoader $loader The loader instance, used to load metadata. - * @return void */ - private function setMetadataLoader(MetadataLoader $loader) + private function setMetadataLoader(MetadataLoader $loader): void { $this->metadataLoader = $loader; } /** * @param FactoryInterface $factory The factory to use to create models. - * @return void */ - private function setSourceFactory(FactoryInterface $factory) + private function setSourceFactory(FactoryInterface $factory): void { $this->sourceFactory = $factory; } @@ -118,7 +106,7 @@ private function setSourceFactory(FactoryInterface $factory) */ private function createMetadata($objType, $metadataIdent = null) { - $metadataIdent = ($metadataIdent !== null) ? $metadataIdent : $objType; + $metadataIdent ??= $objType; return $this->metadataLoader->load($metadataIdent, ModelMetadata::class); } @@ -139,11 +127,11 @@ private function createSource(ModelMetadata $metadata, $sourceIdent = null) if (!$sourceConfig) { throw new UnexpectedValueException( - sprintf('Can not create %s source: "%s" is not defined in metadata.', get_class($this), $sourceIdent) + sprintf('Can not create %s source: "%s" is not defined in metadata.', self::class, $sourceIdent) ); } - $sourceType = isset($sourceConfig['type']) ? $sourceConfig['type'] : self::DEFAULT_SOURCE_TYPE; + $sourceType = ($sourceConfig['type'] ?? self::DEFAULT_SOURCE_TYPE); $source = $this->sourceFactory->create($sourceType); $source->setData($sourceConfig); diff --git a/packages/core/src/Charcoal/Model/Service/ModelLoader.php b/packages/core/src/Charcoal/Model/Service/ModelLoader.php index 3e776aa24..342803078 100644 --- a/packages/core/src/Charcoal/Model/Service/ModelLoader.php +++ b/packages/core/src/Charcoal/Model/Service/ModelLoader.php @@ -42,17 +42,13 @@ final class ModelLoader implements ArrayAccess /** * The model factory. - * - * @var FactoryInterface */ - private $factory; + private \Charcoal\Factory\FactoryInterface $factory; /** * The PSR-6 caching service. - * - * @var CacheItemPoolInterface */ - private $cachePool; + private \Psr\Cache\CacheItemPoolInterface $cachePool; /** * Construct a Model Loader with the dependencies @@ -90,7 +86,7 @@ public function __construct(array $data) * @param mixed $args Unused; Method arguments. * @return ModelInterface */ - public function __call($ident, $args = null) + public function __call(string $ident, ?array $args = null) { unset($args); @@ -103,7 +99,7 @@ public function __call($ident, $args = null) * @param string|integer $ident The object identifier to load. * @return ModelInterface */ - public function __get($ident) + public function __get(string $ident): mixed { return $this->load($ident); } @@ -115,7 +111,7 @@ public function __get($ident) * @param string $ident The object identifier to lookup. * @return boolean */ - public function __isset($ident) + public function __isset(string $ident) { return true; } @@ -127,7 +123,7 @@ public function __isset($ident) * @throws LogicException This method should never be called. * @return void */ - public function __unset($ident) + public function __unset(string $ident) { throw new LogicException( 'Can not unset value on a loader' @@ -136,16 +132,14 @@ public function __unset($ident) // Satisfies ArrayAccess // ============================================================================================= - /** * Determine if an object exists by its key. * * @todo Needs implementation * @see ArrayAccess::offsetExists * @param string $ident The object identifier to lookup. - * @return boolean */ - public function offsetExists($ident) + public function offsetExists($ident): bool { return true; } @@ -157,7 +151,7 @@ public function offsetExists($ident) * @param string|integer $ident The object identifier to load. * @return ModelInterface */ - public function offsetGet($ident) + public function offsetGet($ident): ModelInterface { return $this->load($ident); } @@ -169,9 +163,8 @@ public function offsetGet($ident) * @param string|integer $ident The $object identifier. * @param mixed $obj The object to add. * @throws LogicException This method should never be called. - * @return void */ - public function offsetSet($ident, $obj) + public function offsetSet($ident, $obj): never { throw new LogicException( 'Can not set value on a loader' @@ -184,9 +177,8 @@ public function offsetSet($ident, $obj) * @see ArrayAccess::offsetUnset() * @param string|integer $ident The object identifier to remove. * @throws LogicException This method should never be called. - * @return void */ - public function offsetUnset($ident) + public function offsetUnset($ident): never { throw new LogicException( 'Can not unset value on a loader' @@ -215,14 +207,11 @@ public function load($ident, $useCache = true, $reloadObj = false) $cacheKey = $this->cacheKey($ident); $cacheItem = $this->cachePool->getItem($cacheKey); - if (!$reloadObj) { - if ($cacheItem->isHit()) { - $data = $cacheItem->get(); - $obj = $this->factory->create($this->objType); - $obj->setData($data); - - return $obj; - } + if (!$reloadObj && $cacheItem->isHit()) { + $data = $cacheItem->get(); + $obj = $this->factory->create($this->objType); + $obj->setData($data); + return $obj; } $obj = $this->loadFromSource($ident); @@ -264,9 +253,7 @@ private function cacheKey($ident) $this->setObjKey($model->key()); } - $cacheKey = 'object/' . str_replace('/', '.', $this->objType . '.' . $this->objKey . '.' . $ident); - - return $cacheKey; + return 'object/' . str_replace('/', '.', $this->objType . '.' . $this->objKey . '.' . $ident); } /** @@ -276,9 +263,8 @@ private function cacheKey($ident) * * @param string $objType The object type to load with this loader. * @throws InvalidArgumentException If the object type is not a string. - * @return self */ - private function setObjType($objType) + private function setObjType($objType): self { if (!is_string($objType)) { throw new InvalidArgumentException( @@ -287,7 +273,7 @@ private function setObjType($objType) } $objType = preg_replace('/([a-z])([A-Z])/', '$1-$2', $objType); - $objType = strtolower(str_replace('\\', '/', trim($objType, '\\/'))); + $objType = strtolower(str_replace('\\', '/', trim((string)$objType, '\\/'))); $this->objType = $objType; return $this; @@ -298,9 +284,8 @@ private function setObjType($objType) * * @param string $objKey The object key to use for laoding. * @throws InvalidArgumentException If the object key is not a string. - * @return self */ - private function setObjKey($objKey) + private function setObjKey($objKey): self { if (empty($objKey) && !is_numeric($objKey)) { $this->objKey = null; @@ -321,9 +306,8 @@ private function setObjKey($objKey) * Set the model factory. * * @param FactoryInterface $factory The factory to create models. - * @return self */ - private function setFactory(FactoryInterface $factory) + private function setFactory(FactoryInterface $factory): self { $this->factory = $factory; return $this; @@ -333,9 +317,8 @@ private function setFactory(FactoryInterface $factory) * Set the cache pool handler. * * @param CacheItemPoolInterface $cachePool A PSR-6 compatible cache pool. - * @return self */ - private function setCachePool(CacheItemPoolInterface $cachePool) + private function setCachePool(CacheItemPoolInterface $cachePool): self { $this->cachePool = $cachePool; return $this; diff --git a/packages/core/src/Charcoal/Model/Service/ModelLoaderBuilder.php b/packages/core/src/Charcoal/Model/Service/ModelLoaderBuilder.php index b1c66116c..d4f34fd84 100644 --- a/packages/core/src/Charcoal/Model/Service/ModelLoaderBuilder.php +++ b/packages/core/src/Charcoal/Model/Service/ModelLoaderBuilder.php @@ -16,15 +16,9 @@ */ final class ModelLoaderBuilder { - /** - * @var FactoryInterface - */ - private $factory; + private \Charcoal\Factory\FactoryInterface $factory; - /** - * @var CacheItemPoolInterface - */ - private $cachePool; + private \Psr\Cache\CacheItemPoolInterface $cachePool; /** * @param array $data Builder dependencies. @@ -38,9 +32,8 @@ public function __construct(array $data) /** * @param string $objType The object type of the ModelLoader. * @param string $objKey Optional object key, to set on the ModelLoader. - * @return ModelLoader */ - public function build($objType, $objKey = null) + public function build($objType, $objKey = null): \Charcoal\Model\Service\ModelLoader { return new ModelLoader([ 'factory' => $this->factory, @@ -55,27 +48,24 @@ public function build($objType, $objKey = null) * * @param string $objType The object type of the ModelLoader. * @param string $objKey Optional object key, to set on the ModelLoader. - * @return ModelLoader */ - public function __invoke($objType, $objKey = null) + public function __invoke($objType, $objKey = null): \Charcoal\Model\Service\ModelLoader { return $this->build($objType, $objKey); } /** * @param FactoryInterface $factory The factory to use to create models. - * @return void */ - private function setFactory(FactoryInterface $factory) + private function setFactory(FactoryInterface $factory): void { $this->factory = $factory; } /** * @param CacheItemPoolInterface $cachePool The PSR-6 compliant cache pool. - * @return void */ - private function setCachePool(CacheItemPoolInterface $cachePool) + private function setCachePool(CacheItemPoolInterface $cachePool): void { $this->cachePool = $cachePool; } diff --git a/packages/core/src/Charcoal/Model/ServiceProvider/ModelServiceProvider.php b/packages/core/src/Charcoal/Model/ServiceProvider/ModelServiceProvider.php index 3212f075b..aa52bc186 100644 --- a/packages/core/src/Charcoal/Model/ServiceProvider/ModelServiceProvider.php +++ b/packages/core/src/Charcoal/Model/ServiceProvider/ModelServiceProvider.php @@ -48,9 +48,8 @@ class ModelServiceProvider implements ServiceProviderInterface { /** * @param Container $container A Pimple DI container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { $this->registerModelDependencies($container); $this->registerMetadataDependencies($container); @@ -68,35 +67,29 @@ protected function registerBuilderDependencies(Container $container) * @param Container $container A Pimple DI container. * @return \Charcoal\Factory\FactoryInterface */ - $container['model/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => ModelInterface::class, - 'arguments' => [ $container['model/dependencies'] ] - ]); - }; + $container['model/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => ModelInterface::class, + 'arguments' => [ $container['model/dependencies'] ] + ])); /** * @param Container $container A Pimple DI container. * @return ModelBuilder */ - $container['model/builder'] = function (Container $container) { - return new ModelBuilder([ - 'factory' => $container['model/factory'], - 'metadata_loader' => $container['metadata/loader'], - 'source_factory' => $container['source/factory'] - ]); - }; + $container['model/builder'] = (fn(Container $container): \Charcoal\Model\Service\ModelBuilder => new ModelBuilder([ + 'factory' => $container['model/factory'], + 'metadata_loader' => $container['metadata/loader'], + 'source_factory' => $container['source/factory'] + ])); /** * @param Container $container A Pimple DI container. * @return ModelLoaderBuilder */ - $container['model/loader/builder'] = function (Container $container) { - return new ModelLoaderBuilder([ - 'factory' => $container['model/factory'], - 'cache' => $container['cache'] - ]); - }; + $container['model/loader/builder'] = (fn(Container $container): \Charcoal\Model\Service\ModelLoaderBuilder => new ModelLoaderBuilder([ + 'factory' => $container['model/factory'], + 'cache' => $container['cache'] + ])); } /** @@ -112,9 +105,7 @@ protected function registerCollectionDependencies(Container $container) * @param Container $container A Pimple DI container. * @return \ArrayAccess|\Traversable */ - $container['model/collection'] = $container->factory(function (Container $container) { - return new $container['model/collection/class'](); - }); + $container['model/collection'] = $container->factory(fn(Container $container): object => new $container['model/collection/class']()); /** * @param Container $container A Pimple DI container. @@ -129,16 +120,14 @@ protected function registerCollectionDependencies(Container $container) * @param Container $container A Pimple DI container. * @return \Charcoal\Factory\FactoryInterface */ - $container['model/collection/loader/factory'] = function (Container $container) { - return new Factory([ - 'default_class' => CollectionLoader::class, - 'arguments' => [[ - 'logger' => $container['logger'], - 'factory' => $container['model/factory'], - 'collection' => $container['model/collection/class'] - ]] - ]); - }; + $container['model/collection/loader/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'default_class' => CollectionLoader::class, + 'arguments' => [[ + 'logger' => $container['logger'], + 'factory' => $container['model/factory'], + 'collection' => $container['model/collection/class'] + ]] + ])); } /** @@ -153,16 +142,14 @@ protected function registerModelDependencies(Container $container) * @param Container $container A Pimple DI container. * @return array The model dependencies array. */ - $container['model/dependencies'] = function (Container $container) { - return [ - 'container' => $container, - 'logger' => $container['logger'], - 'view' => $container['view'], - 'property_factory' => $container['property/factory'], - 'metadata_loader' => $container['metadata/loader'], - 'source_factory' => $container['source/factory'] - ]; - }; + $container['model/dependencies'] = (fn(Container $container): array => [ + 'container' => $container, + 'logger' => $container['logger'], + 'view' => $container['view'], + 'property_factory' => $container['property/factory'], + 'metadata_loader' => $container['metadata/loader'], + 'source_factory' => $container['source/factory'] + ]); } // The property factory might be already set from elsewhere; defines it if not. @@ -171,22 +158,20 @@ protected function registerModelDependencies(Container $container) * @param Container $container A Pimple DI container. * @return \Charcoal\Factory\FactoryInterface */ - $container['property/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => PropertyInterface::class, - 'default_class' => GenericProperty::class, - 'resolver_options' => [ - 'prefix' => '\\Charcoal\\Property\\', - 'suffix' => 'Property' - ], - 'arguments' => [[ - 'container' => $container, - 'database' => $container['database'], - 'logger' => $container['logger'], - 'translator' => $container['translator'] - ]] - ]); - }; + $container['property/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => PropertyInterface::class, + 'default_class' => GenericProperty::class, + 'resolver_options' => [ + 'prefix' => '\\Charcoal\\Property\\', + 'suffix' => 'Property' + ], + 'arguments' => [[ + 'container' => $container, + 'database' => $container['database'], + 'logger' => $container['logger'], + 'translator' => $container['translator'] + ]] + ])); } if (!isset($container['source/factory'])) { @@ -194,19 +179,17 @@ protected function registerModelDependencies(Container $container) * @param Container $container A Pimple DI container. * @return \Charcoal\Factory\FactoryInterface */ - $container['source/factory'] = function (Container $container) { - return new Factory([ - 'map' => [ - 'database' => DatabaseSource::class - ], - 'base_class' => SourceInterface::class, - 'arguments' => [[ - 'logger' => $container['logger'], - 'cache' => $container['cache'], - 'pdo' => $container['database'] - ]] - ]); - }; + $container['source/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'map' => [ + 'database' => DatabaseSource::class + ], + 'base_class' => SourceInterface::class, + 'arguments' => [[ + 'logger' => $container['logger'], + 'cache' => $container['cache'], + 'pdo' => $container['database'] + ]] + ])); } } @@ -223,9 +206,9 @@ protected function registerMetadataDependencies(Container $container) * @param Container $container Pimple DI container. * @return MetadataConfig */ - $container['metadata/config'] = function (Container $container) { - $appConfig = isset($container['config']) ? $container['config'] : []; - $metaConfig = isset($appConfig['metadata']) ? $appConfig['metadata'] : null; + $container['metadata/config'] = function (Container $container): \Charcoal\Model\Service\MetadataConfig { + $appConfig = ($container['config'] ?? []); + $metaConfig = ($appConfig['metadata'] ?? null); $metaConfig = new MetadataConfig($metaConfig); if (isset($container['module/classes'])) { @@ -234,7 +217,7 @@ protected function registerMetadataDependencies(Container $container) $modules = $container['module/classes']; foreach ($modules as $module) { if (defined(sprintf('%s::APP_CONFIG', $module))) { - $configPath = ltrim($module::APP_CONFIG, '/'); + $configPath = ltrim((string)$module::APP_CONFIG, '/'); $configPath = $basePath . DIRECTORY_SEPARATOR . $configPath; $configData = $metaConfig->loadFile($configPath); @@ -247,7 +230,7 @@ protected function registerMetadataDependencies(Container $container) }; } - if (!empty($extraPaths)) { + if ($extraPaths !== []) { $metaConfig->addPaths($extraPaths); } } @@ -288,7 +271,7 @@ protected function registerMetadataDependencies(Container $container) * @param Container $container A Pimple DI container. * @return MetadataLoader */ - $container['metadata/loader'] = function (Container $container) { + $container['metadata/loader'] = function (Container $container): \Charcoal\Model\Service\MetadataLoader { $appConfig = $container['config']; $metaConfig = $container['metadata/config']; diff --git a/packages/core/src/Charcoal/Source/AbstractExpression.php b/packages/core/src/Charcoal/Source/AbstractExpression.php index fe6b88a61..5b48a0ffa 100644 --- a/packages/core/src/Charcoal/Source/AbstractExpression.php +++ b/packages/core/src/Charcoal/Source/AbstractExpression.php @@ -71,7 +71,7 @@ abstract public function data(); */ public function setActive($active) { - $this->active = !!$active; + $this->active = (bool)$active; return $this; } @@ -183,7 +183,7 @@ public static function quoteIdentifier($identifier, $tableName = null) if (!is_string($identifier)) { throw new InvalidArgumentException(sprintf( 'Field Name must be a string, received %s', - is_object($identifier) ? get_class($identifier) : gettype($identifier) + get_debug_type($identifier) )); } @@ -191,7 +191,7 @@ public static function quoteIdentifier($identifier, $tableName = null) if (!is_string($tableName)) { throw new InvalidArgumentException(sprintf( 'Table Name must be a string, received %s', - is_object($tableName) ? get_class($tableName) : gettype($tableName) + get_debug_type($tableName) )); } @@ -201,11 +201,7 @@ public static function quoteIdentifier($identifier, $tableName = null) ); } - if ($identifier === '*') { - $template = '%1$s.*'; - } else { - $template = '%1$s.`%2$s`'; - } + $template = $identifier === '*' ? '%1$s.*' : '%1$s.`%2$s`'; return sprintf($template, $tableName, $identifier); } @@ -255,9 +251,9 @@ public static function isCallable($value) * @uses self::diffValues() * @return array An associative array containing only mutated values. */ - public function jsonSerialize() + public function jsonSerialize(): array { - return array_udiff_assoc($this->data(), $this->defaultData(), [ $this, 'diffValues' ]); + return array_udiff_assoc($this->data(), $this->defaultData(), $this->diffValues(...)); } /** @@ -276,9 +272,8 @@ public function serialize() * * @see Serializable * @param string $data The serialized data. - * @return void */ - public function unserialize($data) + public function unserialize($data): void { $data = unserialize($data); $this->setData($data); diff --git a/packages/core/src/Charcoal/Source/AbstractSource.php b/packages/core/src/Charcoal/Source/AbstractSource.php index b5e1dab1e..a980076ca 100644 --- a/packages/core/src/Charcoal/Source/AbstractSource.php +++ b/packages/core/src/Charcoal/Source/AbstractSource.php @@ -29,6 +29,7 @@ /** * Data Storage Source Handler. */ +#[\AllowDynamicProperties] abstract class AbstractSource implements SourceInterface, ConfigurableInterface, @@ -227,7 +228,6 @@ protected function resolvePropertyName($property) * - as 3 parameters: `property`, `value` and `options` * - `addFilter('foo', 42, ['operator' => '<=']);` * - * @deprecated 0.3 To be replaced with FilterCollectionTrait::addFilter() * * @uses self::parseFilterWithModel() * @uses FilterCollectionTrait::processFilter() @@ -239,8 +239,10 @@ protected function resolvePropertyName($property) * @param array $options Optional extra settings to apply on the filter. * @throws InvalidArgumentException If the $param argument is invalid. * @return self + * */ - public function addFilter($param, $value = null, array $options = null) + #![\Deprecated(message: '0.3 To be replaced with FilterCollectionTrait::addFilter()') + public function addFilter($param, $value = null, ?array $options = null) { if (is_string($param) && $value !== null) { $expr = $this->createFilter(); @@ -292,7 +294,7 @@ protected function parseFilterWithModel(FilterInterface $filter) } if ($filter instanceof FilterCollectionInterface) { - $filter->traverseFilters(function (FilterInterface $expr) { + $filter->traverseFilters(function (FilterInterface $expr): void { $this->parseFilterWithModel($expr); }); } @@ -308,7 +310,7 @@ protected function parseFilterWithModel(FilterInterface $filter) * @param array $data Optional expression data. * @return FilterInterface A new filter expression object. */ - protected function createFilter(array $data = null) + protected function createFilter(?array $data = null) { $filter = new Filter(); if ($data !== null) { @@ -320,7 +322,6 @@ protected function createFilter(array $data = null) /** * Append a query order on the source. * - * @deprecated 0.3 To be replaced with OrderCollectionTrait::addOrder() * * @uses self::parseOrderWithModel() * @uses OrderCollectionTrait::processOrder() @@ -333,7 +334,8 @@ protected function createFilter(array $data = null) * @throws InvalidArgumentException If the $param argument is invalid. * @return self */ - public function addOrder($param, $mode = 'asc', array $options = null) + #![\Deprecated(message: '0.3 To be replaced with OrderCollectionTrait::addOrder()')] + public function addOrder($param, $mode = 'asc', ?array $options = null) { if (is_string($param) && $mode !== null) { $expr = $this->createOrder(); @@ -380,7 +382,7 @@ protected function parseOrderWithModel(OrderInterface $order) } if ($order instanceof OrderCollectionInterface) { - $order->traverseOrders(function (OrderInterface $expr) { + $order->traverseOrders(function (OrderInterface $expr): void { $this->parseOrderWithModel($expr); }); } @@ -395,7 +397,7 @@ protected function parseOrderWithModel(OrderInterface $order) * @param array $data Optional expression data. * @return OrderInterface */ - protected function createOrder(array $data = null) + protected function createOrder(?array $data = null) { $order = new Order(); if ($data !== null) { @@ -467,7 +469,7 @@ public function pagination() * @param array $data Optional clause data. * @return PaginationInterface */ - protected function createPagination(array $data = null) + protected function createPagination(?array $data = null) { $pagination = new Pagination(); if ($data !== null) { @@ -529,10 +531,9 @@ public function numPerPage() * @param array $data Optional data. * @return SourceConfig */ - public function createConfig(array $data = null) + public function createConfig(?array $data = null) { - $config = new SourceConfig($data); - return $config; + return new SourceConfig($data); } /** @@ -542,7 +543,7 @@ public function createConfig(array $data = null) * @param StorableInterface $item Optional item to load into. * @return StorableInterface */ - abstract public function loadItem($ident, StorableInterface $item = null); + abstract public function loadItem($ident, ?StorableInterface $item = null); /** * Load items for the given model. @@ -550,7 +551,7 @@ abstract public function loadItem($ident, StorableInterface $item = null); * @param StorableInterface|null $item Optional model. * @return StorableInterface[] */ - abstract public function loadItems(StorableInterface $item = null); + abstract public function loadItems(?StorableInterface $item = null); /** * Save an item (create a new row) in storage. @@ -568,7 +569,7 @@ abstract public function saveItem(StorableInterface $item); * @param array $properties The list of properties to update, if not all. * @return boolean TRUE if the item was updated, otherwise FALSE. */ - abstract public function updateItem(StorableInterface $item, array $properties = null); + abstract public function updateItem(StorableInterface $item, ?array $properties = null); /** * Delete an item from storage. @@ -577,7 +578,7 @@ abstract public function updateItem(StorableInterface $item, array $properties = * @throws UnexpectedValueException If the item does not have an ID. * @return boolean TRUE if the item was deleted, otherwise FALSE. */ - abstract public function deleteItem(StorableInterface $item = null); + abstract public function deleteItem(?StorableInterface $item = null); /** * Allow an object to define how the key getter are called. @@ -597,7 +598,7 @@ protected function getter($key) * @param string $key The key to get the setter from. * @return string The setter method name, for a given key. */ - protected function setter($key) + protected function setter(string $key) { $setter = 'set_' . $key; return $this->camelize($setter); @@ -611,7 +612,7 @@ protected function setter($key) */ protected function camelize($str) { - return lcfirst(implode('', array_map('ucfirst', explode('_', $str)))); + return lcfirst(implode('', array_map(ucfirst(...), explode('_', $str)))); } /** @@ -620,7 +621,7 @@ protected function camelize($str) protected function getModelClassForException() { if ($this->hasModel()) { - return get_class($this->model()); + return $this->model()::class; } return 'Unknown Model'; diff --git a/packages/core/src/Charcoal/Source/Database/DatabaseExpression.php b/packages/core/src/Charcoal/Source/Database/DatabaseExpression.php index c58ff74bd..5526333a7 100644 --- a/packages/core/src/Charcoal/Source/Database/DatabaseExpression.php +++ b/packages/core/src/Charcoal/Source/Database/DatabaseExpression.php @@ -1,5 +1,7 @@ operator(), [ '!', 'NOT' ]); } @@ -88,9 +87,8 @@ public function isNegating() * * @param string[] $conditions The list of conditions to compile. * @param string|null $conjunction The condition separator. - * @return string */ - protected function compileConditions(array $conditions, $conjunction = null) + protected function compileConditions(array $conditions, $conjunction = null): string { if (count($conditions) === 1) { return $conditions[0]; @@ -124,9 +122,8 @@ protected function byCondition() * Retrieve the correctly parenthesized and nested WHERE conditions. * * @throws UnexpectedValueException If the custom condition is empty. - * @return string */ - protected function byFilters() + protected function byFilters(): string { if (!$this->hasFilters()) { throw new UnexpectedValueException( @@ -140,7 +137,7 @@ protected function byFilters() $filter = $filter->sql(); } - if ($filter && strlen($filter) > 0) { + if ($filter && (string)$filter !== '') { $conditions[] = $filter; } } @@ -153,12 +150,11 @@ protected function byFilters() * * @todo Values are often not quoted. * @throws UnexpectedValueException If any required property, function, operator, or value is empty. - * @return string */ - protected function byPredicate() + protected function byPredicate(): string { $fields = $this->fieldIdentifiers(); - if (empty($fields)) { + if ($fields === []) { throw new UnexpectedValueException( 'Property is required.' ); @@ -169,11 +165,7 @@ protected function byPredicate() $operator = $this->operator(); $function = $this->func(); foreach ($fields as $fieldName) { - if ($function !== null) { - $target = sprintf('%1$s(%2$s)', $function, $fieldName); - } else { - $target = $fieldName; - } + $target = $function !== null ? sprintf('%1$s(%2$s)', $function, $fieldName) : $fieldName; switch ($operator) { case 'FIND_IN_SET': diff --git a/packages/core/src/Charcoal/Source/Database/DatabaseOrder.php b/packages/core/src/Charcoal/Source/Database/DatabaseOrder.php index c587e600a..9b1ce2ee3 100644 --- a/packages/core/src/Charcoal/Source/Database/DatabaseOrder.php +++ b/packages/core/src/Charcoal/Source/Database/DatabaseOrder.php @@ -29,10 +29,9 @@ class DatabaseOrder extends Order implements /** * Retrieve the default values for sorting. - * - * @return array */ - public function defaultData() + #[\Override] + public function defaultData(): array { $defaults = parent::defaultData(); $defaults['table'] = DatabaseSource::DEFAULT_TABLE_ALIAS; @@ -77,10 +76,8 @@ public function sql() /** * Retrieve the ORDER BY clause for the {@see self::MODE_RANDOM} mode. - * - * @return string */ - protected function byRandom() + protected function byRandom(): string { return 'RAND()'; } @@ -89,12 +86,11 @@ protected function byRandom() * Generate the ORDER BY clause(s) for the direction mode. * * @throws UnexpectedValueException If any required property is empty. - * @return string */ - protected function byProperty() + protected function byProperty(): string { $fields = $this->fieldIdentifiers(); - if (empty($fields)) { + if ($fields === []) { throw new UnexpectedValueException( 'Property is required.' ); @@ -127,19 +123,18 @@ protected function byCondition() * Retrieve the ORDER BY clause for the {@see self::MODE_VALUES} mode. * * @throws UnexpectedValueException If any required property or values is empty. - * @return string */ - protected function byValues() + protected function byValues(): string { $fields = $this->fieldIdentifiers(); - if (empty($fields)) { + if ($fields === []) { throw new UnexpectedValueException( 'Property is required.' ); } $values = $this->prepareValues($this->values()); - if (empty($values)) { + if ($values === []) { throw new UnexpectedValueException(sprintf( 'Value can not be empty on fields: %s', implode(', ', $fields) @@ -164,7 +159,7 @@ protected function byValues() * @param mixed $values The value to be normalized. * @return array Returns a collection of parsed values. */ - public function prepareValues($values) + public function prepareValues($values): array { if (empty($values)) { return []; @@ -174,9 +169,8 @@ public function prepareValues($values) $values = (array)$values; } - $values = array_filter($values, 'is_scalar'); - $values = array_map('self::quoteValue', $values); + $values = array_filter($values, is_scalar(...)); - return $values; + return array_map(self::quoteValue(...), $values); } } diff --git a/packages/core/src/Charcoal/Source/Database/DatabasePagination.php b/packages/core/src/Charcoal/Source/Database/DatabasePagination.php index 34af33a3f..6b9993a7e 100644 --- a/packages/core/src/Charcoal/Source/Database/DatabasePagination.php +++ b/packages/core/src/Charcoal/Source/Database/DatabasePagination.php @@ -1,5 +1,7 @@ active() && $this->hasLimit()) { $limit = $this->limit(); @@ -31,10 +33,8 @@ public function sql() /** * Determine if the expression has a number per page. - * - * @return boolean */ - public function hasLimit() + public function hasLimit(): bool { return ($this->limit() > 0); } @@ -51,10 +51,8 @@ public function limit() /** * Retrieve the offset from the page number and count. - * - * @return integer */ - public function offset() + public function offset(): int { $page = $this->page(); $limit = $this->numPerPage(); diff --git a/packages/core/src/Charcoal/Source/DatabaseSource.php b/packages/core/src/Charcoal/Source/DatabaseSource.php index 1c27b0ef9..934af45bc 100644 --- a/packages/core/src/Charcoal/Source/DatabaseSource.php +++ b/packages/core/src/Charcoal/Source/DatabaseSource.php @@ -22,6 +22,7 @@ /** * Database Source Handler, through PDO. */ +#[\AllowDynamicProperties] class DatabaseSource extends AbstractSource implements DatabaseSourceInterface { @@ -32,6 +33,8 @@ class DatabaseSource extends AbstractSource implements public const MYSQL_DRIVER_NAME = 'mysql'; public const SQLITE_DRIVER_NAME = 'sqlite'; + protected array $tableExistsCache = []; + /** * The database connector. * @@ -41,10 +44,8 @@ class DatabaseSource extends AbstractSource implements /** * The {@see self::$model}'s table name. - * - * @var string */ - private $table; + private ?string $table = null; /** * Create a new database handler. @@ -80,9 +81,8 @@ public function db() * * @param string $table The source table. * @throws InvalidArgumentException If argument is not a string or alphanumeric/underscore. - * @return self */ - public function setTable($table) + public function setTable($table): static { if (!is_string($table)) { throw new InvalidArgumentException(sprintf( @@ -97,7 +97,7 @@ public function setTable($table) * are valid table names; Although SQL can support more, * there's really no reason to. */ - if (!preg_match('/[A-Za-z0-9_]/', $table)) { + if (!preg_match('/\w/', $table)) { throw new InvalidArgumentException(sprintf( '[%s] Database table name "%s" is invalid: must be alphanumeric / underscore', $this->getModelClassForException(), @@ -111,21 +111,18 @@ public function setTable($table) /** * Determine if a table is assigned. - * - * @return boolean */ - public function hasTable() + public function hasTable(): bool { - return !empty($this->table); + return !in_array($this->table, [null, '', '0'], true); } /** * Get the database's current table. * * @throws RuntimeException If the table was not set. - * @return string */ - public function table() + public function table(): string { if ($this->table === null) { throw new RuntimeException(sprintf( @@ -141,7 +138,7 @@ public function table() * * @return boolean TRUE if the table was created, otherwise FALSE. */ - public function createTable() + public function createTable(): bool { if ($this->tableExists() === true) { return true; @@ -178,7 +175,7 @@ public function createTable() /** @todo Add indexes for all defined list constraints (yea... tough job...) */ if ($driver === self::MYSQL_DRIVER_NAME) { $engine = 'InnoDB'; - $query .= ') ENGINE=' . $engine . ' DEFAULT CHARSET=utf8 COMMENT="' . addslashes($metadata['name']) . '";'; + $query .= ') ENGINE=' . $engine . ' DEFAULT CHARSET=utf8 COMMENT="' . addslashes((string)$metadata['name']) . '";'; } else { $query .= ');'; } @@ -196,7 +193,7 @@ public function createTable() * * @return boolean TRUE if the table was altered, otherwise FALSE. */ - public function alterTable() + public function alterTable(): bool { if ($this->tableExists() === false) { return false; @@ -209,7 +206,7 @@ public function alterTable() foreach ($fields as $field) { $ident = $field->ident(); - if (!array_key_exists($ident, $cols)) { + if (!array_key_exists((string)$ident, $cols)) { $fieldSql = $field->sql(); if ($fieldSql) { // The key does not exist at all. @@ -226,30 +223,27 @@ public function alterTable() // The key exists. Validate. $col = $cols[$ident]; $alter = true; - if (strtolower($col['Type']) !== strtolower($field->sqlType())) { + if (strtolower((string)$col['Type']) !== strtolower($field->sqlType())) { $alter = true; } - if ((strtolower($col['Null']) !== 'no') !== $field->allowNull()) { + if ((strtolower((string)$col['Null']) !== 'no') !== $field->allowNull()) { $alter = true; } if ($col['Default'] !== $field->defaultVal()) { $alter = true; } - - if ($alter === true) { - $fieldSql = $field->sql(); - if ($fieldSql) { - $query = 'ALTER TABLE `' . $table . '` CHANGE `' . $ident . '` ' . $fieldSql; - $this->logger->debug($query); - $dbh->query($query); - } else { - $this->logger->warning('Empty column definition.', [ - 'table' => $table, - 'field' => $ident, - ]); - } + $fieldSql = $field->sql(); + if ($fieldSql) { + $query = 'ALTER TABLE `' . $table . '` CHANGE `' . $ident . '` ' . $fieldSql; + $this->logger->debug($query); + $dbh->query($query); + } else { + $this->logger->warning('Empty column definition.', [ + 'table' => $table, + 'field' => $ident, + ]); } } } @@ -264,11 +258,11 @@ public function alterTable() */ public function tableExists() { - $dbh = $this->db(); + $this->db(); $table = $this->table(); - if (isset($dbh->tableExists, $dbh->tableExists[$table])) { - return $dbh->tableExists[$table]; + if (isset($this->tableExistsCache[$table])) { + return $this->tableExistsCache[$table]; } $exists = $this->performTableExists(); @@ -282,7 +276,7 @@ public function tableExists() * * @return boolean TRUE if the table exists, otherwise FALSE. */ - protected function performTableExists() + protected function performTableExists(): bool { $dbh = $this->db(); $table = $this->table(); @@ -309,14 +303,9 @@ protected function performTableExists() */ protected function setTableExists($exists = true) { - $dbh = $this->db(); $table = $this->table(); - if (!isset($dbh->tableExists)) { - $dbh->tableExists = []; - } - - $dbh->tableExists[$table] = $exists; + $this->tableExistsCache[$table] = $exists; } /** @@ -345,9 +334,9 @@ public function tableStructure() // Normalize SQLite's result (PRAGMA) with mysql's (SHOW COLUMNS) $struct[$col['name']] = [ 'Type' => $col['type'], - 'Null' => !!$col['notnull'] ? 'NO' : 'YES', + 'Null' => $col['notnull'] ? 'NO' : 'YES', 'Default' => $col['dflt_value'], - 'Key' => !!$col['pk'] ? 'PRI' : '', + 'Key' => $col['pk'] ? 'PRI' : '', 'Extra' => '', ]; } @@ -362,7 +351,7 @@ public function tableStructure() * * @return boolean TRUE if the table has no data, otherwise FALSE. */ - public function tableIsEmpty() + public function tableIsEmpty(): bool { $table = $this->table(); $query = sprintf('SELECT NULL FROM `%s` LIMIT 1', $table); @@ -380,7 +369,7 @@ public function tableIsEmpty() * If NULL, retrieve all (from metadata). * @return PropertyField[] */ - private function getModelFields(ModelInterface $model, $properties = null) + private function getModelFields(ModelInterface $model, ?array $properties = null): array { if ($properties === null) { // No custom properties; use all (from model metadata) @@ -398,7 +387,7 @@ private function getModelFields(ModelInterface $model, $properties = null) } $val = $model->propertyValue($propertyIdent); - foreach ($prop->fields($val) as $fieldIdent => $field) { + foreach ($prop->fields($val) as $field) { $fields[$field->ident()] = $field; } } @@ -413,7 +402,7 @@ private function getModelFields(ModelInterface $model, $properties = null) * @param StorableInterface $item Optional item to load into. * @return StorableInterface */ - public function loadItem($ident, StorableInterface $item = null) + public function loadItem($ident, ?StorableInterface $item = null) { $key = $this->model()->key(); @@ -429,12 +418,12 @@ public function loadItem($ident, StorableInterface $item = null) * @throws \Exception If the query fails. * @return StorableInterface */ - public function loadItemFromKey($key, $ident, StorableInterface $item = null) + public function loadItemFromKey($key, $ident, ?StorableInterface $item = null) { - if ($item !== null) { + if ($item instanceof \Charcoal\Source\StorableInterface) { $this->setModel($item); } else { - $class = get_class($this->model()); + $class = $this->model()::class; $item = new $class(); } @@ -472,12 +461,12 @@ public function loadItemFromKey($key, $ident, StorableInterface $item = null) * @throws PDOException If there is a query error. * @return StorableInterface */ - public function loadItemFromQuery($query, array $binds = [], StorableInterface $item = null) + public function loadItemFromQuery($query, array $binds = [], ?StorableInterface $item = null): object { - if ($item !== null) { + if ($item instanceof \Charcoal\Source\StorableInterface) { $this->setModel($item); } else { - $class = get_class($this->model()); + $class = $this->model()::class; $item = new $class(); } @@ -508,9 +497,9 @@ public function loadItemFromQuery($query, array $binds = [], StorableInterface $ * @param StorableInterface|null $item Optional model. * @return StorableInterface[] */ - public function loadItems(StorableInterface $item = null) + public function loadItems(?StorableInterface $item = null): array { - if ($item !== null) { + if ($item instanceof \Charcoal\Source\StorableInterface) { $this->setModel($item); } @@ -526,9 +515,9 @@ public function loadItems(StorableInterface $item = null) * @param StorableInterface|null $item Model Item. * @return StorableInterface[] */ - public function loadItemsFromQuery($query, array $binds = [], StorableInterface $item = null) + public function loadItemsFromQuery($query, array $binds = [], ?StorableInterface $item = null): array { - if ($item !== null) { + if ($item instanceof \Charcoal\Source\StorableInterface) { $this->setModel($item); } @@ -541,14 +530,14 @@ public function loadItemsFromQuery($query, array $binds = [], StorableInterface $sth = $dbh->prepare($query); // @todo Binds - if (!empty($binds)) { + if ($binds !== []) { unset($binds); } $sth->execute(); $sth->setFetchMode(PDO::FETCH_ASSOC); - $className = get_class($model); + $className = $model::class; while ($objData = $sth->fetch()) { $obj = new $className(); $obj->setFlatData($objData); @@ -572,9 +561,7 @@ public function saveItem(StorableInterface $item) $this->createTable(); } - if ($item !== null) { - $this->setModel($item); - } + $this->setModel($item); $model = $this->model(); $table = $this->table(); $struct = array_keys($this->tableStructure()); @@ -609,12 +596,10 @@ public function saveItem(StorableInterface $item) '[%s] Could not save item', $this->getModelClassForException() )); + } elseif ($model->id()) { + return $model->id(); } else { - if ($model->id()) { - return $model->id(); - } else { - return $this->db()->lastInsertId(); - } + return $this->db()->lastInsertId(); } } @@ -625,11 +610,9 @@ public function saveItem(StorableInterface $item) * @param array $properties The list of properties to update, if not all. * @return boolean TRUE if the item was updated, otherwise FALSE. */ - public function updateItem(StorableInterface $item, array $properties = null) + public function updateItem(StorableInterface $item, ?array $properties = null): bool { - if ($item !== null) { - $this->setModel($item); - } + $this->setModel($item); $model = $this->model(); $table = $this->table(); $struct = array_keys($this->tableStructure()); @@ -651,7 +634,7 @@ public function updateItem(StorableInterface $item, array $properties = null) $this->logger->warning( sprintf('Field "%s" not in table structure', $key), [ - 'model' => get_class($model), + 'model' => $model::class, 'table' => $table, 'field' => $key, ] @@ -659,11 +642,11 @@ public function updateItem(StorableInterface $item, array $properties = null) } } - if (empty($updates)) { + if ($updates === []) { $this->logger->warning( 'Could not update items. No valid fields were set or available in database table.', [ - 'model' => get_class($model), + 'model' => $model::class, 'table' => $table, 'properties' => $properties, 'structure' => $struct @@ -704,9 +687,9 @@ public function updateItem(StorableInterface $item, array $properties = null) * @throws UnexpectedValueException If the item does not have an ID. * @return boolean TRUE if the item was deleted, otherwise FALSE. */ - public function deleteItem(StorableInterface $item = null) + public function deleteItem(?StorableInterface $item = null): bool { - if ($item !== null) { + if ($item instanceof \Charcoal\Source\StorableInterface) { $this->setModel($item); } @@ -798,17 +781,15 @@ public function dbPrepare($query, array $binds = [], array $types = []) return false; } - if (!empty($binds)) { - foreach ($binds as $key => $val) { - if ($binds[$key] === null) { - $types[$key] = PDO::PARAM_NULL; - } elseif (!is_scalar($binds[$key])) { - $binds[$key] = json_encode($binds[$key]); - } - $type = (isset($types[$key]) ? $types[$key] : PDO::PARAM_STR); - $param = ':' . $key; - $sth->bindParam($param, $binds[$key], $type); + foreach (array_keys($binds) as $key) { + if ($binds[$key] === null) { + $types[$key] = PDO::PARAM_NULL; + } elseif (!is_scalar($binds[$key])) { + $binds[$key] = json_encode($binds[$key]); } + $type = ($types[$key] ?? PDO::PARAM_STR); + $param = ':' . $key; + $sth->bindParam($param, $binds[$key], $type); } return $sth; @@ -818,9 +799,8 @@ public function dbPrepare($query, array $binds = [], array $types = []) * Compile the SELECT statement for fetching one or more objects. * * @throws UnexpectedValueException If the source does not have a table defined. - * @return string */ - public function sqlLoad() + public function sqlLoad(): string { if (!$this->hasTable()) { throw new UnexpectedValueException(sprintf( @@ -834,18 +814,15 @@ public function sqlLoad() $filters = $this->sqlFilters(); $orders = $this->sqlOrders(); $limits = $this->sqlPagination(); - - $query = 'SELECT ' . $selects . ' FROM ' . $tables . $filters . $orders . $limits; - return $query; + return 'SELECT ' . $selects . ' FROM ' . $tables . $filters . $orders . $limits; } /** * Compile the SELECT statement for fetching the number of objects. * * @throws UnexpectedValueException If the source does not have a table defined. - * @return string */ - public function sqlLoadCount() + public function sqlLoadCount(): string { if (!$this->hasTable()) { throw new UnexpectedValueException(sprintf( @@ -856,18 +833,15 @@ public function sqlLoadCount() $tables = $this->sqlFrom(); $filters = $this->sqlFilters(); - - $query = 'SELECT COUNT(*) FROM ' . $tables . $filters; - return $query; + return 'SELECT COUNT(*) FROM ' . $tables . $filters; } /** * Compile the SELECT clause. * * @throws UnexpectedValueException If the clause has no selectable fields. - * @return string */ - public function sqlSelect() + public function sqlSelect(): string { $properties = $this->properties(); if (empty($properties)) { @@ -879,25 +853,22 @@ public function sqlSelect() $parts[] = Expression::quoteIdentifier($key, self::DEFAULT_TABLE_ALIAS); } - if (empty($parts)) { + if ($parts === []) { throw new UnexpectedValueException(sprintf( '[%s] Can not get SQL SELECT clause; no valid properties', $this->getModelClassForException() )); } - $clause = implode(', ', $parts); - - return $clause; + return implode(', ', $parts); } /** * Compile the FROM clause. * * @throws UnexpectedValueException If the source does not have a table defined. - * @return string */ - public function sqlFrom() + public function sqlFrom(): string { if (!$this->hasTable()) { throw new UnexpectedValueException(sprintf( @@ -927,7 +898,7 @@ public function sqlFilters() ]); $sql = $criteria->sql(); - if ($sql && strlen($sql) > 0) { + if ($sql && (string)$sql !== '') { $sql = ' WHERE ' . $sql; } @@ -936,10 +907,8 @@ public function sqlFilters() /** * Compile the ORDER BY clause. - * - * @return string */ - public function sqlOrders() + public function sqlOrders(): string { if (!$this->hasOrders()) { return ''; @@ -952,12 +921,12 @@ public function sqlOrders() } $sql = $order->sql(); - if ($sql && strlen($sql) > 0) { + if ($sql && (string)$sql !== '') { $parts[] = $sql; } } - if (empty($parts)) { + if ($parts === []) { return ''; } @@ -966,10 +935,8 @@ public function sqlOrders() /** * Compile the LIMIT clause. - * - * @return string */ - public function sqlPagination() + public function sqlPagination(): string { $pager = $this->pagination(); if (!$pager instanceof DatabasePagination) { @@ -977,7 +944,7 @@ public function sqlPagination() } $sql = $pager->sql(); - if ($sql && strlen($sql) > 0) { + if ($sql && $sql !== '') { $sql = ' ' . $sql; } @@ -988,9 +955,9 @@ public function sqlPagination() * Create a new filter expression. * * @param array $data Optional expression data. - * @return DatabaseFilter */ - protected function createFilter(array $data = null) + #[\Override] + protected function createFilter(?array $data = null): \Charcoal\Source\Database\DatabaseFilter { $filter = new DatabaseFilter(); if ($data !== null) { @@ -1003,9 +970,9 @@ protected function createFilter(array $data = null) * Create a new order expression. * * @param array $data Optional expression data. - * @return DatabaseOrder */ - protected function createOrder(array $data = null) + #[\Override] + protected function createOrder(?array $data = null): \Charcoal\Source\Database\DatabaseOrder { $order = new DatabaseOrder(); if ($data !== null) { @@ -1018,9 +985,9 @@ protected function createOrder(array $data = null) * Create a new pagination clause. * * @param array $data Optional clause data. - * @return DatabasePagination */ - protected function createPagination(array $data = null) + #[\Override] + protected function createPagination(?array $data = null): \Charcoal\Source\Database\DatabasePagination { $pagination = new DatabasePagination(); if ($data !== null) { @@ -1034,11 +1001,10 @@ protected function createPagination(array $data = null) * * @see \Charcoal\Config\ConfigurableTrait * @param array $data Optional data. - * @return DatabaseSourceConfig */ - public function createConfig(array $data = null) + #[\Override] + public function createConfig(?array $data = null): \Charcoal\Source\DatabaseSourceConfig { - $config = new DatabaseSourceConfig($data); - return $config; + return new DatabaseSourceConfig($data); } } diff --git a/packages/core/src/Charcoal/Source/DatabaseSourceConfig.php b/packages/core/src/Charcoal/Source/DatabaseSourceConfig.php index 6cfe1042c..da6aeb336 100644 --- a/packages/core/src/Charcoal/Source/DatabaseSourceConfig.php +++ b/packages/core/src/Charcoal/Source/DatabaseSourceConfig.php @@ -1,5 +1,7 @@ 'mysql', @@ -61,9 +43,9 @@ public function defaults() * * @param string $type The database type. * @throws InvalidArgumentException If parameter is not a string. - * @return self */ - public function setType($type) + #[\Override] + public function setType($type): static { if (!is_string($type)) { throw new InvalidArgumentException( @@ -79,7 +61,8 @@ public function setType($type) * * @return string */ - public function type() + #[\Override] + public function type(): ?string { return $this->type; } @@ -89,9 +72,8 @@ public function type() * * @param string $hostname The database server hostname. * @throws InvalidArgumentException If hostname is not a string. - * @return self */ - public function setHostname($hostname) + public function setHostname($hostname): static { if (!is_string($hostname)) { throw new InvalidArgumentException( @@ -107,7 +89,7 @@ public function setHostname($hostname) * * @return string */ - public function hostname() + public function hostname(): ?string { return $this->hostname; } @@ -117,9 +99,8 @@ public function hostname() * * @param string $username The username. * @throws InvalidArgumentException If username is not a string. - * @return self */ - public function setUsername($username) + public function setUsername($username): static { if (!is_string($username)) { throw new InvalidArgumentException( @@ -135,7 +116,7 @@ public function setUsername($username) * * @return string */ - public function username() + public function username(): ?string { return $this->username; } @@ -145,9 +126,8 @@ public function username() * * @param string $password The password. * @throws InvalidArgumentException If password is not a string. - * @return self */ - public function setPassword($password) + public function setPassword($password): static { if (!is_string($password)) { throw new InvalidArgumentException( @@ -163,7 +143,7 @@ public function setPassword($password) * * @return string */ - public function password() + public function password(): ?string { return $this->password; } @@ -173,9 +153,8 @@ public function password() * * @param string $database The database name. * @throws InvalidArgumentException If database is not a string. - * @return self */ - public function setDatabase($database) + public function setDatabase($database): static { if (!is_string($database)) { throw new InvalidArgumentException( @@ -191,7 +170,7 @@ public function setDatabase($database) * * @return string */ - public function database() + public function database(): ?string { return $this->database; } @@ -200,11 +179,10 @@ public function database() * Set whether to disable UTF-8 compatibility or not. * * @param boolean $disableUtf8 The disable flag. - * @return self */ - public function setDisableUtf8($disableUtf8) + public function setDisableUtf8($disableUtf8): static { - $this->disableUtf8 = !!$disableUtf8; + $this->disableUtf8 = (bool)$disableUtf8; return $this; } @@ -213,7 +191,7 @@ public function setDisableUtf8($disableUtf8) * * @return boolean */ - public function disableUtf8() + public function disableUtf8(): ?bool { return $this->disableUtf8; } diff --git a/packages/core/src/Charcoal/Source/DatabaseSourceInterface.php b/packages/core/src/Charcoal/Source/DatabaseSourceInterface.php index 182b87f02..987748c9d 100644 --- a/packages/core/src/Charcoal/Source/DatabaseSourceInterface.php +++ b/packages/core/src/Charcoal/Source/DatabaseSourceInterface.php @@ -1,5 +1,7 @@ $data The expression data; * as an associative array. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -44,7 +44,7 @@ public function setData(array $data) * * @return array An associative array. */ - public function defaultData() + public function defaultData(): array { return [ 'condition' => null, @@ -58,7 +58,7 @@ public function defaultData() * * @return array An associative array. */ - public function data() + public function data(): array { return [ 'condition' => $this->condition(), @@ -72,9 +72,8 @@ public function data() * * @param string|null $condition The custom query expression. * @throws InvalidArgumentException If the parameter is not a valid string expression. - * @return self */ - public function setCondition($condition) + public function setCondition($condition): static { if ($condition === null) { $this->condition = $condition; @@ -98,10 +97,8 @@ public function setCondition($condition) /** * Determine if the expression has a custom condition. - * - * @return boolean */ - public function hasCondition() + public function hasCondition(): bool { return !(empty($this->condition) && !is_numeric($this->condition)); } diff --git a/packages/core/src/Charcoal/Source/ExpressionFieldInterface.php b/packages/core/src/Charcoal/Source/ExpressionFieldInterface.php index 665bf7440..3694c3b3f 100644 --- a/packages/core/src/Charcoal/Source/ExpressionFieldInterface.php +++ b/packages/core/src/Charcoal/Source/ExpressionFieldInterface.php @@ -1,5 +1,7 @@ property); } @@ -130,10 +128,8 @@ public function setTable($table) /** * Determine if a table is assigned. - * - * @return boolean */ - public function hasTable() + public function hasTable(): bool { return !empty($this->table); } @@ -212,7 +208,7 @@ public function fieldName() * * @return string[] */ - public function fieldIdentifiers() + public function fieldIdentifiers(): array { $identifiers = []; $tableName = $this->table(); @@ -243,7 +239,7 @@ public function fieldIdentifier() * @param string $value The string to snakeize. * @return string The snake_case string. */ - protected function snakeize($value) + protected function snakeize($value): string { $key = $value; @@ -251,7 +247,7 @@ protected function snakeize($value) return static::$snakeCache[$key]; } - $value = strtolower(preg_replace('/(?filters); } @@ -72,9 +71,9 @@ public function count() * * @param array $data The expression data; * as an associative array. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -174,7 +173,8 @@ public function setData(array $data) * * @return array An associative array. */ - public function defaultData() + #[\Override] + public function defaultData(): array { return [ 'property' => null, @@ -195,7 +195,8 @@ public function defaultData() * * @return array An associative array. */ - public function data() + #[\Override] + public function data(): array { return [ 'property' => $this->property(), @@ -215,9 +216,8 @@ public function data() * Set the value used for comparison. * * @param mixed $value The value on the right side of the comparison. - * @return self */ - public function setValue($value) + public function setValue($value): static { $this->value = $this::parseValue($value); return $this; @@ -238,9 +238,8 @@ public function value() * * @param string $operator The comparison operator. * @throws InvalidArgumentException If the parameter is not a valid operator. - * @return self */ - public function setOperator($operator) + public function setOperator($operator): static { if (!is_string($operator)) { throw new InvalidArgumentException( @@ -262,10 +261,8 @@ public function setOperator($operator) /** * Retrieve the operator used for comparing field and value. - * - * @return string */ - public function operator() + public function operator(): string { return strtoupper($this->operator); } @@ -275,9 +272,8 @@ public function operator() * * @param string $func The function name to invoke on the field. * @throws InvalidArgumentException If the parameter is not a valid function. - * @return self */ - public function setFunc($func) + public function setFunc($func): static { if ($func === null) { $this->func = $func; @@ -317,9 +313,8 @@ public function func() * * @param string $conjunction The separator to use. * @throws InvalidArgumentException If the parameter is not a valid conjunction. - * @return self */ - public function setConjunction($conjunction) + public function setConjunction($conjunction): static { if (!is_string($conjunction)) { throw new InvalidArgumentException( @@ -354,7 +349,7 @@ public function conjunction() * * @return string[] */ - protected function validOperators() + protected function validOperators(): array { return [ '!', 'NOT', @@ -376,7 +371,7 @@ protected function validOperators() * * @return string[] */ - protected function validFunc() + protected function validFunc(): array { return [ 'ABS', @@ -410,7 +405,7 @@ protected function validFunc() * * @return string[] List of separators (case sensitive). */ - protected function validConjunctions() + protected function validConjunctions(): array { return [ 'AND', '&&', @@ -424,9 +419,8 @@ protected function validConjunctions() * * @see FilterCollectionTrait::createFilter() * @param array $data Optional expression data. - * @return self */ - protected function createFilter(array $data = null) + protected function createFilter(?array $data = null): static { $filter = new static(); if ($data !== null) { @@ -448,8 +442,6 @@ public function traverse(callable $callable) /** * Clone this expression and its subtree of expressions. - * - * @return void */ public function __clone() { diff --git a/packages/core/src/Charcoal/Source/FilterCollectionInterface.php b/packages/core/src/Charcoal/Source/FilterCollectionInterface.php index c0f9d330e..c81437713 100644 --- a/packages/core/src/Charcoal/Source/FilterCollectionInterface.php +++ b/packages/core/src/Charcoal/Source/FilterCollectionInterface.php @@ -1,5 +1,7 @@ filters); } @@ -165,5 +163,5 @@ public function traverseFilters(callable $callable) * @param array $data Optional expression data. * @return FilterInterface A new filter expression object. */ - abstract protected function createFilter(array $data = null); + abstract protected function createFilter(?array $data = null); } diff --git a/packages/core/src/Charcoal/Source/FilterInterface.php b/packages/core/src/Charcoal/Source/FilterInterface.php index bc132ddc2..bc618ba87 100644 --- a/packages/core/src/Charcoal/Source/FilterInterface.php +++ b/packages/core/src/Charcoal/Source/FilterInterface.php @@ -1,5 +1,7 @@ model !== null); } diff --git a/packages/core/src/Charcoal/Source/Order.php b/packages/core/src/Charcoal/Source/Order.php index afd1876a6..06771dd19 100644 --- a/packages/core/src/Charcoal/Source/Order.php +++ b/packages/core/src/Charcoal/Source/Order.php @@ -60,9 +60,9 @@ class Order extends Expression implements * * @param array $data The expression data; * as an associative array. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -114,10 +114,8 @@ public function setData(array $data) } } - if (isset($data['condition']) || isset($data['string'])) { - if (!isset($data['mode'])) { - $this->setMode(self::MODE_CUSTOM); - } + if ((isset($data['condition']) || isset($data['string'])) && !isset($data['mode'])) { + $this->setMode(self::MODE_CUSTOM); } return $this; @@ -128,7 +126,8 @@ public function setData(array $data) * * @return array An associative array. */ - public function defaultData() + #[\Override] + public function defaultData(): array { return [ 'property' => null, @@ -147,7 +146,8 @@ public function defaultData() * * @return array An associative array. */ - public function data() + #[\Override] + public function data(): array { return [ 'property' => $this->property(), @@ -166,9 +166,8 @@ public function data() * * @param string|null $mode The sorting mode. * @throws InvalidArgumentException If the mode is not a string or invalid. - * @return self */ - public function setMode($mode) + public function setMode($mode): static { if ($mode === null) { $this->mode = $mode; @@ -213,9 +212,8 @@ public function mode() * * @param string|null $direction The direction to sort on. * @throws InvalidArgumentException If the direction is not a string. - * @return self */ - public function setDirection($direction) + public function setDirection($direction): static { if ($direction === null) { $this->direction = $direction; @@ -253,9 +251,8 @@ public function direction() * - is a string, the string will be split by ",". * - is an array, the values will be used as is. * - any other data type throws an exception. - * @return self */ - public function setValues($values) + public function setValues($values): static { if ($values === null) { $this->values = $values; @@ -269,11 +266,11 @@ public function setValues($values) ); } - $values = array_map('trim', explode(',', $values)); + $values = array_map(trim(...), explode(',', $values)); } if (is_array($values)) { - if (empty($values)) { + if ($values === []) { throw new InvalidArgumentException( 'Array values can not be empty.' ); @@ -285,16 +282,14 @@ public function setValues($values) throw new InvalidArgumentException(sprintf( 'Order Values must be an array or comma-delimited string, received %s', - is_object($values) ? get_class($values) : gettype($values) + get_debug_type($values) )); } /** * Determine if the Order expression has values. - * - * @return boolean */ - public function hasValues() + public function hasValues(): bool { return !empty($this->values); } @@ -311,10 +306,8 @@ public function values() /** * Retrieve the supported sorting modes. - * - * @return array */ - protected function validModes() + protected function validModes(): array { return [ self::MODE_DESC, diff --git a/packages/core/src/Charcoal/Source/OrderCollectionInterface.php b/packages/core/src/Charcoal/Source/OrderCollectionInterface.php index 9f8abf25c..b737427da 100644 --- a/packages/core/src/Charcoal/Source/OrderCollectionInterface.php +++ b/packages/core/src/Charcoal/Source/OrderCollectionInterface.php @@ -1,5 +1,7 @@ orders); } @@ -165,5 +163,5 @@ public function traverseOrders(callable $callable) * @param array $data Optional expression data. * @return OrderInterface A new order expression object. */ - abstract protected function createOrder(array $data = null); + abstract protected function createOrder(?array $data = null); } diff --git a/packages/core/src/Charcoal/Source/OrderInterface.php b/packages/core/src/Charcoal/Source/OrderInterface.php index d49ab383e..b57ba3ffe 100644 --- a/packages/core/src/Charcoal/Source/OrderInterface.php +++ b/packages/core/src/Charcoal/Source/OrderInterface.php @@ -1,5 +1,7 @@ $data The expression data; * as an associative array. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -63,7 +63,7 @@ public function setData(array $data) * * @return array An associative array. */ - public function defaultData() + public function defaultData(): array { return [ 'page' => self::DEFAULT_PAGE, @@ -78,7 +78,7 @@ public function defaultData() * * @return array An associative array. */ - public function data() + public function data(): array { return [ 'page' => $this->page(), @@ -94,9 +94,8 @@ public function data() * @param integer $page The current page. * Pages should start at 1. * @throws InvalidArgumentException If the parameter is not numeric or < 0. - * @return self */ - public function setPage($page) + public function setPage($page): static { if (!is_numeric($page)) { throw new InvalidArgumentException( @@ -133,9 +132,8 @@ public function page() * @param integer $count The number of results to return, per page. * Use 0 to request all results. * @throws InvalidArgumentException If the parameter is not numeric or < 0. - * @return self */ - public function setNumPerPage($count) + public function setNumPerPage($count): static { if (!is_numeric($count)) { throw new InvalidArgumentException( @@ -166,10 +164,8 @@ public function numPerPage() /** * Retrieve the pagination's lowest possible index. - * - * @return integer */ - public function first() + public function first(): int { $page = $this->page(); $limit = $this->numPerPage(); @@ -184,7 +180,7 @@ public function first() * * @return integer */ - public function last() + public function last(): float|int|array { $first = $this->first(); $limit = $this->numPerPage(); diff --git a/packages/core/src/Charcoal/Source/PaginationInterface.php b/packages/core/src/Charcoal/Source/PaginationInterface.php index f90fdb9a9..d6dcfb324 100644 --- a/packages/core/src/Charcoal/Source/PaginationInterface.php +++ b/packages/core/src/Charcoal/Source/PaginationInterface.php @@ -1,5 +1,7 @@ '' @@ -29,9 +26,8 @@ public function defaults() /** * @param string $type The type of source. * @throws InvalidArgumentException If parameter is not a string. - * @return self */ - public function setType($type) + public function setType($type): static { if (!is_string($type)) { throw new InvalidArgumentException( @@ -45,7 +41,7 @@ public function setType($type) /** * @return string */ - public function type() + public function type(): ?string { return $this->type; } diff --git a/packages/core/src/Charcoal/Source/SourceInterface.php b/packages/core/src/Charcoal/Source/SourceInterface.php index 5d566e29a..c73e251ab 100644 --- a/packages/core/src/Charcoal/Source/SourceInterface.php +++ b/packages/core/src/Charcoal/Source/SourceInterface.php @@ -1,5 +1,7 @@ preSave(); if ($pre === false) { @@ -229,7 +229,7 @@ final public function save() 'Can not save object "%s:%s"; cancelled by %s::preSave()', $this->objType(), $this->id(), - get_called_class() + static::class )); return false; } @@ -240,7 +240,7 @@ final public function save() 'Can not save object "%s:%s"; repository failed for %s', $this->objType(), $this->id(), - get_called_class() + static::class )); return false; } else { @@ -253,7 +253,7 @@ final public function save() 'Saved object "%s:%s" but %s::postSave() failed', $this->objType(), $this->id(), - get_called_class() + static::class )); return false; } @@ -267,7 +267,7 @@ final public function save() * @param string[] $keys If provided, only update the properties specified. * @return boolean TRUE on success. */ - final public function update(array $keys = null) + final public function update(?array $keys = null): bool { $pre = $this->preUpdate($keys); if ($pre === false) { @@ -275,7 +275,7 @@ final public function update(array $keys = null) 'Can not update object "%s:%s"; cancelled by %s::preUpdate()', $this->objType(), $this->id(), - get_called_class() + static::class )); return false; } @@ -286,7 +286,7 @@ final public function update(array $keys = null) 'Can not update object "%s:%s"; repository failed for %s', $this->objType(), $this->id(), - get_called_class() + static::class )); return false; } @@ -297,7 +297,7 @@ final public function update(array $keys = null) 'Updated object "%s:%s" but %s::postUpdate() failed', $this->objType(), $this->id(), - get_called_class() + static::class )); return false; } @@ -310,7 +310,7 @@ final public function update(array $keys = null) * * @return boolean TRUE on success. */ - final public function delete() + final public function delete(): bool { $pre = $this->preDelete(); if ($pre === false) { @@ -318,7 +318,7 @@ final public function delete() 'Can not delete object "%s:%s"; cancelled by %s::preDelete()', $this->objType(), $this->id(), - get_called_class() + static::class )); return false; } @@ -329,7 +329,7 @@ final public function delete() 'Can not delete object "%s:%s"; repository failed for %s', $this->objType(), $this->id(), - get_called_class() + static::class )); return false; } @@ -340,7 +340,7 @@ final public function delete() 'Deleted object "%s:%s" but %s::postDelete() failed', $this->objType(), $this->id(), - get_called_class() + static::class )); return false; } @@ -370,7 +370,7 @@ protected function sourceFactory() { if (!isset($this->sourceFactory)) { throw new RuntimeException( - sprintf('Source factory is not set for "%s"', get_class($this)) + sprintf('Source factory is not set for "%s"', $this::class) ); } return $this->sourceFactory; @@ -381,7 +381,7 @@ protected function sourceFactory() * * @return boolean TRUE to proceed with creation; FALSE to stop creation. */ - protected function preSave() + protected function preSave(): bool { return true; } @@ -391,7 +391,7 @@ protected function preSave() * * @return boolean TRUE to indicate object was created. */ - protected function postSave() + protected function postSave(): bool { return true; } @@ -402,7 +402,7 @@ protected function postSave() * @param string[] $keys Optional list of properties to update. * @return boolean TRUE to proceed with update; FALSE to stop update. */ - protected function preUpdate(array $keys = null) + protected function preUpdate(?array $keys = null): bool { return true; } @@ -413,7 +413,7 @@ protected function preUpdate(array $keys = null) * @param string[] $keys Optional list of properties to update. * @return boolean TRUE to indicate object was updated. */ - protected function postUpdate(array $keys = null) + protected function postUpdate(?array $keys = null): bool { return true; } @@ -423,7 +423,7 @@ protected function postUpdate(array $keys = null) * * @return boolean TRUE to proceed with deletion; FALSE to stop deletion. */ - protected function preDelete() + protected function preDelete(): bool { return true; } @@ -433,7 +433,7 @@ protected function preDelete() * * @return boolean TRUE to indicate object was deleted. */ - protected function postDelete() + protected function postDelete(): bool { return true; } diff --git a/packages/core/src/Charcoal/Validator/AbstractValidator.php b/packages/core/src/Charcoal/Validator/AbstractValidator.php index be98ede35..6bea5c507 100644 --- a/packages/core/src/Charcoal/Validator/AbstractValidator.php +++ b/packages/core/src/Charcoal/Validator/AbstractValidator.php @@ -15,15 +15,10 @@ */ abstract class AbstractValidator implements ValidatorInterface { - /** - * @var ValidatableInterface - */ - protected $model; - /** * @var ValidatorResult[] $results */ - private $results = []; + private array $results = []; /** * Holds a list of all camelized strings. @@ -35,9 +30,8 @@ abstract class AbstractValidator implements ValidatorInterface /** * @param ValidatableInterface $model The object to validate. */ - public function __construct(ValidatableInterface $model) + public function __construct(protected \Charcoal\Validator\ValidatableInterface $model) { - $this->model = $model; } /** @@ -80,7 +74,7 @@ public function log($level, $msg, $ident = null) { $this->addResult( [ - 'ident' => (($ident !== null) ? $ident : ''), + 'ident' => ($ident ?? ''), 'level' => $level, 'message' => $msg ] @@ -160,7 +154,7 @@ public function merge(ValidatorInterface $v, $prefix = null) { $allResults = $v->results(); - foreach ($allResults as $level => $resultset) { + foreach ($allResults as $resultset) { foreach ($resultset as $result) { if ($prefix !== null) { $result->setIdent($prefix . '.' . $result->ident()); @@ -185,8 +179,8 @@ final protected function camelize($value) return static::$camelCache[$key]; } - if (strpos($value, '_') !== false) { - $value = implode('', array_map('ucfirst', explode('_', $value))); + if (str_contains($value, '_')) { + $value = implode('', array_map(ucfirst(...), explode('_', $value))); } static::$camelCache[$key] = lcfirst($value); diff --git a/packages/core/src/Charcoal/Validator/ValidatableInterface.php b/packages/core/src/Charcoal/Validator/ValidatableInterface.php index 09791b9f2..aa0f525e3 100644 --- a/packages/core/src/Charcoal/Validator/ValidatableInterface.php +++ b/packages/core/src/Charcoal/Validator/ValidatableInterface.php @@ -1,5 +1,7 @@ setValidator($v); } diff --git a/packages/core/src/Charcoal/Validator/ValidatorInterface.php b/packages/core/src/Charcoal/Validator/ValidatorInterface.php index a500e19ce..726400766 100644 --- a/packages/core/src/Charcoal/Validator/ValidatorInterface.php +++ b/packages/core/src/Charcoal/Validator/ValidatorInterface.php @@ -1,5 +1,7 @@ setIdent($data['ident']); @@ -69,9 +58,8 @@ public function setData(array $data) /** * @param string $ident The result identigier. * @throws InvalidArgumentException If parameter is not valid. - * @return ValidatorResult */ - public function setIdent($ident) + public function setIdent($ident): static { if (!is_string($ident)) { throw new InvalidArgumentException( @@ -85,7 +73,7 @@ public function setIdent($ident) /** * @return string */ - public function ident() + public function ident(): ?string { return $this->ident; } @@ -93,9 +81,8 @@ public function ident() /** * @param string $level The validation level ('notice', 'warning' or 'error'). * @throws InvalidArgumentException If parameter is not a valid level. - * @return ValidatorResult */ - public function setLevel($level) + public function setLevel($level): static { if (!is_string($level)) { throw new InvalidArgumentException( @@ -114,7 +101,7 @@ public function setLevel($level) /** * @return string */ - public function level() + public function level(): ?string { return $this->level; } @@ -122,9 +109,8 @@ public function level() /** * @param string $message The validation message. * @throws InvalidArgumentException If parameter is not valid. - * @return ValidatorResult */ - public function setMessage($message) + public function setMessage($message): static { if (!is_string($message)) { throw new InvalidArgumentException( @@ -138,7 +124,7 @@ public function setMessage($message) /** * @return string */ - public function message() + public function message(): ?string { return $this->message; } @@ -146,9 +132,8 @@ public function message() /** * @param string|DateTime $ts The datetime value. * @throws InvalidArgumentException If parameter is not valid "datetime". - * @return ValidatorResult */ - public function setTs($ts) + public function setTs($ts): static { if (is_string($ts)) { $ts = new DateTime($ts); @@ -165,7 +150,7 @@ public function setTs($ts) /** * @return DateTime */ - public function ts() + public function ts(): \DateTimeInterface { return $this->ts; } diff --git a/packages/core/tests/Charcoal/AbstractTestCase.php b/packages/core/tests/Charcoal/AbstractTestCase.php index 59ba12ea0..80f1772c4 100644 --- a/packages/core/tests/Charcoal/AbstractTestCase.php +++ b/packages/core/tests/Charcoal/AbstractTestCase.php @@ -1,5 +1,7 @@ assertCount(count($expected), $haystack, $message); $this->assertEquals($expected, $haystack, $message); @@ -27,9 +26,8 @@ public function assertArrayEquals(array $expected, array $haystack, $message = ' * @param array $expected The expected haystack. * @param array $haystack The actual haystack. * @param string $message The error to report. - * @return void */ - public function assertArrayContains(array $expected, array $haystack, $message = '') + public function assertArrayContains(array $expected, array $haystack, $message = ''): void { foreach ($expected as $item) { $this->assertContains($item, $haystack, $message); @@ -42,9 +40,8 @@ public function assertArrayContains(array $expected, array $haystack, $message = * @param array $expected The expected haystack. * @param array $haystack The actual haystack. * @param string $message The error to report. - * @return void */ - public function assertArrayHasKeys(array $expected, array $haystack, $message = '') + public function assertArrayHasKeys(array $expected, array $haystack, $message = ''): void { foreach ($expected as $item) { $this->assertArrayHasKey($item, $haystack, $message); @@ -58,14 +55,13 @@ public function assertArrayHasKeys(array $expected, array $haystack, $message = * @param array $haystack The actual haystack. * @param boolean $strict Whether to check for object identity. * @param string $message The error to report. - * @return void */ public function assertArraySubsets( array $expected, array $haystack, $strict = false, $message = '' - ) { + ): void { foreach ($expected as $key => $val) { $this->assertArraySubset([ $key => $val ], $haystack, $strict, $message); } diff --git a/packages/core/tests/Charcoal/CoreContainerIntegrationTrait.php b/packages/core/tests/Charcoal/CoreContainerIntegrationTrait.php index 57ce03768..9b6c79600 100644 --- a/packages/core/tests/Charcoal/CoreContainerIntegrationTrait.php +++ b/packages/core/tests/Charcoal/CoreContainerIntegrationTrait.php @@ -50,10 +50,9 @@ protected function getContainerProvider() } /** - * @return void * @see CoreContainerProvider */ - private function setupContainer() + private function setupContainer(): void { $provider = new CoreContainerProvider(); $container = new Container(); diff --git a/packages/core/tests/Charcoal/CoreContainerProvider.php b/packages/core/tests/Charcoal/CoreContainerProvider.php index 6de374c33..70a8b4f97 100644 --- a/packages/core/tests/Charcoal/CoreContainerProvider.php +++ b/packages/core/tests/Charcoal/CoreContainerProvider.php @@ -44,9 +44,8 @@ class CoreContainerProvider * Register the unit tests required services. * * @param Container $container A DI container. - * @return void */ - public function registerBaseServices(Container $container) + public function registerBaseServices(Container $container): void { $this->registerConfig($container); $this->registerSource($container); @@ -58,15 +57,12 @@ public function registerBaseServices(Container $container) * Setup the application configset. * * @param Container $container A DI container. - * @return void */ - public function registerConfig(Container $container) + public function registerConfig(Container $container): void { - $container['config'] = function () { - return new AppConfig([ - 'base_path' => realpath(__DIR__ . '/../../..') - ]); - }; + $container['config'] = (fn(): \Charcoal\App\AppConfig => new AppConfig([ + 'base_path' => realpath(__DIR__ . '/../../..') + ])); } /** @@ -75,11 +71,10 @@ public function registerConfig(Container $container) * Note: Uses SQLite to create a database in memory. * * @param Container $container A DI container. - * @return void */ - public function registerSource(Container $container) + public function registerSource(Container $container): void { - $container['database'] = function () { + $container['database'] = function (): \PDO { $pdo = new PDO('sqlite::memory:'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; @@ -90,60 +85,48 @@ public function registerSource(Container $container) * Setup the application's logging interface. * * @param Container $container A DI container. - * @return void */ - public function registerLogger(Container $container) + public function registerLogger(Container $container): void { - $container['logger'] = function () { - return new NullLogger(); - }; + $container['logger'] = (fn(): \Psr\Log\NullLogger => new NullLogger()); } /** * Setup the application's caching interface. * * @param Container $container A DI container. - * @return void */ - public function registerCache(Container $container) + public function registerCache(Container $container): void { - $container['cache'] = function () { - return new Pool(); - }; + $container['cache'] = (fn(): \Stash\Pool => new Pool()); } /** * Setup the application's translator service. * * @param Container $container A DI container. - * @return void */ - public function registerTranslator(Container $container) + public function registerTranslator(Container $container): void { - $container['locales/manager'] = function () { - return new LocalesManager([ - 'locales' => [ - 'en' => [ 'locale' => 'en-US' ] - ] - ]); - }; + $container['locales/manager'] = (fn(): \Charcoal\Translator\LocalesManager => new LocalesManager([ + 'locales' => [ + 'en' => [ 'locale' => 'en-US' ] + ] + ])); - $container['translator'] = function (Container $container) { - return new Translator([ - 'manager' => $container['locales/manager'] - ]); - }; + $container['translator'] = (fn(Container $container): \Charcoal\Translator\Translator => new Translator([ + 'manager' => $container['locales/manager'] + ])); } /** * Setup the application's translator service. * * @param Container $container A DI container. - * @return void */ - public function registerMultilingualTranslator(Container $container) + public function registerMultilingualTranslator(Container $container): void { - $container['locales/manager'] = function () { + $container['locales/manager'] = function (): \Charcoal\Translator\LocalesManager { $manager = new LocalesManager([ 'locales' => [ 'en' => [ @@ -178,7 +161,7 @@ public function registerMultilingualTranslator(Container $container) return $manager; }; - $container['translator'] = function (Container $container) { + $container['translator'] = function (Container $container): \Charcoal\Translator\Translator { $translator = new Translator([ 'manager' => $container['locales/manager'] ]); @@ -198,106 +181,91 @@ public function registerMultilingualTranslator(Container $container) * Setup the framework's metadata loader interface. * * @param Container $container A DI container. - * @return void */ - public function registerMetadataLoader(Container $container) + public function registerMetadataLoader(Container $container): void { - $container['metadata/loader'] = function (Container $container) { - return new MetadataLoader([ - 'cache' => $container['cache'], - 'logger' => $container['logger'], - 'base_path' => $container['config']['base_path'], - 'paths' => [ - 'metadata', - // Standalone - 'vendor/charcoal/property/metadata', - // Monorepo - '/../property/metadata' - ] - ]); - }; + $container['metadata/loader'] = (fn(Container $container): \Charcoal\Model\Service\MetadataLoader => new MetadataLoader([ + 'cache' => $container['cache'], + 'logger' => $container['logger'], + 'base_path' => $container['config']['base_path'], + 'paths' => [ + 'metadata', + // Standalone + 'vendor/charcoal/property/metadata', + // Monorepo + '/../property/metadata' + ] + ])); } /** * Setup the framework's data source factory. * * @param Container $container A DI container. - * @return void */ - public function registerSourceFactory(Container $container) + public function registerSourceFactory(Container $container): void { - $container['source/factory'] = function (Container $container) { - return new Factory([ - 'map' => [ - 'database' => DatabaseSource::class - ], - 'arguments' => [[ - 'logger' => $container['logger'], - 'cache' => $container['cache'], - 'pdo' => $container['database'] - ]] - ]); - }; + $container['source/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'map' => [ + 'database' => DatabaseSource::class + ], + 'arguments' => [[ + 'logger' => $container['logger'], + 'cache' => $container['cache'], + 'pdo' => $container['database'] + ]] + ])); } /** * Setup the framework's model factory. * * @param Container $container A DI container. - * @return void */ - public function registerModelFactory(Container $container) + public function registerModelFactory(Container $container): void { - $container['model/factory'] = function (Container $container) { - return new Factory([ - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'], - 'metadata_loader' => $container['metadata/loader'], - 'source_factory' => $container['source/factory'], - 'property_factory' => $container['property/factory'] - ]] - ]); - }; + $container['model/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'], + 'metadata_loader' => $container['metadata/loader'], + 'source_factory' => $container['source/factory'], + 'property_factory' => $container['property/factory'] + ]] + ])); } /** * Setup the framework's property factory. * * @param Container $container A DI container. - * @return void */ - public function registerPropertyFactory(Container $container) + public function registerPropertyFactory(Container $container): void { - $container['property/factory'] = function (Container $container) { - return new Factory([ - 'resolver_options' => [ - 'prefix' => '\\Charcoal\\Property\\', - 'suffix' => 'Property' - ], - 'arguments' => [[ - 'container' => $container, - 'database' => $container['database'], - 'logger' => $container['logger'], - 'translator' => $container['translator'] - ]] - ]); - }; + $container['property/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'resolver_options' => [ + 'prefix' => '\\Charcoal\\Property\\', + 'suffix' => 'Property' + ], + 'arguments' => [[ + 'container' => $container, + 'database' => $container['database'], + 'logger' => $container['logger'], + 'translator' => $container['translator'] + ]] + ])); } /** * Setup the framework's collection loader interface. * * @param Container $container A DI container. - * @return void */ - public function registerModelCollectionLoader(Container $container) + public function registerModelCollectionLoader(Container $container): void { - $container['model/collection/loader'] = function (Container $container) { - return new CollectionLoader([ - 'logger' => $container['logger'], - 'cache' => $container['cache'] - ]); - }; + $container['model/collection/loader'] = (fn(Container $container): \Charcoal\Loader\CollectionLoader => new CollectionLoader([ + 'logger' => $container['logger'], + 'cache' => $container['cache'] + ])); } } diff --git a/packages/core/tests/Charcoal/Loader/CollectionLoaderTest.php b/packages/core/tests/Charcoal/Loader/CollectionLoaderTest.php index 11b110546..ca9c8e74e 100644 --- a/packages/core/tests/Charcoal/Loader/CollectionLoaderTest.php +++ b/packages/core/tests/Charcoal/Loader/CollectionLoaderTest.php @@ -20,27 +20,18 @@ use Charcoal\Tests\CoreContainerIntegrationTrait; use Charcoal\Tests\ReflectionsTrait; -/** - * - */ +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Loader\CollectionLoader::class, 'camelize')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Loader\CollectionLoader::class, 'getter')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Loader\CollectionLoader::class, 'setter')] class CollectionLoaderTest extends AbstractTestCase { use CoreContainerIntegrationTrait; use ReflectionsTrait; - /** - * @var CollectionLoader - */ - private $loader; + private \Charcoal\Loader\CollectionLoader $loader; - /** - * @var Model - */ - private $model; + private \Charcoal\Model\Model $model; - /** - * @return void - */ protected function setUp(): void { $this->model = $this->createModel(); @@ -49,10 +40,7 @@ protected function setUp(): void $this->loader = $this->createCollectionLoader(); } - /** - * @return CollectionLoader - */ - public function createCollectionLoader() + public function createCollectionLoader(): \Charcoal\Loader\CollectionLoader { $container = $this->getContainer(); @@ -63,18 +51,13 @@ public function createCollectionLoader() ]] ]); - $loader = new CollectionLoader([ + return new CollectionLoader([ 'logger' => $container['logger'], 'factory' => $factory, ]); - - return $loader; } - /** - * @return Model - */ - public function createModel() + public function createModel(): \Charcoal\Model\Model { $container = $this->getContainer(); @@ -117,10 +100,7 @@ public function createModel() return $model; } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $loader = $this->loader; $loader->setModel($this->model); @@ -134,30 +114,21 @@ public function testSetData() $this->assertEquals([ 'id', 'test' ], $loader->properties()); } - /** - * @return void - */ - public function testSetDataIsChainable() + public function testSetDataIsChainable(): void { $loader = $this->loader; $ret = $loader->setData([]); $this->assertSame($ret, $loader); } - /** - * @return void - */ - public function testDefaultCollection() + public function testDefaultCollection(): void { $loader = $this->loader; $collection = $loader->createCollection(); $this->assertInstanceOf(Collection::class, $collection); } - /** - * @return void - */ - public function testCustomCollectionClass() + public function testCustomCollectionClass(): void { $loader = $this->loader; @@ -177,10 +148,7 @@ public function testCustomCollectionClass() $this->assertInternalType('array', $collection); } - /** - * @return void - */ - public function testAll() + public function testAll(): void { $loader = $this->loader; $loader->setModel($this->model) @@ -194,7 +162,7 @@ public function testAll() $this->assertTrue($loader->hasModel()); - $collection = $loader->load(); + $loader->load(); $this->assertEquals(1, 1); @@ -204,13 +172,8 @@ public function testAll() /** * Test camelization. * - * @covers \Charcoal\Loader\CollectionLoader::camelize - * @covers \Charcoal\Loader\CollectionLoader::getter - * @covers \Charcoal\Loader\CollectionLoader::setter - * - * @return void */ - public function testCamelize() + public function testCamelize(): void { $loader = $this->loader; diff --git a/packages/core/tests/Charcoal/Mock/BadStorableMock.php b/packages/core/tests/Charcoal/Mock/BadStorableMock.php index 40765d358..fced583e3 100644 --- a/packages/core/tests/Charcoal/Mock/BadStorableMock.php +++ b/packages/core/tests/Charcoal/Mock/BadStorableMock.php @@ -1,5 +1,7 @@ fail; } @@ -70,7 +71,8 @@ protected function preSave() * @see StorableTrait::postSave() * @return boolean TRUE to indicate object was created. */ - protected function postSave() + #[\Override] + protected function postSave(): bool { return !$this->fail; } @@ -82,7 +84,8 @@ protected function postSave() * @param string[] $keys Optional list of properties to update. * @return boolean TRUE to proceed with update; FALSE to stop update. */ - protected function preUpdate(array $keys = null) + #[\Override] + protected function preUpdate(?array $keys = null): bool { return $this->fail; } @@ -94,7 +97,8 @@ protected function preUpdate(array $keys = null) * @param string[] $keys Optional list of properties to update. * @return boolean TRUE to indicate object was updated. */ - protected function postUpdate(array $keys = null) + #[\Override] + protected function postUpdate(?array $keys = null): bool { return !$this->fail; } @@ -105,7 +109,8 @@ protected function postUpdate(array $keys = null) * @see StorableTrait::preDelete() * @return boolean TRUE to proceed with deletion; FALSE to stop deletion. */ - protected function preDelete() + #[\Override] + protected function preDelete(): bool { return $this->fail; } @@ -116,7 +121,8 @@ protected function preDelete() * @see StorableTrait::postDelete() * @return boolean TRUE to indicate object was deleted. */ - protected function postDelete() + #[\Override] + protected function postDelete(): bool { return !$this->fail; } diff --git a/packages/core/tests/Charcoal/Mock/FilterCollectionClass.php b/packages/core/tests/Charcoal/Mock/FilterCollectionClass.php index b7bbac07b..a6b15238c 100644 --- a/packages/core/tests/Charcoal/Mock/FilterCollectionClass.php +++ b/packages/core/tests/Charcoal/Mock/FilterCollectionClass.php @@ -23,7 +23,7 @@ class FilterCollectionClass implements * @param array $data Optional expression data. * @return FilterInterface */ - protected function createFilter(array $data = null) + protected function createFilter(?array $data = null): \Charcoal\Source\Filter { $filter = new Filter(); if ($data !== null) { diff --git a/packages/core/tests/Charcoal/Mock/GenericModel.php b/packages/core/tests/Charcoal/Mock/GenericModel.php index 64e28d826..584f4b326 100644 --- a/packages/core/tests/Charcoal/Mock/GenericModel.php +++ b/packages/core/tests/Charcoal/Mock/GenericModel.php @@ -1,5 +1,7 @@ [ @@ -55,9 +57,8 @@ public function __construct(array $data = null) /** * @param mixed $name The name of the model. - * @return self */ - public function setName($name) + public function setName($name): static { $this->name = $name; return $this; @@ -71,10 +72,7 @@ public function name() return $this->name; } - /** - * @return string - */ - public function icon() + public function icon(): string { return ''; } diff --git a/packages/core/tests/Charcoal/Mock/MockModule.php b/packages/core/tests/Charcoal/Mock/MockModule.php index e9c7f93da..cebde9ac0 100644 --- a/packages/core/tests/Charcoal/Mock/MockModule.php +++ b/packages/core/tests/Charcoal/Mock/MockModule.php @@ -1,5 +1,7 @@ $data The expression data; * as an associative array. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -40,7 +40,8 @@ public function setData(array $data) * * @return array An associative array. */ - public function defaultData() + #[\Override] + public function defaultData(): array { return [ 'property' => null, @@ -60,7 +61,8 @@ public function defaultData() * * @return array An associative array. */ - public function data() + #[\Override] + public function data(): array { return [ 'property' => $this->property(), @@ -80,9 +82,8 @@ public function data() * * @see OrderCollectionTrait::createOrder() * @param array $data Optional expression data. - * @return self */ - protected function createOrder(array $data = null) + protected function createOrder(?array $data = null): static { $order = new static(); if ($data !== null) { @@ -104,8 +105,6 @@ public function traverse(callable $callable) /** * Clone this expression and its subtree of expressions. - * - * @return void */ public function __clone() { diff --git a/packages/core/tests/Charcoal/Mock/SourceMock.php b/packages/core/tests/Charcoal/Mock/SourceMock.php index c423156ae..b17ff8e66 100644 --- a/packages/core/tests/Charcoal/Mock/SourceMock.php +++ b/packages/core/tests/Charcoal/Mock/SourceMock.php @@ -1,5 +1,7 @@ $this->logger @@ -75,7 +70,7 @@ protected function createSource() * @param mixed $offset The offset to check for. * @return boolean Returns TRUE on success or FALSE on failure. */ - public function offsetExists($offset) + public function offsetExists($offset): bool { return isset($this->data[$offset]); } @@ -88,7 +83,7 @@ public function offsetExists($offset) */ public function offsetGet($offset) { - return isset($this->data[$offset]) ? $this->data[$offset] : null; + return $this->data[$offset] ?? null; } /** @@ -96,9 +91,8 @@ public function offsetGet($offset) * * @param mixed $offset The offset to assign the value to. * @param mixed $value The value to set. - * @return void */ - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { if ($offset === null) { $this->data[] = $value; @@ -111,9 +105,8 @@ public function offsetSet($offset, $value) * Unset an offset. * * @param mixed $offset The offset to unset. - * @return void */ - public function offsetUnset($offset) + public function offsetUnset($offset): void { unset($this->data[$offset]); } diff --git a/packages/core/tests/Charcoal/Mock/ValidatableClass.php b/packages/core/tests/Charcoal/Mock/ValidatableClass.php index 142032f8a..a2004ff0b 100644 --- a/packages/core/tests/Charcoal/Mock/ValidatableClass.php +++ b/packages/core/tests/Charcoal/Mock/ValidatableClass.php @@ -20,9 +20,8 @@ class ValidatableClass implements ValidatableInterface /** * @param array|null $data Validator data. - * @return ValidatorClass */ - public function createValidator(array $data = null) + public function createValidator(?array $data = null): \Charcoal\Tests\Mock\ValidatorClass { $v = new ValidatorClass(); if ($data !== null) { diff --git a/packages/core/tests/Charcoal/Mock/ValidatorClass.php b/packages/core/tests/Charcoal/Mock/ValidatorClass.php index cae083a0d..43d7d2373 100644 --- a/packages/core/tests/Charcoal/Mock/ValidatorClass.php +++ b/packages/core/tests/Charcoal/Mock/ValidatorClass.php @@ -1,5 +1,7 @@ obj = $this->getMockForAbstractClass(AbstractMetadata::class); + $this->obj = new class () extends AbstractMetadata {}; } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->merge([ @@ -39,10 +33,7 @@ public function testSetData() $this->assertEquals('bar', $obj->foo); } - /** - * @return void - */ - public function testArrayAccessOffsetExists() + public function testArrayAccessOffsetExists(): void { $obj = $this->obj; $this->assertFalse(isset($obj['x'])); diff --git a/packages/core/tests/Charcoal/Model/CollectionTest.php b/packages/core/tests/Charcoal/Model/CollectionTest.php index 9ef435593..f13ccda9d 100644 --- a/packages/core/tests/Charcoal/Model/CollectionTest.php +++ b/packages/core/tests/Charcoal/Model/CollectionTest.php @@ -41,9 +41,6 @@ class CollectionTest extends AbstractTestCase */ protected $map; - /** - * @return void - */ protected function setUp(): void { $this->map = [ @@ -66,97 +63,66 @@ protected function setUp(): void // Test \Charcoal\Model\CollectionInterface // ============================================================================================= - - /** - * @return void - */ - public function testCollectionIsConstructed() + public function testCollectionIsConstructed(): void { $c = new Collection; $this->assertSame([], $c->all()); - $c = new Collection(null); + $c = new Collection(); $this->assertSame([], $c->all()); } - /** - * @return void - */ - public function testConstructMethodWithAcceptableData() + public function testConstructMethodWithAcceptableData(): void { [$o1] = $this->arr; $c = new Collection($o1); $this->assertSame([ self::OBJ_1 => $o1 ], $c->all()); } - /** - * @return void - */ - public function testConstructMethodWithUnacceptableData() + public function testConstructMethodWithUnacceptableData(): void { $this->expectException(InvalidArgumentException::class); - $c = new Collection('foo'); + new Collection('foo'); } - /** - * @return void - */ - public function testConstructMethodFromArray() + public function testConstructMethodFromArray(): void { $c = new Collection($this->arr); $this->assertEquals($this->map, $c->all()); } - /** - * @return void - */ - public function testConstructMethodFromTraversable() + public function testConstructMethodFromTraversable(): void { $c = new Collection(new ArrayObject($this->arr)); $this->assertEquals($this->map, $c->all()); } - /** - * @return void - */ - public function testConstructMethodFromCollection() + public function testConstructMethodFromCollection(): void { $c = new Collection(new Collection($this->arr)); $this->assertEquals($this->map, $c->all()); } - /** - * @return void - */ - public function testValues() + public function testValues(): void { $c = new Collection($this->arr); $this->assertEquals($this->arr, $c->values()); } - /** - * @return void - */ - public function testKeys() + public function testKeys(): void { $c = new Collection($this->arr); $this->assertEquals(array_keys($this->map), $c->keys()); } - /** - * @return void - */ - public function testBaseCollection() + public function testBaseCollection(): void { $c = new Collection($this->arr); $this->assertInstanceOf(Collection::class, $c->toBase()); } - /** - * @return void - */ - public function testEmptyCollection() + public function testEmptyCollection(): void { $c = new Collection; @@ -165,10 +131,7 @@ public function testEmptyCollection() $this->assertEquals(null, $c->last()); } - /** - * @return void - */ - public function testFirstItemInCollection() + public function testFirstItemInCollection(): void { [$o1, $o2, $o3, $o4, $o5] = $this->arr; $c = new Collection($this->arr); @@ -176,10 +139,7 @@ public function testFirstItemInCollection() $this->assertEquals($o1, $c->first()); } - /** - * @return void - */ - public function testLastItemInCollection() + public function testLastItemInCollection(): void { [$o1, $o2, $o3, $o4, $o5] = $this->arr; $c = new Collection($this->arr); @@ -187,16 +147,12 @@ public function testLastItemInCollection() $this->assertEquals($o5, $c->last()); } - /** - * @return void - */ - public function testArrayableItems() + public function testArrayableItems(): void { $c = new Collection; $class = new ReflectionClass($c); $method = $class->getMethod('asArray'); - $method->setAccessible(true); $items = new Collection($this->arr); $array = $method->invokeArgs($c, [ $items ]); @@ -211,10 +167,7 @@ public function testArrayableItems() $this->assertSame($this->arr, $array); } - /** - * @return void - */ - public function testRemoveKey() + public function testRemoveKey(): void { [$o1] = $this->arr; @@ -227,30 +180,21 @@ public function testRemoveKey() $this->assertFalse(isset($c[self::OBJ_1])); } - /** - * @return void - */ - public function testAddAcceptableData() + public function testAddAcceptableData(): void { [$o1] = $this->arr; $c = new Collection; $this->assertSame([ $o1->id() => $o1 ], $c->add($o1)->all()); } - /** - * @return void - */ - public function testAddUnacceptableData() + public function testAddUnacceptableData(): void { $this->expectException(InvalidArgumentException::class); $c = new Collection; $c->add('foo'); } - /** - * @return void - */ - public function testGet() + public function testGet(): void { [$o1, $o2, $o3, $o4, $o5] = $this->arr; $c = new Collection($this->arr); @@ -258,10 +202,7 @@ public function testGet() $this->assertSame($o1, $c->get($o1)); } - /** - * @return void - */ - public function testHas() + public function testHas(): void { [$o1, $o2, $o3, $o4, $o5] = $this->arr; $c = new Collection($this->arr); @@ -270,28 +211,19 @@ public function testHas() $this->assertFalse($c->offsetExists('missing')); } - /** - * @return void - */ - public function testClear() + public function testClear(): void { $c = new Collection($this->arr); $this->assertSame([], $c->clear()->all()); } - /** - * @return void - */ - public function testMergeNull() + public function testMergeNull(): void { $c = new Collection($this->arr); $this->assertEquals($this->map, $c->merge(null)->all()); } - /** - * @return void - */ - public function testMergeArray() + public function testMergeArray(): void { [$o1, $o2, $o3, $o4, $o5] = $this->arr; $c = new Collection([ $o1, $o2, $o3, $o4 ]); @@ -299,10 +231,7 @@ public function testMergeArray() $this->assertEquals($this->map, $c->merge([ $o5 ])->all()); } - /** - * @return void - */ - public function testMergeCollection() + public function testMergeCollection(): void { [$o1, $o2, $o3, $o4, $o5] = $this->arr; $c1 = new Collection([ $o1, $o2, $o3, $o4 ]); @@ -313,11 +242,7 @@ public function testMergeCollection() // Test \IteratorAggregate // ============================================================================================= - - /** - * @return void - */ - public function testIterable() + public function testIterable(): void { $c = new Collection($this->arr); @@ -326,10 +251,7 @@ public function testIterable() $this->assertEquals($this->map, $i->getArrayCopy()); } - /** - * @return void - */ - public function testCachingIterator() + public function testCachingIterator(): void { [$o1, $o2, $o3, $o4, $o5] = $this->arr; $c = new Collection($this->arr); @@ -353,11 +275,7 @@ public function testCachingIterator() // Test \Countable // ============================================================================================= - - /** - * @return void - */ - public function testCountable() + public function testCountable(): void { $c = new Collection($this->arr); $this->assertCount(count($this->arr), $c); @@ -365,11 +283,7 @@ public function testCountable() // Test \ArrayAccess // ============================================================================================= - - /** - * @return void - */ - public function testArrayAccess() + public function testArrayAccess(): void { [$o1, $o2, $o3, $o4, $o5] = $this->arr; @@ -390,10 +304,7 @@ public function testArrayAccess() $this->assertEquals($o4, $c[-1]); } - /** - * @return void - */ - public function testArrayAccessOffsetExists() + public function testArrayAccessOffsetExists(): void { $c = new Collection($this->arr); $this->assertTrue($c->offsetExists(0)); @@ -401,10 +312,7 @@ public function testArrayAccessOffsetExists() $this->assertFalse($c->offsetExists(5)); } - /** - * @return void - */ - public function testArrayAccessOffsetGet() + public function testArrayAccessOffsetGet(): void { [$o1, $o2] = $this->arr; @@ -413,10 +321,7 @@ public function testArrayAccessOffsetGet() $this->assertEquals($o2, $c->offsetGet(1)); } - /** - * @return void - */ - public function testArrayAccessOffsetGetWithNegativeOffset() + public function testArrayAccessOffsetGetWithNegativeOffset(): void { [$o1, $o2, $o3, $o4, $o5] = $this->arr; @@ -426,19 +331,13 @@ public function testArrayAccessOffsetGetWithNegativeOffset() $this->assertEquals($o3, $c->offsetGet(-1)); } - /** - * @return void - */ - public function testArrayAccessOffsetGetOnNonExist() + public function testArrayAccessOffsetGetOnNonExist(): void { $c = new Collection($this->arr); $this->assertEquals(null, $c->offsetGet(10)); } - /** - * @return void - */ - public function testArrayAccessOffsetSet() + public function testArrayAccessOffsetSet(): void { [$o1, $o2] = $this->arr; $c = new Collection($o1); @@ -447,11 +346,7 @@ public function testArrayAccessOffsetSet() $this->assertEquals($o2, $c[1]); } - /** - * - * @return void - */ - public function testArrayAccessOffsetSetWithOffset() + public function testArrayAccessOffsetSetWithOffset(): void { $this->expectException(LogicException::class); [$o1] = $this->arr; @@ -460,11 +355,7 @@ public function testArrayAccessOffsetSetWithOffset() $c->offsetSet(1, $o1); } - /** - * - * @return void - */ - public function testArrayAccessOffsetSetWithKey() + public function testArrayAccessOffsetSetWithKey(): void { $this->expectException(LogicException::class); [$o1] = $this->arr; @@ -473,10 +364,7 @@ public function testArrayAccessOffsetSetWithKey() $c->offsetSet(self::OBJ_1, $o1); } - /** - * @return void - */ - public function testArrayAccessOffsetUnset() + public function testArrayAccessOffsetUnset(): void { $c = new Collection($this->arr); @@ -484,10 +372,7 @@ public function testArrayAccessOffsetUnset() $this->assertEquals(null, $c[self::OBJ_2]); } - /** - * @return void - */ - public function testArrayAccessOffsetUnsetWithKey() + public function testArrayAccessOffsetUnsetWithKey(): void { $c = new Collection($this->arr); diff --git a/packages/core/tests/Charcoal/Model/ModelMetadataTest.php b/packages/core/tests/Charcoal/Model/ModelMetadataTest.php index 0af4aefce..61f8e1372 100644 --- a/packages/core/tests/Charcoal/Model/ModelMetadataTest.php +++ b/packages/core/tests/Charcoal/Model/ModelMetadataTest.php @@ -13,23 +13,14 @@ */ class ModelMetadataTest extends AbstractTestCase { - /** - * @var ModelMetadata - */ - private $obj; - - /** - * @return void - */ + private \Charcoal\Model\ModelMetadata $obj; + protected function setUp(): void { $this->obj = new ModelMetadata(); } - /** - * @return void - */ - public function testSetIdent() + public function testSetIdent(): void { $ret = $this->obj->setIdent('foo'); $this->assertSame($ret, $this->obj); @@ -39,10 +30,7 @@ public function testSetIdent() $this->obj->setIdent(false); } - /** - * @return void - */ - public function testArrayAccessGet() + public function testArrayAccessGet(): void { $obj = $this->obj; $obj->foo = 'bar'; @@ -50,10 +38,7 @@ public function testArrayAccessGet() $this->assertEquals($obj->foo, $obj['foo']); } - /** - * @return void - */ - public function testArrayAccessSet() + public function testArrayAccessSet(): void { $obj = $this->obj; $obj['foo'] = 'bar'; @@ -61,25 +46,19 @@ public function testArrayAccessSet() $this->assertEquals($obj->foo, $obj['foo']); } - /** - * @return void - */ - public function testArrayAccessUnset() + public function testArrayAccessUnset(): void { $obj = $this->obj; - $this->assertObjectNotHasAttribute('foo', $obj); + $this->assertFalse(property_exists($obj, 'foo')); $obj['foo'] = 'bar'; - $this->assertObjectHasAttribute('foo', $obj); + $this->assertTrue(property_exists($obj, 'foo')); unset($obj['foo']); //$this->assertObjectNotHasAttribute('foo', $obj); } - /** - * @return void - */ - public function testMerge() + public function testMerge(): void { $data = [ 'foo' => 'bar', @@ -93,10 +72,7 @@ public function testMerge() $this->assertEquals($obj->bar, 'foo'); } - /** - * @return void - */ - public function testMergeIsChainable() + public function testMergeIsChainable(): void { $obj = $this->obj; $ret = $obj->merge([]); diff --git a/packages/core/tests/Charcoal/Model/ModelTest.php b/packages/core/tests/Charcoal/Model/ModelTest.php index dad743937..42eddb2a8 100644 --- a/packages/core/tests/Charcoal/Model/ModelTest.php +++ b/packages/core/tests/Charcoal/Model/ModelTest.php @@ -24,10 +24,8 @@ class ModelTest extends AbstractTestCase /** * Retrieve the model's mock metadata. - * - * @return array */ - private function getModelMetadata() + private function getModelMetadata(): array { return [ 'properties' => [ @@ -75,10 +73,8 @@ private function createModel() /** * Drop the SQL table. - * - * @return void */ - private function dropTable() + private function dropTable(): void { $container = $this->getContainer(); @@ -87,10 +83,8 @@ private function dropTable() /** * Retrieve the model's mock object data. - * - * @return array */ - private function getHuxleyData() + private function getHuxleyData(): array { return [ 'id' => 1, @@ -104,7 +98,7 @@ private function getHuxleyData() * * @return integer The saved object ID. */ - private function saveHuxley() + private function saveHuxley(): bool { $obj = $this->obj; $obj->setData($this->getHuxleyData()); @@ -116,8 +110,6 @@ private function saveHuxley() * Set up the test. * * Create the SQL table for the test, dropping any existing table. - * - * @return void */ protected function setUp(): void { @@ -130,17 +122,12 @@ protected function setUp(): void * Tear down the test. * * Drop any existing SQL table. - * - * @return void */ protected function tearDown(): void { $this->dropTable(); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $obj = $this->obj; @@ -148,10 +135,7 @@ public function testConstructor() $this->assertInstanceOf(ModelInterface::class, $obj); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ 'name' => 'Orwell' ]); @@ -160,10 +144,7 @@ public function testSetData() $this->assertEquals('Orwell', $obj->name); } - /** - * @return void - */ - public function testSetFlatData() + public function testSetFlatData(): void { $obj = $this->obj; $ret = $obj->setFlatData([ 'name' => 'Clarke' ]); @@ -172,22 +153,16 @@ public function testSetFlatData() $this->assertEquals('Clarke', $obj->name); } - /** - * @return void - */ - public function testSave() + public function testSave(): void { $ret = $this->saveHuxley(); $this->assertEquals(1, $ret); } - /** - * @return void - */ - public function testLoad() + public function testLoad(): void { - $ret = $this->saveHuxley(); + $this->saveHuxley(); $obj1 = $this->createModel(); $obj1->load(1); @@ -195,10 +170,7 @@ public function testLoad() $this->assertEquals($this->getHuxleyData(), $obj1->data()); } - /** - * @return void - */ - public function testUpdate() + public function testUpdate(): void { $ret = $this->saveHuxley(); @@ -226,10 +198,7 @@ public function testUpdate() $this->assertEquals('Screenwriter', $obj2['role']); } - /** - * @return void - */ - public function testDelete() + public function testDelete(): void { $ret = $this->saveHuxley(); @@ -242,19 +211,15 @@ public function testDelete() $this->assertEquals(null, $obj1['id']); } - /** - * @return void - */ - public function testSerializeUnserialize() + public function testSerializeUnserialize(): void { $obj = $this->obj; $data = $this->getHuxleyData(); $obj->setData($data); - $serialized = serialize($obj); $this->assertEquals( - 'C:20:"Charcoal\Model\Model":69:{a:3:{s:2:"id";i:1;s:4:"name";s:6:"Huxley";s:4:"role";s:8:"Novelist";}}', + 'O:20:"Charcoal\Model\Model":3:{s:2:"id";i:1;s:4:"name";s:6:"Huxley";s:4:"role";s:8:"Novelist";}', serialize($obj) ); @@ -265,10 +230,7 @@ public function testSerializeUnserialize() $this->assertEquals('Huxley', $obj2['name']); } - /** - * @return void - */ - public function testJsonSerialize() + public function testJsonSerialize(): void { $obj = $this->obj; $data = $this->getHuxleyData(); diff --git a/packages/core/tests/Charcoal/Model/ModelValidatorTest.php b/packages/core/tests/Charcoal/Model/ModelValidatorTest.php index 9fd4736e7..d8d88e5f9 100644 --- a/packages/core/tests/Charcoal/Model/ModelValidatorTest.php +++ b/packages/core/tests/Charcoal/Model/ModelValidatorTest.php @@ -1,5 +1,7 @@ getContainer(); @@ -31,20 +30,14 @@ protected function model() ]); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $model = $this->model(); $obj = new ModelValidator($model); $this->assertInstanceOf(ModelValidator::class, $obj); } - /** - * @return void - */ - public function testValidateModel() + public function testValidateModel(): void { $model = $this->model(); $model->setMetadata([ diff --git a/packages/core/tests/Charcoal/Model/Service/MetadataLoaderTest.php b/packages/core/tests/Charcoal/Model/Service/MetadataLoaderTest.php index fd02a4cae..e8198d818 100644 --- a/packages/core/tests/Charcoal/Model/Service/MetadataLoaderTest.php +++ b/packages/core/tests/Charcoal/Model/Service/MetadataLoaderTest.php @@ -1,5 +1,7 @@ getContainer(); @@ -33,10 +32,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testLoadData() + public function testLoadData(): void { $this->assertInstanceOf(MetadataLoader::class, $this->obj); //$ret = $this->obj->load('test', $this->); diff --git a/packages/core/tests/Charcoal/Model/Service/ModelLoaderBuilderTest.php b/packages/core/tests/Charcoal/Model/Service/ModelLoaderBuilderTest.php index fd973062a..0648993fc 100644 --- a/packages/core/tests/Charcoal/Model/Service/ModelLoaderBuilderTest.php +++ b/packages/core/tests/Charcoal/Model/Service/ModelLoaderBuilderTest.php @@ -24,9 +24,6 @@ class ModelLoaderBuilderTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -52,19 +49,13 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testBuild() + public function testBuild(): void { $ret = $this->obj->build(GenericModel::class, 'name'); $this->assertInstanceOf(ModelLoader::class, $ret); } - /** - * @return void - */ - public function testInvokable() + public function testInvokable(): void { $builder = $this->obj; $ret = $builder(GenericModel::class); diff --git a/packages/core/tests/Charcoal/Model/Service/ModelLoaderTest.php b/packages/core/tests/Charcoal/Model/Service/ModelLoaderTest.php index 3390e30a0..5553c5fab 100644 --- a/packages/core/tests/Charcoal/Model/Service/ModelLoaderTest.php +++ b/packages/core/tests/Charcoal/Model/Service/ModelLoaderTest.php @@ -1,5 +1,7 @@ expectException(Exception::class); $this->obj->load('foobar'); diff --git a/packages/core/tests/Charcoal/Model/ServiceProvider/ModelServiceProviderTest.php b/packages/core/tests/Charcoal/Model/ServiceProvider/ModelServiceProviderTest.php index d2e5704a2..915f47222 100644 --- a/packages/core/tests/Charcoal/Model/ServiceProvider/ModelServiceProviderTest.php +++ b/packages/core/tests/Charcoal/Model/ServiceProvider/ModelServiceProviderTest.php @@ -51,9 +51,6 @@ class ModelServiceProviderTest extends AbstractTestCase public $obj; - /** - * @return void - */ protected function setUp(): void { $this->obj = new ModelServiceProvider(); @@ -70,9 +67,8 @@ protected function setUp(): void * - view * * @todo Use ContainerIntegrationTrait? - * @return Container */ - private function container() + private function container(): \Pimple\Container { $container = new Container(); @@ -117,10 +113,7 @@ private function container() return $container; } - /** - * @return void - */ - public function testFactories() + public function testFactories(): void { $container = $this->container(); @@ -136,10 +129,7 @@ public function testFactories() $this->assertInstanceOf(FactoryInterface::class, $container['source/factory']); } - /** - * @return void - */ - public function testRegisterSetsModelBuilder() + public function testRegisterSetsModelBuilder(): void { $container = $this->container(); $this->obj->register($container); @@ -148,10 +138,7 @@ public function testRegisterSetsModelBuilder() $this->assertInstanceOf(ModelBuilder::class, $container['model/builder']); } - /** - * @return void - */ - public function testRegisterSetsModelLoaderBuilder() + public function testRegisterSetsModelLoaderBuilder(): void { $container = $this->container(); $this->obj->register($container); @@ -160,10 +147,7 @@ public function testRegisterSetsModelLoaderBuilder() $this->assertInstanceOf(ModelLoaderBuilder::class, $container['model/loader/builder']); } - /** - * @return void - */ - public function testRegisterSetsMetadataLoader() + public function testRegisterSetsMetadataLoader(): void { $container = $this->container(); $this->obj->register($container); @@ -172,17 +156,14 @@ public function testRegisterSetsMetadataLoader() $this->assertInstanceOf(MetadataLoader::class, $container['metadata/loader']); } - /** - * @return void - */ - public function testExtraMetadataPaths() + public function testExtraMetadataPaths(): void { $container = new Container([ 'config' => [ - 'base_path' => dirname(dirname(dirname(dirname(__DIR__)))), + 'base_path' => dirname(__DIR__, 4), ], 'module/classes' => [ - 'Charcoal\\Tests\\Mock\\MockModule', + \Charcoal\Tests\Mock\MockModule::class, ], ]); diff --git a/packages/core/tests/Charcoal/ReflectionsTrait.php b/packages/core/tests/Charcoal/ReflectionsTrait.php index 3a63ff2b1..047d2c172 100644 --- a/packages/core/tests/Charcoal/ReflectionsTrait.php +++ b/packages/core/tests/Charcoal/ReflectionsTrait.php @@ -18,13 +18,10 @@ trait ReflectionsTrait * * @param mixed $class The class name or object that contains the method. * @param string $name The method name to reflect. - * @return ReflectionMethod */ - public function getMethod($class, $name) + public function getMethod($class, $name): \ReflectionMethod { - $reflected = new ReflectionMethod($class, $name); - $reflected->setAccessible(true); - return $reflected; + return new ReflectionMethod($class, $name); } /** @@ -38,7 +35,7 @@ public function getMethod($class, $name) public function callMethod($object, $name, array $args = []) { $method = $this->getMethod($object, $name); - if (empty($args)) { + if ($args === []) { return $method->invoke($object); } else { return $method->invokeArgs($object, $args); @@ -65,13 +62,10 @@ public function callMethodWith($object, $name, ...$args) * * @param mixed $class The class name or object that contains the property. * @param string $name The property name to reflect. - * @return ReflectionProperty */ - public function getProperty($class, $name) + public function getProperty($class, $name): \ReflectionProperty { - $reflected = new ReflectionProperty($class, $name); - $reflected->setAccessible(true); - return $reflected; + return new ReflectionProperty($class, $name); } /** @@ -92,9 +86,8 @@ public function getPropertyValue($object, $name) * @param mixed $object The object to access. * @param string $name The property name to affect. * @param mixed $value The new value. - * @return void */ - public function setPropertyValue($object, $name, $value) + public function setPropertyValue($object, $name, $value): void { $this->getProperty($object, $name)->setValue($object, $value); } diff --git a/packages/core/tests/Charcoal/Source/AbstractExpressionTest.php b/packages/core/tests/Charcoal/Source/AbstractExpressionTest.php index a82b15ba5..95bf86449 100644 --- a/packages/core/tests/Charcoal/Source/AbstractExpressionTest.php +++ b/packages/core/tests/Charcoal/Source/AbstractExpressionTest.php @@ -2,6 +2,7 @@ namespace Charcoal\Tests\Source; +use Charcoal\Property\DateTimeProperty; use stdClass; use DateTime; use InvalidArgumentException; @@ -27,7 +28,16 @@ class AbstractExpressionTest extends AbstractTestCase */ final protected function createExpression() { - return $this->getMockForAbstractClass(AbstractExpression::class); + return new class () extends AbstractExpression + { + public function defaultData() + { + } + + public function data() + { + } + }; } /** @@ -37,10 +47,8 @@ final protected function createExpression() * 1. Default state * 2. Mutated state * 3. Chainable method - * - * @return void */ - public function testName() + public function testName(): void { $obj = $this->createExpression(); @@ -57,10 +65,8 @@ public function testName() /** * Test "name" property with invalid value. - * - * @return void */ - public function testNameWithInvalidValue() + public function testNameWithInvalidValue(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setName(0); @@ -74,10 +80,8 @@ public function testNameWithInvalidValue() * 2. Mutated state * 3. Chainable method * 4. Cast value to boolean - * - * @return void */ - public function testActive() + public function testActive(): void { $obj = $this->createExpression(); @@ -102,16 +106,19 @@ public function testActive() /** * Test value parsing. * - * @dataProvider provideParsableValues * * @param mixed $value The value to test. * @param mixed $expected The expected result. - * @return void */ - public function testParseValue($value, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('provideParsableValues')] + public function testParseValue($value, int|string|bool|null $expected): void { $obj = $this->createExpression(); + if ($value instanceof \Closure) { + $value = $value->call($this); + } + $this->assertEquals($expected, $obj::parseValue($value)); } @@ -119,14 +126,16 @@ public function testParseValue($value, $expected) * Provide data for value parsing. * * @used-by self::testParseValue() - * @return array */ - public function provideParsableValues() + public static function provideParsableValues(): array { - $container = $this->getContainer(); + $prop = function () { + $container = $this->getContainer(); + return $container['property/factory'] + ->create('date-time') + ->setVal('13 July 2004'); + }; - $prop = $container['property/factory']->create('date-time'); - $prop->setVal('13 July 2004'); $time = new DateTime('8 June 1995'); return [ @@ -144,13 +153,12 @@ public function provideParsableValues() /** * Test value quoting. * - * @dataProvider provideQuotableValues * * @param mixed $value The value to test. * @param mixed $expected The expected result. - * @return void */ - public function testQuoteValue($value, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('provideQuotableValues')] + public function testQuoteValue(int|string|bool|\stdClass|array|null $value, int|string|\stdClass|array|null $expected): void { $obj = $this->createExpression(); @@ -161,9 +169,8 @@ public function testQuoteValue($value, $expected) * Provide data for value quoting. * * @used-by self::testQuoteValue() - * @return array */ - public function provideQuotableValues() + public static function provideQuotableValues(): array { $obj = new stdClass(); @@ -182,14 +189,13 @@ public function provideQuotableValues() /** * Test field quoting. * - * @dataProvider provideQuotableIdentifiers * * @param mixed $fieldName The field name. * @param mixed $tableName The table name. * @param mixed $expected The expected identifier. - * @return void */ - public function testQuoteIdentifier($fieldName, $tableName, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('provideQuotableIdentifiers')] + public function testQuoteIdentifier(?string $fieldName, ?string $tableName, string $expected): void { $obj = $this->createExpression(); @@ -200,9 +206,8 @@ public function testQuoteIdentifier($fieldName, $tableName, $expected) * Provide data for field quoting. * * @used-by self::testQuoteIdentifier() - * @return array */ - public function provideQuotableIdentifiers() + public static function provideQuotableIdentifiers(): array { return [ [ null, null, '' ], @@ -216,10 +221,8 @@ public function provideQuotableIdentifiers() /** * Test field quoting with invalid field name. - * - * @return void */ - public function testQuoteIdentifierWithInvalidFieldName() + public function testQuoteIdentifierWithInvalidFieldName(): void { $this->expectException(InvalidArgumentException::class); $obj = $this->createExpression(); @@ -228,10 +231,8 @@ public function testQuoteIdentifierWithInvalidFieldName() /** * Test field quoting with blank table name. - * - * @return void */ - public function testQuoteIdentifierWithBlankTableName() + public function testQuoteIdentifierWithBlankTableName(): void { $this->expectException(InvalidArgumentException::class); $obj = $this->createExpression(); @@ -240,10 +241,8 @@ public function testQuoteIdentifierWithBlankTableName() /** * Test field quoting with invalid table name. - * - * @return void */ - public function testQuoteIdentifierWithInvalidTableName() + public function testQuoteIdentifierWithInvalidTableName(): void { $this->expectException(InvalidArgumentException::class); $obj = $this->createExpression(); @@ -253,14 +252,13 @@ public function testQuoteIdentifierWithInvalidTableName() /** * Test value differentiation. * - * @dataProvider provideDiffValues * * @param mixed $a The custom value. * @param mixed $b The default value. * @param mixed $expected The expected result. - * @return void */ - public function testDiffValues($a, $b, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('provideDiffValues')] + public function testDiffValues(int $a, int|string $b, int $expected): void { $obj = $this->createExpression(); @@ -271,9 +269,8 @@ public function testDiffValues($a, $b, $expected) * Provide data for value differentiation. * * @used-by self::testDiffValues() - * @return array */ - public function provideDiffValues() + public static function provideDiffValues(): array { return [ 'Same Type' => [ 5, 5, 0 ], @@ -284,13 +281,12 @@ public function provideDiffValues() /** * Test callable detection. * - * @dataProvider provideCallableValues * * @param mixed $value The value to test. * @param mixed $expected The expected result. - * @return void */ - public function testIsCallable($value, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('provideCallableValues')] + public function testIsCallable(string|\Closure|null $value, bool $expected): void { $obj = $this->createExpression(); @@ -301,14 +297,13 @@ public function testIsCallable($value, $expected) * Provide data for callable detection. * * @used-by self::testIsCallable() - * @return array */ - public function provideCallableValues() + public static function provideCallableValues(): array { return [ 'Null Type' => [ null, false ], 'String Type' => [ 'strval', false ], - 'Closure' => [ function () { + 'Closure' => [ function (): void { }, true ], ]; } diff --git a/packages/core/tests/Charcoal/Source/AbstractSourceTest.php b/packages/core/tests/Charcoal/Source/AbstractSourceTest.php index 744c195a0..d24924f51 100644 --- a/packages/core/tests/Charcoal/Source/AbstractSourceTest.php +++ b/packages/core/tests/Charcoal/Source/AbstractSourceTest.php @@ -2,6 +2,8 @@ namespace Charcoal\Tests\Source; +use Charcoal\Source\StorableInterface; +use Charcoal\Source\UnexpectedValueException; use RuntimeException; use InvalidArgumentException; @@ -34,6 +36,25 @@ /** * Test {@see AbstractSource} and {@see SourceInterface}. */ +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'setProperties')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'addProperties')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'resolvePropertyName')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'hasProperties')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'addProperty')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'removeProperty')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'addFilter')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'parseFilterWithModel')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'createFilter')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'addOrder')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'parseOrderWithModel')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'createOrder')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'pagination')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'hasPagination')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'setPagination')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'createPagination')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'camelize')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'getter')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\AbstractSource::class, 'setter')] class AbstractSourceTest extends AbstractTestCase { use AssertionsTrait; @@ -49,16 +70,20 @@ class AbstractSourceTest extends AbstractTestCase /** * Setup the test. - * - * @return void */ protected function setUp(): void { $container = $this->getContainer(); - $this->obj = $this->getMockForAbstractClass(AbstractSource::class, [[ + $this->obj = new class ([ 'logger' => $container['logger'] - ]]); + ]) extends AbstractSource { + public function loadItem($ident, ?StorableInterface $item = null) {} + public function loadItems(?StorableInterface $item = null) {} + public function saveItem(StorableInterface $item) {} + public function updateItem(StorableInterface $item, ?array $properties = null) {} + public function deleteItem(?StorableInterface $item = null) {} + }; } /** @@ -83,10 +108,8 @@ final public function createProperty() * - clear the filters * - clear the orders * - @todo clear the pagination - * - * @return void */ - public function testReset() + public function testReset(): void { $obj = $this->obj; $filter = $this->createFilter(); @@ -114,10 +137,8 @@ public function testReset() * Assert that the `setData` method: * - is chainable * - set the data (properties, filters, orders & pagination) - * - * @return void */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ @@ -137,10 +158,8 @@ public function testSetData() * Assert that the `setModel` method: * - is chainable * - set the model (retrievable with the `model` method) - * - * @return void */ - public function testSetModel() + public function testSetModel(): void { $container = $this->getContainer(); @@ -159,10 +178,7 @@ public function testSetModel() $this->assertSame($model, $obj->model()); } - /** - * @return void - */ - public function testModelWithoutSetThrowsException() + public function testModelWithoutSetThrowsException(): void { $obj = $this->obj; $this->expectException(RuntimeException::class); @@ -175,13 +191,8 @@ public function testModelWithoutSetThrowsException() * - set the properties * - reset the properties, when called again * - * @covers \Charcoal\Source\AbstractSource::setProperties - * @covers \Charcoal\Source\AbstractSource::addProperties - * @covers \Charcoal\Source\AbstractSource::resolvePropertyName - * - * @return void */ - public function testSetProperties() + public function testSetProperties(): void { $obj = $this->obj; $ret = $obj->setProperties([ 'foo' ]); @@ -199,11 +210,8 @@ public function testSetProperties() * 1. Empty; Default state * 2. Populated; Mutated state * - * @covers \Charcoal\Source\AbstractSource::hasProperties - * - * @return void */ - public function testHasProperties() + public function testHasProperties(): void { $obj = $this->obj; @@ -218,12 +226,8 @@ public function testHasProperties() /** * Test property collection appending. * - * @covers \Charcoal\Source\AbstractSource::addProperty - * @covers \Charcoal\Source\AbstractSource::resolvePropertyName - * - * @return void */ - public function testAddProperty() + public function testAddProperty(): void { $obj = $this->obj; $this->assertEquals([], $obj->properties()); @@ -238,12 +242,8 @@ public function testAddProperty() /** * Test property collection appending. * - * @covers \Charcoal\Source\AbstractSource::removeProperty - * @covers \Charcoal\Source\AbstractSource::resolvePropertyName - * - * @return void */ - public function testRemoveProperty() + public function testRemoveProperty(): void { $obj = $this->obj; $obj->setProperties([ 'foo', 'bar', 'qux' ]); @@ -256,11 +256,8 @@ public function testRemoveProperty() /** * Test failure when appending an invalid property name. * - * @covers \Charcoal\Source\AbstractSource::resolvePropertyName - * - * @return void */ - public function testInvalidPropertyNameResolution() + public function testInvalidPropertyNameResolution(): void { $obj = $this->obj; $this->expectException(InvalidArgumentException::class); @@ -270,11 +267,8 @@ public function testInvalidPropertyNameResolution() /** * Test failure when appending an blank property name. * - * @covers \Charcoal\Source\AbstractSource::resolvePropertyName - * - * @return void */ - public function testBlankPropertyNameResolution() + public function testBlankPropertyNameResolution(): void { $obj = $this->obj; $this->expectException(InvalidArgumentException::class); @@ -284,11 +278,8 @@ public function testBlankPropertyNameResolution() /** * Test failure when appending a unnamed property object. * - * @covers \Charcoal\Source\AbstractSource::resolvePropertyName - * - * @return void */ - public function testAnonymousPropertyNameResolution() + public function testAnonymousPropertyNameResolution(): void { $obj = $this->obj; $prop = $this->createProperty()->setIdent(''); @@ -299,11 +290,8 @@ public function testAnonymousPropertyNameResolution() /** * Test appending a named property object. * - * @covers \Charcoal\Source\AbstractSource::resolvePropertyName - * - * @return void */ - public function testNamedPropertyNameResolution() + public function testNamedPropertyNameResolution(): void { $obj = $this->obj; $prop = $this->createProperty(); @@ -329,11 +317,8 @@ public function testNamedPropertyNameResolution() * an Expression object with given extra data is returned * 6. Chainable method * - * @covers \Charcoal\Source\AbstractSource::addFilter - * - * @return void */ - public function testAddFilter() + public function testAddFilter(): void { $obj = $this->obj; @@ -394,11 +379,8 @@ public function testAddFilter() * 3. If a tree of expressions is passed, the source will traverse * all expressions. * - * @covers \Charcoal\Source\AbstractSource::parseFilterWithModel - * - * @return void */ - public function testParseFilterWithModel() + public function testParseFilterWithModel(): void { $model = $this->createModel(); $source = $this->obj; @@ -438,11 +420,8 @@ public function testParseFilterWithModel() * 2. Instance of {@see Filter} * * @see \Charcoal\Tests\Source\FilterTest::testCreateFilter - * @covers \Charcoal\Source\AbstractSource::createFilter - * - * @return void */ - public function testCreateFilter() + public function testCreateFilter(): void { $result = $this->callMethodWith($this->obj, 'createFilter', [ 'name' => 'foo' ]); $this->assertInstanceOf(Filter::class, $result); @@ -467,11 +446,8 @@ public function testCreateFilter() * an Expression object with given extra data is returned * 6. Chainable method * - * @covers \Charcoal\Source\AbstractSource::addOrder - * - * @return void */ - public function testAddOrder() + public function testAddOrder(): void { $obj = $this->obj; @@ -530,11 +506,8 @@ public function testAddOrder() * 2. If a tree of expressions is passed, the source will traverse * all expressions. * - * @covers \Charcoal\Source\AbstractSource::parseOrderWithModel - * - * @return void */ - public function testParseOrderWithModel() + public function testParseOrderWithModel(): void { $model = $this->createModel(); $source = $this->obj; @@ -567,11 +540,8 @@ public function testParseOrderWithModel() * 1. Instance of {@see ExpressionInterface} * 2. Instance of {@see Order} * - * @covers \Charcoal\Source\AbstractSource::createOrder - * - * @return void */ - public function testCreateOrder() + public function testCreateOrder(): void { $result = $this->callMethodWith($this->obj, 'createOrder', [ 'name' => 'foo' ]); $this->assertInstanceOf(Order::class, $result); @@ -586,12 +556,8 @@ public function testCreateOrder() * 1. Default state is NULL * 2. Create paginator if state is NULL * - * @covers \Charcoal\Source\AbstractSource::pagination - * @covers \Charcoal\Source\AbstractSource::hasPagination - * - * @return void */ - public function testGetPagination() + public function testGetPagination(): void { /** 1. Default state is NULL */ $this->assertFalse($this->obj->hasPagination()); @@ -612,11 +578,8 @@ public function testGetPagination() * 4. Accepts up to two numeric arguments * 5. Chainable method * - * @covers \Charcoal\Source\AbstractSource::setPagination - * - * @return void */ - public function testSetPagination() + public function testSetPagination(): void { $obj = $this->obj; @@ -653,11 +616,8 @@ public function testSetPagination() /** * Test the failure when assigning an invalid pagination expression. * - * @covers \Charcoal\Source\AbstractSource::setPagination - * - * @return void */ - public function testProcessExpressionWithInvalidValue() + public function testProcessExpressionWithInvalidValue(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setPagination(false); @@ -670,11 +630,8 @@ public function testProcessExpressionWithInvalidValue() * 1. Instance of {@see ExpressionInterface} * 2. Instance of {@see PaginationInterface} * - * @covers \Charcoal\Source\AbstractSource::createPagination - * - * @return void */ - public function testCreatePagination() + public function testCreatePagination(): void { $result = $this->callMethodWith($this->obj, 'createPagination', [ 'name' => 'foo' ]); $this->assertInstanceOf(Pagination::class, $result); @@ -682,10 +639,7 @@ public function testCreatePagination() $this->assertEquals('foo', $result->name()); } - /** - * @return void - */ - public function testSetPage() + public function testSetPage(): void { $obj = $this->obj; $this->assertEquals(1, $obj->page()); @@ -698,10 +652,7 @@ public function testSetPage() $obj->setPage('foo'); } - /** - * @return void - */ - public function testNumPerPage() + public function testNumPerPage(): void { $obj = $this->obj; $this->assertEquals(Pagination::DEFAULT_COUNT, $obj->numPerPage()); @@ -713,10 +664,7 @@ public function testNumPerPage() $obj->setNumPerPage('foobar'); } - /** - * @return void - */ - public function testCreateConfig() + public function testCreateConfig(): void { $obj = $this->obj; $config = $obj->createConfig([ 'type' => 'foo' ]); @@ -727,13 +675,8 @@ public function testCreateConfig() /** * Test camelization. * - * @covers \Charcoal\Source\AbstractSource::camelize - * @covers \Charcoal\Source\AbstractSource::getter - * @covers \Charcoal\Source\AbstractSource::setter - * - * @return void */ - public function testCamelize() + public function testCamelize(): void { $obj = $this->obj; @@ -748,9 +691,8 @@ public function testCamelize() * Create a query filter expression, for testing. * * @param array $data Optional expression data. - * @return Filter */ - final public function createFilter(array $data = null) + final public function createFilter(?array $data = null): \Charcoal\Source\Filter { $expr = new Filter(); if ($data !== null) { @@ -763,9 +705,8 @@ final public function createFilter(array $data = null) * Create query sorting expression, for testing. * * @param array $data Optional expression data. - * @return Order */ - final public function createOrder(array $data = null) + final public function createOrder(?array $data = null): \Charcoal\Source\Order { $expr = new Order(); if ($data !== null) { @@ -778,9 +719,8 @@ final public function createOrder(array $data = null) * Create query pagination expression, for testing. * * @param array $data Optional expression data. - * @return Pagination */ - final public function createPagination(array $data = null) + final public function createPagination(?array $data = null): \Charcoal\Source\Pagination { $expr = new Pagination(); if ($data !== null) { @@ -806,10 +746,8 @@ final protected function createModel() /** * Retrieve the model's mock metadata. - * - * @return array */ - final protected function getModelMetadata() + final protected function getModelMetadata(): array { return [ 'properties' => [ diff --git a/packages/core/tests/Charcoal/Source/Database/DatabaseExpressionTest.php b/packages/core/tests/Charcoal/Source/Database/DatabaseExpressionTest.php index 083ff6141..f7f34bccd 100644 --- a/packages/core/tests/Charcoal/Source/Database/DatabaseExpressionTest.php +++ b/packages/core/tests/Charcoal/Source/Database/DatabaseExpressionTest.php @@ -21,20 +21,16 @@ class DatabaseExpressionTest extends AbstractTestCase /** * Create expression for testing. - * - * @return DatabaseExpression */ - final protected function createExpression() + final protected function createExpression(): \Charcoal\Source\Database\DatabaseExpression { return new DatabaseExpression(); } /** * Test influence of "active" property on SQL compilation. - * - * @return void */ - public function testInactiveExpression() + public function testInactiveExpression(): void { $obj = $this->createExpression(); $obj->setCondition(' /* xyzzy */ '); @@ -48,10 +44,8 @@ public function testInactiveExpression() /** * Test "condition" property. - * - * @return void */ - public function testCustomSql() + public function testCustomSql(): void { $obj = $this->createExpression(); @@ -61,10 +55,8 @@ public function testCustomSql() /** * Test invalid custom SQL. - * - * @return void */ - public function testCustomSqlWithoutQuery() + public function testCustomSqlWithoutQuery(): void { $obj = $this->createExpression(); diff --git a/packages/core/tests/Charcoal/Source/Database/DatabaseFilterTest.php b/packages/core/tests/Charcoal/Source/Database/DatabaseFilterTest.php index 9e4e0b543..050fe478d 100644 --- a/packages/core/tests/Charcoal/Source/Database/DatabaseFilterTest.php +++ b/packages/core/tests/Charcoal/Source/Database/DatabaseFilterTest.php @@ -21,6 +21,7 @@ /** * Test {@see DatabaseFilter}. */ +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\Database\DatabaseFilter::class, 'isNegating')] class DatabaseFilterTest extends AbstractTestCase { use CoreContainerIntegrationTrait; @@ -29,10 +30,8 @@ class DatabaseFilterTest extends AbstractTestCase /** * Create expression for testing. - * - * @return DatabaseFilter */ - final protected function createExpression() + final protected function createExpression(): \Charcoal\Source\Database\DatabaseFilter { return new DatabaseFilter(); } @@ -56,10 +55,8 @@ final public function createProperty() * Test default table name for default data values. * * @see \Charcoal\Tests\Source\Database\DatabaseOrderTest::testDefaultValues() - * - * @return void */ - public function testDefaultValues() + public function testDefaultValues(): void { $obj = $this->createExpression(); @@ -71,10 +68,8 @@ public function testDefaultValues() /** * Test influence of "active" property on SQL compilation. - * - * @return void */ - public function testInactiveExpression() + public function testInactiveExpression(): void { $obj = $this->createExpression(); $obj->setProperty('foo')->setValue('Charcoal'); @@ -94,11 +89,8 @@ public function testInactiveExpression() * 2. Negatable Operators * 3. Ignored Operators * - * @covers \Charcoal\Source\Database\DatabaseFilter::isNegating - * - * @return void */ - public function testNegation() + public function testNegation(): void { $obj = $this->createExpression(); @@ -119,10 +111,8 @@ public function testNegation() /** * Test SQL without conditions. - * - * @return void */ - public function testBlankSql() + public function testBlankSql(): void { $obj = $this->createExpression(); @@ -131,10 +121,8 @@ public function testBlankSql() /** * Test invalid SQL predicate. - * - * @return void */ - public function testSqlWithoutPredicate() + public function testSqlWithoutPredicate(): void { $obj = $this->createExpression(); @@ -147,13 +135,12 @@ public function testSqlWithoutPredicate() /** * Test nested filters. * - * @dataProvider providedNestedExpressions * * @param array $conditions The expressions to define. * @param string $expected The expected compiled SQL string. - * @return void */ - public function testNestedSql(array $conditions, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('providedNestedExpressions')] + public function testNestedSql(array $conditions, $expected): void { $obj = $this->createExpression(); $obj->addFilters($conditions); @@ -165,13 +152,12 @@ public function testNestedSql(array $conditions, $expected) * * @example [ [ , ] ] * @used-by self::testNestedSql() - * @return array */ - public function providedNestedExpressions() + public static function providedNestedExpressions(): array { return [ - 'One Level' => $this->nestedExpressionsDataset1(), - 'Two Levels' => $this->nestedExpressionsDataset2(), + 'One Level' => self::nestedExpressionsDataset1(), + 'Two Levels' => self::nestedExpressionsDataset2(), ]; } @@ -179,9 +165,8 @@ public function providedNestedExpressions() * Dataset #1 for testing nested expressions. * * @used-by self::providedNestedExpressions() - * @return array */ - protected function nestedExpressionsDataset1() + protected static function nestedExpressionsDataset1(): array { $time = new DateTime('3 days ago'); @@ -213,9 +198,8 @@ protected function nestedExpressionsDataset1() * Dataset #2 for testing nested expressions. * * @used-by self::providedNestedExpressions() - * @return array */ - protected function nestedExpressionsDataset2() + protected static function nestedExpressionsDataset2(): array { $time = date('Y-m-d'); @@ -265,10 +249,8 @@ protected function nestedExpressionsDataset2() /** * Test nested filters has precedence over other features. - * - * @return void */ - public function testNestedSqlPrecedence() + public function testNestedSqlPrecedence(): void { $obj = $this->createExpression(); @@ -282,10 +264,8 @@ public function testNestedSqlPrecedence() /** * Test invalid SQL nested filters. - * - * @return void */ - public function testSqlWithoutNestedExpressions() + public function testSqlWithoutNestedExpressions(): void { $obj = $this->createExpression(); @@ -297,10 +277,8 @@ public function testSqlWithoutNestedExpressions() /** * Test "condition" property with and without placeholders. - * - * @return void */ - public function testCustomSql() + public function testCustomSql(): void { $obj = $this->createExpression(); @@ -310,10 +288,8 @@ public function testCustomSql() /** * Test the negation of the "condition" property with the "operator" property. - * - * @return void */ - public function testCustomSqlNegation() + public function testCustomSqlNegation(): void { $obj = $this->createExpression(); @@ -323,10 +299,8 @@ public function testCustomSqlNegation() /** * Test "condition" property has precedence over other features. - * - * @return void */ - public function testCustomSqlPrecedence() + public function testCustomSqlPrecedence(): void { $obj = $this->createExpression(); @@ -340,10 +314,8 @@ public function testCustomSqlPrecedence() /** * Test invalid custom SQL. - * - * @return void */ - public function testCustomSqlWithoutQuery() + public function testCustomSqlWithoutQuery(): void { $obj = $this->createExpression(); @@ -355,10 +327,8 @@ public function testCustomSqlWithoutQuery() /** * Test condition compilation. - * - * @return void */ - public function testCompileConditions() + public function testCompileConditions(): void { $obj = $this->createExpression(); @@ -369,10 +339,8 @@ public function testCompileConditions() /** * Test basic SQL operator without a value. - * - * @return void */ - public function testSqlOperatorWithoutValue() + public function testSqlOperatorWithoutValue(): void { $obj = $this->createExpression(); @@ -388,12 +356,11 @@ public function testSqlOperatorWithoutValue() /** * Test comparison SQL operators. * - * @dataProvider provideComparisonOperators * * @param string $operator A SQL operator. - * @return void */ - public function testSqlComparisonOperators($operator) + #[\PHPUnit\Framework\Attributes\DataProvider('provideComparisonOperators')] + public function testSqlComparisonOperators(string $operator): void { $obj = $this->createExpression(); $obj->setData([ @@ -408,12 +375,11 @@ public function testSqlComparisonOperators($operator) /** * Test condition-style SQL operators ("value" is ignored). * - * @dataProvider provideConditionalOperators * * @param string $operator A SQL operator. - * @return void */ - public function testSqlConditionalOperators($operator) + #[\PHPUnit\Framework\Attributes\DataProvider('provideConditionalOperators')] + public function testSqlConditionalOperators(string $operator): void { $obj = $this->createExpression(); $obj->setData([ @@ -428,12 +394,11 @@ public function testSqlConditionalOperators($operator) /** * Test NOT-style SQL operators ("value" is ignored). * - * @dataProvider provideNegationOperators * * @param string $operator A SQL operator. - * @return void */ - public function testSqlNegationOperators($operator) + #[\PHPUnit\Framework\Attributes\DataProvider('provideNegationOperators')] + public function testSqlNegationOperators(string $operator): void { $obj = $this->createExpression(); $obj->setData([ @@ -448,14 +413,13 @@ public function testSqlNegationOperators($operator) /** * Test list-based SQL operators. * - * @dataProvider provideSetOperators * * @param string $operator A SQL operator. * @param string $delimiter The set's delimiter. * @param string $expected The expected result. - * @return void */ - public function testSqlSetOperators($operator, $delimiter, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('provideSetOperators')] + public function testSqlSetOperators(string $operator, string $delimiter, string $expected): void { $obj = $this->createExpression(); @@ -475,14 +439,13 @@ public function testSqlSetOperators($operator, $delimiter, $expected) /** * Test list-based SQL operator without a value. * - * @dataProvider provideSetOperators * * @param string $operator A SQL operator. * @param string $delimiter The set's delimiter. * @param string $expected Unused; The expected result. - * @return void */ - public function testSqlSetOperatorsWithoutValue($operator, $delimiter, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('provideSetOperators')] + public function testSqlSetOperatorsWithoutValue(string $operator, string $delimiter, string $expected): void { $obj = $this->createExpression(); @@ -497,10 +460,8 @@ public function testSqlSetOperatorsWithoutValue($operator, $delimiter, $expected /** * Test SQL function. - * - * @return void */ - public function testSqlFunction() + public function testSqlFunction(): void { $obj = $this->createExpression(); $obj->setData([ @@ -515,10 +476,8 @@ public function testSqlFunction() /** * Test SQL condition with multiple field names. - * - * @return void */ - public function testSqlFields() + public function testSqlFields(): void { $container = $this->getContainer(); @@ -543,9 +502,8 @@ public function testSqlFields() * Provide data for simple operators. * * @used-by self::testSqlComparisonOperators() - * @return array */ - public function provideComparisonOperators() + public static function provideComparisonOperators(): array { return [ [ '=' ], [ '!=' ], @@ -559,9 +517,8 @@ public function provideComparisonOperators() * Provide data for sets-style operators. * * @used-by self::testSqlSetOperators() - * @return array */ - public function provideSetOperators() + public static function provideSetOperators(): array { return [ 'FIND_IN_SET' => [ 'FIND_IN_SET', ',', 'FIND_IN_SET(\'%2$s\', %1$s)' ], @@ -574,9 +531,8 @@ public function provideSetOperators() * Provide data for condition-style operators. * * @used-by self::testSqlConditionalOperators() - * @return array */ - public function provideConditionalOperators() + public static function provideConditionalOperators(): array { return [ [ 'IS NULL' ], [ 'IS NOT NULL' ], @@ -590,9 +546,8 @@ public function provideConditionalOperators() * Provide data for logical NOT operators. * * @used-by self::testSqlNegationOperators() - * @return array */ - public function provideNegationOperators() + public static function provideNegationOperators(): array { return [ [ '!' ], diff --git a/packages/core/tests/Charcoal/Source/Database/DatabaseOrderTest.php b/packages/core/tests/Charcoal/Source/Database/DatabaseOrderTest.php index f0c502fe1..f24263e71 100644 --- a/packages/core/tests/Charcoal/Source/Database/DatabaseOrderTest.php +++ b/packages/core/tests/Charcoal/Source/Database/DatabaseOrderTest.php @@ -23,10 +23,8 @@ class DatabaseOrderTest extends AbstractTestCase /** * Create expression for testing. - * - * @return DatabaseOrder */ - final protected function createExpression() + final protected function createExpression(): \Charcoal\Source\Database\DatabaseOrder { return new DatabaseOrder(); } @@ -35,10 +33,8 @@ final protected function createExpression() * Test default table name for default data values. * * @see \Charcoal\Tests\Source\Database\DatabaseFilterTest::testDefaultValues() - * - * @return void */ - public function testDefaultValues() + public function testDefaultValues(): void { $obj = $this->createExpression(); @@ -50,10 +46,8 @@ public function testDefaultValues() /** * Test influence of "active" property on SQL compilation. - * - * @return void */ - public function testInactiveExpression() + public function testInactiveExpression(): void { $obj = $this->createExpression(); $obj->setMode('asc')->setProperty('foo'); @@ -67,10 +61,8 @@ public function testInactiveExpression() /** * Test SQL without a mode. - * - * @return void */ - public function testBlankSql() + public function testBlankSql(): void { $obj = $this->createExpression(); @@ -80,10 +72,8 @@ public function testBlankSql() /** * Test SQL with custom mode and placeholders. - * - * @return void */ - public function testSqlCustomMode() + public function testSqlCustomMode(): void { $obj = $this->createExpression(); @@ -94,10 +84,8 @@ public function testSqlCustomMode() /** * Test that "custom" and "values" mode have precedence over other features * when the mode is undefined. - * - * @return void */ - public function testSqlModeResolutionAndPrecedence() + public function testSqlModeResolutionAndPrecedence(): void { $obj = $this->createExpression(); @@ -114,10 +102,8 @@ public function testSqlModeResolutionAndPrecedence() /** * Test SQL with random mode. - * - * @return void */ - public function testSqlRandomMode() + public function testSqlRandomMode(): void { $obj = $this->createExpression(); @@ -128,13 +114,12 @@ public function testSqlRandomMode() /** * Test SQL with direction mode. * - * @dataProvider provideSqlDirectionMode * * @param mixed $mode The directional mode to set. * @param mixed $expected The expected SQL direction. - * @return void */ - public function testSqlDirectionMode($mode, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('provideSqlDirectionMode')] + public function testSqlDirectionMode(string $mode, string $expected): void { $obj = $this->createExpression(); @@ -149,9 +134,8 @@ public function testSqlDirectionMode($mode, $expected) * Provide data for selecting directional ordering. * * @used-by self::testSqlDirectionMode() - * @return array */ - public function provideSqlDirectionMode() + public static function provideSqlDirectionMode(): array { return [ [ 'asc', 'ASC' ], @@ -161,10 +145,8 @@ public function provideSqlDirectionMode() /** * Test direction mode without property. - * - * @return void */ - public function testSqlDirectionModeWithoutProperty() + public function testSqlDirectionModeWithoutProperty(): void { $obj = $this->createExpression(); @@ -174,10 +156,8 @@ public function testSqlDirectionModeWithoutProperty() /** * Test SQL with values mode. - * - * @return void */ - public function testSqlValuesMode() + public function testSqlValuesMode(): void { $obj = $this->createExpression(); $obj->setMode('values') @@ -189,10 +169,8 @@ public function testSqlValuesMode() /** * Test values mode without property. - * - * @return void */ - public function testSqlValuesModeWithoutProperty() + public function testSqlValuesModeWithoutProperty(): void { $obj = $this->createExpression(); @@ -204,10 +182,8 @@ public function testSqlValuesModeWithoutProperty() /** * Test values mode without values. - * - * @return void */ - public function testSqlValuesModeWithoutValues() + public function testSqlValuesModeWithoutValues(): void { $obj = $this->createExpression(); @@ -219,10 +195,8 @@ public function testSqlValuesModeWithoutValues() /** * Test invalid custom SQL. - * - * @return void */ - public function testSqlCustomModeWithoutQuery() + public function testSqlCustomModeWithoutQuery(): void { $obj = $this->createExpression(); @@ -234,10 +208,8 @@ public function testSqlCustomModeWithoutQuery() /** * Test invalid property SQL. - * - * @return void */ - public function testSqlWithoutModeWithoutProperty() + public function testSqlWithoutModeWithoutProperty(): void { $obj = $this->createExpression(); @@ -249,10 +221,8 @@ public function testSqlWithoutModeWithoutProperty() /** * Test helper methods. - * - * @return void */ - public function testPrepareValues() + public function testPrepareValues(): void { $obj = $this->createExpression(); diff --git a/packages/core/tests/Charcoal/Source/Database/DatabasePaginationTest.php b/packages/core/tests/Charcoal/Source/Database/DatabasePaginationTest.php index 1314f565b..f97d5fb88 100644 --- a/packages/core/tests/Charcoal/Source/Database/DatabasePaginationTest.php +++ b/packages/core/tests/Charcoal/Source/Database/DatabasePaginationTest.php @@ -21,20 +21,16 @@ class DatabasePaginationTest extends AbstractTestCase /** * Create expression for testing. - * - * @return DatabasePagination */ - final protected function createExpression() + final protected function createExpression(): \Charcoal\Source\Database\DatabasePagination { return new DatabasePagination(); } /** * Test influence of "active" property on SQL compilation. - * - * @return void */ - public function testInactiveExpression() + public function testInactiveExpression(): void { $obj = $this->createExpression(); $obj->setNumPerPage(10); @@ -48,10 +44,8 @@ public function testInactiveExpression() /** * Test "page" property without "num_per_page". - * - * @return void */ - public function testSqlOffsetWithoutLimit() + public function testSqlOffsetWithoutLimit(): void { $obj = $this->createExpression(); @@ -64,10 +58,8 @@ public function testSqlOffsetWithoutLimit() /** * Test "page" property with "num_per_page". - * - * @return void */ - public function testSqlOffsetWithLimit() + public function testSqlOffsetWithLimit(): void { $obj = $this->createExpression(); @@ -83,10 +75,8 @@ public function testSqlOffsetWithLimit() /** * Test "num_per_page" property without "page". - * - * @return void */ - public function testSqlLimitWithoutOffset() + public function testSqlLimitWithoutOffset(): void { $obj = $this->createExpression(); @@ -99,10 +89,8 @@ public function testSqlLimitWithoutOffset() /** * Test helper methods. - * - * @return void */ - public function testUtilities() + public function testUtilities(): void { $obj = $this->createExpression(); diff --git a/packages/core/tests/Charcoal/Source/DatabaseExpressionTestTrait.php b/packages/core/tests/Charcoal/Source/DatabaseExpressionTestTrait.php index f9f24b0f0..d5661ffca 100644 --- a/packages/core/tests/Charcoal/Source/DatabaseExpressionTestTrait.php +++ b/packages/core/tests/Charcoal/Source/DatabaseExpressionTestTrait.php @@ -35,10 +35,8 @@ abstract public function testInactiveExpression(); * * Assertions: * 1. Implements {@see ExpressionInterface} - * - * @return void */ - public function testConstruct() + public function testConstruct(): void { $obj = $this->createExpression(); diff --git a/packages/core/tests/Charcoal/Source/DatabaseSourceConfigTest.php b/packages/core/tests/Charcoal/Source/DatabaseSourceConfigTest.php index 8890b86a2..9f74a4141 100644 --- a/packages/core/tests/Charcoal/Source/DatabaseSourceConfigTest.php +++ b/packages/core/tests/Charcoal/Source/DatabaseSourceConfigTest.php @@ -13,10 +13,7 @@ */ class DatabaseSourceConfigTest extends AbstractTestCase { - /** - * @return void - */ - public function testDefaultData() + public function testDefaultData(): void { $obj = new DatabaseSourceConfig(); $defaults = $obj->defaults(); @@ -26,20 +23,14 @@ public function testDefaultData() $this->assertEquals($obj->hostname(), $defaults['hostname']); } - /** - * @return void - */ - public function testMerge() + public function testMerge(): void { $obj = new DatabaseSourceConfig(); $ret = $obj->merge([]); $this->assertSame($ret, $obj); } - /** - * @return void - */ - public function testSetHostname() + public function testSetHostname(): void { $obj = new DatabaseSourceConfig(); $this->assertEquals('localhost', $obj->hostname()); @@ -51,10 +42,7 @@ public function testSetHostname() $obj->setHostname(false); } - /** - * @return void - */ - public function testSetUsername() + public function testSetUsername(): void { $obj = new DatabaseSourceConfig(); $this->assertEquals(null, $obj->username()); @@ -66,10 +54,7 @@ public function testSetUsername() $obj->setUsername(false); } - /** - * @return void - */ - public function testSetPassword() + public function testSetPassword(): void { $obj = new DatabaseSourceConfig(); $this->assertEquals('', $obj->password()); @@ -81,10 +66,7 @@ public function testSetPassword() $obj->setPassword(false); } - /** - * @return void - */ - public function testSetDatabase() + public function testSetDatabase(): void { $obj = new DatabaseSourceConfig(); $this->assertEquals(null, $obj->database()); @@ -96,10 +78,7 @@ public function testSetDatabase() $obj->setDatabase(false); } - /** - * @return void - */ - public function testSetDisableUtf8() + public function testSetDisableUtf8(): void { $obj = new DatabaseSourceConfig(); $this->assertEquals(false, $obj->disableUtf8()); diff --git a/packages/core/tests/Charcoal/Source/DatabaseSourceTest.php b/packages/core/tests/Charcoal/Source/DatabaseSourceTest.php index 213989c22..d95f6fb98 100644 --- a/packages/core/tests/Charcoal/Source/DatabaseSourceTest.php +++ b/packages/core/tests/Charcoal/Source/DatabaseSourceTest.php @@ -1,5 +1,7 @@ getContainer(); diff --git a/packages/core/tests/Charcoal/Source/DatabaseTestModel.php b/packages/core/tests/Charcoal/Source/DatabaseTestModel.php index e52ed51e6..1548f4804 100644 --- a/packages/core/tests/Charcoal/Source/DatabaseTestModel.php +++ b/packages/core/tests/Charcoal/Source/DatabaseTestModel.php @@ -1,5 +1,7 @@ getMockForTrait(ExpressionFieldTrait::class); - - return $obj; + return new class implements ExpressionFieldInterface { + use ExpressionFieldTrait; + }; } /** @@ -69,10 +67,8 @@ final public function createProperty() * 3. Chainable method * 4. Accepts Property * 5. Accepts NULL - * - * @return void */ - public function testProperty() + public function testProperty(): void { $obj = $this->createField(); @@ -100,10 +96,8 @@ public function testProperty() /** * Test the "property" determiner. - * - * @return void */ - public function testHasProperty() + public function testHasProperty(): void { $obj = $this->createField(); $this->assertFalse($obj->hasProperty()); @@ -114,10 +108,8 @@ public function testHasProperty() /** * Test "property" property with blank value. - * - * @return void */ - public function testPropertyWithBlankValue() + public function testPropertyWithBlankValue(): void { $this->expectException(InvalidArgumentException::class); $this->createField()->setProperty(''); @@ -125,10 +117,8 @@ public function testPropertyWithBlankValue() /** * Test "property" property with invalid property. - * - * @return void */ - public function testPropertyWithInvalidProperty() + public function testPropertyWithInvalidProperty(): void { $container = $this->getContainer(); $property = $container['property/factory']->create('generic'); @@ -139,10 +129,8 @@ public function testPropertyWithInvalidProperty() /** * Test "property" property with invalid value. - * - * @return void */ - public function testPropertyWithInvalidValue() + public function testPropertyWithInvalidValue(): void { $this->expectException(InvalidArgumentException::class); $this->createField()->setProperty([]); @@ -156,10 +144,8 @@ public function testPropertyWithInvalidValue() * 2. Mutated state * 3. Chainable method * 4. Accepts NULL - * - * @return void */ - public function testTable() + public function testTable(): void { $obj = $this->createField(); @@ -181,10 +167,8 @@ public function testTable() /** * Test the "table" determiner. - * - * @return void */ - public function testHasTable() + public function testHasTable(): void { $obj = $this->createField(); $this->assertFalse($obj->hasTable()); @@ -195,10 +179,8 @@ public function testHasTable() /** * Test "table" property with blank value. - * - * @return void */ - public function testTableWithBlankValue() + public function testTableWithBlankValue(): void { $this->expectException(InvalidArgumentException::class); $this->createField()->setTable(''); @@ -206,10 +188,8 @@ public function testTableWithBlankValue() /** * Test "table" property with invalid value. - * - * @return void */ - public function testTableWithInvalidValue() + public function testTableWithInvalidValue(): void { $this->expectException(InvalidArgumentException::class); $this->createField()->setTable([]); @@ -222,10 +202,8 @@ public function testTableWithInvalidValue() * 1. Default state * 2. With column name * 3. With property instance - * - * @return void */ - public function testFieldNames() + public function testFieldNames(): void { $obj = $this->createField(); @@ -252,10 +230,8 @@ public function testFieldNames() * 1. Default state * 2. With column name * 3. With property instance - * - * @return void */ - public function testFieldName() + public function testFieldName(): void { $obj = $this->createField(); @@ -282,10 +258,8 @@ public function testFieldName() * 1. Default state * 2. With column name * 3. With table name - * - * @return void */ - public function testFieldIdentifiers() + public function testFieldIdentifiers(): void { $obj = $this->createField(); @@ -310,10 +284,8 @@ public function testFieldIdentifiers() * 1. Default state * 2. With column name * 3. With table name - * - * @return void */ - public function testFieldIdentifier() + public function testFieldIdentifier(): void { $obj = $this->createField(); diff --git a/packages/core/tests/Charcoal/Source/ExpressionTest.php b/packages/core/tests/Charcoal/Source/ExpressionTest.php index a486017e5..5f3e9c6b2 100644 --- a/packages/core/tests/Charcoal/Source/ExpressionTest.php +++ b/packages/core/tests/Charcoal/Source/ExpressionTest.php @@ -21,10 +21,8 @@ class ExpressionTest extends AbstractTestCase /** * Create expression for testing. - * - * @return Expression */ - final protected function createExpression() + final protected function createExpression(): \Charcoal\Source\Expression { return new Expression(); } @@ -33,9 +31,8 @@ final protected function createExpression() * Provide data for value parsing. * * @used-by ExpressionTestTrait::testDefaultValues() - * @return array */ - final public function provideDefaultValues() + final public static function provideDefaultValues(): array { return [ 'condition' => [ 'condition', null ], @@ -54,10 +51,8 @@ final public function provideDefaultValues() * 4. Trimmed value * 5. Accepts NULL * 6. Swaps blank string for NULL - * - * @return void */ - public function testConditionExpression() + public function testConditionExpression(): void { $obj = $this->createExpression(); @@ -87,10 +82,8 @@ public function testConditionExpression() /** * Test the conditional check of "condition". - * - * @return void */ - public function testHasConditionExpression() + public function testHasConditionExpression(): void { $obj = $this->createExpression(); @@ -99,16 +92,14 @@ public function testHasConditionExpression() $obj->setCondition(' '); $this->assertFalse($obj->hasCondition()); - $that = $obj->setCondition('1 = 1'); + $obj->setCondition('1 = 1'); $this->assertTrue($obj->hasCondition()); } /** * Test "condition" property with invalid value. - * - * @return void */ - public function testConditionExpressionWithInvalidValue() + public function testConditionExpressionWithInvalidValue(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setCondition([]); @@ -120,10 +111,8 @@ public function testConditionExpressionWithInvalidValue() * Assertions: * 1. Mutate all options * 2. Partially mutated state - * - * @return void */ - public function testData() + public function testData(): void { /** 1. Mutate all options */ $mutation = [ diff --git a/packages/core/tests/Charcoal/Source/ExpressionTestFieldTrait.php b/packages/core/tests/Charcoal/Source/ExpressionTestFieldTrait.php index 9207605d8..f4d11d6ee 100644 --- a/packages/core/tests/Charcoal/Source/ExpressionTestFieldTrait.php +++ b/packages/core/tests/Charcoal/Source/ExpressionTestFieldTrait.php @@ -6,6 +6,8 @@ use Charcoal\Source\ExpressionInterface; use Charcoal\Source\ExpressionFieldInterface; use Charcoal\Source\ExpressionFieldTrait; +use Charcoal\Source\Filter; +use Charcoal\Source\Order; /** * Shared tests for implementations of {@see ExpressionFieldTrait} @@ -15,10 +17,8 @@ trait ExpressionTestFieldTrait { /** * Test deprecated "table_name" property. - * - * @return void */ - public function testDeprecatedTableNameExpression() + public function testDeprecatedTableNameExpression(): void { $obj = $this->createExpression(); @@ -28,24 +28,17 @@ public function testDeprecatedTableNameExpression() /** * Test "table_name" property deprecation notice. - * - * @used-by self::testDeprecatedTableNameErrorInPhp7() - * - * @return void - */ - public function delegatedTestDeprecatedTableNameError() - { - $this->createExpression()->setData([ 'table_name' => 'foobar' ]); - } - - /** - * @requires PHP >= 7.0 - * @return void */ - public function testDeprecatedTableNameErrorInPhp7() + public function testDeprecatedTableNameError(): void { - $this->expectDeprecation(); - $this->delegatedTestDeprecatedTableNameError(); + $expression = $this->createExpression(); + $message = match (get_class($expression)) { + Filter::class => 'Filter expression option "table_name" is deprecated in favour of "table": foobar', + Order::class => 'Sort expression option "table_name" is deprecated in favour of "table": foobar', + default => 'Expression option "table_name" is deprecated in favour of "table": foobar', + }; + $this->expectUserDeprecationMessage($message); + $expression->setData([ 'table_name' => 'foobar' ]); } /** @@ -53,16 +46,15 @@ public function testDeprecatedTableNameErrorInPhp7() * * @param ExpressionFieldInterface $obj The expression to test. * @param array|null $expected The expected data subset. - * @return void */ - public function assertStructHasFieldData(ExpressionFieldInterface $obj, array $expected = null) + public function assertStructHasFieldData(ExpressionFieldInterface $obj, ?array $expected = null): void { - if (empty($expected)) { + if ($expected === null || $expected === []) { $expected = [ 'property' => 'col', 'table' => 'tbl', ]; - $obj->setData($mutation); + $obj->setData($expected); } $data = $obj->data(); diff --git a/packages/core/tests/Charcoal/Source/ExpressionTestTrait.php b/packages/core/tests/Charcoal/Source/ExpressionTestTrait.php index 5356bcaaa..84a77e1a3 100644 --- a/packages/core/tests/Charcoal/Source/ExpressionTestTrait.php +++ b/packages/core/tests/Charcoal/Source/ExpressionTestTrait.php @@ -12,7 +12,7 @@ * Shared tests for implementations of {@see AbstractExpression} * and {@see ExpressionInterface}. */ -trait ExpressionTestTrait +trait ExpressionTestTrait { /** * @return \Pimple\Container @@ -33,17 +33,15 @@ abstract protected function createExpression(); * @used-by self::testDefaultValues() * @return array */ - abstract public function provideDefaultValues(); + abstract public static function provideDefaultValues(); /** * Test new instance. * * Assertions: * 1. Implements {@see ExpressionInterface} - * - * @return void */ - final public function testConstruct() + final public function testConstruct(): void { $obj = $this->createExpression(); @@ -56,10 +54,8 @@ final public function testConstruct() * * Assertions: * 1. Getter returns an array - * - * @return void */ - final public function testDefaultValuesMethod() + final public function testDefaultValuesMethod(): void { $obj = $this->createExpression(); @@ -74,9 +70,9 @@ final public function testDefaultValuesMethod() * * @param mixed $key The data key test. * @param mixed $expected The expected data value. - * @return void */ - final public function testDefaultValues($key, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('provideDefaultValues')] + final public function testDefaultValues($key, $expected): void { $obj = $this->createExpression(); $data = $obj->defaultData(); @@ -91,10 +87,8 @@ final public function testDefaultValues($key, $expected) * Assertions: * 1. Getter returns an array * 2. Setter is chainable - * - * @return void */ - final public function testDataMethod() + final public function testDataMethod(): void { $obj = $this->createExpression(); @@ -108,10 +102,8 @@ final public function testDataMethod() /** * Test data structure with default state. - * - * @return void */ - final public function testDefaultData() + final public function testDefaultData(): void { $obj = $this->createExpression(); $this->assertEquals($obj->defaultData(), $obj->data()); @@ -122,16 +114,15 @@ final public function testDefaultData() * * @param ExpressionInterface $obj The expression to test. * @param array|null $expected The expected data subset. - * @return void */ - final public function assertStructHasBasicData(ExpressionInterface $obj, array $expected = null) + final public function assertStructHasBasicData(ExpressionInterface $obj, ?array $expected = null): void { - if (empty($expected)) { + if ($expected === null || $expected === []) { $expected = [ 'active' => false, 'name' => 'foo', ]; - $obj->setData($mutation); + $obj->setData($expected); } $data = $obj->data(); @@ -151,10 +142,8 @@ final public function assertStructHasBasicData(ExpressionInterface $obj, array $ * Assertions: * 1. Serialization from default state * 2. Serialization from mutated state - * - * @return void */ - public function testJsonSerializable() + public function testJsonSerializable(): void { $obj = $this->createExpression(); @@ -181,16 +170,14 @@ public function testJsonSerializable() * Assertions: * 1. Serialization from default state * 2. Serialization from mutated state - * - * @return void */ - public function testSerializable() + public function testSerializable(): void { $obj = $this->createExpression(); /** 1. Serialization from default state */ $that = unserialize(serialize($obj)); - $this->assertInstanceOf(get_class($obj), $that); + $this->assertInstanceOf($obj::class, $that); $this->assertEquals($obj, $that); $this->assertTrue($that->active()); $this->assertNull($that->name()); @@ -202,7 +189,7 @@ public function testSerializable() ]; $obj->setData($mutation); $that = unserialize(serialize($obj)); - $this->assertInstanceOf(get_class($obj), $that); + $this->assertInstanceOf($obj::class, $that); $this->assertEquals($obj, $that); $this->assertFalse($that->active()); $this->assertEquals('foo', $that->name()); diff --git a/packages/core/tests/Charcoal/Source/FilterCollectionTraitTest.php b/packages/core/tests/Charcoal/Source/FilterCollectionTraitTest.php index 6993a1028..6c4c470c1 100644 --- a/packages/core/tests/Charcoal/Source/FilterCollectionTraitTest.php +++ b/packages/core/tests/Charcoal/Source/FilterCollectionTraitTest.php @@ -20,6 +20,14 @@ /** * Test {@see FilterCollectionTrait} and {@see FilterCollectionInterface}. */ +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\FilterCollectionTrait::class, 'createFilter')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\FilterCollectionTrait::class, 'filters')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\FilterCollectionTrait::class, 'hasFilters')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\FilterCollectionTrait::class, 'setFilters')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\FilterCollectionTrait::class, 'addFilters')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\FilterCollectionTrait::class, 'addFilter')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\FilterCollectionTrait::class, 'processFilter')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\FilterCollectionTrait::class, 'traverseFilters')] class FilterCollectionTraitTest extends AbstractTestCase { use AssertionsTrait; @@ -28,10 +36,8 @@ class FilterCollectionTraitTest extends AbstractTestCase /** * Create mock object for testing. - * - * @return FilterCollectionClass */ - final public function createCollector() + final public function createCollector(): \Charcoal\Tests\Mock\FilterCollectionClass { return new FilterCollectionClass(); } @@ -40,9 +46,8 @@ final public function createCollector() * Create expression for testing. * * @param array $data Optional expression data. - * @return Filter */ - final protected function createExpression(array $data = null) + final protected function createExpression(?array $data = null): \Charcoal\Source\Filter { $expr = new Filter(); if ($data !== null) { @@ -58,11 +63,8 @@ final protected function createExpression(array $data = null) * 1. Instance of {@see ExpressionInterface} * 2. Instance of {@see FilterInterface} * - * @covers \Charcoal\Source\FilterCollectionTrait::createFilter - * - * @return void */ - public function testCreateExpression() + public function testCreateExpression(): void { $obj = $this->createCollector(); @@ -78,11 +80,8 @@ public function testCreateExpression() * 1. Empty; Default state * 2. Populated; Mutated state * - * @covers \Charcoal\Source\FilterCollectionTrait::filters - * - * @return void */ - public function testGetExpressions() + public function testGetExpressions(): void { $obj = $this->createCollector(); @@ -103,11 +102,8 @@ public function testGetExpressions() * 1. Empty; Default state * 2. Populated; Mutated state * - * @covers \Charcoal\Source\FilterCollectionTrait::hasFilters - * - * @return void */ - public function testHasExpressions() + public function testHasExpressions(): void { $obj = $this->createCollector(); @@ -126,11 +122,8 @@ public function testHasExpressions() * 1. Replaces expressions with a new collection * 2. Chainable method * - * @covers \Charcoal\Source\FilterCollectionTrait::setFilters - * - * @return void */ - public function testSetExpressions() + public function testSetExpressions(): void { $obj = $this->createCollector(); $exp1 = $this->createExpression(); @@ -157,11 +150,8 @@ public function testSetExpressions() * 1. Appends an array of items to the internal collection * 2. Chainable method * - * @covers \Charcoal\Source\FilterCollectionTrait::addFilters - * - * @return void */ - public function testAddExpressions() + public function testAddExpressions(): void { $obj = $this->createCollector(); $exp1 = $this->createExpression(); @@ -184,11 +174,8 @@ public function testAddExpressions() /** * Test the mass addition of expressions with names. * - * @covers \Charcoal\Source\FilterCollectionTrait::addFilters - * - * @return void */ - public function testAddExpressionsMap() + public function testAddExpressionsMap(): void { $obj = $this->createCollector(); $map = [ @@ -216,11 +203,8 @@ public function testAddExpressionsMap() * 1. Appends one item to the internal collection * 2. Chainable method * - * @covers \Charcoal\Source\FilterCollectionTrait::addFilter - * - * @return void */ - public function testAddExpression() + public function testAddExpression(): void { $obj = $this->createCollector(); $expr = $this->createExpression(); @@ -251,11 +235,8 @@ public function testAddExpression() * 4. If an instance of {@see FilterInterface} is provided, * the Expression object is used as is. * - * @covers \Charcoal\Source\FilterCollectionTrait::processFilter - * - * @return void */ - public function testProcessExpression() + public function testProcessExpression(): void { $obj = $this->createCollector(); @@ -275,9 +256,7 @@ public function testProcessExpression() $this->assertArrayContains($struct, $result->data()); /** 3. Closure */ - $lambda = function (FilterInterface $expr, FilterCollectionInterface $tested) use ($struct) { - return $expr->setData($struct); - }; + $lambda = (fn(FilterInterface $expr, FilterCollectionInterface $tested) => $expr->setData($struct)); $result = $this->callMethodWith($obj, 'processFilter', $lambda); $this->assertInstanceOf(FilterInterface::class, $result); $this->assertArrayContains($struct, $result->data()); @@ -291,11 +270,8 @@ public function testProcessExpression() /** * Test the failure when parsing an invalid expression. * - * @covers \Charcoal\Source\FilterCollectionTrait::processFilter - * - * @return void */ - public function testProcessExpressionWithInvalidValue() + public function testProcessExpressionWithInvalidValue(): void { $obj = $this->createCollector(); @@ -310,11 +286,8 @@ public function testProcessExpressionWithInvalidValue() * 1. Applies callback to internal collection * 2. Chainable method * - * @covers \Charcoal\Source\FilterCollectionTrait::traverseFilters - * - * @return void */ - public function testTraverseExpressions() + public function testTraverseExpressions(): void { $obj = $this->createCollector(); $exp1 = $this->createExpression(); @@ -327,7 +300,7 @@ public function testTraverseExpressions() /** 1. Traverse internal collection */ $obj->addFilters([ $exp1, $exp4 ]); - $that = $obj->traverseFilters(function (FilterInterface $exp) { + $that = $obj->traverseFilters(function (FilterInterface $exp): void { $exp->setProperty('foo'); }); diff --git a/packages/core/tests/Charcoal/Source/FilterTest.php b/packages/core/tests/Charcoal/Source/FilterTest.php index 61acabdea..cd0fc37aa 100644 --- a/packages/core/tests/Charcoal/Source/FilterTest.php +++ b/packages/core/tests/Charcoal/Source/FilterTest.php @@ -17,6 +17,9 @@ /** * Test {@see Filter} and {@see FilterInterface}. */ +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\Filter::class, '__clone')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\Filter::class, 'count')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\Filter::class, 'createFilter')] class FilterTest extends AbstractTestCase { use CoreContainerIntegrationTrait; @@ -29,7 +32,7 @@ class FilterTest extends AbstractTestCase * * @return Order */ - final protected function createExpression() + final protected function createExpression(): \Charcoal\Source\Filter { return new Filter(); } @@ -39,10 +42,8 @@ final protected function createExpression() * * Assertions: * 1. Implements {@see FilterInterface} - * - * @return void */ - public function testFilterConstruct() + public function testFilterConstruct(): void { $obj = $this->createExpression(); @@ -53,11 +54,8 @@ public function testFilterConstruct() /** * Test deep cloning of expression trees. * - * @covers \Charcoal\Source\Filter::__clone - * - * @return void */ - public function testDeepCloning() + public function testDeepCloning(): void { $obj = $this->createExpression(); $obj->addFilters([ @@ -88,9 +86,8 @@ public function testDeepCloning() * Provide data for value parsing. * * @used-by ExpressionTestTrait::testDefaultValues() - * @return array */ - final public function provideDefaultValues() + final public static function provideDefaultValues(): array { return [ 'property' => [ 'property', null ], @@ -116,10 +113,8 @@ final public function provideDefaultValues() * * Note: {@see Filter::value()} uses {@see \Charcoal\Source\AbstractExpression::parseValue()}. * Tests for `parseValue()` are performed in {@see ExpressionTestTrait::testParseValue()}. - * - * @return void */ - public function testValue() + public function testValue(): void { $obj = $this->createExpression(); @@ -137,10 +132,8 @@ public function testValue() /** * Test deprecated "val" property. - * - * @return void */ - public function testDeprecatedValExpression() + public function testDeprecatedValExpression(): void { $obj = $this->createExpression(); @@ -150,29 +143,13 @@ public function testDeprecatedValExpression() /** * Test "val" property deprecation notice. - * - * @used-by self::testDeprecatedValErrorInPhp7() - * - * @return void */ - public function delegatedTestDeprecatedValError() + public function testDeprecatedValError(): void { + $this->expectUserDeprecationMessage('Filter expression option "val" is deprecated in favour of "value": qux'); $this->createExpression()->setData([ 'val' => 'qux' ]); } - /** - * - * - * @requires PHP >= 7.0 - * @return void - */ - public function testDeprecatedValErrorInPhp7() - { - $this->expectDeprecation(); - $this->delegatedTestDeprecatedValError(); - } - - /** * Test the "operator" property. * @@ -181,10 +158,8 @@ public function testDeprecatedValErrorInPhp7() * 2. Mutated state * 3. Chainable method * 4. Accepts mixed case - * - * @return void */ - public function testOperator() + public function testOperator(): void { $obj = $this->createExpression(); @@ -206,10 +181,8 @@ public function testOperator() /** * Test "operator" property with unsupported operator. - * - * @return void */ - public function testOperatorWithUnsupportedOperator() + public function testOperatorWithUnsupportedOperator(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setOperator('foo'); @@ -217,10 +190,8 @@ public function testOperatorWithUnsupportedOperator() /** * Test "operator" property with invalid value. - * - * @return void */ - public function testOperatorWithInvalidValue() + public function testOperatorWithInvalidValue(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setOperator(42); @@ -235,10 +206,8 @@ public function testOperatorWithInvalidValue() * 3. Chainable method * 4. Accepts mixed case * 5. Accepts NULL - * - * @return void */ - public function testFunc() + public function testFunc(): void { $obj = $this->createExpression(); @@ -264,10 +233,8 @@ public function testFunc() /** * Test "func" property with unsupported func. - * - * @return void */ - public function testFuncWithUnsupportedFunction() + public function testFuncWithUnsupportedFunction(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setFunc('xyzzy'); @@ -275,10 +242,8 @@ public function testFuncWithUnsupportedFunction() /** * Test "func" property with invalid value. - * - * @return void */ - public function testFuncWithInvalidValue() + public function testFuncWithInvalidValue(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setFunc(33); @@ -292,10 +257,8 @@ public function testFuncWithInvalidValue() * 2. Mutated state * 3. Chainable method * 4. Accepts mixed case - * - * @return void */ - public function testConjunction() + public function testConjunction(): void { $obj = $this->createExpression(); @@ -317,10 +280,8 @@ public function testConjunction() /** * Test "conjunction" property with unsupported conjunction. - * - * @return void */ - public function testConjunctionWithUnsupportedConjunction() + public function testConjunctionWithUnsupportedConjunction(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setConjunction('qux'); @@ -328,10 +289,8 @@ public function testConjunctionWithUnsupportedConjunction() /** * Test "conjunction" property with invalid value. - * - * @return void */ - public function testConjunctionWithInvalidValue() + public function testConjunctionWithInvalidValue(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setConjunction(11); @@ -339,10 +298,8 @@ public function testConjunctionWithInvalidValue() /** * Test deprecated "operand" property. - * - * @return void */ - public function testDeprecatedOperandExpression() + public function testDeprecatedOperandExpression(): void { $obj = $this->createExpression(); @@ -352,28 +309,13 @@ public function testDeprecatedOperandExpression() /** * Test "operand" property deprecation notice. - * - * @used-by self::testDeprecatedOperandErrorInPhp7() - * - * @return void */ - public function delegatedTestDeprecatedOperandError() + public function testDeprecatedOperandError(): void { + $this->expectUserDeprecationMessage('Query expression option "operand" is deprecated in favour of "conjunction": XOR'); $this->createExpression()->setData([ 'operand' => 'XOR' ]); } - /** - * - * - * @requires PHP >= 7.0 - * @return void - */ - public function testDeprecatedOperandErrorInPhp7() - { - $this->expectDeprecation(); - $this->delegatedTestDeprecatedOperandError(); - } - /** * Test implementation of {@see Countable}. * @@ -381,11 +323,8 @@ public function testDeprecatedOperandErrorInPhp7() * 1. Default state * 2. Mutated state * - * @covers \Charcoal\Source\Filter::count - * - * @return void */ - public function testCount() + public function testCount(): void { $obj = $this->createExpression(); @@ -405,11 +344,8 @@ public function testCount() * 2. Instance of {@see Filter} * * @see \Charcoal\Tests\Source\AbstractSourceTest::testCreateFilter - * @covers \Charcoal\Source\Filter::createFilter - * - * @return void */ - public function testCreateFilter() + public function testCreateFilter(): void { $obj = $this->createExpression(); @@ -426,10 +362,8 @@ public function testCreateFilter() * 1. Mutate all options * 2. Partially mutated state * 3. Mutation via aliases - * - * @return void */ - public function testData() + public function testData(): void { /** 1. Mutate all options */ $exp1 = $this->createExpression(); @@ -514,10 +448,8 @@ public function testData() * Test deprecated "string" property. * * @see OrderTest::testDeprecatedStringExpression() - * - * @return void */ - public function testDeprecatedStringExpression() + public function testDeprecatedStringExpression(): void { $obj = $this->createExpression(); @@ -529,23 +461,10 @@ public function testDeprecatedStringExpression() * Test "string" property deprecation notice. * * @see OrderTest::testDeprecatedStringError() - * - * @used-by self::testDeprecatedStringErrorInPhp7() - * - * @return void */ - public function delegatedTestDeprecatedStringError() + public function testDeprecatedStringError(): void { + $this->expectUserDeprecationMessage('Filter expression option "string" is deprecated in favour of "condition": 1 = 1'); $this->createExpression()->setData([ 'string' => '1 = 1' ]); } - - /** - * @requires PHP >= 7.0 - * @return void - */ - public function testDeprecatedStringErrorInPhp7() - { - $this->expectDeprecation(); - $this->delegatedTestDeprecatedStringError(); - } } diff --git a/packages/core/tests/Charcoal/Source/OrderCollectionTraitTest.php b/packages/core/tests/Charcoal/Source/OrderCollectionTraitTest.php index fa2c91048..5dfc2bbc6 100644 --- a/packages/core/tests/Charcoal/Source/OrderCollectionTraitTest.php +++ b/packages/core/tests/Charcoal/Source/OrderCollectionTraitTest.php @@ -21,6 +21,14 @@ /** * Test {@see OrderCollectionTrait} and {@see OrderCollectionInterface}. */ +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\OrderCollectionTrait::class, 'createOrder')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\OrderCollectionTrait::class, 'orders')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\OrderCollectionTrait::class, 'hasOrders')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\OrderCollectionTrait::class, 'setOrders')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\OrderCollectionTrait::class, 'addOrders')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\OrderCollectionTrait::class, 'addOrder')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\OrderCollectionTrait::class, 'processOrder')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\OrderCollectionTrait::class, 'traverseOrders')] class OrderCollectionTraitTest extends AbstractTestCase { use AssertionsTrait; @@ -29,10 +37,8 @@ class OrderCollectionTraitTest extends AbstractTestCase /** * Create mock object for testing. - * - * @return OrderCollectionClass */ - final public function createCollector() + final public function createCollector(): \Charcoal\Tests\Mock\OrderCollectionClass { return new OrderCollectionClass(); } @@ -41,9 +47,8 @@ final public function createCollector() * Create expression for testing. * * @param array $data Optional expression data. - * @return Order */ - final protected function createExpression(array $data = null) + final protected function createExpression(?array $data = null): \Charcoal\Source\Order { $expr = new Order(); if ($data !== null) { @@ -59,11 +64,8 @@ final protected function createExpression(array $data = null) * 1. Instance of {@see ExpressionInterface} * 2. Instance of {@see OrderInterface} * - * @covers \Charcoal\Source\OrderCollectionTrait::createOrder - * - * @return void */ - public function testCreateExpression() + public function testCreateExpression(): void { $obj = $this->createCollector(); @@ -79,11 +81,8 @@ public function testCreateExpression() * 1. Empty; Default state * 2. Populated; Mutated state * - * @covers \Charcoal\Source\OrderCollectionTrait::orders - * - * @return void */ - public function testGetExpressions() + public function testGetExpressions(): void { $obj = $this->createCollector(); @@ -104,11 +103,8 @@ public function testGetExpressions() * 1. Empty; Default state * 2. Populated; Mutated state * - * @covers \Charcoal\Source\OrderCollectionTrait::hasOrders - * - * @return void */ - public function testHasExpressions() + public function testHasExpressions(): void { $obj = $this->createCollector(); @@ -127,11 +123,8 @@ public function testHasExpressions() * 1. Replaces expressions with a new collection * 2. Chainable method * - * @covers \Charcoal\Source\OrderCollectionTrait::setOrders - * - * @return void */ - public function testSetExpressions() + public function testSetExpressions(): void { $obj = $this->createCollector(); $exp1 = $this->createExpression(); @@ -158,11 +151,8 @@ public function testSetExpressions() * 1. Appends an array of items to the internal collection * 2. Chainable method * - * @covers \Charcoal\Source\OrderCollectionTrait::addOrders - * - * @return void */ - public function testAddExpressions() + public function testAddExpressions(): void { $obj = $this->createCollector(); $exp1 = $this->createExpression(); @@ -185,11 +175,8 @@ public function testAddExpressions() /** * Test the mass addition of expressions with names. * - * @covers \Charcoal\Source\OrderCollectionTrait::addOrders - * - * @return void */ - public function testAddExpressionsMap() + public function testAddExpressionsMap(): void { $obj = $this->createCollector(); $map = [ @@ -217,11 +204,8 @@ public function testAddExpressionsMap() * 1. Appends one item to the internal collection * 2. Chainable method * - * @covers \Charcoal\Source\OrderCollectionTrait::addOrder - * - * @return void */ - public function testAddExpression() + public function testAddExpression(): void { $obj = $this->createCollector(); $expr = $this->createExpression(); @@ -252,11 +236,8 @@ public function testAddExpression() * 4. If an instance of {@see OrderInterface} is provided, * the Expression object is used as is. * - * @covers \Charcoal\Source\OrderCollectionTrait::processOrder - * - * @return void */ - public function testProcessExpression() + public function testProcessExpression(): void { $obj = $this->createCollector(); @@ -276,9 +257,7 @@ public function testProcessExpression() $this->assertArrayContains($struct, $result->data()); /** 3. Closure */ - $lambda = function (OrderInterface $expr, OrderCollectionInterface $tested) use ($struct) { - return $expr->setData($struct); - }; + $lambda = (fn(OrderInterface $expr, OrderCollectionInterface $tested) => $expr->setData($struct)); $result = $this->callMethodWith($obj, 'processOrder', $lambda); $this->assertInstanceOf(OrderInterface::class, $result); $this->assertArrayContains($struct, $result->data()); @@ -292,11 +271,8 @@ public function testProcessExpression() /** * Test the failure when parsing an invalid expression. * - * @covers \Charcoal\Source\OrderCollectionTrait::processOrder - * - * @return void */ - public function testProcessExpressionWithInvalidValue() + public function testProcessExpressionWithInvalidValue(): void { $obj = $this->createCollector(); @@ -311,11 +287,8 @@ public function testProcessExpressionWithInvalidValue() * 1. Replaces expressions with a new collection * 2. Chainable method * - * @covers \Charcoal\Source\OrderCollectionTrait::traverseOrders - * - * @return void */ - public function testTraverseExpressions() + public function testTraverseExpressions(): void { $obj = $this->createCollector(); $exp1 = new OrderTree(); @@ -329,7 +302,7 @@ public function testTraverseExpressions() $obj->addOrders([ $exp1 ]); $i = 0; - $that = $obj->traverseOrders(function (OrderInterface $exp) use (&$i) { + $that = $obj->traverseOrders(function (OrderInterface $exp) use (&$i): void { $i++; $exp->setProperty('foo'); }); diff --git a/packages/core/tests/Charcoal/Source/OrderTest.php b/packages/core/tests/Charcoal/Source/OrderTest.php index 3274bfcb8..38d86ec17 100644 --- a/packages/core/tests/Charcoal/Source/OrderTest.php +++ b/packages/core/tests/Charcoal/Source/OrderTest.php @@ -23,10 +23,8 @@ class OrderTest extends AbstractTestCase /** * Create expression for testing. - * - * @return Order */ - final protected function createExpression() + final protected function createExpression(): \Charcoal\Source\Order { return new Order(); } @@ -36,10 +34,8 @@ final protected function createExpression() * * Assertions: * 1. Implements {@see OrderInterface} - * - * @return void */ - public function testOrderConstruct() + public function testOrderConstruct(): void { $obj = $this->createExpression(); @@ -51,9 +47,8 @@ public function testOrderConstruct() * Provide data for value parsing. * * @used-by ExpressionTestTrait::testDefaultValues() - * @return array */ - final public function provideDefaultValues() + final public static function provideDefaultValues(): array { return [ 'property' => [ 'property', null ], @@ -76,10 +71,8 @@ final public function provideDefaultValues() * 3. Chainable method * 4. Accepts NULL * 5. Unsupported direction sets DESC - * - * @return void */ - public function testDirection() + public function testDirection(): void { $obj = $this->createExpression(); @@ -98,16 +91,14 @@ public function testDirection() $this->assertNull($obj->direction()); /** 5. Unsupported Direction */ - $that = $obj->setDirection('foo'); + $obj->setDirection('foo'); $this->assertEquals('DESC', $obj->direction()); } /** * Test "direction" property with invalid value. - * - * @return void */ - public function testDirectionWithInvalidValue() + public function testDirectionWithInvalidValue(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setDirection(0); @@ -122,10 +113,8 @@ public function testDirectionWithInvalidValue() * 3. Chainable method * 4. Accepts mixed case * 5. Accepts NULL - * - * @return void */ - public function testMode() + public function testMode(): void { $obj = $this->createExpression(); @@ -151,10 +140,8 @@ public function testMode() /** * Test "direction" property when selecting a direction "mode". - * - * @return void */ - public function testDirectionMode() + public function testDirectionMode(): void { $obj = $this->createExpression(); @@ -172,10 +159,8 @@ public function testDirectionMode() /** * Test "mode" property with unsupported mode. - * - * @return void */ - public function testModeWithUnsupportedMode() + public function testModeWithUnsupportedMode(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setMode('foobar'); @@ -183,10 +168,8 @@ public function testModeWithUnsupportedMode() /** * Test "mode" property with invalid value. - * - * @return void */ - public function testModeWithInvalidValue() + public function testModeWithInvalidValue(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setMode([]); @@ -200,10 +183,8 @@ public function testModeWithInvalidValue() * 2. Mutated state * 3. Chainable method * 4. Accepts NULL - * - * @return void */ - public function testValues() + public function testValues(): void { $obj = $this->createExpression(); @@ -233,10 +214,8 @@ public function testValues() /** * Test "mode" property with blank string. - * - * @return void */ - public function testValuesWithBlankValue() + public function testValuesWithBlankValue(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setValues(''); @@ -244,10 +223,8 @@ public function testValuesWithBlankValue() /** * Test "mode" property with blank string. - * - * @return void */ - public function testValuesWithEmptyArray() + public function testValuesWithEmptyArray(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setValues([]); @@ -255,10 +232,8 @@ public function testValuesWithEmptyArray() /** * Test "mode" property with invalid value. - * - * @return void */ - public function testValuesWithInvalidValue() + public function testValuesWithInvalidValue(): void { $this->expectException(InvalidArgumentException::class); $this->createExpression()->setValues(42); @@ -271,10 +246,8 @@ public function testValuesWithInvalidValue() * 1. Mutate all options * 2. Partially mutated state * 3. Auto-set mode from "condition" - * - * @return void */ - public function testData() + public function testData(): void { /** 1. Mutate all options */ $values = [ 'foo', 'baz', 'qux' ]; @@ -342,10 +315,8 @@ public function testData() * Test deprecated "string" property. * * @see FilterTest::testDeprecatedStringExpression() - * - * @return void */ - public function testDeprecatedStringExpression() + public function testDeprecatedStringExpression(): void { $obj = $this->createExpression(); @@ -357,25 +328,10 @@ public function testDeprecatedStringExpression() * Test "string" property deprecation notice. * * @see FilterTest::testDeprecatedStringError() - * - * @used-by self::testDeprecatedStringErrorInPhp7() - * - * @return void */ - public function delegatedTestDeprecatedStringError() + public function testDeprecatedStringError(): void { + $this->expectUserDeprecationMessage('Sort expression option "string" is deprecated in favour of "condition": 1 = 1'); $this->createExpression()->setData([ 'string' => '1 = 1' ]); } - - /** - * - * - * @requires PHP >= 7.0 - * @return void - */ - public function testDeprecatedStringErrorInPhp7() - { - $this->expectDeprecation(); - $this->delegatedTestDeprecatedStringError(); - } } diff --git a/packages/core/tests/Charcoal/Source/PaginationTest.php b/packages/core/tests/Charcoal/Source/PaginationTest.php index 8f75981ba..f57c42afc 100644 --- a/packages/core/tests/Charcoal/Source/PaginationTest.php +++ b/packages/core/tests/Charcoal/Source/PaginationTest.php @@ -21,10 +21,8 @@ class PaginationTest extends AbstractTestCase /** * Create expression for testing. - * - * @return Pagination */ - final protected function createExpression() + final protected function createExpression(): \Charcoal\Source\Pagination { return new Pagination(); } @@ -34,10 +32,8 @@ final protected function createExpression() * * Assertions: * 1. Implements {@see PaginationInterface} - * - * @return void */ - public function testPaginationConstruct() + public function testPaginationConstruct(): void { $obj = $this->createExpression(); @@ -49,9 +45,8 @@ public function testPaginationConstruct() * Provide data for value parsing. * * @used-by ExpressionTestTrait::testDefaultValues() - * @return array */ - final public function provideDefaultValues() + final public static function provideDefaultValues(): array { return [ 'page num' => [ 'page', 1 ], @@ -70,10 +65,8 @@ final public function provideDefaultValues() * 3. Chainable method * 4. Accepts float * 5. Swaps zero for one - * - * @return void */ - public function testPageNum() + public function testPageNum(): void { $obj = $this->createExpression(); @@ -99,10 +92,8 @@ public function testPageNum() /** * Test "page" property with negative value. - * - * @return void */ - public function testPageNumWithNegativeValue() + public function testPageNumWithNegativeValue(): void { $obj = $this->createExpression(); @@ -112,10 +103,8 @@ public function testPageNumWithNegativeValue() /** * Test "page" property with invalid value. - * - * @return void */ - public function testPageNumWithInvalidValue() + public function testPageNumWithInvalidValue(): void { $obj = $this->createExpression(); @@ -131,10 +120,8 @@ public function testPageNumWithInvalidValue() * 2. Mutated state * 3. Chainable method * 4. Accepts float - * - * @return void */ - public function testNumPerPage() + public function testNumPerPage(): void { $obj = $this->createExpression(); @@ -156,10 +143,8 @@ public function testNumPerPage() /** * Test "num_per_page" property with negative value. - * - * @return void */ - public function testNumPerPageWithNegativeValue() + public function testNumPerPageWithNegativeValue(): void { $obj = $this->createExpression(); @@ -169,10 +154,8 @@ public function testNumPerPageWithNegativeValue() /** * Test "num_per_page" property with invalid value. - * - * @return void */ - public function testNumPerPageWithInvalidValue() + public function testNumPerPageWithInvalidValue(): void { $obj = $this->createExpression(); @@ -187,10 +170,8 @@ public function testNumPerPageWithInvalidValue() * 1. Mutate all options * 2. Partially mutated state * 3. Mutation via aliases - * - * @return void */ - public function testData() + public function testData(): void { /** 1. Mutate all options */ $mutation = [ @@ -244,10 +225,8 @@ public function testData() /** * Test lowest possible index. - * - * @return void */ - public function testFirst() + public function testFirst(): void { $obj = $this->createExpression(); @@ -262,10 +241,8 @@ public function testFirst() /** * Test highest possible index. - * - * @return void */ - public function testLast() + public function testLast(): void { $obj = $this->createExpression(); diff --git a/packages/core/tests/Charcoal/Source/SourceConfigTest.php b/packages/core/tests/Charcoal/Source/SourceConfigTest.php index f84c5653e..78bc901e6 100644 --- a/packages/core/tests/Charcoal/Source/SourceConfigTest.php +++ b/packages/core/tests/Charcoal/Source/SourceConfigTest.php @@ -13,10 +13,7 @@ */ class SourceConfigTest extends AbstractTestCase { - /** - * @return void - */ - public function testDefaultData() + public function testDefaultData(): void { $obj = new SourceConfig(); $defaults = $obj->defaults(); @@ -24,10 +21,7 @@ public function testDefaultData() $this->assertEquals($obj->type(), $defaults['type']); } - /** - * @return void - */ - public function testSetType() + public function testSetType(): void { $obj = new SourceConfig(); $ret = $obj->setType('foo'); diff --git a/packages/core/tests/Charcoal/Source/StorableTraitTest.php b/packages/core/tests/Charcoal/Source/StorableTraitTest.php index 83ae6750d..270adafbd 100644 --- a/packages/core/tests/Charcoal/Source/StorableTraitTest.php +++ b/packages/core/tests/Charcoal/Source/StorableTraitTest.php @@ -25,6 +25,24 @@ /** * Test {@see StorableTrait} and {@see StorableInterface}. */ +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'setKey')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'key')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'setId')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'id')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'setSourceFactory')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'sourceFactory')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'createSource')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'setSource')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'source')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'save')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'preSave')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'postSave')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'update')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'preUpdate')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'postUpdate')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'delete')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'preDelete')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Source\StorableTrait::class, 'postDelete')] class StorableTraitTest extends AbstractTestCase { use ReflectionsTrait; @@ -38,8 +56,6 @@ class StorableTraitTest extends AbstractTestCase /** * Setup the test. - * - * @return void */ protected function setUp(): void { @@ -48,10 +64,8 @@ protected function setUp(): void /** * Create datasource repository for testing. - * - * @return SourceMock */ - final protected function createSource() + final protected function createSource(): \Charcoal\Tests\Mock\SourceMock { return new SourceMock([ 'logger' => new NullLogger() @@ -66,12 +80,8 @@ final protected function createSource() * 2. Mutated state * 3. Chainable method * - * @covers \Charcoal\Source\StorableTrait::setKey - * @covers \Charcoal\Source\StorableTrait::key - * - * @return void */ - public function testKey() + public function testKey(): void { $obj = $this->obj; @@ -89,11 +99,8 @@ public function testKey() /** * Test for invalid data type when assigning a primary object key. * - * @covers \Charcoal\Source\StorableTrait::setKey - * - * @return void */ - public function testKeyWithInvalidDataType() + public function testKeyWithInvalidDataType(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setKey(null); @@ -102,11 +109,8 @@ public function testKeyWithInvalidDataType() /** * Test for invalid character set when assigning a primary object key. * - * @covers \Charcoal\Source\StorableTrait::setKey - * - * @return void */ - public function testKeyWithInvalidCharacters() + public function testKeyWithInvalidCharacters(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setKey('foo-bar'); @@ -120,12 +124,8 @@ public function testKeyWithInvalidCharacters() * 2. Mutated state * 3. Chainable method * - * @covers \Charcoal\Source\StorableTrait::setId - * @covers \Charcoal\Source\StorableTrait::id - * - * @return void */ - public function testId() + public function testId(): void { $obj = $this->obj; @@ -149,11 +149,8 @@ public function testId() /** * Test for invalid data type when assigning a unique object ID. * - * @covers \Charcoal\Source\StorableTrait::setId - * - * @return void */ - public function testIdWithInvalidDataType() + public function testIdWithInvalidDataType(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setId(null); @@ -162,12 +159,8 @@ public function testIdWithInvalidDataType() /** * Test the unique object ID with an alternate primary key. * - * @covers \Charcoal\Source\StorableTrait::setId - * @covers \Charcoal\Source\StorableTrait::id - * - * @return void */ - public function testAltId() + public function testAltId(): void { $obj = $this->obj; @@ -180,12 +173,8 @@ public function testAltId() /** * Test repository factory. * - * @covers \Charcoal\Source\StorableTrait::setSourceFactory - * @covers \Charcoal\Source\StorableTrait::sourceFactory - * - * @return void */ - public function testSourceFactory() + public function testSourceFactory(): void { $obj = $this->obj; @@ -203,11 +192,8 @@ public function testSourceFactory() /** * Test for missing repository factory. * - * @covers \Charcoal\Source\StorableTrait::sourceFactory - * - * @return void */ - public function testMissingSourceFactory() + public function testMissingSourceFactory(): void { $this->expectException(RuntimeException::class); $this->callMethod($this->obj, 'sourceFactory'); @@ -223,13 +209,8 @@ public function testMissingSourceFactory() * 4. Storable can create a repository * 5. Chainable method * - * @covers \Charcoal\Source\StorableTrait::createSource - * @covers \Charcoal\Source\StorableTrait::setSource - * @covers \Charcoal\Source\StorableTrait::source - * - * @return void */ - public function testSource() + public function testSource(): void { $obj = $this->obj; @@ -262,13 +243,8 @@ public function testSource() * 2. Fail Early * 3. Fail Late * - * @covers \Charcoal\Source\StorableTrait::save - * @covers \Charcoal\Source\StorableTrait::preSave - * @covers \Charcoal\Source\StorableTrait::postSave - * - * @return void */ - public function testSave() + public function testSave(): void { $src = $this->createSource(); @@ -296,13 +272,8 @@ public function testSave() * 2. Fail Early * 3. Fail Late * - * @covers \Charcoal\Source\StorableTrait::update - * @covers \Charcoal\Source\StorableTrait::preUpdate - * @covers \Charcoal\Source\StorableTrait::postUpdate - * - * @return void */ - public function testUpdate() + public function testUpdate(): void { $src = $this->createSource(); @@ -330,13 +301,8 @@ public function testUpdate() * 2. Fail Early * 3. Fail Late * - * @covers \Charcoal\Source\StorableTrait::delete - * @covers \Charcoal\Source\StorableTrait::preDelete - * @covers \Charcoal\Source\StorableTrait::postDelete - * - * @return void */ - public function testDelete() + public function testDelete(): void { $src = $this->createSource(); diff --git a/packages/core/tests/Charcoal/Validator/ValidatableTraitTest.php b/packages/core/tests/Charcoal/Validator/ValidatableTraitTest.php index 4116f8ae4..0601dc331 100644 --- a/packages/core/tests/Charcoal/Validator/ValidatableTraitTest.php +++ b/packages/core/tests/Charcoal/Validator/ValidatableTraitTest.php @@ -16,18 +16,12 @@ class ValidatableTraitTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $this->obj = new ValidatableClass(); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $obj = $this->obj; $this->assertInstanceOf(ValidatableClass::class, $obj); diff --git a/packages/core/tests/Charcoal/Validator/ValidatorResultTest.php b/packages/core/tests/Charcoal/Validator/ValidatorResultTest.php index c15badce4..957449c73 100644 --- a/packages/core/tests/Charcoal/Validator/ValidatorResultTest.php +++ b/packages/core/tests/Charcoal/Validator/ValidatorResultTest.php @@ -13,20 +13,14 @@ */ class ValidatorResultTest extends AbstractTestCase { - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = new ValidatorResult(); $ret = $obj->setData([]); $this->assertSame($ret, $obj); } - /** - * @return void - */ - public function testSetIdent() + public function testSetIdent(): void { $obj = new ValidatorResult(); $this->assertEquals(null, $obj->ident()); @@ -39,10 +33,7 @@ public function testSetIdent() $obj->setIdent(false); } - /** - * @return void - */ - public function testSetLevel() + public function testSetLevel(): void { $obj = new ValidatorResult(); $this->assertEquals(null, $obj->level()); @@ -55,20 +46,14 @@ public function testSetLevel() $obj->setLevel(false); } - /** - * @return void - */ - public function testSetLevelWithInvalidLevelsThrowException() + public function testSetLevelWithInvalidLevelsThrowException(): void { $obj = new ValidatorResult(); $this->expectException(InvalidArgumentException::class); $obj->setLevel('foo'); } - /** - * @return void - */ - public function testSetMessage() + public function testSetMessage(): void { $obj = new ValidatorResult(); $this->assertEquals('', $obj->message()); @@ -81,10 +66,7 @@ public function testSetMessage() $obj->setMessage(false); } - /** - * @return void - */ - public function testSetTs() + public function testSetTs(): void { $obj = new ValidatorResult(); $ret = $obj->setTs('2015-01-01 00:00:00'); diff --git a/packages/core/tests/Charcoal/Validator/ValidatorTest.php b/packages/core/tests/Charcoal/Validator/ValidatorTest.php index 687dd3dc9..4aa900fd9 100644 --- a/packages/core/tests/Charcoal/Validator/ValidatorTest.php +++ b/packages/core/tests/Charcoal/Validator/ValidatorTest.php @@ -26,28 +26,19 @@ class ValidatorTest extends AbstractTestCase */ public $model; - /** - * @return void - */ protected function setUp(): void { $this->model = new ValidatableClass(); $this->obj = new ValidatorClass($this->model); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $obj = $this->obj; - $this->assertInstanceOf('\Charcoal\Validator\AbstractValidator', $obj); + $this->assertInstanceOf(\Charcoal\Validator\AbstractValidator::class, $obj); } - /** - * @return void - */ - public function testError() + public function testError(): void { $obj = $this->obj; $ret = $obj->error('foo'); @@ -55,10 +46,7 @@ public function testError() // var_dump($obj->errorResults()); } - /** - * @return void - */ - public function testWarning() + public function testWarning(): void { $obj = $this->obj; $ret = $obj->warning('foo'); @@ -66,10 +54,7 @@ public function testWarning() // var_dump($obj->warningResults()); } - /** - * @return void - */ - public function testNotice() + public function testNotice(): void { $obj = $this->obj; $ret = $obj->notice('foo'); @@ -77,10 +62,7 @@ public function testNotice() // var_dump($obj->noticeResults()); } - /** - * @return void - */ - public function testAddResult() + public function testAddResult(): void { $result = [ 'ident' => 'bar', @@ -100,11 +82,8 @@ public function testAddResult() $obj->addResult(false); } - /** - * @group time-sensitive - * @return void - */ - public function testResults() + #[\PHPUnit\Framework\Attributes\Group('time-sensitive')] + public function testResults(): void { $result = [ 'ident' => 'bar', @@ -128,10 +107,7 @@ public function testResults() $this->assertEquals([ ValidatorClass::ERROR => [ $expectedResult ] ], $actualResult); } - /** - * @return void - */ - public function testErrorResults() + public function testErrorResults(): void { $result1 = [ 'ident' => 'bar', @@ -161,10 +137,7 @@ public function testErrorResults() $this->assertEquals([ $expectedResult ], $actualResult); } - /** - * @return void - */ - public function testWarningResults() + public function testWarningResults(): void { $result1 = [ 'ident' => 'bar', @@ -194,10 +167,7 @@ public function testWarningResults() $this->assertEquals([ $expectedResult ], $actualResult); } - /** - * @return void - */ - public function testNoticeResults() + public function testNoticeResults(): void { $result1 = [ 'ident' => 'bar', @@ -227,10 +197,7 @@ public function testNoticeResults() $this->assertEquals([ $expectedResult ], $actualResult); } - /** - * @return void - */ - public function testMerge() + public function testMerge(): void { $result1 = [ 'ident' => 'bar', diff --git a/packages/core/tests/bootstrap.php b/packages/core/tests/bootstrap.php new file mode 100644 index 000000000..90929e3b5 --- /dev/null +++ b/packages/core/tests/bootstrap.php @@ -0,0 +1,14 @@ + - - > + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/email/src/Charcoal/Email/Api/V1/LinkAction.php b/packages/email/src/Charcoal/Email/Api/V1/LinkAction.php index c0d2cc1fd..0a347ee66 100644 --- a/packages/email/src/Charcoal/Email/Api/V1/LinkAction.php +++ b/packages/email/src/Charcoal/Email/Api/V1/LinkAction.php @@ -19,37 +19,18 @@ */ class LinkAction { - /** - * @var string - */ - private $linkId; - - /** - * @var Tracker - */ - private $tracker; - - /** - * @var FactoryInterface - */ - private $modelFactory; - /** * @param string $linkId Link ID. * @param Tracker $tracker Tracker service. * @param FactoryInterface $modelFactory Model factory, to create Link objects. */ - public function __construct(string $linkId, Tracker $tracker, FactoryInterface $modelFactory) + public function __construct(private readonly string $linkId, private readonly Tracker $tracker, private readonly FactoryInterface $modelFactory) { - $this->linkId = $linkId; - $this->tracker = $tracker; - $this->modelFactory = $modelFactory; } /** * @param Request $request PSR-7 Request. * @param Response $response PSR-7 Response. - * @return Response */ public function __invoke(Request $request, Response $response): Response { diff --git a/packages/email/src/Charcoal/Email/Api/V1/OpenAction.php b/packages/email/src/Charcoal/Email/Api/V1/OpenAction.php index 96b45f563..7c1fbcc92 100644 --- a/packages/email/src/Charcoal/Email/Api/V1/OpenAction.php +++ b/packages/email/src/Charcoal/Email/Api/V1/OpenAction.php @@ -17,30 +17,17 @@ */ class OpenAction { - /** - * @var string - */ - private $emailId; - - /** - * @var Tracker - */ - private $tracker; - /** * @param string $emailId Email log ID. * @param Tracker $tracker Tracker service. */ - public function __construct(string $emailId, Tracker $tracker) + public function __construct(private readonly string $emailId, private readonly Tracker $tracker) { - $this->emailId = $emailId; - $this->tracker = $tracker; } /** * @param Request $request PSR-7 Request. * @param Response $response PSR-7 Response. - * @return Response */ public function __invoke(Request $request, Response $response): Response { @@ -55,7 +42,7 @@ public function __invoke(Request $request, Response $response): Response /** * @return boolean|false|string */ - private function getBlankPng() + private function getBlankPng(): string { return base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII='); } diff --git a/packages/email/src/Charcoal/Email/ApiModule.php b/packages/email/src/Charcoal/Email/ApiModule.php index 1a1d3a98d..37fac45b5 100644 --- a/packages/email/src/Charcoal/Email/ApiModule.php +++ b/packages/email/src/Charcoal/Email/ApiModule.php @@ -19,28 +19,23 @@ class ApiModule extends AbstractModule { public const BASE_PATH = '/email/v1'; - /** - * @return self - */ - public function setUp() + #[\Override] + public function setUp(): static { $this->setupPublicRoutes(); return $this; } - /** - * @return void - */ - private function setupPublicRoutes() + private function setupPublicRoutes(): void { $container = $this->app()->getContainer(); - $this->app()->group(self::BASE_PATH, function () use ($container) { + $this->app()->group(self::BASE_PATH, function () use ($container): void { $group = $this; - $group->get('/link/{linkId}', function (Request $request, Response $response, array $args) use ($container) { + $group->get('/link/{linkId}', function (Request $request, Response $response, array $args) use ($container): \Psr\Http\Message\ResponseInterface { $action = new LinkAction( $args['linkId'], $container['email/tracker'], @@ -49,7 +44,7 @@ private function setupPublicRoutes() return $action($request, $response); }); - $group->get('/open/{emailId}[.png]', function (Request $request, Response $response, array $args) use ($container) { + $group->get('/open/{emailId}[.png]', function (Request $request, Response $response, array $args) use ($container): \Psr\Http\Message\ResponseInterface { $action = new OpenAction( $args['emailId'], $container['email/tracker'] diff --git a/packages/email/src/Charcoal/Email/Email.php b/packages/email/src/Charcoal/Email/Email.php index 670bac83e..ba001c927 100644 --- a/packages/email/src/Charcoal/Email/Email.php +++ b/packages/email/src/Charcoal/Email/Email.php @@ -46,38 +46,28 @@ class Email extends AbstractEntity implements /** * The campaign ID. - * - * @var string */ - private $campaign; + private ?string $campaign = null; /** * The recipient email address(es). - * - * @var array */ - private $to = []; + private array $to = []; /** * The CC recipient email address(es). - * - * @var array */ - private $cc = []; + private array $cc = []; /** * The BCC recipient email address(es). - * - * @var array */ - private $bcc = []; + private array $bcc = []; /** * The sender's email address. - * - * @var string */ - private $from; + private ?string $from = null; /** * The email address to reply to the message. @@ -88,24 +78,18 @@ class Email extends AbstractEntity implements /** * The email subject. - * - * @var string */ - private $subject; + private ?string $subject = null; /** * The HTML message body. - * - * @var string */ - private $msgHtml; + private ?string $msgHtml = null; /** * The plain-text message body. - * - * @var string */ - private $msgTxt; + private ?string $msgTxt = null; /** * @var array @@ -133,35 +117,18 @@ class Email extends AbstractEntity implements /** * The data to pass onto the view controller. - * - * @var array */ - private $templateData = []; + private array $templateData = []; - /** - * @var PHPMailer - */ - private $phpMailer; + private \PHPMailer\PHPMailer\PHPMailer $phpMailer; - /** - * @var FactoryInterface - */ - private $templateFactory; + private \Charcoal\Factory\FactoryInterface $templateFactory; - /** - * @var FactoryInterface - */ - private $queueItemFactory; + private \Charcoal\Factory\FactoryInterface $queueItemFactory; - /** - * @var FactoryInterface - */ - private $logFactory; + private \Charcoal\Factory\FactoryInterface $logFactory; - /** - * @var Tracker - */ - private $tracker; + private \Charcoal\Email\Services\Tracker $tracker; /** * Construct a new Email object with the given dependencies. @@ -191,9 +158,8 @@ public function __construct(array $data) * Set the campaign ID. * * @param string $campaign The campaign identifier. - * @return self */ - public function setCampaign(string $campaign) + public function setCampaign(string $campaign): static { $this->campaign = $campaign; return $this; @@ -203,10 +169,8 @@ public function setCampaign(string $campaign) * Get the campaign identifier. * * If it has not been explicitely set, it will be auto-generated (with uniqid). - * - * @return string */ - public function campaign() + public function campaign(): string { if ($this->campaign === null) { $this->campaign = $this->generateCampaign(); @@ -219,9 +183,8 @@ public function campaign() * * @param string|array $email The recipient email address(es). * @throws InvalidArgumentException If the email address is invalid. - * @return self */ - public function setTo($email) + public function setTo($email): static { if (is_string($email)) { $email = [ $email ]; @@ -253,9 +216,8 @@ public function setTo($email) * * @param mixed $email The recipient email address to add. * @throws InvalidArgumentException If the email address is invalid. - * @return self */ - public function addTo($email) + public function addTo($email): static { $this->to[] = $this->parseEmail($email); return $this; @@ -266,7 +228,7 @@ public function addTo($email) * * @return string[] */ - public function to() + public function to(): array { return $this->to; } @@ -276,9 +238,8 @@ public function to() * * @param string|array $email The CC recipient email address(es). * @throws InvalidArgumentException If the email address is invalid. - * @return self */ - public function setCc($email) + public function setCc($email): static { if (is_string($email)) { $email = [ $email ]; @@ -310,9 +271,8 @@ public function setCc($email) * * @param mixed $email The CC recipient email address to add. * @throws InvalidArgumentException If the email address is invalid. - * @return self */ - public function addCc($email) + public function addCc($email): static { $this->cc[] = $this->parseEmail($email); return $this; @@ -323,7 +283,7 @@ public function addCc($email) * * @return string[] */ - public function cc() + public function cc(): array { return $this->cc; } @@ -333,9 +293,8 @@ public function cc() * * @param string|array $email The BCC recipient email address(es). * @throws InvalidArgumentException If the email address is invalid. - * @return self */ - public function setBcc($email) + public function setBcc($email): static { if (is_string($email)) { // Means we have a straight email @@ -368,9 +327,8 @@ public function setBcc($email) * * @param mixed $email The BCC recipient email address to add. * @throws InvalidArgumentException If the email address is invalid. - * @return self */ - public function addBcc($email) + public function addBcc($email): static { $this->bcc[] = $this->parseEmail($email); return $this; @@ -381,7 +339,7 @@ public function addBcc($email) * * @return string[] */ - public function bcc() + public function bcc(): array { return $this->bcc; } @@ -391,10 +349,9 @@ public function bcc() * * @param string|array $email An email address. * @throws InvalidArgumentException If the email is not a string or an array. - * @return self * @todo Implement optional "Sender" field. */ - public function setFrom($email) + public function setFrom($email): static { $this->from = $this->parseEmail($email); return $this; @@ -405,7 +362,7 @@ public function setFrom($email) * * @return string */ - public function from() + public function from(): ?string { if ($this->from === null) { $this->setFrom($this->config()->defaultFrom()); @@ -418,9 +375,8 @@ public function from() * * @param mixed $email The sender's "Reply-To" email address. * @throws InvalidArgumentException If the email is not a string or an array. - * @return self */ - public function setReplyTo($email) + public function setReplyTo($email): static { $this->replyTo = $this->parseEmail($email); return $this; @@ -443,9 +399,8 @@ public function replyTo() * Set the email subject. * * @param string $subject The email subject. - * @return self */ - public function setSubject(string $subject) + public function setSubject(string $subject): static { $this->subject = $subject; return $this; @@ -465,9 +420,8 @@ public function subject(): string * Set the email's HTML message body. * * @param string $body The HTML message body. - * @return self */ - public function setMsgHtml(string $body) + public function setMsgHtml(string $body): static { $this->msgHtml = $body; return $this; @@ -478,8 +432,6 @@ public function setMsgHtml(string $body) * * If the message is not explitely set, it will be * auto-generated from a template view. - * - * @return string */ public function msgHtml(): string { @@ -493,9 +445,8 @@ public function msgHtml(): string * Set the email's plain-text message body. * * @param string $body The message's text body. - * @return self */ - public function setMsgTxt(string $body) + public function setMsgTxt(string $body): static { $this->msgTxt = $body; return $this; @@ -506,8 +457,6 @@ public function setMsgTxt(string $body) * * If the plain-text message is not explitely set, * it will be auto-generated from the HTML message. - * - * @return string */ public function msgTxt(): string { @@ -521,9 +470,8 @@ public function msgTxt(): string * Set the email's attachments. * * @param array $attachments The file attachments. - * @return self */ - public function setAttachments(array $attachments) + public function setAttachments(array $attachments): static { foreach ($attachments as $att) { $this->addAttachment($att); @@ -535,9 +483,8 @@ public function setAttachments(array $attachments) * Add an attachment to the email. * * @param mixed $attachment A single file attachment. - * @return self */ - public function addAttachment($attachment) + public function addAttachment($attachment): static { $this->attachments[] = $attachment; return $this; @@ -557,18 +504,15 @@ public function attachments() * Enable or disable logging for this particular email. * * @param boolean $log The log-enabled flag. - * @return self */ - public function setLogEnabled($log) + public function setLogEnabled($log): static { - $this->logEnabled = !!$log; + $this->logEnabled = (bool)$log; return $this; } /** * Determine if logging is enabled for this particular email. - * - * @return boolean */ public function logEnabled(): bool { @@ -582,18 +526,15 @@ public function logEnabled(): bool * Enable or disable email open tracking for this particular email. * * @param boolean $track The track flag. - * @return self */ - public function setTrackOpenEnabled($track) + public function setTrackOpenEnabled($track): static { - $this->trackOpenEnabled = !!$track; + $this->trackOpenEnabled = (bool)$track; return $this; } /** * Determine if email open tracking is enabled for this particular email. - * - * @return boolean */ public function trackOpenEnabled(): bool { @@ -607,18 +548,15 @@ public function trackOpenEnabled(): bool * Enable or disable email links tracking for this particular email. * * @param boolean $track The track flag. - * @return self */ - public function setTrackLinksEnabled($track) + public function setTrackLinksEnabled($track): static { - $this->trackLinksEnabled = !!$track; + $this->trackLinksEnabled = (bool)$track; return $this; } /** * Determine if email links tracking is enabled for this particular email. - * - * @return boolean */ public function trackLinksEnabled(): bool { @@ -694,10 +632,10 @@ public function send(): bool $logId = uniqid(); - if ($this->trackOpenEnabled() === true) { + if ($this->trackOpenEnabled()) { $this->tracker->addOpenTrackingImage($this, $logId); } - if ($this->trackLinksEnabled() === true) { + if ($this->trackLinksEnabled()) { $this->tracker->replaceLinksWithTracker($this, $logId); } @@ -717,7 +655,7 @@ public function send(): bool throw new EmailNotSentException($e->getMessage(), $e->getCode(), $e); } - if ($this->logEnabled() === true) { + if ($this->logEnabled()) { try { $this->logSend($ret, $logId, $mail); } catch (PDOException $e) { @@ -760,9 +698,8 @@ protected function setSmtpOptions(PHPMailer $mail) * Enqueue the email for each recipient. * * @param mixed $ts A date/time to initiate the queue processing. - * @return self */ - public function queue($ts = null) + public function queue($ts = null): static { $recipients = $this->to(); $author = $this->from(); @@ -773,7 +710,7 @@ public function queue($ts = null) $queueId = $this->queueId(); foreach ($recipients as $to) { - if (is_string($to) && !empty($to)) { + if (is_string($to) && ($to !== '' && $to !== '0')) { $queueItem = $this->queueItemFactory()->create(EmailQueueItem::class); $queueItem->setTo($to); @@ -800,7 +737,7 @@ public function queue($ts = null) * @param array $data The template data. * @return Email Chainable */ - public function setTemplateData(array $data) + public function setTemplateData(array $data): static { $this->templateData = $data; return $this; @@ -808,8 +745,6 @@ public function setTemplateData(array $data) /** * Get the template data for the view. - * - * @return array */ public function templateData(): array { @@ -847,15 +782,12 @@ public function viewController() * @param FactoryInterface $factory The factory to use to create email template objects. * @return Email Chainable */ - protected function setTemplateFactory(FactoryInterface $factory) + protected function setTemplateFactory(FactoryInterface $factory): static { $this->templateFactory = $factory; return $this; } - /** - * @return FactoryInterface - */ protected function templateFactory(): FactoryInterface { return $this->templateFactory; @@ -865,15 +797,12 @@ protected function templateFactory(): FactoryInterface * @param FactoryInterface $factory The factory to use to create email queue item objects. * @return Email Chainable */ - protected function setQueueItemFactory(FactoryInterface $factory) + protected function setQueueItemFactory(FactoryInterface $factory): static { $this->queueItemFactory = $factory; return $this; } - /** - * @return FactoryInterface - */ protected function queueItemFactory(): FactoryInterface { return $this->queueItemFactory; @@ -883,15 +812,12 @@ protected function queueItemFactory(): FactoryInterface * @param FactoryInterface $factory The factory to use to create log objects. * @return Email Chainable */ - protected function setLogFactory(FactoryInterface $factory) + protected function setLogFactory(FactoryInterface $factory): static { $this->logFactory = $factory; return $this; } - /** - * @return FactoryInterface - */ protected function logFactory(): FactoryInterface { return $this->logFactory; @@ -899,9 +825,8 @@ protected function logFactory(): FactoryInterface /** * @param Tracker $tracker Tracker service. - * @return void */ - public function setTracker(Tracker $tracker) + public function setTracker(Tracker $tracker): void { $this->tracker = $tracker; } @@ -910,25 +835,16 @@ public function setTracker(Tracker $tracker) * Get the email's HTML message from the template, if applicable. * * @see ViewableInterface::render() - * @return string */ protected function generateMsgHtml(): string { $templateIdent = $this->templateIdent(); - if (!$templateIdent) { - $message = ''; - } else { - $message = $this->render($templateIdent); - } - - return $message; + return $templateIdent ? $this->render($templateIdent) : ''; } /** * Generates a unique identifier ideal for a campaign ID. - * - * @return string */ protected function generateCampaign(): string { @@ -984,18 +900,17 @@ protected function stripHtml(string $html): string '#]*?>.*?#siu' ], '', - $str + (string)$str ); - $str = strip_tags($str); + $str = strip_tags((string)$str); // Trim whitespace $str = str_replace("\t", '', $str); $str = preg_replace('#\n\r|\r\n#', "\n", $str); - $str = preg_replace('#\n{3,}#', "\n\n", $str); - $str = preg_replace('/ {2,}/', ' ', $str); - $str = implode("\n", array_map('trim', explode("\n", $str))); - $str = trim($str) . "\n"; - return $str; + $str = preg_replace('#\n{3,}#', "\n\n", (string)$str); + $str = preg_replace('/ {2,}/', ' ', (string)$str); + $str = implode("\n", array_map(trim(...), explode("\n", (string)$str))); + return trim($str) . "\n"; } /** @@ -1004,7 +919,6 @@ protected function stripHtml(string $html): string * @param boolean $result Success or failure. * @param string $logId Email log id. * @param PHPMailer $mailer The raw mailer. - * @return void */ protected function logSend(bool $result, string $logId, PHPMailer $mailer): void { @@ -1045,10 +959,8 @@ protected function logSend(bool $result, string $logId, PHPMailer $mailer): void /** * Temporary hack to fulfills the Configurable Interface. - * - * @return EmailConfig */ - public function createConfig() + public function createConfig(): \Charcoal\Email\EmailConfig { // This should really be avoided. $this->logger->warning('AbstractEmail::createConfig() was called, but should not.'); diff --git a/packages/email/src/Charcoal/Email/EmailAwareTrait.php b/packages/email/src/Charcoal/Email/EmailAwareTrait.php index 8a0de6228..51c732278 100644 --- a/packages/email/src/Charcoal/Email/EmailAwareTrait.php +++ b/packages/email/src/Charcoal/Email/EmailAwareTrait.php @@ -19,16 +19,12 @@ trait EmailAwareTrait /** * @param Parser $parser Email parser service. - * @return void */ protected function setParser(Parser $parser): void { $this->parser = $parser; } - /** - * @return Parser - */ protected function getParser(): Parser { if ($this->parser === null) { @@ -40,7 +36,6 @@ protected function getParser(): Parser /** * @param mixed $email An email value (either a string or an array). * @throws InvalidArgumentException If the email is invalid. - * @return string */ protected function parseEmail($email): string { @@ -52,7 +47,6 @@ protected function parseEmail($email): string * * @param mixed $var An email array (containing an "email" key and optionally a "name" key). * @throws InvalidArgumentException If the email is invalid. - * @return array|null */ protected function emailToArray($var): ?array { @@ -64,7 +58,6 @@ protected function emailToArray($var): ?array * * @param array $arr An email array (containing an "email" key and optionally a "name" key). * @throws InvalidArgumentException If the email array is invalid. - * @return string */ protected function emailFromArray(array $arr): string { diff --git a/packages/email/src/Charcoal/Email/EmailConfig.php b/packages/email/src/Charcoal/Email/EmailConfig.php index 068d46e92..dd1083ba3 100644 --- a/packages/email/src/Charcoal/Email/EmailConfig.php +++ b/packages/email/src/Charcoal/Email/EmailConfig.php @@ -17,94 +17,69 @@ class EmailConfig extends AbstractConfig /** * Whether SMTP should be used. - * - * @var boolean $smtp */ - private $smtp = false; + private bool $smtp = false; /** * The SMTP hostname. - * - * @var string $smtpHostname */ - private $smtpHostname; + private ?string $smtpHostname = null; /** * The SMTP port. - * - * @var integer $smtpPort */ - private $smtpPort; + private ?int $smtpPort = null; /** * The SMTP security type. - * - * @var string $smtpSecurity */ - private $smtpSecurity = ''; + private string $smtpSecurity = ''; /** * Whether SMTP requires authentication. - * - * @var boolean $smtpAuth */ - private $smtpAuth; + private ?bool $smtpAuth = null; /** * The SMTP username. - * - * @var string $smtpUsername */ - private $smtpUsername; + private ?string $smtpUsername = null; /** * The SMTP password. - * - * @var string $smtpPassword */ - private $smtpPassword; + private ?string $smtpPassword = null; /** * The default sender's email address. - * - * @var string $defaultFrom */ - private $defaultFrom; + private ?string $defaultFrom = null; /** * The default "Reply-To" email address. - * - * @var string $defaultReplyTo */ - private $defaultReplyTo; + private ?string $defaultReplyTo = null; /** * Whether the email (open) should be tracked by default. - * - * @var boolean $defaultTrack */ - private $defaultTrackOpenEnabled; + private ?bool $defaultTrackOpenEnabled = null; /** * Whether the email (links) should be tracked by default. - * - * @var boolean $defaultTrack */ - private $defaultTrackLinksEnabled; + private ?bool $defaultTrackLinksEnabled = null; /** * Whether the email should be logged by default. - * - * @var boolean $defaultLog */ - private $defaultLogEnabled; + private ?bool $defaultLogEnabled = null; /** * Default email configuration. - * - * @return array */ + #[\Override] public function defaults(): array { return [ @@ -124,20 +99,17 @@ public function defaults(): array * * @param boolean $smtp If the email should be sent using SMTP or not. * @throws InvalidArgumentException If the SMTP state is not a boolean. - * @return self */ - public function setSmtp($smtp) + public function setSmtp($smtp): static { - $this->smtp = !!$smtp; + $this->smtp = (bool)$smtp; return $this; } /** * Determine if SMTP should be used. - * - * @return boolean */ - public function smtp() + public function smtp(): bool { return $this->smtp; } @@ -147,9 +119,8 @@ public function smtp() * * @param string $hostname The SMTP hostname. * @throws InvalidArgumentException If the SMTP hostname is not a string. - * @return self */ - public function setSmtpHostname($hostname) + public function setSmtpHostname($hostname): static { if (!is_string($hostname)) { throw new InvalidArgumentException( @@ -167,7 +138,7 @@ public function setSmtpHostname($hostname) * * @return string */ - public function smtpHostname() + public function smtpHostname(): ?string { return $this->smtpHostname; } @@ -177,9 +148,8 @@ public function smtpHostname() * * @param integer $port The SMTP port. * @throws InvalidArgumentException If the SMTP port is not an integer. - * @return self */ - public function setSmtpPort($port) + public function setSmtpPort($port): static { if (!is_int($port)) { throw new InvalidArgumentException( @@ -197,7 +167,7 @@ public function setSmtpPort($port) * * @return integer */ - public function smtpPort() + public function smtpPort(): ?int { return $this->smtpPort; } @@ -206,11 +176,10 @@ public function smtpPort() * Set whether SMTP requires authentication. * * @param boolean $auth The SMTP authentication flag (if auth is required). - * @return self */ - public function setSmtpAuth($auth) + public function setSmtpAuth($auth): static { - $this->smtpAuth = !!$auth; + $this->smtpAuth = (bool)$auth; return $this; } @@ -219,7 +188,7 @@ public function setSmtpAuth($auth) * * @return boolean */ - public function smtpAuth() + public function smtpAuth(): ?bool { return $this->smtpAuth; } @@ -229,9 +198,8 @@ public function smtpAuth() * * @param string $username The SMTP username, if using authentication. * @throws InvalidArgumentException If the SMTP username is not a string. - * @return self */ - public function setSmtpUsername($username) + public function setSmtpUsername($username): static { if (!is_string($username)) { throw new InvalidArgumentException( @@ -249,7 +217,7 @@ public function setSmtpUsername($username) * * @return string */ - public function smtpUsername() + public function smtpUsername(): ?string { return $this->smtpUsername; } @@ -259,9 +227,8 @@ public function smtpUsername() * * @param string $password The SMTP password, if using authentication. * @throws InvalidArgumentException If the SMTP password is not a string. - * @return self */ - public function setSmtpPassword($password) + public function setSmtpPassword($password): static { if (!is_string($password)) { throw new InvalidArgumentException( @@ -279,7 +246,7 @@ public function setSmtpPassword($password) * * @return string */ - public function smtpPassword() + public function smtpPassword(): ?string { return $this->smtpPassword; } @@ -289,9 +256,8 @@ public function smtpPassword() * * @param string $security The SMTP security type (empty, "TLS", or "SSL"). * @throws InvalidArgumentException If the security type is not valid (empty, "TLS", or "SSL"). - * @return self */ - public function setSmtpSecurity($security) + public function setSmtpSecurity($security): static { $security = strtoupper($security); $validSecurity = [ '', 'TLS', 'SSL' ]; @@ -309,10 +275,8 @@ public function setSmtpSecurity($security) /** * Get the SMTP security type. - * - * @return string */ - public function smtpSecurity() + public function smtpSecurity(): string { return $this->smtpSecurity; } @@ -321,9 +285,8 @@ public function smtpSecurity() * Set the default sender's email address. * * @param string|array $email The default "From" email address. - * @return self */ - public function setDefaultFrom($email) + public function setDefaultFrom($email): static { $this->defaultFrom = $this->parseEmail($email); return $this; @@ -334,7 +297,7 @@ public function setDefaultFrom($email) * * @return string */ - public function defaultFrom() + public function defaultFrom(): ?string { return $this->defaultFrom; } @@ -343,9 +306,8 @@ public function defaultFrom() * Set the default "Reply-To" email address. * * @param string|array $email The default "Reply-To" email address. - * @return self */ - public function setDefaultReplyTo($email) + public function setDefaultReplyTo($email): static { $this->defaultReplyTo = $this->parseEmail($email); return $this; @@ -356,7 +318,7 @@ public function setDefaultReplyTo($email) * * @return string */ - public function defaultReplyTo() + public function defaultReplyTo(): ?string { return $this->defaultReplyTo; } @@ -365,11 +327,10 @@ public function defaultReplyTo() * Set whether the email sending should be logged by default. * * @param boolean $log The default log flag. - * @return self */ - public function setDefaultLogEnabled($log) + public function setDefaultLogEnabled($log): static { - $this->defaultLogEnabled = !!$log; + $this->defaultLogEnabled = (bool)$log; return $this; } @@ -378,7 +339,7 @@ public function setDefaultLogEnabled($log) * * @return boolean */ - public function defaultLogEnabled() + public function defaultLogEnabled(): ?bool { return $this->defaultLogEnabled; } @@ -387,11 +348,10 @@ public function defaultLogEnabled() * Set whether the email (open) should be tracked by default. * * @param boolean $track The default track flag. - * @return self */ - public function setDefaultTrackOpenEnabled($track) + public function setDefaultTrackOpenEnabled($track): static { - $this->defaultTrackOpenEnabled = !!$track; + $this->defaultTrackOpenEnabled = (bool)$track; return $this; } @@ -400,7 +360,7 @@ public function setDefaultTrackOpenEnabled($track) * * @return boolean */ - public function defaultTrackOpenEnabled() + public function defaultTrackOpenEnabled(): ?bool { return $this->defaultTrackOpenEnabled; } @@ -409,11 +369,10 @@ public function defaultTrackOpenEnabled() * Set whether the email links should be tracked by default. * * @param boolean $track The default track flag. - * @return self */ - public function setDefaultTrackLinksEnabled($track) + public function setDefaultTrackLinksEnabled($track): static { - $this->defaultTrackLinksEnabled = !!$track; + $this->defaultTrackLinksEnabled = (bool)$track; return $this; } @@ -422,7 +381,7 @@ public function setDefaultTrackLinksEnabled($track) * * @return boolean */ - public function defaultTrackLinksEnabled() + public function defaultTrackLinksEnabled(): ?bool { return $this->defaultTrackLinksEnabled; } diff --git a/packages/email/src/Charcoal/Email/EmailInterface.php b/packages/email/src/Charcoal/Email/EmailInterface.php index ca4204066..4ff73e087 100644 --- a/packages/email/src/Charcoal/Email/EmailInterface.php +++ b/packages/email/src/Charcoal/Email/EmailInterface.php @@ -156,8 +156,6 @@ public function setMsgHtml(string $body); /** * Get the email's HTML message body. - * - * @return string */ public function msgHtml(): string; @@ -171,8 +169,6 @@ public function setMsgTxt(string $body); /** * Get the email's plain-text message body. - * - * @return string */ public function msgTxt(): string; @@ -209,8 +205,6 @@ public function setLogEnabled($log); /** * Determine if logging is enabled for this particular email. - * - * @return boolean */ public function logEnabled(): bool; @@ -224,8 +218,6 @@ public function setTrackOpenEnabled($track); /** * Determine if tracking is enabled for this particular email. - * - * @return boolean */ public function trackLinksEnabled(): bool; @@ -239,8 +231,6 @@ public function setTrackLinksEnabled($track); /** * Determine if tracking is enabled for this particular email. - * - * @return boolean */ public function trackOpenEnabled(): bool; diff --git a/packages/email/src/Charcoal/Email/EmailLog.php b/packages/email/src/Charcoal/Email/EmailLog.php index 376ebda71..1a8ec67d9 100644 --- a/packages/email/src/Charcoal/Email/EmailLog.php +++ b/packages/email/src/Charcoal/Email/EmailLog.php @@ -1,5 +1,7 @@ to = $this->parseEmail($email); - } catch (Exception $e) { + } catch (Exception) { $this->logger->warning(sprintf('Invalid "to" email: "%s"', strval($email))); } @@ -103,7 +94,7 @@ public function setTo($email) * * @return string */ - public function to() + public function to(): ?string { return $this->to; } @@ -112,13 +103,12 @@ public function to() * Set the sender's email address. * * @param string|array $email An email address. - * @return self */ - public function setFrom($email) + public function setFrom($email): static { try { $this->from = $this->parseEmail($email); - } catch (Exception $e) { + } catch (Exception) { $this->logger->warning(sprintf('Invalid "from" email: "%s"', strval($email))); } @@ -130,7 +120,7 @@ public function setFrom($email) * * @return string */ - public function from() + public function from(): ?string { return $this->from; } @@ -139,9 +129,8 @@ public function from() * Set the email subject. * * @param string $subject The email subject. - * @return self */ - public function setSubject($subject) + public function setSubject($subject): static { $this->subject = $subject; @@ -162,9 +151,8 @@ public function subject() * Set the email's HTML message body. * * @param string $body The HTML message body. - * @return self */ - public function setMsgHtml($body) + public function setMsgHtml($body): static { $this->msgHtml = $body; @@ -185,9 +173,8 @@ public function msgHtml() * Set the email's plain-text message body. * * @param string $body The plain-text mesage body. - * @return self */ - public function setMsgTxt($body) + public function setMsgTxt($body): static { $this->msgTxt = $body; @@ -208,9 +195,8 @@ public function msgTxt() * Set the campaign ID. * * @param string $campaign The campaign identifier. - * @return self */ - public function setCampaign($campaign) + public function setCampaign($campaign): static { $this->campaign = $campaign; @@ -240,9 +226,9 @@ public function campaign() * processed. */ public function process( - callable $alwaysCallback = null, - callable $successCallback = null, - callable $failureCallback = null + ?callable $alwaysCallback = null, + ?callable $successCallback = null, + ?callable $failureCallback = null ): ?bool { $email = $this->emailFactory()->create('email'); $email->setData($this->data()); @@ -269,16 +255,13 @@ public function process( // Clear cumbersome DB data $this->setMsgHtml(null) ->setMsgTxt(null); - - array_push($propsToUpdate, 'msg_html', 'msg_txt'); - + $propsToUpdate[] = 'msg_html'; + $propsToUpdate[] = 'msg_txt'; if ($successCallback !== null) { $successCallback($this); } - } else { - if ($failureCallback !== null) { - $failureCallback($this); - } + } elseif ($failureCallback !== null) { + $failureCallback($this); } $this->update(array_merge([ @@ -294,8 +277,8 @@ public function process( /** * @param Container $container Pimple DI container. - * @return void */ + #[\Override] protected function setDependencies(Container $container): void { parent::setDependencies($container); @@ -305,9 +288,9 @@ protected function setDependencies(Container $container): void /** * Hook called before saving the item. * - * @return boolean * @see \Charcoal\Queue\QueueItemTrait::preSaveQueueItem() */ + #[\Override] protected function preSave(): bool { parent::preSave(); @@ -317,9 +300,6 @@ protected function preSave(): bool return true; } - /** - * @return FactoryInterface - */ protected function emailFactory(): FactoryInterface { return $this->emailFactory; @@ -327,7 +307,6 @@ protected function emailFactory(): FactoryInterface /** * @param FactoryInterface $factory The factory to create email objects. - * @return void */ private function setEmailFactory(FactoryInterface $factory): void { diff --git a/packages/email/src/Charcoal/Email/EmailQueueManager.php b/packages/email/src/Charcoal/Email/EmailQueueManager.php index 9d94e33fe..ff6b7af4f 100644 --- a/packages/email/src/Charcoal/Email/EmailQueueManager.php +++ b/packages/email/src/Charcoal/Email/EmailQueueManager.php @@ -1,5 +1,7 @@ queueId = $queueId; @@ -110,9 +100,8 @@ public function queueId() * Set the error code. * * @param string $errorCode The error code. - * @return self */ - public function setErrorCode($errorCode) + public function setErrorCode($errorCode): static { $this->errorCode = $errorCode; @@ -134,9 +123,8 @@ public function errorCode() * * @param string $messageId The Message-ID. * @throws InvalidArgumentException If the Message-ID is not a string. - * @return self */ - public function setMessageId($messageId) + public function setMessageId($messageId): static { if (!is_string($messageId)) { throw new InvalidArgumentException( @@ -154,7 +142,7 @@ public function setMessageId($messageId) * * @return string */ - public function messageId() + public function messageId(): ?string { return $this->messageId; } @@ -164,9 +152,8 @@ public function messageId() * * @param string $campaign The campaign identifier. * @throws InvalidArgumentException If the campaign is invalid. - * @return self */ - public function setCampaign($campaign) + public function setCampaign($campaign): static { if ($campaign !== null && !is_string($campaign)) { throw new InvalidArgumentException( @@ -194,9 +181,8 @@ public function campaign() * * @param string|array $email An email address. * @throws InvalidArgumentException If the email address is invalid. - * @return self */ - public function setFrom($email) + public function setFrom($email): static { $this->from = $this->parseEmail($email); return $this; @@ -207,7 +193,7 @@ public function setFrom($email) * * @return string */ - public function from() + public function from(): ?string { return $this->from; } @@ -216,9 +202,8 @@ public function from() * Set the recipient's email address. * * @param string|array $email An email address. - * @return self */ - public function setTo($email) + public function setTo($email): static { $this->to = $this->parseEmail($email); return $this; @@ -229,7 +214,7 @@ public function setTo($email) * * @return string */ - public function to() + public function to(): ?string { return $this->to; } @@ -239,9 +224,8 @@ public function to() * * @param string $subject The email subject. * @throws InvalidArgumentException If the subject is not a string. - * @return self */ - public function setSubject($subject) + public function setSubject($subject): static { if (!is_string($subject)) { throw new InvalidArgumentException( @@ -259,7 +243,7 @@ public function setSubject($subject) * * @return string */ - public function subject() + public function subject(): ?string { return $this->subject; } @@ -267,9 +251,8 @@ public function subject() /** * @param null|string|DateTime $ts The "send date" datetime value. * @throws InvalidArgumentException If the ts is not a valid datetime value. - * @return self */ - public function setSendTs($ts) + public function setSendTs($ts): static { if ($ts === null) { $this->sendTs = null; @@ -280,7 +263,7 @@ public function setSendTs($ts) try { $ts = new DateTime($ts); } catch (Exception $e) { - throw new InvalidArgumentException($e->getMessage()); + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); } } @@ -294,23 +277,20 @@ public function setSendTs($ts) return $this; } - /** - * @return null|DateTimeInterface - */ - public function sendTs() + public function sendTs(): ?\DateTimeInterface { return $this->sendTs; } /** * @see StorableTrait::preSave() - * @return boolean */ + #[\Override] protected function preSave(): bool { parent::preSave(); - if ($this->sendTs() === null) { + if (!$this->sendTs() instanceof \DateTimeInterface) { $this->setSendTs('now'); } diff --git a/packages/email/src/Charcoal/Email/Objects/Link.php b/packages/email/src/Charcoal/Email/Objects/Link.php index 4a3ae36f3..09c489bca 100644 --- a/packages/email/src/Charcoal/Email/Objects/Link.php +++ b/packages/email/src/Charcoal/Email/Objects/Link.php @@ -24,17 +24,13 @@ class Link extends AbstractModel /** * @param string $emailId The email (log) id. - * @return self */ - public function setEmail(?string $emailId) + public function setEmail(?string $emailId): static { $this->email = $emailId; return $this; } - /** - * @return string|null - */ public function email(): ?string { return $this->email; @@ -42,17 +38,13 @@ public function email(): ?string /** * @param string $url The original (and target) URL. - * @return self */ - public function setUrl(?string $url) + public function setUrl(?string $url): static { $this->url = $url; return $this; } - /** - * @return string|null - */ public function url(): ?string { return $this->url; diff --git a/packages/email/src/Charcoal/Email/Objects/LinkLog.php b/packages/email/src/Charcoal/Email/Objects/LinkLog.php index e9d83e5aa..5f728b584 100644 --- a/packages/email/src/Charcoal/Email/Objects/LinkLog.php +++ b/packages/email/src/Charcoal/Email/Objects/LinkLog.php @@ -16,26 +16,16 @@ */ class LinkLog extends AbstractModel { - /** - * @var string|null - */ - private $link; + private ?string $link = null; - /** - * @var DateTimeInterface|null - */ - private $ts; + private ?\DateTimeInterface $ts = null; - /** - * @var string|null - */ - private $ip; + private ?string $ip = null; /** * @param string|null $linkId The link id. - * @return self */ - public function setLink(?string $linkId) + public function setLink(?string $linkId): static { $this->link = $linkId; return $this; @@ -52,9 +42,8 @@ public function link(): ?string /** * @param null|string|DateTimeInterface $ts The "timestamp" datetime value. * @throws InvalidArgumentException If the timestamp is not a valid datetime value. - * @return self */ - public function setTs($ts) + public function setTs($ts): static { if ($ts === null) { $this->ts = null; @@ -65,7 +54,7 @@ public function setTs($ts) try { $ts = new DateTime($ts); } catch (Exception $e) { - throw new InvalidArgumentException($e->getMessage()); + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); } } @@ -79,27 +68,20 @@ public function setTs($ts) return $this; } - /** - * @return null|DateTimeInterface - */ - public function ts() + public function ts(): ?\DateTimeInterface { return $this->ts; } /** * @param string|null $ip The IP address. - * @return self */ - public function setIp(?string $ip) + public function setIp(?string $ip): static { $this->ip = $ip; return $this; } - /** - * @return string|null - */ public function ip(): ?string { return $this->ip; diff --git a/packages/email/src/Charcoal/Email/Objects/OpenLog.php b/packages/email/src/Charcoal/Email/Objects/OpenLog.php index 6fca61256..0edc6e3b1 100644 --- a/packages/email/src/Charcoal/Email/Objects/OpenLog.php +++ b/packages/email/src/Charcoal/Email/Objects/OpenLog.php @@ -16,35 +16,22 @@ */ class OpenLog extends AbstractModel { - /** - * @var string|null - */ - private $email; + private ?string $email = null; - /** - * @var DateTimeInterface|null - */ - private $ts; + private ?\DateTimeInterface $ts = null; - /** - * @var string|null - */ - private $ip; + private ?string $ip = null; /** * @param string|null $emailId The email (log) id. - * @return self */ - public function setEmail(?string $emailId) + public function setEmail(?string $emailId): static { $this->email = $emailId; return $this; } - /** - * @return string|null - */ public function email(): ?string { return $this->email; @@ -53,9 +40,8 @@ public function email(): ?string /** * @param null|string|DateTimeInterface $ts The "timestamp" datetime value. * @throws InvalidArgumentException If the timestamp is not a valid datetime value. - * @return self */ - public function setTs($ts) + public function setTs($ts): static { if ($ts === null) { $this->ts = null; @@ -66,7 +52,7 @@ public function setTs($ts) try { $ts = new DateTime($ts); } catch (Exception $e) { - throw new InvalidArgumentException($e->getMessage()); + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); } } @@ -80,27 +66,20 @@ public function setTs($ts) return $this; } - /** - * @return null|DateTimeInterface - */ - public function ts() + public function ts(): ?\DateTimeInterface { return $this->ts; } /** * @param string|null $ip The IP address. - * @return self */ - public function setIp(?string $ip) + public function setIp(?string $ip): static { $this->ip = $ip; return $this; } - /** - * @return string|null - */ public function ip(): ?string { return $this->ip; diff --git a/packages/email/src/Charcoal/Email/Script/ProcessQueueScript.php b/packages/email/src/Charcoal/Email/Script/ProcessQueueScript.php index 086b89d3d..18a195eb4 100644 --- a/packages/email/src/Charcoal/Email/Script/ProcessQueueScript.php +++ b/packages/email/src/Charcoal/Email/Script/ProcessQueueScript.php @@ -27,17 +27,13 @@ class ProcessQueueScript extends AbstractScript implements CronScriptInterface { use CronScriptTrait; - /** - * @var FactoryInterface - */ - private $queueItemFactory; + private ?\Charcoal\Factory\FactoryInterface $queueItemFactory = null; /** * Process all messages currently in queue. * * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { @@ -67,10 +63,9 @@ public function run(RequestInterface $request, ResponseInterface $response): Res /** * Default script arguments. - * - * @return array */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'queue-id' => [ @@ -98,9 +93,7 @@ public function defaultArguments() 'castTo' => 'int', ], ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** @@ -108,7 +101,7 @@ public function defaultArguments() * * @return EmailQueueManager */ - protected function makeQueueManager() + protected function makeQueueManager(): object { $cli = $this->climate(); @@ -147,8 +140,6 @@ protected function makeQueueManager() /** * Retrieve the class name of the queue manager model. - * - * @return string */ protected function getQueueManagerClass(): string { @@ -162,7 +153,7 @@ protected function getProcessedQueueCallback(): callable { $climate = $this->climate(); - $callback = function ($success, $failures, $skipped) use ($climate): void { + return function ($success, $failures, $skipped) use ($climate): void { if (!empty($success)) { $climate->green()->out(sprintf('%s emails were successfully sent.', count($success))); } @@ -175,14 +166,12 @@ protected function getProcessedQueueCallback(): callable $climate->dim()->out(sprintf('%s emails were skipped.', count($skipped))); } }; - - return $callback; } /** * @param Container $container Pimple DI container. - * @return void */ + #[\Override] protected function setDependencies(Container $container): void { parent::setDependencies($container); @@ -191,7 +180,6 @@ protected function setDependencies(Container $container): void /** * @param FactoryInterface $factory The factory to create queue items. - * @return void */ private function setQueueItemFactory(FactoryInterface $factory): void { diff --git a/packages/email/src/Charcoal/Email/ServiceProvider/EmailServiceProvider.php b/packages/email/src/Charcoal/Email/ServiceProvider/EmailServiceProvider.php index bbafb8c37..2c428bb21 100644 --- a/packages/email/src/Charcoal/Email/ServiceProvider/EmailServiceProvider.php +++ b/packages/email/src/Charcoal/Email/ServiceProvider/EmailServiceProvider.php @@ -33,7 +33,6 @@ class EmailServiceProvider implements ServiceProviderInterface { /** * @param Container $container A pimple container instance. - * @return void */ public function register(Container $container): void { @@ -43,65 +42,54 @@ public function register(Container $container): void */ $container['email/config'] = function (Container $container): EmailConfig { $appConfig = $container['config']; - $emailConfig = new EmailConfig($appConfig['email']); - return $emailConfig; + return new EmailConfig($appConfig['email']); }; /** * @param Container $container Pimple DI container. * @return ViewInterface */ - $container['email/view'] = function (Container $container): ViewInterface { - return $container['view']; - }; + $container['email/view'] = (fn(Container $container): ViewInterface => $container['view']); /** * @param Container $container Pimple DI Container. * @return FactoryInterface */ - $container['email/factory'] = function (Container $container): FactoryInterface { - return new GenericFactory([ - 'map' => [ - 'email' => Email::class - ], - 'base_class' => EmailInterface::class, - 'default_class' => Email::class, - 'arguments' => [[ - 'logger' => $container['logger'], - 'config' => $container['email/config'], - 'view' => $container['email/view'], - 'template_factory' => $container['template/factory'], - 'queue_item_factory' => $container['model/factory'], - 'log_factory' => $container['model/factory'], - 'tracker' => $container['email/tracker'] - ]] - ]); - }; + $container['email/factory'] = (fn(Container $container): FactoryInterface => new GenericFactory([ + 'map' => [ + 'email' => Email::class + ], + 'base_class' => EmailInterface::class, + 'default_class' => Email::class, + 'arguments' => [[ + 'logger' => $container['logger'], + 'config' => $container['email/config'], + 'view' => $container['email/view'], + 'template_factory' => $container['template/factory'], + 'queue_item_factory' => $container['model/factory'], + 'log_factory' => $container['model/factory'], + 'tracker' => $container['email/tracker'] + ]] + ])); /** * @return Parser */ - $container['email/parser'] = function (): Parser { - return new Parser(); - }; + $container['email/parser'] = (fn(): Parser => new Parser()); /** * @param Container $container Pimple DI Container. * @return Tracker */ - $container['email/tracker'] = function (Container $container): Tracker { - return new Tracker( - (string)$container['base-url'], - $container['model/factory'] - ); - }; + $container['email/tracker'] = (fn(Container $container): Tracker => new Tracker( + (string)$container['base-url'], + $container['model/factory'] + )); /** * @param Container $container Pimple DI container. * @return \Charcoal\Email\EmailInterface */ - $container['email'] = $container->factory(function (Container $container): EmailInterface { - return $container['email/factory']->create('email'); - }); + $container['email'] = $container->factory(fn(Container $container): EmailInterface => $container['email/factory']->create('email')); } } diff --git a/packages/email/src/Charcoal/Email/Services/Parser.php b/packages/email/src/Charcoal/Email/Services/Parser.php index 841a4bff7..64b3aebb6 100644 --- a/packages/email/src/Charcoal/Email/Services/Parser.php +++ b/packages/email/src/Charcoal/Email/Services/Parser.php @@ -19,7 +19,6 @@ class Parser /** * @param string|array $email An email value (either a string or an array). * @throws InvalidArgumentException If the email is invalid. - * @return string */ public function parse($email): string { @@ -40,7 +39,6 @@ public function parse($email): string * * @param string $var An email array (containing an "email" key and optionally a "name" key). * @throws InvalidArgumentException If the email is invalid. - * @return array */ public function emailToArray(string $var): array { @@ -56,7 +54,6 @@ public function emailToArray(string $var): array * * @param array $arr An email array (containing an "email" key and optionally a "name" key). * @throws InvalidArgumentException If the email array is invalid. - * @return string */ public function emailFromArray(array $arr): string { @@ -72,7 +69,8 @@ public function emailFromArray(array $arr): string return $email; } - $name = str_replace('"', '', filter_var($arr['name'], FILTER_SANITIZE_STRING)); + $name = htmlspecialchars($arr['name'], ENT_NOQUOTES, 'UTF-8'); + $name = str_replace('"', '', $name); return sprintf('"%s" <%s>', $name, $email); } } diff --git a/packages/email/src/Charcoal/Email/Services/Tracker.php b/packages/email/src/Charcoal/Email/Services/Tracker.php index a1c9c265a..83a329afc 100644 --- a/packages/email/src/Charcoal/Email/Services/Tracker.php +++ b/packages/email/src/Charcoal/Email/Services/Tracker.php @@ -22,30 +22,17 @@ */ class Tracker { - /** - * @var string - */ - private $baseUrl; - - /** - * @var FactoryInterface - */ - private $modelFactory; - /** * @param string $baseUrl Base URL. * @param FactoryInterface $modelFactory Model factory to create link and log objects. */ - public function __construct(string $baseUrl, FactoryInterface $modelFactory) + public function __construct(private readonly string $baseUrl, private readonly FactoryInterface $modelFactory) { - $this->baseUrl = $baseUrl; - $this->modelFactory = $modelFactory; } /** * @param Email $email Email object to update. * @param string $emailLogId Email log ID, to generate image link for. - * @return void */ public function addOpenTrackingImage(Email &$email, string $emailLogId): void { @@ -64,7 +51,6 @@ public function addOpenTrackingImage(Email &$email, string $emailLogId): void /** * @param Email $email Email object to update. * @param string $emailLogId Email log ID, to generate links for. - * @return void */ public function replaceLinksWithTracker(Email &$email, string $emailLogId): void { @@ -83,7 +69,6 @@ public function replaceLinksWithTracker(Email &$email, string $emailLogId): void /** * @param string $emailLogId Email log ID, to track. * @param string|null $ip Client IP address. - * @return void */ public function trackOpen(string $emailLogId, ?string $ip): void { @@ -97,7 +82,6 @@ public function trackOpen(string $emailLogId, ?string $ip): void /** * @param string $linkId Link ID, to track. * @param string|null $ip Client IP address. - * @return void */ public function trackLink(string $linkId, ?string $ip): void { @@ -111,7 +95,6 @@ public function trackLink(string $linkId, ?string $ip): void /** * @param string $emailLogId Email log ID, to create link for. * @param string $url URL to redirect to. - * @return string */ private function createLink(string $emailLogId, string $url): string { diff --git a/packages/email/tests/Charcoal/AbstractTestCase.php b/packages/email/tests/Charcoal/AbstractTestCase.php index 59ba12ea0..80f1772c4 100644 --- a/packages/email/tests/Charcoal/AbstractTestCase.php +++ b/packages/email/tests/Charcoal/AbstractTestCase.php @@ -1,5 +1,7 @@ obj = $this->getMockForTrait('\Charcoal\Email\EmailAwareTrait'); + $this->obj = new class { + use \Charcoal\Email\EmailAwareTrait; + }; } - public function getMethod($obj, $name) + public function getMethod($obj, $name): \ReflectionMethod { $class = new ReflectionClass($obj); - $method = $class->getMethod($name); - $method->setAccessible(true); - return $method; + return $class->getMethod($name); } - /** - * @dataProvider emailToArrayProvider - */ - public function testEmailToArray($val, $exp) + #[\PHPUnit\Framework\Attributes\DataProvider('emailToArrayProvider')] + public function testEmailToArray(string $val, array $exp): void { $method = $this->getMethod($this->obj, 'emailToArray'); $res = $method->invokeArgs($this->obj, [$val]); $this->assertEquals($res, $exp); } - public function emailToArrayProvider() + public static function emailToArrayProvider(): array { return [ ['mat@locomotive.ca', ['email'=>'mat@locomotive.ca', 'name'=>'']], diff --git a/packages/email/tests/Charcoal/Email/EmailConfigTest.php b/packages/email/tests/Charcoal/Email/EmailConfigTest.php index e4941625b..a979ef820 100644 --- a/packages/email/tests/Charcoal/Email/EmailConfigTest.php +++ b/packages/email/tests/Charcoal/Email/EmailConfigTest.php @@ -18,7 +18,7 @@ protected function setUp(): void { $this->obj = new EmailConfig(); } - public function testSetData() + public function testSetData(): void { $data = [ 'smtp' => true, @@ -43,7 +43,7 @@ public function testSetData() $this->assertEquals(true, $this->obj->defaultTrackLinksEnabled()); } - public function testSetSmtp() + public function testSetSmtp(): void { $ret = $this->obj->setSmtp(true); $this->assertSame($ret, $this->obj); @@ -53,7 +53,7 @@ public function testSetSmtp() $this->assertFalse($this->obj->smtp()); } - public function testSetSmtpHostname() + public function testSetSmtpHostname(): void { $ret = $this->obj->setSmtpHostname('foobar'); $this->assertSame($ret, $this->obj); @@ -63,7 +63,7 @@ public function testSetSmtpHostname() $this->obj->setSmtpHostname([]); } - public function testSetSmtpPort() + public function testSetSmtpPort(): void { $ret = $this->obj->setSmtpPort(42); $this->assertSame($ret, $this->obj); @@ -73,7 +73,7 @@ public function testSetSmtpPort() $this->obj->setSmtpPort('foo'); } - public function testSetSmtpAuth() + public function testSetSmtpAuth(): void { $ret = $this->obj->setSmtpAuth(true); $this->assertSame($ret, $this->obj); @@ -83,7 +83,7 @@ public function testSetSmtpAuth() $this->assertFalse($this->obj->smtpAuth()); } - public function testSetSmtpUsername() + public function testSetSmtpUsername(): void { $ret = $this->obj->setSmtpUsername('foobar'); $this->assertSame($ret, $this->obj); @@ -93,7 +93,7 @@ public function testSetSmtpUsername() $this->obj->setSmtpUsername([]); } - public function testSetSmtpPassword() + public function testSetSmtpPassword(): void { $ret = $this->obj->setSmtpPassword('foobar'); $this->assertSame($ret, $this->obj); @@ -103,7 +103,7 @@ public function testSetSmtpPassword() $this->obj->setSmtpPassword([]); } - public function testSetDefaultFrom() + public function testSetDefaultFrom(): void { $ret = $this->obj->setDefaultFrom('test@example.com'); $this->assertSame($ret, $this->obj); @@ -119,7 +119,7 @@ public function testSetDefaultFrom() $this->obj->setDefaultFrom(123); } - public function testSetDefaultReplyTo() + public function testSetDefaultReplyTo(): void { $ret = $this->obj->setDefaultReplyTo('test@example.com'); $this->assertSame($ret, $this->obj); @@ -135,21 +135,21 @@ public function testSetDefaultReplyTo() $this->obj->setDefaultReplyTo(123); } - public function testSetDefaultLogEnabled() + public function testSetDefaultLogEnabled(): void { $ret = $this->obj->setDefaultLogEnabled(true); $this->assertSame($ret, $this->obj); $this->assertEquals(true, $this->obj->defaultLogEnabled()); } - public function testSetDefaultTrackOpenEnabled() + public function testSetDefaultTrackOpenEnabled(): void { $ret = $this->obj->setDefaultTrackOpenEnabled(true); $this->assertSame($ret, $this->obj); $this->assertEquals(true, $this->obj->defaultTrackOpenEnabled()); } - public function testSetDefaultTrackLinksEnabled() + public function testSetDefaultTrackLinksEnabled(): void { $ret = $this->obj->setDefaultTrackLinksEnabled(true); $this->assertSame($ret, $this->obj); diff --git a/packages/email/tests/Charcoal/Email/EmailQueueItemTest.php b/packages/email/tests/Charcoal/Email/EmailQueueItemTest.php index 173f407ac..4cb7f42e1 100644 --- a/packages/email/tests/Charcoal/Email/EmailQueueItemTest.php +++ b/packages/email/tests/Charcoal/Email/EmailQueueItemTest.php @@ -16,8 +16,6 @@ class EmailQueueItemTest extends AbstractTestCase /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -26,20 +24,15 @@ protected function setUp(): void /** * Create tested class. - * - * @return EmailQueueItem */ - public function createObj() + public function createObj(): \Charcoal\Email\EmailQueueItem { return new EmailQueueItem([ 'logger' => new NullLogger() ]); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(QueueItemInterface::class, $this->obj); } diff --git a/packages/email/tests/Charcoal/Email/EmailQueueManagerTest.php b/packages/email/tests/Charcoal/Email/EmailQueueManagerTest.php index b0b0324dc..747a28e68 100644 --- a/packages/email/tests/Charcoal/Email/EmailQueueManagerTest.php +++ b/packages/email/tests/Charcoal/Email/EmailQueueManagerTest.php @@ -26,7 +26,7 @@ protected function setUp(): void ]); } - public function testProto() + public function testProto(): void { $ret = $this->obj->queueItemProto(); $this->assertInstanceOf(EmailQueueItem::class, $ret); diff --git a/packages/email/tests/Charcoal/Email/EmailTest.php b/packages/email/tests/Charcoal/Email/EmailTest.php index c03d6f48f..71e4ff39e 100644 --- a/packages/email/tests/Charcoal/Email/EmailTest.php +++ b/packages/email/tests/Charcoal/Email/EmailTest.php @@ -32,7 +32,7 @@ protected function setUp(): void ]); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ @@ -69,7 +69,7 @@ public function testSetData() $this->assertEquals(true, $obj->trackLinksEnabled()); } - public function testSetCampaign() + public function testSetCampaign(): void { $obj = $this->obj; $ret = $obj->setCampaign('foo'); @@ -77,7 +77,7 @@ public function testSetCampaign() $this->assertEquals('foo', $obj->campaign()); } - public function testGenerateCampaign() + public function testGenerateCampaign(): void { $obj = $this->obj; $ret = $obj->campaign(); @@ -92,7 +92,7 @@ public function testGenerateCampaign() * - Resets the "to" value before setting it, at every call. * - Throws an exception if the to argument is not a string. */ - public function testSetTo() + public function testSetTo(): void { $obj = $this->obj; @@ -123,7 +123,7 @@ public function testSetTo() $obj->setTo(false); } - public function testAddTo() + public function testAddTo(): void { $obj = $this->obj; $ret = $obj->addTo('test@example.com'); @@ -137,7 +137,7 @@ public function testAddTo() $obj->addTo(false); } - public function testSetCc() + public function testSetCc(): void { $obj = $this->obj; @@ -160,7 +160,7 @@ public function testSetCc() $obj->SetCc(false); } - public function testAddCc() + public function testAddCc(): void { $obj = $this->obj; $ret = $obj->addCc('test@example.com'); @@ -174,7 +174,7 @@ public function testAddCc() $obj->addCc(false); } - public function testSetBcc() + public function testSetBcc(): void { $obj = $this->obj; @@ -197,7 +197,7 @@ public function testSetBcc() $obj->setBcc(false); } - public function testAddBcc() + public function testAddBcc(): void { $obj = $this->obj; $ret = $obj->addBcc('test@example.com'); @@ -211,7 +211,7 @@ public function testAddBcc() $obj->addBcc(false); } - public function testSetFrom() + public function testSetFrom(): void { $obj = $this->obj; //$config = $obj->config()->setDefaultFrom('default@example.com'); @@ -231,7 +231,7 @@ public function testSetFrom() $obj->setFrom(false); } - public function testSetReplyTo() + public function testSetReplyTo(): void { $obj = $this->obj; //$config = $obj->config()->setDefaultReplyTo('default@example.com'); @@ -251,7 +251,7 @@ public function testSetReplyTo() $obj->setReplyTo(false); } - public function testSetSubject() + public function testSetSubject(): void { $obj = $this->obj; $ret = $obj->setSubject('foo'); @@ -259,7 +259,7 @@ public function testSetSubject() $this->assertEquals('foo', $obj->subject()); } - public function testSetMsgHtml() + public function testSetMsgHtml(): void { $obj = $this->obj; $ret = $obj->setMsgHtml('foo'); @@ -267,7 +267,7 @@ public function testSetMsgHtml() $this->assertEquals('foo', $obj->msgHtml()); } - public function testSetMsgTxt() + public function testSetMsgTxt(): void { $obj = $this->obj; $ret = $obj->setMsgTxt('foo'); @@ -275,7 +275,7 @@ public function testSetMsgTxt() $this->assertEquals('foo', $obj->msgTxt()); } - public function testConvertHtml() + public function testConvertHtml(): void { $obj = $this->obj; $html = file_get_contents(__DIR__.'/../../data/example.html'); @@ -287,7 +287,7 @@ public function testConvertHtml() $this->assertEquals($txt, $obj->msgTxt()); } - public function testSetAttachments() + public function testSetAttachments(): void { $obj = $this->obj; $ret = $obj->setAttachments(['foo']); @@ -295,7 +295,7 @@ public function testSetAttachments() $this->assertEquals(['foo'], $obj->attachments()); } - public function testSetLogEnabled() + public function testSetLogEnabled(): void { $obj = $this->obj; // $this->config()->setDefaultLogEnabled(false); @@ -309,7 +309,7 @@ public function testSetLogEnabled() $this->assertNotTrue($obj->logEnabled()); } - public function testSetTrackOpenEnabled() + public function testSetTrackOpenEnabled(): void { $obj = $this->obj; // $this->config()->setDefaultTrackOpenEnabled(false); @@ -323,7 +323,7 @@ public function testSetTrackOpenEnabled() $this->assertNotTrue($obj->trackOpenEnabled()); } - public function testSetTrackLinksEnabled() + public function testSetTrackLinksEnabled(): void { $obj = $this->obj; // $this->config()->setDefaultTrackLinksEnabled(false); diff --git a/packages/email/tests/Charcoal/Email/Objects/EmailLogTest.php b/packages/email/tests/Charcoal/Email/Objects/EmailLogTest.php index d1ebb3f9c..80f8445de 100644 --- a/packages/email/tests/Charcoal/Email/Objects/EmailLogTest.php +++ b/packages/email/tests/Charcoal/Email/Objects/EmailLogTest.php @@ -22,7 +22,7 @@ protected function setUp(): void ]); } - public function testSetData() + public function testSetData(): void { $ret = $this->obj->setData([ 'queue_id' => 'foo', @@ -44,7 +44,7 @@ public function testSetData() $this->assertEquals(new DateTime('2010-01-02 03:45:00'), $this->obj->sendTs()); } - public function testKey() + public function testKey(): void { $this->assertEquals('id', $this->obj->key()); } diff --git a/packages/email/tests/Charcoal/Email/Services/TrackerTest.php b/packages/email/tests/Charcoal/Email/Services/TrackerTest.php index 51844cfa1..db1e8e58b 100644 --- a/packages/email/tests/Charcoal/Email/Services/TrackerTest.php +++ b/packages/email/tests/Charcoal/Email/Services/TrackerTest.php @@ -15,15 +15,12 @@ */ class TrackerTest extends TestCase { - /** - * @var Tracker - */ - private $obj; + private \Charcoal\Email\Services\Tracker $obj; /** * @var Email */ - private $email; + private mixed $email; /** * @@ -39,7 +36,7 @@ public function setUp(): void /** * */ - public function testAddOpenTrackingImageWithBody() + public function testAddOpenTrackingImageWithBody(): void { $html = '

Hello

'; $this->email->setMsgHtml($html); @@ -52,7 +49,7 @@ public function testAddOpenTrackingImageWithBody() /** * */ - public function testAddOpenTrackingImageWithoutBody() + public function testAddOpenTrackingImageWithoutBody(): void { $html = '

Hello

'; $this->email->setMsgHtml($html); @@ -64,7 +61,7 @@ public function testAddOpenTrackingImageWithoutBody() /** * */ - public function testReplaceLinksWithTracker() + public function testReplaceLinksWithTracker(): void { $html = ''; $id = uniqid(); diff --git a/packages/email/tests/bootstrap.php b/packages/email/tests/bootstrap.php index 5f58b07cf..e60dd9ae2 100644 --- a/packages/email/tests/bootstrap.php +++ b/packages/email/tests/bootstrap.php @@ -1,10 +1,12 @@ - -> + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal/Factory - - + + ./src/Charcoal/Factory - - + + + + + + + + + - + - - - - - diff --git a/packages/factory/src/Charcoal/Factory/AbstractFactory.php b/packages/factory/src/Charcoal/Factory/AbstractFactory.php index b6337578f..1c5a55215 100644 --- a/packages/factory/src/Charcoal/Factory/AbstractFactory.php +++ b/packages/factory/src/Charcoal/Factory/AbstractFactory.php @@ -39,10 +39,7 @@ abstract class AbstractFactory implements FactoryInterface */ private $defaultClass = ''; - /** - * @var array $arguments - */ - private $arguments; + private ?array $arguments = null; /** * @var callable $callback @@ -52,9 +49,8 @@ abstract class AbstractFactory implements FactoryInterface /** * Keeps loaded instances in memory, in `[$type => $instance]` format. * Used with the `get()` method only. - * @var array $instances */ - private $instances = []; + private array $instances = []; /** * @var callable $resolver @@ -70,7 +66,7 @@ abstract class AbstractFactory implements FactoryInterface /** * @param array $data Constructor dependencies. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { if (isset($data['base_class'])) { $this->setBaseClass($data['base_class']); @@ -89,7 +85,7 @@ public function __construct(array $data = null) } if (!isset($data['resolver'])) { - $opts = isset($data['resolver_options']) ? $data['resolver_options'] : null; + $opts = ($data['resolver_options'] ?? null); $data['resolver'] = new GenericResolver($opts); } @@ -118,13 +114,13 @@ public function __construct(array $data = null) * @throws InvalidArgumentException If type argument is not a string or is not an available type. * @return mixed The instance / object */ - final public function create($type, array $args = null, callable $cb = null) + final public function create($type, ?array $args = null, ?callable $cb = null) { if (!is_string($type)) { throw new InvalidArgumentException( sprintf( '%s: Type must be a string.', - get_called_class() + static::class ) ); } @@ -133,7 +129,7 @@ final public function create($type, array $args = null, callable $cb = null) $args = $this->arguments(); } - $pool = get_called_class(); + $pool = static::class; if (isset($this->resolved[$pool][$type])) { $className = $this->resolved[$pool][$type]; } else { @@ -147,7 +143,7 @@ final public function create($type, array $args = null, callable $cb = null) throw new InvalidArgumentException( sprintf( '%1$s: Type "%2$s" is not a valid type. (Using default class "%3$s")', - get_called_class(), + static::class, $type, $defaultClass ) @@ -168,7 +164,7 @@ final public function create($type, array $args = null, callable $cb = null) throw new Exception( sprintf( '%1$s: Class "%2$s" must be an instance of "%3$s"', - get_called_class(), + static::class, $className, $baseClass ) @@ -192,7 +188,7 @@ final public function create($type, array $args = null, callable $cb = null) * @throws InvalidArgumentException If type argument is not a string. * @return mixed The instance / object */ - final public function get($type, array $args = null) + final public function get($type, ?array $args = null) { if (!is_string($type)) { throw new InvalidArgumentException( @@ -216,7 +212,7 @@ final public function get($type, array $args = null) */ public function setBaseClass($type) { - if (!is_string($type) || empty($type)) { + if (!is_string($type) || ($type === '' || $type === '0')) { throw new InvalidArgumentException( 'Class name or type must be a non-empty string.' ); @@ -259,7 +255,7 @@ public function baseClass() */ public function setDefaultClass($type) { - if (!is_string($type) || empty($type)) { + if (!is_string($type) || ($type === '' || $type === '0')) { throw new InvalidArgumentException( 'Class name or type must be a non-empty string.' ); @@ -351,8 +347,7 @@ public function resolve($type) } $resolver = $this->resolver(); - $resolved = $resolver($type); - return $resolved; + return $resolver($type); } /** @@ -381,11 +376,7 @@ public function isResolvable($type) $resolver = $this->resolver(); $resolved = $resolver($type); - if (class_exists($resolved)) { - return true; - } - - return false; + return class_exists($resolved); } @@ -411,7 +402,7 @@ protected function createClass($className, $args) if (!is_array($args)) { return new $className($args); } - if (count(array_filter(array_keys($args), 'is_string')) > 0) { + if (count(array_filter(array_keys($args), is_string(...))) > 0) { return new $className($args); } else { /** @@ -463,9 +454,8 @@ protected function addClassToMap($type, $className) /** * @param callable $resolver The class resolver instance to use. - * @return self */ - private function setResolver(callable $resolver) + private function setResolver(callable $resolver): static { $this->resolver = $resolver; return $this; @@ -475,9 +465,8 @@ private function setResolver(callable $resolver) * Add multiple types, in a an array of `type` => `className`. * * @param string[] $map The map (key=>classname) to use. - * @return self */ - private function setMap(array $map) + private function setMap(array $map): static { // Resets (overwrites) map. $this->map = []; @@ -492,9 +481,8 @@ private function setMap(array $map) * * @param mixed $obj The object to pass to callback(s). * @param callable $customCallback An optional additional custom callback. - * @return void */ - private function runCallbacks(&$obj, callable $customCallback = null) + private function runCallbacks(&$obj, ?callable $customCallback = null): void { $factoryCallback = $this->callback(); if (isset($factoryCallback)) { diff --git a/packages/factory/src/Charcoal/Factory/FactoryInterface.php b/packages/factory/src/Charcoal/Factory/FactoryInterface.php index 04e218bd4..f56fb5432 100644 --- a/packages/factory/src/Charcoal/Factory/FactoryInterface.php +++ b/packages/factory/src/Charcoal/Factory/FactoryInterface.php @@ -1,5 +1,7 @@ resolve($type); } @@ -80,7 +80,7 @@ public function __invoke($type) * @throws InvalidArgumentException If the type parameter is not a string. * @return string The resolved class name (FQN). */ - public function resolve($type) + public function resolve($type): string { if (!is_string($type)) { throw new InvalidArgumentException( @@ -91,7 +91,7 @@ public function resolve($type) // Normalize requested type with prefix / suffix, if applicable. $type = $this->prefix . $type . $this->suffix; - $capitalizeNext = function (&$i) { + $capitalizeNext = function (&$i): void { $i = ucfirst($i); }; @@ -107,8 +107,6 @@ public function resolve($type) $type = str_replace($rep, $target, $type); } - $class = '\\' . trim($type, '\\'); - - return $class; + return '\\' . trim($type, '\\'); } } diff --git a/packages/factory/src/Charcoal/Factory/MapFactory.php b/packages/factory/src/Charcoal/Factory/MapFactory.php index 601043fbe..5608570b8 100644 --- a/packages/factory/src/Charcoal/Factory/MapFactory.php +++ b/packages/factory/src/Charcoal/Factory/MapFactory.php @@ -1,5 +1,7 @@ resolverPrefix; } @@ -95,7 +80,7 @@ public function resolverPrefix() * @throws InvalidArgumentException If the suffix argument is not a string. * @return ResolverFactory Chainable */ - public function setResolverSuffix($suffix) + public function setResolverSuffix($suffix): static { if (!is_string($suffix)) { throw new InvalidArgumentException( @@ -106,10 +91,7 @@ public function setResolverSuffix($suffix) return $this; } - /** - * @return string - */ - public function resolverSuffix() + public function resolverSuffix(): string { return $this->resolverSuffix; } @@ -118,16 +100,13 @@ public function resolverSuffix() * @param array $capitals The array of letter to "calitalize-next" (uppercase next letter in the string). * @return ResolverFactory Chainable */ - public function setResolverCapitals(array $capitals) + public function setResolverCapitals(array $capitals): static { $this->resolverCapitals = $capitals; return $this; } - /** - * @return array - */ - public function resolverCapitals() + public function resolverCapitals(): array { return $this->resolverCapitals; } @@ -136,16 +115,13 @@ public function resolverCapitals() * @param array $replacements The array (key=>value) of replacements. * @return ResolverFactory Chainable */ - public function setResolverReplacements(array $replacements) + public function setResolverReplacements(array $replacements): static { $this->resolverReplacements = $replacements; return $this; } - /** - * @return array - */ - public function resolverReplacements() + public function resolverReplacements(): array { return $this->resolverReplacements; } @@ -157,7 +133,8 @@ public function resolverReplacements() * @throws InvalidArgumentException If the type parameter is not a string. * @return string The resolved class name (FQN). */ - public function resolve($type) + #[\Override] + public function resolve($type): string { if (!is_string($type)) { throw new InvalidArgumentException( @@ -165,7 +142,7 @@ public function resolve($type) ); } - $capitalize_next = function (&$i) { + $capitalize_next = function (&$i): void { $i = ucfirst($i); }; @@ -192,9 +169,9 @@ public function resolve($type) /** * @param string $type The "type" of object to resolve (the object ident). * @throws InvalidArgumentException If the type parameter is not a string. - * @return boolean */ - public function isResolvable($type) + #[\Override] + public function isResolvable($type): bool { if (!is_string($type)) { throw new InvalidArgumentException( diff --git a/packages/factory/tests/Charcoal/AbstractTestCase.php b/packages/factory/tests/Charcoal/AbstractTestCase.php index 59ba12ea0..80f1772c4 100644 --- a/packages/factory/tests/Charcoal/AbstractTestCase.php +++ b/packages/factory/tests/Charcoal/AbstractTestCase.php @@ -1,5 +1,7 @@ obj = $this->getMockForAbstractClass(AbstractFactory::class); + $this->obj = new class extends AbstractFactory {}; } - /** - * @return void - */ - public function testConstructorBaseClassAndDefaultClass() + public function testConstructorBaseClassAndDefaultClass(): void { - $obj = $this->getMockForAbstractClass(AbstractFactory::class, [[ + $obj = new class ([ 'base_class' => DateTimeInterface::class, 'default_class' => DateTime::class - ]]); + ]) extends AbstractFactory {}; $this->assertEquals(DateTimeInterface::class, $obj->baseClass()); $this->assertEquals(DateTime::class, $obj->defaultClass()); } - /** - * @return void - */ - public function testConstructorArguments() + public function testConstructorArguments(): void { - $obj = $this->getMockForAbstractClass(AbstractFactory::class, [[ + $obj = new class ([ 'arguments' => ['2018-01-01 15:30:00'] - ]]); + ]) extends AbstractFactory {}; $ret = $obj->create(DateTime::class); $this->assertEquals('2018-01-01 15:30:00', $ret->format('Y-m-d H:i:s')); } - /** - * @return void - */ - public function testConstructorMap() + public function testConstructorMap(): void { - $obj = $this->getMockForAbstractClass(AbstractFactory::class, [[ + $obj = new class ([ 'map' => [ 'foo' => DateTime::class ] - ]]); + ]) extends AbstractFactory {}; $ret = $obj->create('foo'); $this->assertInstanceOf(DateTime::class, $ret); $this->expectException(InvalidArgumentException::class); - $obj2 = $this->getMockForAbstractClass(AbstractFactory::class, [[ + new class ([ 'map' => [DateTime::class] - ]]); + ]) extends AbstractFactory {}; } - /** - * @return void - */ - public function testConstructorCallback() + public function testConstructorCallback(): void { - $obj = $this->getMockForAbstractClass(AbstractFactory::class, [[ + $obj = new class ([ 'callback' => function ($obj) { $obj->setDate(2015, 7, 8); $obj->setTime(11, 59, 59); return $obj; } - ]]); + ]) extends AbstractFactory {}; $ret = $obj->create(DateTime::class); $this->assertEquals('2015-07-08 11:59:59', $ret->format('Y-m-d H:i:s')); @@ -97,10 +82,8 @@ public function testConstructorCallback() * - Is chainable * - Properly sets the baseClass value. * - Throws an exception if the parameter is not a valid (existing) class - * - * @return void */ - public function testSetBaseClass() + public function testSetBaseClass(): void { $obj = $this->obj; $this->assertSame('', $obj->baseClass()); @@ -113,10 +96,7 @@ public function testSetBaseClass() $obj->setBaseClass('foobar'); } - /** - * @return void - */ - public function testSetBaseClassNotAString() + public function testSetBaseClassNotAString(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setBaseClass(false); @@ -132,10 +112,8 @@ public function testSetBaseClassNotAString() * - Throws an exception if the parameter is not a valid (existing) class * Also asserts that subsequent call to `create()`: * - Create an instance of the default class if an invalid parameters is sent. - * - * @return void */ - public function testSetDefaultClass() + public function testSetDefaultClass(): void { $this->assertSame('', $this->obj->defaultClass()); @@ -150,10 +128,7 @@ public function testSetDefaultClass() $this->obj->setDefaultClass('foobar'); } - /** - * @return void - */ - public function testSetDefaultClassNotAString() + public function testSetDefaultClassNotAString(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setDefaultClass(false); @@ -164,10 +139,8 @@ public function testSetDefaultClassNotAString() * Asserts that the create method: * - Creates an object of the given class. * - Returns a new object on every call. - * - * @return void */ - public function testCreate() + public function testCreate(): void { $ret = $this->obj->create(DateTime::class); $this->assertInstanceOf(DateTime::class, $ret); @@ -176,10 +149,7 @@ public function testCreate() $this->assertNotSame($ret, $ret2); } - /** - * @return void - */ - public function testCreateInvalidArgumentException() + public function testCreateInvalidArgumentException(): void { $this->expectException(InvalidArgumentException::class); $this->obj->create(false); @@ -189,10 +159,8 @@ public function testCreateInvalidArgumentException() * Asserts that the get method: * - Returns an object of the given class. * - Returns the exact same object if called multiple times. - * - * @return void */ - public function testGet() + public function testGet(): void { $ret = $this->obj->get(DateTime::class); $this->assertInstanceOf(DateTime::class, $ret); @@ -201,19 +169,13 @@ public function testGet() $this->assertSame($ret, $ret2); } - /** - * @return void - */ - public function testGetInvalidArgumentException() + public function testGetInvalidArgumentException(): void { $this->expectException(InvalidArgumentException::class); $this->obj->get(false); } - /** - * @return void - */ - public function testDefaultResolver() + public function testDefaultResolver(): void { $ret = $this->obj->create('date-time'); $this->assertInstanceOf(DateTime::class, $ret); diff --git a/packages/factory/tests/Charcoal/Factory/GenericFactoryTest.php b/packages/factory/tests/Charcoal/Factory/GenericFactoryTest.php index b7363df61..ab583f28e 100644 --- a/packages/factory/tests/Charcoal/Factory/GenericFactoryTest.php +++ b/packages/factory/tests/Charcoal/Factory/GenericFactoryTest.php @@ -15,18 +15,12 @@ class GenericFactoryTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $this->obj = new GenericFactory(); } - /** - * @return void - */ - public function testIsResolvable() + public function testIsResolvable(): void { $this->assertTrue($this->obj->isResolvable('DateTime')); $this->assertFalse($this->obj->isResolvable('foobaz')); @@ -35,36 +29,28 @@ public function testIsResolvable() $this->obj->isResolvable(false); } - /** - * @return void - */ - public function testCreate() + public function testCreate(): void { $ret = $this->obj->create('\DateTime'); $this->assertInstanceOf('\DateTime', $ret); $this->expectException(\Exception::class); - $ret2 = $this->obj->create('foobar'); + $this->obj->create('foobar'); } /** * Asserts that the AbstractFactory's `create()` method, as GenericFactory: * - Returns the default class when passing an invalid argument, if set * - Throws an exception when passing an invalid argument, if no default class is set - * - * @return void */ - public function testCreateDefaultClass() + public function testCreateDefaultClass(): void { $this->obj->setDefaultClass('\DateTime'); $ret = $this->obj->create('foobar'); $this->assertInstanceOf('\DateTime', $ret); } - /** - * @return void - */ - public function testCreateCreatesNewInstance() + public function testCreateCreatesNewInstance(): void { $ret1 = $this->obj->create('\DateTime'); $ret2 = $this->obj->create('\DateTime'); @@ -72,20 +58,14 @@ public function testCreateCreatesNewInstance() $this->assertNotSame($ret1, $ret2); } - /** - * @return void - */ - public function testCreateCallback() + public function testCreateCallback(): void { - $ret = $this->obj->create('\DateTime', null, function($obj) { + $this->obj->create('\DateTime', null, function($obj): void { $this->assertInstanceOf('\DateTime', $obj); }); } - /** - * @return void - */ - public function testGetReturnsSameInstance() + public function testGetReturnsSameInstance(): void { $ret1 = $this->obj->get('\DateTime'); $ret2 = $this->obj->get('\DateTime'); @@ -93,17 +73,14 @@ public function testGetReturnsSameInstance() $this->assertSame($ret1, $ret2); } - /** - * @return void - */ - public function testCreateBaseClass() + public function testCreateBaseClass(): void { $this->obj->setBaseClass('\DateTimeInterface'); $ret = $this->obj->create('\DateTime'); $this->assertInstanceOf('\DateTime', $ret); $this->expectException(\Exception::class); - $this->obj->setBaseClass('\Charcoal\Factory\FactoryInterface'); + $this->obj->setBaseClass(\Charcoal\Factory\FactoryInterface::class); $this->obj->create('\DateTime'); } } diff --git a/packages/factory/tests/Charcoal/Factory/ResolverFactoryTest.php b/packages/factory/tests/Charcoal/Factory/ResolverFactoryTest.php index 76b46872c..8e2a0797f 100644 --- a/packages/factory/tests/Charcoal/Factory/ResolverFactoryTest.php +++ b/packages/factory/tests/Charcoal/Factory/ResolverFactoryTest.php @@ -15,18 +15,12 @@ class ResolverFactoryTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $this->obj = new ResolverFactory(); } - /** - * @return void - */ - public function testSetResolverPrefix() + public function testSetResolverPrefix(): void { $this->assertEquals('', $this->obj->resolverPrefix()); $ret = $this->obj->setResolverPrefix('foo'); @@ -37,10 +31,7 @@ public function testSetResolverPrefix() $this->obj->setResolverPrefix(false); } - /** - * @return void - */ - public function testSetResolverSuffix() + public function testSetResolverSuffix(): void { $this->assertEquals('', $this->obj->resolverSuffix()); $ret = $this->obj->setResolverSuffix('foo'); @@ -51,10 +42,7 @@ public function testSetResolverSuffix() $this->obj->setResolverSuffix(false); } - /** - * @return void - */ - public function testSetResolverCapitals() + public function testSetResolverCapitals(): void { $ret = $this->obj->setResolverCapitals(['$']); $this->assertSame($ret, $this->obj); @@ -63,10 +51,7 @@ public function testSetResolverCapitals() $this->assertEquals('\$Abc$De', $this->obj->resolve('$abc$de')); } - /** - * @return void - */ - public function testSetResoverReplacements() + public function testSetResoverReplacements(): void { $ret = $this->obj->setResolverReplacements(['$'=>'_']); $this->assertSame($ret, $this->obj); @@ -76,13 +61,12 @@ public function testSetResoverReplacements() } /** - * @dataProvider providerResolve * * @param string $type Factory key. * @param string $classname Factory class name. - * @return void */ - public function testResolve($type, $classname) + #[\PHPUnit\Framework\Attributes\DataProvider('providerResolve')] + public function testResolve(string $type, string $classname): void { $this->assertEquals($classname, $this->obj->resolve($type)); @@ -91,19 +75,13 @@ public function testResolve($type, $classname) $this->assertEquals($classname.'Test', $this->obj->resolve($type)); } - /** - * @return void - */ - public function testResolveWithoutStringThrowsException() + public function testResolveWithoutStringThrowsException(): void { $this->expectException(\InvalidArgumentException::class); $this->obj->resolve(false); } - /** - * @return void - */ - public function testIsResolvable() + public function testIsResolvable(): void { $this->assertFalse($this->obj->isResolvable('foo')); $this->assertTrue($this->obj->isResolvable('charcoal/factory/map-factory')); @@ -112,19 +90,13 @@ public function testIsResolvable() $this->obj->isResolvable(false); } - /** - * @return void - */ - public function testCreate() + public function testCreate(): void { $ret = $this->obj->create('charcoal/factory/map-factory'); - $this->assertInstanceOf('\Charcoal\Factory\MapFactory', $ret); + $this->assertInstanceOf(\Charcoal\Factory\MapFactory::class, $ret); } - /** - * @return array - */ - public function providerResolve() + public static function providerResolve(): array { return [ ['foo', '\Foo'], diff --git a/packages/factory/tests/bootstrap.php b/packages/factory/tests/bootstrap.php new file mode 100644 index 000000000..90929e3b5 --- /dev/null +++ b/packages/factory/tests/bootstrap.php @@ -0,0 +1,14 @@ +span,.bb-tooltip td>svg{display:inline-block;width:10px;height:10px;margin-right:6px}.bb-tooltip.value{text-align:right}.bb-area{stroke-width:0;opacity:.2}.bb-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}text.bb-chart-arcs-gauge-title{dominant-baseline:middle;font-size:2.7em}.bb-chart-arcs .bb-chart-arcs-background{fill:#e0e0e0;stroke:#fff}.bb-chart-arcs .bb-chart-arcs-gauge-unit{fill:#000;font-size:16px}.bb-chart-arcs .bb-chart-arcs-gauge-max,.bb-chart-arcs .bb-chart-arcs-gauge-min{fill:#777}.bb-chart-arcs .bb-levels circle{fill:none;stroke:#848282;stroke-width:.5px}.bb-chart-arcs .bb-levels text{fill:#848282}.bb-chart-radars .bb-levels polygon{fill:none;stroke:#848282;stroke-width:.5px}.bb-chart-radars .bb-levels text{fill:#848282}.bb-chart-radars .bb-axis line{stroke:#848282;stroke-width:.5px}.bb-chart-radars .bb-axis text{font-size:1.15em;cursor:default}.bb-chart-radars .bb-shapes polygon{fill-opacity:.2;stroke-width:1px}.bb-button{position:absolute;top:10px;right:10px}.bb-button .bb-zoom-reset{font-size:11px;border:solid 1px #ccc;background-color:#fff;padding:5px;border-radius:5px;cursor:pointer} diff --git a/packages/image/build/report/_css/bootstrap.min.css b/packages/image/build/report/_css/bootstrap.min.css new file mode 100644 index 000000000..27d4921cd --- /dev/null +++ b/packages/image/build/report/_css/bootstrap.min.css @@ -0,0 +1,6 @@ +@charset "UTF-8";/*! + * Bootstrap v5.3.6 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-color:#212529;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#6ea8fe;--bs-secondary-text-emphasis:#a7acb1;--bs-success-text-emphasis:#75b798;--bs-info-text-emphasis:#6edff6;--bs-warning-text-emphasis:#ffda6a;--bs-danger-text-emphasis:#ea868f;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#161719;--bs-success-bg-subtle:#051b11;--bs-info-bg-subtle:#032830;--bs-warning-bg-subtle:#332701;--bs-danger-bg-subtle:#2c0b0e;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#084298;--bs-secondary-border-subtle:#41464b;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#087990;--bs-warning-border-subtle:#997404;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherit;--bs-link-color:#6ea8fe;--bs-link-hover-color:#8bb9fe;--bs-link-color-rgb:110,168,254;--bs-link-hover-color-rgb:139,185,254;--bs-code-color:#e685b5;--bs-highlight-color:#dee2e6;--bs-highlight-bg:#664d03;--bs-border-color:#495057;--bs-border-color-translucent:rgba(255, 255, 255, 0.15);--bs-form-valid-color:#75b798;--bs-form-valid-border-color:#75b798;--bs-form-invalid-color:#ea868f;--bs-form-invalid-border-color:#ea868f}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-decoration:underline}a:hover{--bs-link-color-rgb:var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;line-height:inherit;font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-weight:300;line-height:1.2;font-size:calc(1.625rem + 4.5vw)}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-weight:300;line-height:1.2;font-size:calc(1.575rem + 3.9vw)}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-weight:300;line-height:1.2;font-size:calc(1.525rem + 3.3vw)}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-weight:300;line-height:1.2;font-size:calc(1.475rem + 2.7vw)}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-weight:300;line-height:1.2;font-size:calc(1.425rem + 2.1vw)}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-weight:300;line-height:1.2;font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:var(--bs-border-color);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#cfe2ff;--bs-table-border-color:#a6b5cc;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:#e2e3e5;--bs-table-border-color:#b5b6b7;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#d1e7dd;--bs-table-border-color:#a7b9b1;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#cff4fc;--bs-table-border-color:#a6c3ca;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fff3cd;--bs-table-border-color:#ccc2a4;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f8d7da;--bs-table-border-color:#c6acae;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#f8f9fa;--bs-table-border-color:#c6c7c8;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#212529;--bs-table-border-color:#4d5154;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg:var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;max-width:100%;height:100%;padding:1rem .75rem;overflow:hidden;color:rgba(var(--bs-body-color-rgb),.65);text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem;padding-left:.75rem}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>textarea:focus~label::after,.form-floating>textarea:not(:placeholder-shown)~label::after{position:absolute;inset:1rem 0.375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>textarea:disabled~label::after{background-color:var(--bs-secondary-bg)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#6c757d}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select,.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select,.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(-1 * var(--bs-border-width));border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + .75rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:400;--bs-btn-line-height:1.5;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:var(--bs-border-width);--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0b5ed7;--bs-btn-hover-border-color:#0a58ca;--bs-btn-focus-shadow-rgb:49,132,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0a58ca;--bs-btn-active-border-color:#0a53be;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#0d6efd;--bs-btn-disabled-border-color:#0d6efd}.btn-secondary{--bs-btn-color:#fff;--bs-btn-bg:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#5c636a;--bs-btn-hover-border-color:#565e64;--bs-btn-focus-shadow-rgb:130,138,145;--bs-btn-active-color:#fff;--bs-btn-active-bg:#565e64;--bs-btn-active-border-color:#51585e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#6c757d;--bs-btn-disabled-border-color:#6c757d}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#157347;--bs-btn-hover-border-color:#146c43;--bs-btn-focus-shadow-rgb:60,153,110;--bs-btn-active-color:#fff;--bs-btn-active-bg:#146c43;--bs-btn-active-border-color:#13653f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#198754;--bs-btn-disabled-border-color:#198754}.btn-info{--bs-btn-color:#000;--bs-btn-bg:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#31d2f2;--bs-btn-hover-border-color:#25cff2;--bs-btn-focus-shadow-rgb:11,172,204;--bs-btn-active-color:#000;--bs-btn-active-bg:#3dd5f3;--bs-btn-active-border-color:#25cff2;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#0dcaf0;--bs-btn-disabled-border-color:#0dcaf0}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffca2c;--bs-btn-hover-border-color:#ffc720;--bs-btn-focus-shadow-rgb:217,164,6;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffcd39;--bs-btn-active-border-color:#ffc720;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#ffc107;--bs-btn-disabled-border-color:#ffc107}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#bb2d3b;--bs-btn-hover-border-color:#b02a37;--bs-btn-focus-shadow-rgb:225,83,97;--bs-btn-active-color:#fff;--bs-btn-active-bg:#b02a37;--bs-btn-active-border-color:#a52834;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#dc3545;--bs-btn-disabled-border-color:#dc3545}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d3d4d5;--bs-btn-hover-border-color:#c6c7c8;--bs-btn-focus-shadow-rgb:211,212,213;--bs-btn-active-color:#000;--bs-btn-active-bg:#c6c7c8;--bs-btn-active-border-color:#babbbc;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f8f9fa;--bs-btn-disabled-border-color:#f8f9fa}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#424649;--bs-btn-hover-border-color:#373b3e;--bs-btn-focus-shadow-rgb:66,70,73;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4d5154;--bs-btn-active-border-color:#373b3e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#212529;--bs-btn-disabled-border-color:#212529}.btn-outline-primary{--bs-btn-color:#0d6efd;--bs-btn-border-color:#0d6efd;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#0d6efd;--bs-btn-hover-border-color:#0d6efd;--bs-btn-focus-shadow-rgb:13,110,253;--bs-btn-active-color:#fff;--bs-btn-active-bg:#0d6efd;--bs-btn-active-border-color:#0d6efd;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0d6efd;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0d6efd;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#6c757d;--bs-btn-border-color:#6c757d;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#6c757d;--bs-btn-hover-border-color:#6c757d;--bs-btn-focus-shadow-rgb:108,117,125;--bs-btn-active-color:#fff;--bs-btn-active-bg:#6c757d;--bs-btn-active-border-color:#6c757d;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#6c757d;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#198754;--bs-btn-border-color:#198754;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#198754;--bs-btn-hover-border-color:#198754;--bs-btn-focus-shadow-rgb:25,135,84;--bs-btn-active-color:#fff;--bs-btn-active-bg:#198754;--bs-btn-active-border-color:#198754;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#198754;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#198754;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#0dcaf0;--bs-btn-border-color:#0dcaf0;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#0dcaf0;--bs-btn-hover-border-color:#0dcaf0;--bs-btn-focus-shadow-rgb:13,202,240;--bs-btn-active-color:#000;--bs-btn-active-bg:#0dcaf0;--bs-btn-active-border-color:#0dcaf0;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#0dcaf0;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#0dcaf0;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#ffc107;--bs-btn-border-color:#ffc107;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#ffc107;--bs-btn-hover-border-color:#ffc107;--bs-btn-focus-shadow-rgb:255,193,7;--bs-btn-active-color:#000;--bs-btn-active-bg:#ffc107;--bs-btn-active-border-color:#ffc107;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#ffc107;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#ffc107;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#dc3545;--bs-btn-border-color:#dc3545;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#dc3545;--bs-btn-hover-border-color:#dc3545;--bs-btn-focus-shadow-rgb:220,53,69;--bs-btn-active-color:#fff;--bs-btn-active-bg:#dc3545;--bs-btn-active-border-color:#dc3545;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#dc3545;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#dc3545;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#f8f9fa;--bs-btn-border-color:#f8f9fa;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f8f9fa;--bs-btn-hover-border-color:#f8f9fa;--bs-btn-focus-shadow-rgb:248,249,250;--bs-btn-active-color:#000;--bs-btn-active-bg:#f8f9fa;--bs-btn-active-border-color:#f8f9fa;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f8f9fa;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f8f9fa;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#212529;--bs-btn-border-color:#212529;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#212529;--bs-btn-hover-border-color:#212529;--bs-btn-focus-shadow-rgb:33,37,41;--bs-btn-active-color:#fff;--bs-btn-active-bg:#212529;--bs-btn-active-border-color:#212529;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#212529;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#212529;--bs-gradient:none}.btn-link{--bs-btn-font-weight:400;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#6c757d;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:49,132,253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.25rem;--bs-btn-padding-x:0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#6c757d;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius,0)}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#dee2e6;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#dee2e6;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#0d6efd;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(-1 * var(--bs-border-width))}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(-1 * var(--bs-border-width))}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:nth-child(n+3),.btn-group-vertical>:not(.btn-check)+.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-grow:1;flex-basis:0;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:0.5rem;--bs-navbar-color:rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color:rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color:rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-grow:1;flex-basis:100%;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child)>.card-header,.card-group>.card:not(:last-child)>.card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child)>.card-footer,.card-group>.card:not(:last-child)>.card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child)>.card-header,.card-group>.card:not(:first-child)>.card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child)>.card-footer,.card-group>.card:not(:first-child)>.card-img-bottom{border-bottom-left-radius:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23052c65' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}.accordion-flush>.accordion-item>.accordion-collapse,.accordion-flush>.accordion-item>.accordion-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:var(--bs-border-color);--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:var(--bs-border-color);--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#0d6efd;--bs-pagination-active-border-color:#0d6efd;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(-1 * var(--bs-border-width))}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:700;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:var(--bs-progress-height)}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#0d6efd;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#0d6efd;--bs-list-group-active-border-color:#0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:not(.active):focus,.list-group-item-action:not(.active):hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:not(.active):active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;filter:var(--bs-btn-close-filter);border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{--bs-btn-close-filter:invert(1) grayscale(100%) brightness(200%)}:root,[data-bs-theme=light]{--bs-btn-close-filter: }[data-bs-theme=dark]{--bs-btn-close-filter:invert(1) grayscale(100%) brightness(200%)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color:var(--bs-body-color);--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transform:translate(0,-50px);transition:transform .3s ease-out}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin-top:calc(-.5 * var(--bs-modal-header-padding-y));margin-right:calc(-.5 * var(--bs-modal-header-padding-x));margin-bottom:calc(-.5 * var(--bs-modal-header-padding-y));margin-left:auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-footer,.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-footer,.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-footer,.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-footer,.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-footer,.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-footer,.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:inherit;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;filter:var(--bs-carousel-control-icon-filter);border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:var(--bs-carousel-indicator-active-bg);background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:var(--bs-carousel-caption-color);text-align:center}.carousel-dark{--bs-carousel-indicator-active-bg:#000;--bs-carousel-caption-color:#000;--bs-carousel-control-icon-filter:invert(1) grayscale(100)}:root,[data-bs-theme=light]{--bs-carousel-indicator-active-bg:#fff;--bs-carousel-caption-color:#fff;--bs-carousel-control-icon-filter: }[data-bs-theme=dark]{--bs-carousel-indicator-active-bg:#000;--bs-carousel-caption-color:#000;--bs-carousel-control-icon-filter:invert(1) grayscale(100)}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-right:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y));margin-left:auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(10,88,202,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(86,94,100,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(20,108,67,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(61,213,243,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(255,205,57,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(176,42,55,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(249,250,251,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(26,30,33,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.visually-hidden *,.visually-hidden-focusable:not(:focus):not(:focus-within) *{overflow:hidden!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/packages/image/build/report/_css/custom.css b/packages/image/build/report/_css/custom.css new file mode 100644 index 000000000..e69de29bb diff --git a/packages/image/build/report/_css/octicons.css b/packages/image/build/report/_css/octicons.css new file mode 100644 index 000000000..31d97867a --- /dev/null +++ b/packages/image/build/report/_css/octicons.css @@ -0,0 +1,5 @@ +.octicon { + display: inline-block; + vertical-align: text-top; + fill: currentColor; +} diff --git a/packages/image/build/report/_css/style.css b/packages/image/build/report/_css/style.css new file mode 100644 index 000000000..4303bf844 --- /dev/null +++ b/packages/image/build/report/_css/style.css @@ -0,0 +1,274 @@ + +:root { + /* Implementing an auto-selection of dark/light theme via: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark */ + color-scheme: light dark; + + /* PHPUnit light/dark colors */ + --phpunit-breadcrumbs: light-dark(var(--bs-gray-200), var(--bs-gray-800)); + --phpunit-success-bar: light-dark(#28a745 ,#1f8135); + --phpunit-success-high: light-dark(#99cb84, #3d5c4e); + --phpunit-success-medium: light-dark(#c3e3b5,#3c6051); + --phpunit-success-low: light-dark(#dff0d8, #2d4431); + --phpunit-warning: light-dark(#fcf8e3, #3e3408); + --phpunit-warning-bar: light-dark(#ffc107 ,#c19406); + --phpunit-danger: light-dark(#f2dede, #42221e); + --phpunit-danger-bar: light-dark(#dc3545, #a62633); + + /* Bootstrap v5.3 default colors (light, dark) */ + --bs-body-bg-rgb: 255, 255, 255; + --bs-body-bg: light-dark(#fff, #212529); + --bs-body-color-rgb: light-dark(33, 37, 41, 222, 226, 230); + --bs-body-color: light-dark(#212529, #dee2e6); + --bs-border-color-translucent: light-dark(rgba(0, 0, 0, 0.175), rgba(255, 255, 255, 0.15)); + --bs-border-color: light-dark(#dee2e6, #495057); + --bs-code-color: light-dark(#d63384, #e685b5); + --bs-danger-bg-subtle: light-dark(#f8d7da, #2c0b0e); + --bs-danger-border-subtle: light-dark(#f1aeb5, #842029); + --bs-danger-text-emphasis: light-dark(#58151c, #ea868f); + --bs-dark-bg-subtle: light-dark(#ced4da, #1a1d20); + --bs-dark-border-subtle: light-dark(#adb5bd, #343a40); + --bs-dark-text-emphasis: light-dark(#495057, #dee2e6); + --bs-emphasis-color-rgb: 0, 0, 0; + --bs-emphasis-color: light-dark(#000, #fff); + --bs-form-invalid-border-color: light-dark(#dc3545, #ea868f); + --bs-form-invalid-color: light-dark(#dc3545, #ea868f); + --bs-form-valid-border-color: light-dark(#198754, #75b798); + --bs-form-valid-color: light-dark(#198754, #75b798); + --bs-highlight-bg: light-dark(#fff3cd, #664d03); + --bs-highlight-color: light-dark(#212529, #dee2e6); + --bs-info-bg-subtle: light-dark(#cff4fc, #032830); + --bs-info-border-subtle: light-dark(#9eeaf9, #087990); + --bs-info-text-emphasis: light-dark(#055160, #6edff6); + --bs-light-bg-subtle: light-dark(#fcfcfd, #343a40); + --bs-light-border-subtle: light-dark(#e9ecef, #495057); + --bs-light-text-emphasis: light-dark(#495057, #f8f9fa); + --bs-link-color-rgb: 13, 110, 253; + --bs-link-color: light-dark(#0d6efd, #6ea8fe); + --bs-link-hover-color-rgb: 10, 88, 202; + --bs-link-hover-color: light-dark(#0a58ca, #8bb9fe); + --bs-primary-bg-subtle: light-dark(#cfe2ff, #031633); + --bs-primary-border-subtle: light-dark(#9ec5fe, #084298); + --bs-primary-text-emphasis: light-dark(#052c65, #6ea8fe); + --bs-secondary-bg-rgb: 233, 236, 239; + --bs-secondary-bg-subtle: light-dark(#e2e3e5, #161719); + --bs-secondary-bg: light-dark(#e9ecef, #343a40); + --bs-secondary-border-subtle: light-dark(#c4c8cb, #41464b); + --bs-secondary-color-rgb: 33, 37, 41; + --bs-secondary-color: light-dark(rgba(33, 37, 41, 0.75), rgba(222, 226, 230, 0.75)); + --bs-secondary-text-emphasis: light-dark(#2b2f32, #a7acb1); + --bs-success-bg-subtle: light-dark(#d1e7dd, #051b11); + --bs-success-border-subtle: light-dark(#a3cfbb, #0f5132); + --bs-success-text-emphasis: light-dark(#0a3622, #75b798); + --bs-tertiary-bg-rgb: light-dark(248, 249, 250, 43, 48, 53); + --bs-tertiary-bg: light-dark(#f8f9fa, #2b3035); + --bs-tertiary-color-rgb: 33, 37, 41; + --bs-tertiary-color: light-dark(rgba(33, 37, 41, 0.5), rgba(222, 226, 230, 0.5)); + --bs-warning-bg-subtle: light-dark(#fff3cd, #332701); + --bs-warning-border-subtle: light-dark(#ffe69c, #997404); + --bs-warning-text-emphasis: light-dark(#664d03, #ffda6a); +} + +@media (prefers-color-scheme: dark) { + :root { + --bs-body-bg-rgb: 33, 37, 41; + --bs-emphasis-color-rgb: 255, 255, 255; + --bs-link-color-rgb: 110, 168, 254; + --bs-link-hover-color-rgb: 139, 185, 254; + --bs-secondary-bg-rgb: 52, 58, 64; + --bs-secondary-color-rgb: 222, 226, 230; + --bs-tertiary-color-rgb: 222, 226, 230; + } + + /* Invert icon's colors on dark mode to improve readability */ + img.octicon { filter: invert(1); } +} + +body { + font-family: sans-serif; + font-size: 1em; + font-kerning: normal; + text-rendering: optimizeLegibility; + padding-top: 10px; +} + +nav .breadcrumb { + border-radius: var(--bs-border-radius); + background-color: var(--phpunit-breadcrumbs); + padding: .75rem 1rem; +} + +.popover { + max-width: none; +} + +.popover-body { + max-height: 90vh; + overflow-y: auto; +} + +.octicon { + margin-right:.25em; + vertical-align: baseline; + width: 0.75em; +} + +.table-bordered>thead>tr>td { + border-bottom-width: 1px; +} + +.table tbody>tr>td, .table thead>tr>td { + padding-top: 3px; + padding-bottom: 3px; +} + +.table-condensed tbody>tr>td { + padding-top: 0; + padding-bottom: 0; +} + +.table .progress { + margin-bottom: inherit; +} + +.table-borderless th, .table-borderless td { + border: 0 !important; +} + +.table tbody tr.covered-by-large-tests, .table tbody tr.covered-by-large-tests td, li.covered-by-large-tests, tr.success, tr.success td, td.success, li.success, span.success { + background-color: var(--phpunit-success-low); +} + +.table tbody tr.covered-by-medium-tests, .table tbody tr.covered-by-medium-tests td, li.covered-by-medium-tests { + background-color: var(--phpunit-success-medium); +} + +.table tbody tr.covered-by-small-tests, .table tbody tr.covered-by-small-tests td, li.covered-by-small-tests { + background-color: var(--phpunit-success-high); +} + +.table tbody tr.warning, .table tbody tr.warning td, .table tbody td.warning, li.warning, span.warning { + background-color: var(--phpunit-warning); +} + +.table tbody tr.danger, .table tbody tr.danger td, .table tbody td.danger, li.danger, span.danger { + background-color: var(--phpunit-danger); +} + +.table tbody td.info { + background-color: rgb(from var(--bs-info) r g b / 0.25); +} + +td.big { + vertical-align: middle; + width: 117px; +} + +td.small { +} + +td.codeLine { + font-family: "Source Code Pro", var(--bs-font-monospace); + white-space: pre-wrap; +} + +td span.comment { + color: var(--bs-secondary-color); +} + +td span.default { + color: var(--bs-body-color); +} + +td span.html { + color: var(--bs-secondary-color); +} + +td span.keyword { + color: var(--bs-body-color); + font-weight: bold; +} + +pre span.string { + color: var(--bs-body-color); +} + +span.success, span.warning, span.danger { + margin-right: 2px; + padding-left: 10px; + padding-right: 10px; + text-align: center; +} + +#toplink { + position: fixed; + left: 5px; + bottom: 5px; + outline: 0; +} + +svg text { + font-family: var(--bs-font-sans-serif); + font-size: 11px; + color: var(--bs-gray); + fill: var(--bs-gray); +} + +.scrollbox { + height:245px; + overflow-x:scroll; + overflow-y:scroll; +} + +table + .structure-heading { + border-top: 1px solid var(--bs-gray-200); + padding-top: 0.5em; +} + +table#code td:first-of-type { + padding-left: .75em; + padding-right: .75em; +} + +table#code td:first-of-type a { + text-decoration: none; +} + +.legend { + font-weight: bold; + margin-right: 2px; + padding-left: 10px; + padding-right: 10px; + text-align: center; +} + +.covered-by-small-tests { + background-color: var(--phpunit-success-high); +} + +.covered-by-medium-tests { + background-color: var(--phpunit-success-medium); +} + +.covered-by-large-tests { + background-color: var(--phpunit-success-low); +} + +.not-covered { + background-color: var(--phpunit-danger); +} + +.not-coverable { + background-color: var(--phpunit-warning); +} + +.progress-bar.bg-success { + background-color: var(--phpunit-success-bar) !important; +} + +.progress-bar.bg-warning { + background-color: var(--phpunit-warning-bar) !important; +} + +.progress-bar.bg-danger { + background-color: var(--phpunit-danger-bar) !important; +} diff --git a/packages/image/build/report/_icons/file-code.svg b/packages/image/build/report/_icons/file-code.svg new file mode 100644 index 000000000..5b4b19953 --- /dev/null +++ b/packages/image/build/report/_icons/file-code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/image/build/report/_icons/file-directory.svg b/packages/image/build/report/_icons/file-directory.svg new file mode 100644 index 000000000..4bf1f1caa --- /dev/null +++ b/packages/image/build/report/_icons/file-directory.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/image/build/report/_js/billboard.pkgd.min.js b/packages/image/build/report/_js/billboard.pkgd.min.js new file mode 100644 index 000000000..52128a864 --- /dev/null +++ b/packages/image/build/report/_js/billboard.pkgd.min.js @@ -0,0 +1,57 @@ +/*! + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + * + * billboard.js, JavaScript chart library + * https://naver.github.io/billboard.js/ + * + * @version 3.15.1 + * + * All-in-one packaged file for ease use of 'billboard.js' with dependant d3.js modules & polyfills. + * - @types/d3-selection ^3.0.11 + * - @types/d3-transition ^3.0.9 + * - d3-axis ^3.0.0 + * - d3-brush ^3.0.0 + * - d3-drag ^3.0.0 + * - d3-dsv ^3.0.1 + * - d3-ease ^3.0.1 + * - d3-hierarchy ^3.1.2 + * - d3-interpolate ^3.0.1 + * - d3-scale ^4.0.2 + * - d3-selection ^3.0.0 + * - d3-shape ^3.2.0 + * - d3-time-format ^4.1.0 + * - d3-transition ^3.0.1 + * - d3-zoom ^3.0.0 + */(function(Xa,zn){if(typeof exports=="object"&&typeof module=="object")module.exports=zn();else if(typeof define=="function"&&define.amd)define([],zn);else{var Ha=zn();for(var x in Ha)(typeof exports=="object"?exports:Xa)[x]=Ha[x]}})(this,function(){return function(){"use strict";var Cs=[function(x,b,r){r(1),r(97),r(98),r(99),r(100),r(101),r(102),r(103),r(104),r(105),r(106),r(107),r(108),r(109),r(110),r(111),r(124),r(126),r(136),r(137),r(139),r(143),r(146),r(148),r(150),r(151),r(152),r(153),r(155),r(156),r(158),r(159),r(161),r(165),r(166),r(167),r(168),r(173),r(174),r(176),r(177),r(178),r(180),r(184),r(185),r(186),r(187),r(188),r(193),r(195),r(196),r(198),r(201),r(202),r(203),r(204),r(205),r(207),r(218),r(220),r(221),r(223),r(224),r(227),r(230),r(236),r(237),r(238),r(239),r(240),r(241),r(245),r(246),r(248),r(249),r(250),r(252),r(253),r(254),r(255),r(256),r(261),r(262),r(263),r(264),r(266),r(267),r(268),r(270),r(271),r(272),r(273),r(93),r(274),r(275),r(283),r(285),r(287),r(288),r(289),r(290),r(291),r(293),r(294),r(295),r(296),r(297),r(298),r(300),r(301),r(302),r(303),r(304),r(305),r(306),r(307),r(311),r(312),r(314),r(316),r(317),r(318),r(319),r(320),r(322),r(324),r(325),r(326),r(327),r(329),r(330),r(332),r(333),r(334),r(335),r(337),r(338),r(339),r(340),r(341),r(342),r(343),r(344),r(345),r(347),r(348),r(349),r(350),r(351),r(352),r(353),r(354),r(355),r(356),r(357),r(359),r(360),r(361),r(362),r(386),r(387),r(388),r(389),r(390),r(391),r(392),r(393),r(394),r(395),r(397),r(398),r(399),r(400),r(401),r(402),r(403),r(404),r(405),r(406),r(413),r(415),r(416),r(418),r(419),r(420),r(421),r(422),r(424),r(434),r(436),r(438),r(440),r(442),r(444),r(446),r(447),r(449),r(452),r(453),r(454),r(455),r(456),r(460),r(461),r(463),r(464),r(465),r(466),r(468),r(469),r(470),r(471),r(472),r(473),r(474),r(476),r(479),r(482),r(485),r(486),r(487),r(488),r(489),r(490),r(491),r(492),r(493),r(494),r(495),r(496),r(497),r(505),r(506),r(507),r(508),r(509),r(510),r(511),r(512),r(513),r(514),r(515),r(516),r(517),r(519),r(520),r(521),r(522),r(523),r(524),r(525),r(526),r(527),r(528),r(529),r(530),r(531),r(532),r(533),r(534),r(535),r(536),r(537),r(538),r(539),r(540),r(541),r(542),r(543),r(544),r(545),r(546),r(549),r(551),r(553),r(554),r(557),r(558),r(560),r(561),r(562),r(566),r(567),r(568),r(569),r(572),r(577),r(578),r(579),r(580),r(581),r(582),r(583),r(80)},function(x,b,r){r(2),r(90),r(92),r(93),r(96)},function(x,b,r){var u=r(3),d=r(4),h=r(8),p=r(14),y=r(36),T=r(6),$=r(26),A=r(7),E=r(38),R=r(24),I=r(46),O=r(12),C=r(18),D=r(68),M=r(11),F=r(71),z=r(73),U=r(57),j=r(75),G=r(66),B=r(5),V=r(44),Y=r(72),Z=r(10),J=r(47),q=r(77),nt=r(34),rt=r(53),_=r(54),tt=r(40),et=r(33),lt=r(78),mt=r(79),gt=r(81),xt=r(82),yt=r(51),Ut=r(83).forEach,Dt=rt("hidden"),Xt="Symbol",Qt="prototype",kt=yt.set,me=yt.getterFor(Xt),ge=Object[Qt],ae=d.Symbol,Mt=ae&&ae[Qt],Ht=d.RangeError,re=d.TypeError,se=d.QObject,ee=B.f,fe=V.f,Pe=j.f,Me=Z.f,$e=p([].push),ce=nt("symbols"),Ae=nt("op-symbols"),Te=nt("wks"),de=!se||!se[Qt]||!se[Qt].findChild,bt=function(It,Pt,Ct){var Nt=ee(ge,Pt);Nt&&delete ge[Pt],fe(It,Pt,Ct),Nt&&It!==ge&&fe(ge,Pt,Nt)},Ft=T&&A(function(){return F(fe({},"a",{get:function(){return fe(this,"a",{value:7}).a}})).a!==7})?bt:fe,Tt=function(It,Pt){var Ct=ce[It]=F(Mt);return kt(Ct,{type:Xt,tag:It,description:Pt}),T||(Ct.description=Pt),Ct},qt=function(Pt,Ct,Nt){Pt===ge&&qt(Ae,Ct,Nt),I(Pt);var Et=C(Ct);return I(Nt),E(ce,Et)?(Nt.enumerable?(E(Pt,Dt)&&Pt[Dt][Et]&&(Pt[Dt][Et]=!1),Nt=F(Nt,{enumerable:M(0,!1)})):(E(Pt,Dt)||fe(Pt,Dt,M(1,F(null))),Pt[Dt][Et]=!0),Ft(Pt,Et,Nt)):fe(Pt,Et,Nt)},te=function(Pt,Ct){I(Pt);var Nt=O(Ct),Et=z(Nt).concat(ut(Nt));return Ut(Et,function(ie){(!T||h(Yt,Nt,ie))&&qt(Pt,ie,Nt[ie])}),Pt},Zt=function(Pt,Ct){return Ct===void 0?F(Pt):te(F(Pt),Ct)},Yt=function(Pt){var Ct=C(Pt),Nt=h(Me,this,Ct);return this===ge&&E(ce,Ct)&&!E(Ae,Ct)?!1:Nt||!E(this,Ct)||!E(ce,Ct)||E(this,Dt)&&this[Dt][Ct]?Nt:!0},Ye=function(Pt,Ct){var Nt=O(Pt),Et=C(Ct);if(!(Nt===ge&&E(ce,Et)&&!E(Ae,Et))){var ie=ee(Nt,Et);return ie&&E(ce,Et)&&!(E(Nt,Dt)&&Nt[Dt][Et])&&(ie.enumerable=!0),ie}},Ze=function(Pt){var Ct=Pe(O(Pt)),Nt=[];return Ut(Ct,function(Et){!E(ce,Et)&&!E(_,Et)&&$e(Nt,Et)}),Nt},ut=function(It){var Pt=It===ge,Ct=Pe(Pt?Ae:O(It)),Nt=[];return Ut(Ct,function(Et){E(ce,Et)&&(!Pt||E(ge,Et))&&$e(Nt,ce[Et])}),Nt};$||(ae=function(){if(R(Mt,this))throw new re("Symbol is not a constructor");var Pt=!arguments.length||arguments[0]===void 0?void 0:D(arguments[0]),Ct=tt(Pt),Nt=function(Et){var ie=this===void 0?d:this;ie===ge&&h(Nt,Ae,Et),E(ie,Dt)&&E(ie[Dt],Ct)&&(ie[Dt][Ct]=!1);var we=M(1,Et);try{Ft(ie,Ct,we)}catch(Rt){if(!(Rt instanceof Ht))throw Rt;bt(ie,Ct,we)}};return T&&de&&Ft(ge,Ct,{configurable:!0,set:Nt}),Tt(Ct,Pt)},Mt=ae[Qt],J(Mt,"toString",function(){return me(this).tag}),J(ae,"withoutSetter",function(It){return Tt(tt(It),It)}),Z.f=Yt,V.f=qt,Y.f=te,B.f=Ye,U.f=j.f=Ze,G.f=ut,lt.f=function(It){return Tt(et(It),It)},T&&(q(Mt,"description",{configurable:!0,get:function(){return me(this).description}}),y||J(ge,"propertyIsEnumerable",Yt,{unsafe:!0}))),u({global:!0,constructor:!0,wrap:!0,forced:!$,sham:!$},{Symbol:ae}),Ut(z(Te),function(It){mt(It)}),u({target:Xt,stat:!0,forced:!$},{useSetter:function(){de=!0},useSimple:function(){de=!1}}),u({target:"Object",stat:!0,forced:!$,sham:!T},{create:Zt,defineProperty:qt,defineProperties:te,getOwnPropertyDescriptor:Ye}),u({target:"Object",stat:!0,forced:!$},{getOwnPropertyNames:Ze}),gt(),xt(ae,Xt),_[Dt]=!0},function(x,b,r){var u=r(4),d=r(5).f,h=r(43),p=r(47),y=r(37),T=r(55),$=r(67);x.exports=function(A,E){var R=A.target,I=A.global,O=A.stat,C,D,M,F,z,U;if(I?D=u:O?D=u[R]||y(R,{}):D=u[R]&&u[R].prototype,D)for(M in E){if(z=E[M],A.dontCallGetSet?(U=d(D,M),F=U&&U.value):F=D[M],C=$(I?M:R+(O?".":"#")+M,A.forced),!C&&F!==void 0){if(typeof z==typeof F)continue;T(z,F)}(A.sham||F&&F.sham)&&h(z,"sham",!0),p(D,M,z,A)}}},function(x){var b=function(r){return r&&r.Math===Math&&r};x.exports=b(typeof globalThis=="object"&&globalThis)||b(typeof window=="object"&&window)||b(typeof self=="object"&&self)||b(typeof global=="object"&&global)||b(typeof this=="object"&&this)||function(){return this}()||Function("return this")()},function(x,b,r){var u=r(6),d=r(8),h=r(10),p=r(11),y=r(12),T=r(18),$=r(38),A=r(41),E=Object.getOwnPropertyDescriptor;b.f=u?E:function(I,O){if(I=y(I),O=T(O),A)try{return E(I,O)}catch(C){}if($(I,O))return p(!d(h.f,I,O),I[O])}},function(x,b,r){var u=r(7);x.exports=!u(function(){return Object.defineProperty({},1,{get:function(){return 7}})[1]!==7})},function(x){x.exports=function(b){try{return!!b()}catch(r){return!0}}},function(x,b,r){var u=r(9),d=Function.prototype.call;x.exports=u?d.bind(d):function(){return d.apply(d,arguments)}},function(x,b,r){var u=r(7);x.exports=!u(function(){var d=function(){}.bind();return typeof d!="function"||d.hasOwnProperty("prototype")})},function(x,b){var r={}.propertyIsEnumerable,u=Object.getOwnPropertyDescriptor,d=u&&!r.call({1:2},1);b.f=d?function(p){var y=u(this,p);return!!y&&y.enumerable}:r},function(x){x.exports=function(b,r){return{enumerable:!(b&1),configurable:!(b&2),writable:!(b&4),value:r}}},function(x,b,r){var u=r(13),d=r(16);x.exports=function(h){return u(d(h))}},function(x,b,r){var u=r(14),d=r(7),h=r(15),p=Object,y=u("".split);x.exports=d(function(){return!p("z").propertyIsEnumerable(0)})?function(T){return h(T)==="String"?y(T,""):p(T)}:p},function(x,b,r){var u=r(9),d=Function.prototype,h=d.call,p=u&&d.bind.bind(h,h);x.exports=u?p:function(y){return function(){return h.apply(y,arguments)}}},function(x,b,r){var u=r(14),d=u({}.toString),h=u("".slice);x.exports=function(p){return h(d(p),8,-1)}},function(x,b,r){var u=r(17),d=TypeError;x.exports=function(h){if(u(h))throw new d("Can't call method on "+h);return h}},function(x){x.exports=function(b){return b==null}},function(x,b,r){var u=r(19),d=r(22);x.exports=function(h){var p=u(h,"string");return d(p)?p:p+""}},function(x,b,r){var u=r(8),d=r(20),h=r(22),p=r(29),y=r(32),T=r(33),$=TypeError,A=T("toPrimitive");x.exports=function(E,R){if(!d(E)||h(E))return E;var I=p(E,A),O;if(I){if(R===void 0&&(R="default"),O=u(I,E,R),!d(O)||h(O))return O;throw new $("Can't convert object to primitive value")}return R===void 0&&(R="number"),y(E,R)}},function(x,b,r){var u=r(21);x.exports=function(d){return typeof d=="object"?d!==null:u(d)}},function(x){var b=typeof document=="object"&&document.all;x.exports=typeof b=="undefined"&&b!==void 0?function(r){return typeof r=="function"||r===b}:function(r){return typeof r=="function"}},function(x,b,r){var u=r(23),d=r(21),h=r(24),p=r(25),y=Object;x.exports=p?function(T){return typeof T=="symbol"}:function(T){var $=u("Symbol");return d($)&&h($.prototype,y(T))}},function(x,b,r){var u=r(4),d=r(21),h=function(p){return d(p)?p:void 0};x.exports=function(p,y){return arguments.length<2?h(u[p]):u[p]&&u[p][y]}},function(x,b,r){var u=r(14);x.exports=u({}.isPrototypeOf)},function(x,b,r){var u=r(26);x.exports=u&&!Symbol.sham&&typeof Symbol.iterator=="symbol"},function(x,b,r){var u=r(27),d=r(7),h=r(4),p=h.String;x.exports=!!Object.getOwnPropertySymbols&&!d(function(){var y=Symbol("symbol detection");return!p(y)||!(Object(y)instanceof Symbol)||!Symbol.sham&&u&&u<41})},function(x,b,r){var u=r(4),d=r(28),h=u.process,p=u.Deno,y=h&&h.versions||p&&p.version,T=y&&y.v8,$,A;T&&($=T.split("."),A=$[0]>0&&$[0]<4?1:+($[0]+$[1])),!A&&d&&($=d.match(/Edge\/(\d+)/),(!$||$[1]>=74)&&($=d.match(/Chrome\/(\d+)/),$&&(A=+$[1]))),x.exports=A},function(x,b,r){var u=r(4),d=u.navigator,h=d&&d.userAgent;x.exports=h?String(h):""},function(x,b,r){var u=r(30),d=r(17);x.exports=function(h,p){var y=h[p];return d(y)?void 0:u(y)}},function(x,b,r){var u=r(21),d=r(31),h=TypeError;x.exports=function(p){if(u(p))return p;throw new h(d(p)+" is not a function")}},function(x){var b=String;x.exports=function(r){try{return b(r)}catch(u){return"Object"}}},function(x,b,r){var u=r(8),d=r(21),h=r(20),p=TypeError;x.exports=function(y,T){var $,A;if(T==="string"&&d($=y.toString)&&!h(A=u($,y))||d($=y.valueOf)&&!h(A=u($,y))||T!=="string"&&d($=y.toString)&&!h(A=u($,y)))return A;throw new p("Can't convert object to primitive value")}},function(x,b,r){var u=r(4),d=r(34),h=r(38),p=r(40),y=r(26),T=r(25),$=u.Symbol,A=d("wks"),E=T?$.for||$:$&&$.withoutSetter||p;x.exports=function(R){return h(A,R)||(A[R]=y&&h($,R)?$[R]:E("Symbol."+R)),A[R]}},function(x,b,r){var u=r(35);x.exports=function(d,h){return u[d]||(u[d]=h||{})}},function(x,b,r){var u=r(36),d=r(4),h=r(37),p="__core-js_shared__",y=x.exports=d[p]||h(p,{});(y.versions||(y.versions=[])).push({version:"3.41.0",mode:u?"pure":"global",copyright:"\xA9 2014-2025 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.41.0/LICENSE",source:"https://github.com/zloirock/core-js"})},function(x){x.exports=!1},function(x,b,r){var u=r(4),d=Object.defineProperty;x.exports=function(h,p){try{d(u,h,{value:p,configurable:!0,writable:!0})}catch(y){u[h]=p}return p}},function(x,b,r){var u=r(14),d=r(39),h=u({}.hasOwnProperty);x.exports=Object.hasOwn||function(y,T){return h(d(y),T)}},function(x,b,r){var u=r(16),d=Object;x.exports=function(h){return d(u(h))}},function(x,b,r){var u=r(14),d=0,h=Math.random(),p=u(1 .toString);x.exports=function(y){return"Symbol("+(y===void 0?"":y)+")_"+p(++d+h,36)}},function(x,b,r){var u=r(6),d=r(7),h=r(42);x.exports=!u&&!d(function(){return Object.defineProperty(h("div"),"a",{get:function(){return 7}}).a!==7})},function(x,b,r){var u=r(4),d=r(20),h=u.document,p=d(h)&&d(h.createElement);x.exports=function(y){return p?h.createElement(y):{}}},function(x,b,r){var u=r(6),d=r(44),h=r(11);x.exports=u?function(p,y,T){return d.f(p,y,h(1,T))}:function(p,y,T){return p[y]=T,p}},function(x,b,r){var u=r(6),d=r(41),h=r(45),p=r(46),y=r(18),T=TypeError,$=Object.defineProperty,A=Object.getOwnPropertyDescriptor,E="enumerable",R="configurable",I="writable";b.f=u?h?function(C,D,M){if(p(C),D=y(D),p(M),typeof C=="function"&&D==="prototype"&&"value"in M&&I in M&&!M[I]){var F=A(C,D);F&&F[I]&&(C[D]=M.value,M={configurable:R in M?M[R]:F[R],enumerable:E in M?M[E]:F[E],writable:!1})}return $(C,D,M)}:$:function(C,D,M){if(p(C),D=y(D),p(M),d)try{return $(C,D,M)}catch(F){}if("get"in M||"set"in M)throw new T("Accessors not supported");return"value"in M&&(C[D]=M.value),C}},function(x,b,r){var u=r(6),d=r(7);x.exports=u&&d(function(){return Object.defineProperty(function(){},"prototype",{value:42,writable:!1}).prototype!==42})},function(x,b,r){var u=r(20),d=String,h=TypeError;x.exports=function(p){if(u(p))return p;throw new h(d(p)+" is not an object")}},function(x,b,r){var u=r(21),d=r(44),h=r(48),p=r(37);x.exports=function(y,T,$,A){A||(A={});var E=A.enumerable,R=A.name!==void 0?A.name:T;if(u($)&&h($,R,A),A.global)E?y[T]=$:p(T,$);else{try{A.unsafe?y[T]&&(E=!0):delete y[T]}catch(I){}E?y[T]=$:d.f(y,T,{value:$,enumerable:!1,configurable:!A.nonConfigurable,writable:!A.nonWritable})}return y}},function(x,b,r){var u=r(14),d=r(7),h=r(21),p=r(38),y=r(6),T=r(49).CONFIGURABLE,$=r(50),A=r(51),E=A.enforce,R=A.get,I=String,O=Object.defineProperty,C=u("".slice),D=u("".replace),M=u([].join),F=y&&!d(function(){return O(function(){},"length",{value:8}).length!==8}),z=String(String).split("String"),U=x.exports=function(j,G,B){C(I(G),0,7)==="Symbol("&&(G="["+D(I(G),/^Symbol\(([^)]*)\).*$/,"$1")+"]"),B&&B.getter&&(G="get "+G),B&&B.setter&&(G="set "+G),(!p(j,"name")||T&&j.name!==G)&&(y?O(j,"name",{value:G,configurable:!0}):j.name=G),F&&B&&p(B,"arity")&&j.length!==B.arity&&O(j,"length",{value:B.arity});try{B&&p(B,"constructor")&&B.constructor?y&&O(j,"prototype",{writable:!1}):j.prototype&&(j.prototype=void 0)}catch(Y){}var V=E(j);return p(V,"source")||(V.source=M(z,typeof G=="string"?G:"")),j};Function.prototype.toString=U(function(){return h(this)&&R(this).source||$(this)},"toString")},function(x,b,r){var u=r(6),d=r(38),h=Function.prototype,p=u&&Object.getOwnPropertyDescriptor,y=d(h,"name"),T=y&&function(){}.name==="something",$=y&&(!u||u&&p(h,"name").configurable);x.exports={EXISTS:y,PROPER:T,CONFIGURABLE:$}},function(x,b,r){var u=r(14),d=r(21),h=r(35),p=u(Function.toString);d(h.inspectSource)||(h.inspectSource=function(y){return p(y)}),x.exports=h.inspectSource},function(x,b,r){var u=r(52),d=r(4),h=r(20),p=r(43),y=r(38),T=r(35),$=r(53),A=r(54),E="Object already initialized",R=d.TypeError,I=d.WeakMap,O,C,D,M=function(j){return D(j)?C(j):O(j,{})},F=function(j){return function(G){var B;if(!h(G)||(B=C(G)).type!==j)throw new R("Incompatible receiver, "+j+" required");return B}};if(u||T.state){var z=T.state||(T.state=new I);z.get=z.get,z.has=z.has,z.set=z.set,O=function(j,G){if(z.has(j))throw new R(E);return G.facade=j,z.set(j,G),G},C=function(j){return z.get(j)||{}},D=function(j){return z.has(j)}}else{var U=$("state");A[U]=!0,O=function(j,G){if(y(j,U))throw new R(E);return G.facade=j,p(j,U,G),G},C=function(j){return y(j,U)?j[U]:{}},D=function(j){return y(j,U)}}x.exports={set:O,get:C,has:D,enforce:M,getterFor:F}},function(x,b,r){var u=r(4),d=r(21),h=u.WeakMap;x.exports=d(h)&&/native code/.test(String(h))},function(x,b,r){var u=r(34),d=r(40),h=u("keys");x.exports=function(p){return h[p]||(h[p]=d(p))}},function(x){x.exports={}},function(x,b,r){var u=r(38),d=r(56),h=r(5),p=r(44);x.exports=function(y,T,$){for(var A=d(T),E=p.f,R=h.f,I=0;IR;)d(E,O=A[R++])&&(~p(I,O)||T(I,O));return I}},function(x,b,r){var u=r(12),d=r(60),h=r(63),p=function(y){return function(T,$,A){var E=u(T),R=h(E);if(R===0)return!y&&-1;var I=d(A,R),O;if(y&&$!==$){for(;R>I;)if(O=E[I++],O!==O)return!0}else for(;R>I;I++)if((y||I in E)&&E[I]===$)return y||I||0;return!y&&-1}};x.exports={includes:p(!0),indexOf:p(!1)}},function(x,b,r){var u=r(61),d=Math.max,h=Math.min;x.exports=function(p,y){var T=u(p);return T<0?d(T+y,0):h(T,y)}},function(x,b,r){var u=r(62);x.exports=function(d){var h=+d;return h!==h||h===0?0:u(h)}},function(x){var b=Math.ceil,r=Math.floor;x.exports=Math.trunc||function(d){var h=+d;return(h>0?r:b)(h)}},function(x,b,r){var u=r(64);x.exports=function(d){return u(d.length)}},function(x,b,r){var u=r(61),d=Math.min;x.exports=function(h){var p=u(h);return p>0?d(p,9007199254740991):0}},function(x){x.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(x,b){b.f=Object.getOwnPropertySymbols},function(x,b,r){var u=r(7),d=r(21),h=/#|\.prototype\./,p=function(E,R){var I=T[y(E)];return I===A?!0:I===$?!1:d(R)?u(R):!!R},y=p.normalize=function(E){return String(E).replace(h,".").toLowerCase()},T=p.data={},$=p.NATIVE="N",A=p.POLYFILL="P";x.exports=p},function(x,b,r){var u=r(69),d=String;x.exports=function(h){if(u(h)==="Symbol")throw new TypeError("Cannot convert a Symbol value to a string");return d(h)}},function(x,b,r){var u=r(70),d=r(21),h=r(15),p=r(33),y=p("toStringTag"),T=Object,$=h(function(){return arguments}())==="Arguments",A=function(E,R){try{return E[R]}catch(I){}};x.exports=u?h:function(E){var R,I,O;return E===void 0?"Undefined":E===null?"Null":typeof(I=A(R=T(E),y))=="string"?I:$?h(R):(O=h(R))==="Object"&&d(R.callee)?"Arguments":O}},function(x,b,r){var u=r(33),d=u("toStringTag"),h={};h[d]="z",x.exports=String(h)==="[object z]"},function(x,b,r){var u=r(46),d=r(72),h=r(65),p=r(54),y=r(74),T=r(42),$=r(53),A=">",E="<",R="prototype",I="script",O=$("IE_PROTO"),C=function(){},D=function(j){return E+I+A+j+E+"/"+I+A},M=function(j){j.write(D("")),j.close();var G=j.parentWindow.Object;return j=null,G},F=function(){var j=T("iframe"),G="java"+I+":",B;return j.style.display="none",y.appendChild(j),j.src=String(G),B=j.contentWindow.document,B.open(),B.write(D("document.F=Object")),B.close(),B.F},z,U=function(){try{z=new ActiveXObject("htmlfile")}catch(G){}U=typeof document!="undefined"?document.domain&&z?M(z):F():M(z);for(var j=h.length;j--;)delete U[R][h[j]];return U()};p[O]=!0,x.exports=Object.create||function(G,B){var V;return G!==null?(C[R]=u(G),V=new C,C[R]=null,V[O]=G):V=U(),B===void 0?V:d.f(V,B)}},function(x,b,r){var u=r(6),d=r(45),h=r(44),p=r(46),y=r(12),T=r(73);b.f=u&&!d?Object.defineProperties:function(A,E){p(A);for(var R=y(E),I=T(E),O=I.length,C=0,D;O>C;)h.f(A,D=I[C++],R[D]);return A}},function(x,b,r){var u=r(58),d=r(65);x.exports=Object.keys||function(p){return u(p,d)}},function(x,b,r){var u=r(23);x.exports=u("document","documentElement")},function(x,b,r){var u=r(15),d=r(12),h=r(57).f,p=r(76),y=typeof window=="object"&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],T=function($){try{return h($)}catch(A){return p(y)}};x.exports.f=function(A){return y&&u(A)==="Window"?T(A):h(d(A))}},function(x,b,r){var u=r(14);x.exports=u([].slice)},function(x,b,r){var u=r(48),d=r(44);x.exports=function(h,p,y){return y.get&&u(y.get,p,{getter:!0}),y.set&&u(y.set,p,{setter:!0}),d.f(h,p,y)}},function(x,b,r){var u=r(33);b.f=u},function(x,b,r){var u=r(80),d=r(38),h=r(78),p=r(44).f;x.exports=function(y){var T=u.Symbol||(u.Symbol={});d(T,y)||p(T,y,{value:h.f(y)})}},function(x,b,r){var u=r(4);x.exports=u},function(x,b,r){var u=r(8),d=r(23),h=r(33),p=r(47);x.exports=function(){var y=d("Symbol"),T=y&&y.prototype,$=T&&T.valueOf,A=h("toPrimitive");T&&!T[A]&&p(T,A,function(E){return u($,this)},{arity:1})}},function(x,b,r){var u=r(44).f,d=r(38),h=r(33),p=h("toStringTag");x.exports=function(y,T,$){y&&!$&&(y=y.prototype),y&&!d(y,p)&&u(y,p,{configurable:!0,value:T})}},function(x,b,r){var u=r(84),d=r(14),h=r(13),p=r(39),y=r(63),T=r(86),$=d([].push),A=function(E){var R=E===1,I=E===2,O=E===3,C=E===4,D=E===6,M=E===7,F=E===5||D;return function(z,U,j,G){for(var B=p(z),V=h(B),Y=y(V),Z=u(U,j),J=0,q=G||T,nt=R?q(z,Y):I||M?q(z,0):void 0,rt,_;Y>J;J++)if((F||J in V)&&(rt=V[J],_=Z(rt,J,B),E))if(R)nt[J]=_;else if(_)switch(E){case 3:return!0;case 5:return rt;case 6:return J;case 2:$(nt,rt)}else switch(E){case 4:return!1;case 7:$(nt,rt)}return D?-1:O||C?C:nt}};x.exports={forEach:A(0),map:A(1),filter:A(2),some:A(3),every:A(4),find:A(5),findIndex:A(6),filterReject:A(7)}},function(x,b,r){var u=r(85),d=r(30),h=r(9),p=u(u.bind);x.exports=function(y,T){return d(y),T===void 0?y:h?p(y,T):function(){return y.apply(T,arguments)}}},function(x,b,r){var u=r(15),d=r(14);x.exports=function(h){if(u(h)==="Function")return d(h)}},function(x,b,r){var u=r(87);x.exports=function(d,h){return new(u(d))(h===0?0:h)}},function(x,b,r){var u=r(88),d=r(89),h=r(20),p=r(33),y=p("species"),T=Array;x.exports=function($){var A;return u($)&&(A=$.constructor,d(A)&&(A===T||u(A.prototype))?A=void 0:h(A)&&(A=A[y],A===null&&(A=void 0))),A===void 0?T:A}},function(x,b,r){var u=r(15);x.exports=Array.isArray||function(h){return u(h)==="Array"}},function(x,b,r){var u=r(14),d=r(7),h=r(21),p=r(69),y=r(23),T=r(50),$=function(){},A=y("Reflect","construct"),E=/^\s*(?:class|function)\b/,R=u(E.exec),I=!E.test($),O=function(M){if(!h(M))return!1;try{return A($,[],M),!0}catch(F){return!1}},C=function(M){if(!h(M))return!1;switch(p(M)){case"AsyncFunction":case"GeneratorFunction":case"AsyncGeneratorFunction":return!1}try{return I||!!R(E,T(M))}catch(F){return!0}};C.sham=!0,x.exports=!A||d(function(){var D;return O(O.call)||!O(Object)||!O(function(){D=!0})||D})?C:O},function(x,b,r){var u=r(3),d=r(23),h=r(38),p=r(68),y=r(34),T=r(91),$=y("string-to-symbol-registry"),A=y("symbol-to-string-registry");u({target:"Symbol",stat:!0,forced:!T},{for:function(E){var R=p(E);if(h($,R))return $[R];var I=d("Symbol")(R);return $[R]=I,A[I]=R,I}})},function(x,b,r){var u=r(26);x.exports=u&&!!Symbol.for&&!!Symbol.keyFor},function(x,b,r){var u=r(3),d=r(38),h=r(22),p=r(31),y=r(34),T=r(91),$=y("symbol-to-string-registry");u({target:"Symbol",stat:!0,forced:!T},{keyFor:function(E){if(!h(E))throw new TypeError(p(E)+" is not a symbol");if(d($,E))return $[E]}})},function(x,b,r){var u=r(3),d=r(23),h=r(94),p=r(8),y=r(14),T=r(7),$=r(21),A=r(22),E=r(76),R=r(95),I=r(26),O=String,C=d("JSON","stringify"),D=y(/./.exec),M=y("".charAt),F=y("".charCodeAt),z=y("".replace),U=y(1 .toString),j=/[\uD800-\uDFFF]/g,G=/^[\uD800-\uDBFF]$/,B=/^[\uDC00-\uDFFF]$/,V=!I||T(function(){var q=d("Symbol")("stringify detection");return C([q])!=="[null]"||C({a:q})!=="{}"||C(Object(q))!=="{}"}),Y=T(function(){return C("\uDF06\uD834")!=='"\\udf06\\ud834"'||C("\uDEAD")!=='"\\udead"'}),Z=function(q,nt){var rt=E(arguments),_=R(nt);if(!(!$(_)&&(q===void 0||A(q))))return rt[1]=function(tt,et){if($(_)&&(et=p(_,this,O(tt),et)),!A(et))return et},h(C,null,rt)},J=function(q,nt,rt){var _=M(rt,nt-1),tt=M(rt,nt+1);return D(G,q)&&!D(B,tt)||D(B,q)&&!D(G,_)?"\\u"+U(F(q,0),16):q};C&&u({target:"JSON",stat:!0,arity:3,forced:V||Y},{stringify:function(nt,rt,_){var tt=E(arguments),et=h(V?Z:C,null,tt);return Y&&typeof et=="string"?z(et,j,J):et}})},function(x,b,r){var u=r(9),d=Function.prototype,h=d.apply,p=d.call;x.exports=typeof Reflect=="object"&&Reflect.apply||(u?p.bind(h):function(){return p.apply(h,arguments)})},function(x,b,r){var u=r(14),d=r(88),h=r(21),p=r(15),y=r(68),T=u([].push);x.exports=function($){if(h($))return $;if(d($)){for(var A=$.length,E=[],R=0;Rj&&R(_,arguments[j]),_});if(J.prototype=Y,B!=="Error"?y?y(J,Z):T(J,Z,{name:!0}):O&&U in V&&($(J,V,U),$(J,V,"prepareStackTrace")),T(J,V),!C)try{Y.name!==B&&h(Y,"name",B),Y.constructor=J}catch(q){}return J}}},function(x,b,r){var u=r(114),d=r(20),h=r(16),p=r(115);x.exports=Object.setPrototypeOf||("__proto__"in{}?function(){var y=!1,T={},$;try{$=u(Object.prototype,"__proto__","set"),$(T,[]),y=T instanceof Array}catch(A){}return function(E,R){return h(E),p(R),d(E)&&(y?$(E,R):E.__proto__=R),E}}():void 0)},function(x,b,r){var u=r(14),d=r(30);x.exports=function(h,p,y){try{return u(d(Object.getOwnPropertyDescriptor(h,p)[y]))}catch(T){}}},function(x,b,r){var u=r(116),d=String,h=TypeError;x.exports=function(p){if(u(p))return p;throw new h("Can't set "+d(p)+" as a prototype")}},function(x,b,r){var u=r(20);x.exports=function(d){return u(d)||d===null}},function(x,b,r){var u=r(44).f;x.exports=function(d,h,p){p in d||u(d,p,{configurable:!0,get:function(){return h[p]},set:function(y){h[p]=y}})}},function(x,b,r){var u=r(21),d=r(20),h=r(113);x.exports=function(p,y,T){var $,A;return h&&u($=y.constructor)&&$!==T&&d(A=$.prototype)&&A!==T.prototype&&h(p,A),p}},function(x,b,r){var u=r(68);x.exports=function(d,h){return d===void 0?arguments.length<2?"":h:u(d)}},function(x,b,r){var u=r(20),d=r(43);x.exports=function(h,p){u(p)&&"cause"in p&&d(h,"cause",p.cause)}},function(x,b,r){var u=r(43),d=r(122),h=r(123),p=Error.captureStackTrace;x.exports=function(y,T,$,A){h&&(p?p(y,T):u(y,"stack",d($,A)))}},function(x,b,r){var u=r(14),d=Error,h=u("".replace),p=function($){return String(new d($).stack)}("zxcasd"),y=/\n\s*at [^:]*:[^\n]*/,T=y.test(p);x.exports=function($,A){if(T&&typeof $=="string"&&!d.prepareStackTrace)for(;A--;)$=h($,y,"");return $}},function(x,b,r){var u=r(7),d=r(11);x.exports=!u(function(){var h=new Error("a");return"stack"in h?(Object.defineProperty(h,"stack",d(1,7)),h.stack!==7):!0})},function(x,b,r){var u=r(47),d=r(125),h=Error.prototype;h.toString!==d&&u(h,"toString",d)},function(x,b,r){var u=r(6),d=r(7),h=r(46),p=r(119),y=Error.prototype.toString,T=d(function(){if(u){var $=Object.create(Object.defineProperty({},"name",{get:function(){return this===$}}));if(y.call($)!=="true")return!0}return y.call({message:1,name:2})!=="2: 1"||y.call({})!=="Error"});x.exports=T?function(){var A=h(this),E=p(A.name,"Error"),R=p(A.message);return E?R?E+": "+R:E:R}:y},function(x,b,r){r(127)},function(x,b,r){var u=r(3),d=r(24),h=r(128),p=r(113),y=r(55),T=r(71),$=r(43),A=r(11),E=r(120),R=r(121),I=r(130),O=r(119),C=r(33),D=C("toStringTag"),M=Error,F=[].push,z=function(G,B){var V=d(U,this),Y;p?Y=p(new M,V?h(this):U):(Y=V?this:T(U),$(Y,D,"Error")),B!==void 0&&$(Y,"message",O(B)),R(Y,z,Y.stack,1),arguments.length>2&&E(Y,arguments[2]);var Z=[];return I(G,F,{that:Z}),$(Y,"errors",Z),Y};p?p(z,M):y(z,M,{name:!0});var U=z.prototype=T(M.prototype,{constructor:A(1,z),message:A(1,""),name:A(1,"AggregateError")});u({global:!0,constructor:!0,arity:2},{AggregateError:z})},function(x,b,r){var u=r(38),d=r(21),h=r(39),p=r(53),y=r(129),T=p("IE_PROTO"),$=Object,A=$.prototype;x.exports=y?$.getPrototypeOf:function(E){var R=h(E);if(u(R,T))return R[T];var I=R.constructor;return d(I)&&R instanceof I?I.prototype:R instanceof $?A:null}},function(x,b,r){var u=r(7);x.exports=!u(function(){function d(){}return d.prototype.constructor=null,Object.getPrototypeOf(new d)!==d.prototype})},function(x,b,r){var u=r(84),d=r(8),h=r(46),p=r(31),y=r(131),T=r(63),$=r(24),A=r(133),E=r(134),R=r(135),I=TypeError,O=function(D,M){this.stopped=D,this.result=M},C=O.prototype;x.exports=function(D,M,F){var z=F&&F.that,U=!!(F&&F.AS_ENTRIES),j=!!(F&&F.IS_RECORD),G=!!(F&&F.IS_ITERATOR),B=!!(F&&F.INTERRUPTED),V=u(M,z),Y,Z,J,q,nt,rt,_,tt=function(lt){return Y&&R(Y,"normal",lt),new O(!0,lt)},et=function(lt){return U?(h(lt),B?V(lt[0],lt[1],tt):V(lt[0],lt[1])):B?V(lt,tt):V(lt)};if(j)Y=D.iterator;else if(G)Y=D;else{if(Z=E(D),!Z)throw new I(p(D)+" is not iterable");if(y(Z)){for(J=0,q=T(D);q>J;J++)if(nt=et(D[J]),nt&&$(C,nt))return nt;return new O(!1)}Y=A(D,Z)}for(rt=j?D.next:Y.next;!(_=d(rt,Y)).done;){try{nt=et(_.value)}catch(lt){R(Y,"throw",lt)}if(typeof nt=="object"&&nt&&$(C,nt))return nt}return new O(!1)}},function(x,b,r){var u=r(33),d=r(132),h=u("iterator"),p=Array.prototype;x.exports=function(y){return y!==void 0&&(d.Array===y||p[h]===y)}},function(x){x.exports={}},function(x,b,r){var u=r(8),d=r(30),h=r(46),p=r(31),y=r(134),T=TypeError;x.exports=function($,A){var E=arguments.length<2?y($):A;if(d(E))return h(u(E,$));throw new T(p($)+" is not iterable")}},function(x,b,r){var u=r(69),d=r(29),h=r(17),p=r(132),y=r(33),T=y("iterator");x.exports=function($){if(!h($))return d($,T)||d($,"@@iterator")||p[u($)]}},function(x,b,r){var u=r(8),d=r(46),h=r(29);x.exports=function(p,y,T){var $,A;d(p);try{if($=h(p,"return"),!$){if(y==="throw")throw T;return T}$=u($,p)}catch(E){A=!0,$=E}if(y==="throw")throw T;if(A)throw $;return d($),T}},function(x,b,r){var u=r(3),d=r(23),h=r(94),p=r(7),y=r(112),T="AggregateError",$=d(T),A=!p(function(){return $([1]).errors[0]!==1})&&p(function(){return $([1],T,{cause:7}).cause!==7});u({global:!0,constructor:!0,arity:2,forced:A},{AggregateError:y(T,function(E){return function(I,O){return h(E,this,arguments)}},A,!0)})},function(x,b,r){var u=r(3),d=r(39),h=r(63),p=r(61),y=r(138);u({target:"Array",proto:!0},{at:function($){var A=d(this),E=h(A),R=p($),I=R>=0?R:E+R;return I<0||I>=E?void 0:A[I]}}),y("at")},function(x,b,r){var u=r(33),d=r(71),h=r(44).f,p=u("unscopables"),y=Array.prototype;y[p]===void 0&&h(y,p,{configurable:!0,value:d(null)}),x.exports=function(T){y[p][T]=!0}},function(x,b,r){var u=r(3),d=r(7),h=r(88),p=r(20),y=r(39),T=r(63),$=r(140),A=r(141),E=r(86),R=r(142),I=r(33),O=r(27),C=I("isConcatSpreadable"),D=O>=51||!d(function(){var z=[];return z[C]=!1,z.concat()[0]!==z}),M=function(z){if(!p(z))return!1;var U=z[C];return U!==void 0?!!U:h(z)},F=!D||!R("concat");u({target:"Array",proto:!0,arity:1,forced:F},{concat:function(U){var j=y(this),G=E(j,0),B=0,V,Y,Z,J,q;for(V=-1,Z=arguments.length;Vr)throw b("Maximum allowed index exceeded");return u}},function(x,b,r){var u=r(6),d=r(44),h=r(11);x.exports=function(p,y,T){u?d.f(p,y,h(0,T)):p[y]=T}},function(x,b,r){var u=r(7),d=r(33),h=r(27),p=d("species");x.exports=function(y){return h>=51||!u(function(){var T=[],$=T.constructor={};return $[p]=function(){return{foo:1}},T[y](Boolean).foo!==1})}},function(x,b,r){var u=r(3),d=r(144),h=r(138);u({target:"Array",proto:!0},{copyWithin:d}),h("copyWithin")},function(x,b,r){var u=r(39),d=r(60),h=r(63),p=r(145),y=Math.min;x.exports=[].copyWithin||function($,A){var E=u(this),R=h(E),I=d($,R),O=d(A,R),C=arguments.length>2?arguments[2]:void 0,D=y((C===void 0?R:d(C,R))-O,R-I),M=1;for(O0;)O in E?E[I]=E[O]:p(E,I),I+=M,O+=M;return E}},function(x,b,r){var u=r(31),d=TypeError;x.exports=function(h,p){if(!delete h[p])throw new d("Cannot delete property "+u(p)+" of "+u(h))}},function(x,b,r){var u=r(3),d=r(83).every,h=r(147),p=h("every");u({target:"Array",proto:!0,forced:!p},{every:function(T){return d(this,T,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(7);x.exports=function(d,h){var p=[][d];return!!p&&u(function(){p.call(null,h||function(){return 1},1)})}},function(x,b,r){var u=r(3),d=r(149),h=r(138);u({target:"Array",proto:!0},{fill:d}),h("fill")},function(x,b,r){var u=r(39),d=r(60),h=r(63);x.exports=function(y){for(var T=u(this),$=h(T),A=arguments.length,E=d(A>1?arguments[1]:void 0,$),R=A>2?arguments[2]:void 0,I=R===void 0?$:d(R,$);I>E;)T[E++]=y;return T}},function(x,b,r){var u=r(3),d=r(83).filter,h=r(142),p=h("filter");u({target:"Array",proto:!0,forced:!p},{filter:function(T){return d(this,T,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(83).find,h=r(138),p="find",y=!0;p in[]&&Array(1)[p](function(){y=!1}),u({target:"Array",proto:!0,forced:y},{find:function($){return d(this,$,arguments.length>1?arguments[1]:void 0)}}),h(p)},function(x,b,r){var u=r(3),d=r(83).findIndex,h=r(138),p="findIndex",y=!0;p in[]&&Array(1)[p](function(){y=!1}),u({target:"Array",proto:!0,forced:y},{findIndex:function($){return d(this,$,arguments.length>1?arguments[1]:void 0)}}),h(p)},function(x,b,r){var u=r(3),d=r(154).findLast,h=r(138);u({target:"Array",proto:!0},{findLast:function(y){return d(this,y,arguments.length>1?arguments[1]:void 0)}}),h("findLast")},function(x,b,r){var u=r(84),d=r(13),h=r(39),p=r(63),y=function(T){var $=T===1;return function(A,E,R){for(var I=h(A),O=d(I),C=p(O),D=u(E,R),M,F;C-- >0;)if(M=O[C],F=D(M,C,I),F)switch(T){case 0:return M;case 1:return C}return $?-1:void 0}};x.exports={findLast:y(0),findLastIndex:y(1)}},function(x,b,r){var u=r(3),d=r(154).findLastIndex,h=r(138);u({target:"Array",proto:!0},{findLastIndex:function(y){return d(this,y,arguments.length>1?arguments[1]:void 0)}}),h("findLastIndex")},function(x,b,r){var u=r(3),d=r(157),h=r(39),p=r(63),y=r(61),T=r(86);u({target:"Array",proto:!0},{flat:function(){var A=arguments.length?arguments[0]:void 0,E=h(this),R=p(E),I=T(E,0);return I.length=d(I,E,E,R,0,A===void 0?1:y(A)),I}})},function(x,b,r){var u=r(88),d=r(63),h=r(140),p=r(84),y=function(T,$,A,E,R,I,O,C){for(var D=R,M=0,F=O?p(O,C):!1,z,U;M0&&u(z)?(U=d(z),D=y(T,$,z,U,D,I-1)-1):(h(D+1),T[D]=z),D++),M++;return D};x.exports=y},function(x,b,r){var u=r(3),d=r(157),h=r(30),p=r(39),y=r(63),T=r(86);u({target:"Array",proto:!0},{flatMap:function(A){var E=p(this),R=y(E),I;return h(A),I=T(E,0),I.length=d(I,E,E,R,0,1,A,arguments.length>1?arguments[1]:void 0),I}})},function(x,b,r){var u=r(3),d=r(160);u({target:"Array",proto:!0,forced:[].forEach!==d},{forEach:d})},function(x,b,r){var u=r(83).forEach,d=r(147),h=d("forEach");x.exports=h?[].forEach:function(y){return u(this,y,arguments.length>1?arguments[1]:void 0)}},function(x,b,r){var u=r(3),d=r(162),h=r(164),p=!h(function(y){Array.from(y)});u({target:"Array",stat:!0,forced:p},{from:d})},function(x,b,r){var u=r(84),d=r(8),h=r(39),p=r(163),y=r(131),T=r(89),$=r(63),A=r(141),E=r(133),R=r(134),I=Array;x.exports=function(C){var D=h(C),M=T(this),F=arguments.length,z=F>1?arguments[1]:void 0,U=z!==void 0;U&&(z=u(z,F>2?arguments[2]:void 0));var j=R(D),G=0,B,V,Y,Z,J,q;if(j&&!(this===I&&y(j)))for(V=M?new this:[],Z=E(D,j),J=Z.next;!(Y=d(J,Z)).done;G++)q=U?p(Z,z,[Y.value,G],!0):Y.value,A(V,G,q);else for(B=$(D),V=M?new this(B):I(B);B>G;G++)q=U?z(D[G],G):D[G],A(V,G,q);return V.length=G,V}},function(x,b,r){var u=r(46),d=r(135);x.exports=function(h,p,y,T){try{return T?p(u(y)[0],y[1]):p(y)}catch($){d(h,"throw",$)}}},function(x,b,r){var u=r(33),d=u("iterator"),h=!1;try{var p=0,y={next:function(){return{done:!!p++}},return:function(){h=!0}};y[d]=function(){return this},Array.from(y,function(){throw 2})}catch(T){}x.exports=function(T,$){try{if(!$&&!h)return!1}catch(R){return!1}var A=!1;try{var E={};E[d]=function(){return{next:function(){return{done:A=!0}}}},T(E)}catch(R){}return A}},function(x,b,r){var u=r(3),d=r(59).includes,h=r(7),p=r(138),y=h(function(){return!Array(1).includes()});u({target:"Array",proto:!0,forced:y},{includes:function($){return d(this,$,arguments.length>1?arguments[1]:void 0)}}),p("includes")},function(x,b,r){var u=r(3),d=r(85),h=r(59).indexOf,p=r(147),y=d([].indexOf),T=!!y&&1/y([1],1,-0)<0,$=T||!p("indexOf");u({target:"Array",proto:!0,forced:$},{indexOf:function(E){var R=arguments.length>1?arguments[1]:void 0;return T?y(this,E,R)||0:h(this,E,R)}})},function(x,b,r){var u=r(3),d=r(88);u({target:"Array",stat:!0},{isArray:d})},function(x,b,r){var u=r(12),d=r(138),h=r(132),p=r(51),y=r(44).f,T=r(169),$=r(172),A=r(36),E=r(6),R="Array Iterator",I=p.set,O=p.getterFor(R);x.exports=T(Array,"Array",function(D,M){I(this,{type:R,target:u(D),index:0,kind:M})},function(){var D=O(this),M=D.target,F=D.index++;if(!M||F>=M.length)return D.target=null,$(void 0,!0);switch(D.kind){case"keys":return $(F,!1);case"values":return $(M[F],!1)}return $([F,M[F]],!1)},"values");var C=h.Arguments=h.Array;if(d("keys"),d("values"),d("entries"),!A&&E&&C.name!=="values")try{y(C,"name",{value:"values"})}catch(D){}},function(x,b,r){var u=r(3),d=r(8),h=r(36),p=r(49),y=r(21),T=r(170),$=r(128),A=r(113),E=r(82),R=r(43),I=r(47),O=r(33),C=r(132),D=r(171),M=p.PROPER,F=p.CONFIGURABLE,z=D.IteratorPrototype,U=D.BUGGY_SAFARI_ITERATORS,j=O("iterator"),G="keys",B="values",V="entries",Y=function(){return this};x.exports=function(Z,J,q,nt,rt,_,tt){T(q,J,nt);var et=function(kt){if(kt===rt&&yt)return yt;if(!U&&kt&&kt in gt)return gt[kt];switch(kt){case G:return function(){return new q(this,kt)};case B:return function(){return new q(this,kt)};case V:return function(){return new q(this,kt)}}return function(){return new q(this)}},lt=J+" Iterator",mt=!1,gt=Z.prototype,xt=gt[j]||gt["@@iterator"]||rt&>[rt],yt=!U&&xt||et(rt),Ut=J==="Array"&>.entries||xt,Dt,Xt,Qt;if(Ut&&(Dt=$(Ut.call(new Z)),Dt!==Object.prototype&&Dt.next&&(!h&&$(Dt)!==z&&(A?A(Dt,z):y(Dt[j])||I(Dt,j,Y)),E(Dt,lt,!0,!0),h&&(C[lt]=Y))),M&&rt===B&&xt&&xt.name!==B&&(!h&&F?R(gt,"name",B):(mt=!0,yt=function(){return d(xt,this)})),rt)if(Xt={values:et(B),keys:_?yt:et(G),entries:et(V)},tt)for(Qt in Xt)(U||mt||!(Qt in gt))&&I(gt,Qt,Xt[Qt]);else u({target:J,proto:!0,forced:U||mt},Xt);return(!h||tt)&>[j]!==yt&&I(gt,j,yt,{name:rt}),C[J]=yt,Xt}},function(x,b,r){var u=r(171).IteratorPrototype,d=r(71),h=r(11),p=r(82),y=r(132),T=function(){return this};x.exports=function($,A,E,R){var I=A+" Iterator";return $.prototype=d(u,{next:h(+!R,E)}),p($,I,!1,!0),y[I]=T,$}},function(x,b,r){var u=r(7),d=r(21),h=r(20),p=r(71),y=r(128),T=r(47),$=r(33),A=r(36),E=$("iterator"),R=!1,I,O,C;[].keys&&(C=[].keys(),"next"in C?(O=y(y(C)),O!==Object.prototype&&(I=O)):R=!0);var D=!h(I)||u(function(){var M={};return I[E].call(M)!==M});D?I={}:A&&(I=p(I)),d(I[E])||T(I,E,function(){return this}),x.exports={IteratorPrototype:I,BUGGY_SAFARI_ITERATORS:R}},function(x){x.exports=function(b,r){return{value:b,done:r}}},function(x,b,r){var u=r(3),d=r(14),h=r(13),p=r(12),y=r(147),T=d([].join),$=h!==Object,A=$||!y("join",",");u({target:"Array",proto:!0,forced:A},{join:function(R){return T(p(this),R===void 0?",":R)}})},function(x,b,r){var u=r(3),d=r(175);u({target:"Array",proto:!0,forced:d!==[].lastIndexOf},{lastIndexOf:d})},function(x,b,r){var u=r(94),d=r(12),h=r(61),p=r(63),y=r(147),T=Math.min,$=[].lastIndexOf,A=!!$&&1/[1].lastIndexOf(1,-0)<0,E=y("lastIndexOf"),R=A||!E;x.exports=R?function(O){if(A)return u($,this,arguments)||0;var C=d(this),D=p(C);if(D===0)return-1;var M=D-1;for(arguments.length>1&&(M=T(M,h(arguments[1]))),M<0&&(M=D+M);M>=0;M--)if(M in C&&C[M]===O)return M||0;return-1}:$},function(x,b,r){var u=r(3),d=r(83).map,h=r(142),p=h("map");u({target:"Array",proto:!0,forced:!p},{map:function(T){return d(this,T,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(7),h=r(89),p=r(141),y=Array,T=d(function(){function $(){}return!(y.of.call($)instanceof $)});u({target:"Array",stat:!0,forced:T},{of:function(){for(var A=0,E=arguments.length,R=new(h(this)?this:y)(E);E>A;)p(R,A,arguments[A++]);return R.length=E,R}})},function(x,b,r){var u=r(3),d=r(39),h=r(63),p=r(179),y=r(140),T=r(7),$=T(function(){return[].push.call({length:4294967296},1)!==4294967297}),A=function(){try{Object.defineProperty([],"length",{writable:!1}).push()}catch(R){return R instanceof TypeError}},E=$||!A();u({target:"Array",proto:!0,arity:1,forced:E},{push:function(I){var O=d(this),C=h(O),D=arguments.length;y(C+D);for(var M=0;M79&&p<83,$=T||!h("reduce");u({target:"Array",proto:!0,forced:$},{reduce:function(E){var R=arguments.length;return d(this,E,R,R>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(30),d=r(39),h=r(13),p=r(63),y=TypeError,T="Reduce of empty array with no initial value",$=function(A){return function(E,R,I,O){var C=d(E),D=h(C),M=p(C);if(u(R),M===0&&I<2)throw new y(T);var F=A?M-1:0,z=A?-1:1;if(I<2)for(;;){if(F in D){O=D[F],F+=z;break}if(F+=z,A?F<0:M<=F)throw new y(T)}for(;A?F>=0:M>F;F+=z)F in D&&(O=R(O,D[F],F,C));return O}};x.exports={left:$(!1),right:$(!0)}},function(x,b,r){var u=r(183);x.exports=u==="NODE"},function(x,b,r){var u=r(4),d=r(28),h=r(15),p=function(y){return d.slice(0,y.length)===y};x.exports=function(){return p("Bun/")?"BUN":p("Cloudflare-Workers")?"CLOUDFLARE":p("Deno/")?"DENO":p("Node.js/")?"NODE":u.Bun&&typeof Bun.version=="string"?"BUN":u.Deno&&typeof Deno.version=="object"?"DENO":h(u.process)==="process"?"NODE":u.window&&u.document?"BROWSER":"REST"}()},function(x,b,r){var u=r(3),d=r(181).right,h=r(147),p=r(27),y=r(182),T=!y&&p>79&&p<83,$=T||!h("reduceRight");u({target:"Array",proto:!0,forced:$},{reduceRight:function(E){return d(this,E,arguments.length,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(14),h=r(88),p=d([].reverse),y=[1,2];u({target:"Array",proto:!0,forced:String(y)===String(y.reverse())},{reverse:function(){return h(this)&&(this.length=this.length),p(this)}})},function(x,b,r){var u=r(3),d=r(88),h=r(89),p=r(20),y=r(60),T=r(63),$=r(12),A=r(141),E=r(33),R=r(142),I=r(76),O=R("slice"),C=E("species"),D=Array,M=Math.max;u({target:"Array",proto:!0,forced:!O},{slice:function(z,U){var j=$(this),G=T(j),B=y(z,G),V=y(U===void 0?G:U,G),Y,Z,J;if(d(j)&&(Y=j.constructor,h(Y)&&(Y===D||d(Y.prototype))?Y=void 0:p(Y)&&(Y=Y[C],Y===null&&(Y=void 0)),Y===D||Y===void 0))return I(j,B,V);for(Z=new(Y===void 0?D:Y)(M(V-B,0)),J=0;B1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(14),h=r(30),p=r(39),y=r(63),T=r(145),$=r(68),A=r(7),E=r(189),R=r(147),I=r(190),O=r(191),C=r(27),D=r(192),M=[],F=d(M.sort),z=d(M.push),U=A(function(){M.sort(void 0)}),j=A(function(){M.sort(null)}),G=R("sort"),B=!A(function(){if(C)return C<70;if(!(I&&I>3)){if(O)return!0;if(D)return D<603;var Z="",J,q,nt,rt;for(J=65;J<76;J++){switch(q=String.fromCharCode(J),J){case 66:case 69:case 70:case 72:nt=3;break;case 68:case 71:nt=4;break;default:nt=2}for(rt=0;rt<47;rt++)M.push({k:q+rt,v:nt})}for(M.sort(function(_,tt){return tt.v-_.v}),rt=0;rt$(q)?1:-1}};u({target:"Array",proto:!0,forced:V},{sort:function(J){J!==void 0&&h(J);var q=p(this);if(B)return J===void 0?F(q):F(q,J);var nt=[],rt=y(q),_,tt;for(tt=0;tt0;)p[E]=p[--E];E!==$++&&(p[E]=A)}else for(var R=d(T/2),I=h(u(p,0,R),y),O=h(u(p,R),y),C=I.length,D=O.length,M=0,F=0;Mj-Y+V;J--)R(U,J-1)}else if(V>Y)for(J=j-Y;J>G;J--)q=J+Y-1,nt=J+V-1,q in U?U[nt]=U[q]:R(U,nt);for(J=0;J2?p:u(h),$=new d(T);T>y;)$[y]=h[y++];return $}},function(x,b,r){var u=r(4);x.exports=function(d,h){var p=u[d],y=p&&p.prototype;return y&&y[h]}},function(x,b,r){var u=r(3),d=r(138),h=r(140),p=r(63),y=r(60),T=r(12),$=r(61),A=Array,E=Math.max,R=Math.min;u({target:"Array",proto:!0},{toSpliced:function(O,C){var D=T(this),M=p(D),F=y(O,M),z=arguments.length,U=0,j,G,B,V;for(z===0?j=G=0:z===1?(j=0,G=M-F):(j=z-2,G=R(E($(C),0),M-F)),B=h(M+j-G),V=A(B);U=A||R<0)throw new h("Incorrect index");for(var I=new y(A),O=0;O>8&255]},se=function(bt){return[bt&255,bt>>8&255,bt>>16&255,bt>>24&255]},ee=function(bt){return bt[3]<<24|bt[2]<<16|bt[1]<<8|bt[0]},fe=function(bt){return ae(D(bt),23,4)},Pe=function(bt){return ae(bt,52,8)},Me=function(bt,Ft,Tt){$(bt[rt],Ft,{configurable:!0,get:function(){return Tt(this)[Ft]}})},$e=function(bt,Ft,Tt,qt){var te=lt(bt),Zt=C(Tt),Yt=!!qt;if(Zt+Ft>te.byteLength)throw new kt(tt);var Ye=te.bytes,Ze=Zt+te.byteOffset,ut=j(Ye,Ze,Ze+Ft);return Yt?ut:ge(ut)},ce=function(bt,Ft,Tt,qt,te,Zt){var Yt=lt(bt),Ye=C(Tt),Ze=qt(+te),ut=!!Zt;if(Ye+Ft>Yt.byteLength)throw new kt(tt);for(var It=Yt.bytes,Pt=Ye+Yt.byteOffset,Ct=0;CtZt)throw new kt("Wrong offset");if(qt=qt===void 0?Zt-Yt:O(qt),Yt+qt>Zt)throw new kt(_);mt(this,{type:nt,buffer:Ft,byteLength:qt,byteOffset:Yt,bytes:te.bytes}),h||(this.buffer=Ft,this.byteLength=qt,this.byteOffset=Yt)},Dt=Ut[rt],h&&(Me(xt,"byteLength",et),Me(Ut,"buffer",lt),Me(Ut,"byteLength",lt),Me(Ut,"byteOffset",lt)),A(Dt,{getInt8:function(Ft){return $e(this,1,Ft)[0]<<24>>24},getUint8:function(Ft){return $e(this,1,Ft)[0]},getInt16:function(Ft){var Tt=$e(this,2,Ft,arguments.length>1?arguments[1]:!1);return(Tt[1]<<8|Tt[0])<<16>>16},getUint16:function(Ft){var Tt=$e(this,2,Ft,arguments.length>1?arguments[1]:!1);return Tt[1]<<8|Tt[0]},getInt32:function(Ft){return ee($e(this,4,Ft,arguments.length>1?arguments[1]:!1))},getUint32:function(Ft){return ee($e(this,4,Ft,arguments.length>1?arguments[1]:!1))>>>0},getFloat32:function(Ft){return Mt($e(this,4,Ft,arguments.length>1?arguments[1]:!1),23)},getFloat64:function(Ft){return Mt($e(this,8,Ft,arguments.length>1?arguments[1]:!1),52)},setInt8:function(Ft,Tt){ce(this,1,Ft,Ht,Tt)},setUint8:function(Ft,Tt){ce(this,1,Ft,Ht,Tt)},setInt16:function(Ft,Tt){ce(this,2,Ft,re,Tt,arguments.length>2?arguments[2]:!1)},setUint16:function(Ft,Tt){ce(this,2,Ft,re,Tt,arguments.length>2?arguments[2]:!1)},setInt32:function(Ft,Tt){ce(this,4,Ft,se,Tt,arguments.length>2?arguments[2]:!1)},setUint32:function(Ft,Tt){ce(this,4,Ft,se,Tt,arguments.length>2?arguments[2]:!1)},setFloat32:function(Ft,Tt){ce(this,4,Ft,fe,Tt,arguments.length>2?arguments[2]:!1)},setFloat64:function(Ft,Tt){ce(this,8,Ft,Pe,Tt,arguments.length>2?arguments[2]:!1)}});else{var Ae=Z&>.name!==q;!E(function(){gt(1)})||!E(function(){new gt(-1)})||E(function(){return new gt,new gt(1.5),new gt(NaN),gt.length!==1||Ae&&!J})?(xt=function(Ft){return R(this,yt),G(new gt(C(Ft)),this,xt)},xt[rt]=yt,yt.constructor=xt,B(xt,gt)):Ae&&J&&T(gt,"name",q),z&&F(Dt)!==Xt&&z(Dt,Xt);var Te=new Ut(new xt(2)),de=d(Dt.setInt8);Te.setInt8(0,2147483648),Te.setInt8(1,2147483649),(Te.getInt8(0)||!Te.getInt8(1))&&A(Dt,{setInt8:function(Ft,Tt){de(this,Ft,Tt<<24>>24)},setUint8:function(Ft,Tt){de(this,Ft,Tt<<24>>24)}},{unsafe:!0})}V(xt,q),V(Ut,nt),x.exports={ArrayBuffer:xt,DataView:Ut}},function(x){x.exports=typeof ArrayBuffer!="undefined"&&typeof DataView!="undefined"},function(x,b,r){var u=r(47);x.exports=function(d,h,p){for(var y in h)u(d,y,h[y],p);return d}},function(x,b,r){var u=r(24),d=TypeError;x.exports=function(h,p){if(u(p,h))return h;throw new d("Incorrect invocation")}},function(x,b,r){var u=r(61),d=r(64),h=RangeError;x.exports=function(p){if(p===void 0)return 0;var y=u(p),T=d(y);if(y!==T)throw new h("Wrong length or index");return T}},function(x,b,r){var u=r(214),d=11920928955078125e-23,h=34028234663852886e22,p=11754943508222875e-54;x.exports=Math.fround||function(T){return u(T,d,h,p)}},function(x,b,r){var u=r(215),d=r(216),h=Math.abs,p=2220446049250313e-31;x.exports=function(y,T,$,A){var E=+y,R=h(E),I=u(E);if(R$||C!==C?I*(1/0):I*C}},function(x){x.exports=Math.sign||function(r){var u=+r;return u===0||u!==u?u:u<0?-1:1}},function(x){var b=2220446049250313e-31,r=1/b;x.exports=function(u){return u+r-r}},function(x){var b=Array,r=Math.abs,u=Math.pow,d=Math.floor,h=Math.log,p=Math.LN2,y=function($,A,E){var R=b(E),I=E*8-A-1,O=(1<>1,D=A===23?u(2,-24)-u(2,-77):0,M=$<0||$===0&&1/$<0?1:0,F=0,z,U,j;for($=r($),$!==$||$===1/0?(U=$!==$?1:0,z=O):(z=d(h($)/p),j=u(2,-z),$*j<1&&(z--,j*=2),z+C>=1?$+=D/j:$+=D*u(2,1-C),$*j>=2&&(z++,j/=2),z+C>=O?(U=0,z=O):z+C>=1?(U=($*j-1)*u(2,A),z+=C):(U=$*u(2,C-1)*u(2,A),z=0));A>=8;)R[F++]=U&255,U/=256,A-=8;for(z=z<0;)R[F++]=z&255,z/=256,I-=8;return R[F-1]|=M*128,R},T=function($,A){var E=$.length,R=E*8-A-1,I=(1<>1,C=R-7,D=E-1,M=$[D--],F=M&127,z;for(M>>=7;C>0;)F=F*256+$[D--],C-=8;for(z=F&(1<<-C)-1,F>>=-C,C+=A;C>0;)z=z*256+$[D--],C-=8;if(F===0)F=1-O;else{if(F===I)return z?NaN:M?-1/0:1/0;z+=u(2,A),F-=O}return(M?-1:1)*z*u(2,F-A)};x.exports={pack:y,unpack:T}},function(x,b,r){var u=r(3),d=r(219),h=d.NATIVE_ARRAY_BUFFER_VIEWS;u({target:"ArrayBuffer",stat:!0,forced:!h},{isView:d.isView})},function(x,b,r){var u=r(209),d=r(6),h=r(4),p=r(21),y=r(20),T=r(38),$=r(69),A=r(31),E=r(43),R=r(47),I=r(77),O=r(24),C=r(128),D=r(113),M=r(33),F=r(40),z=r(51),U=z.enforce,j=z.get,G=h.Int8Array,B=G&&G.prototype,V=h.Uint8ClampedArray,Y=V&&V.prototype,Z=G&&C(G),J=B&&C(B),q=Object.prototype,nt=h.TypeError,rt=M("toStringTag"),_=F("TYPED_ARRAY_TAG"),tt="TypedArrayConstructor",et=u&&!!D&&$(h.opera)!=="Opera",lt=!1,mt,gt,xt,yt={Int8Array:1,Uint8Array:1,Uint8ClampedArray:1,Int16Array:2,Uint16Array:2,Int32Array:4,Uint32Array:4,Float32Array:4,Float64Array:8},Ut={BigInt64Array:8,BigUint64Array:8},Dt=function(Ht){if(!y(Ht))return!1;var re=$(Ht);return re==="DataView"||T(yt,re)||T(Ut,re)},Xt=function(Mt){var Ht=C(Mt);if(y(Ht)){var re=j(Ht);return re&&T(re,tt)?re[tt]:Xt(Ht)}},Qt=function(Mt){if(!y(Mt))return!1;var Ht=$(Mt);return T(yt,Ht)||T(Ut,Ht)},kt=function(Mt){if(Qt(Mt))return Mt;throw new nt("Target is not a typed array")},me=function(Mt){if(p(Mt)&&(!D||O(Z,Mt)))return Mt;throw new nt(A(Mt)+" is not a typed array constructor")},ge=function(Mt,Ht,re,se){if(d){if(re)for(var ee in yt){var fe=h[ee];if(fe&&T(fe.prototype,Mt))try{delete fe.prototype[Mt]}catch(Pe){try{fe.prototype[Mt]=Ht}catch(Me){}}}(!J[Mt]||re)&&R(J,Mt,re?Ht:et&&B[Mt]||Ht,se)}},ae=function(Mt,Ht,re){var se,ee;if(d){if(D){if(re){for(se in yt)if(ee=h[se],ee&&T(ee,Mt))try{delete ee[Mt]}catch(fe){}}if(!Z[Mt]||re)try{return R(Z,Mt,re?Ht:et&&Z[Mt]||Ht)}catch(fe){}else return}for(se in yt)ee=h[se],ee&&(!ee[Mt]||re)&&R(ee,Mt,Ht)}};for(mt in yt)gt=h[mt],xt=gt&>.prototype,xt?U(xt)[tt]=gt:et=!1;for(mt in Ut)gt=h[mt],xt=gt&>.prototype,xt&&(U(xt)[tt]=gt);if((!et||!p(Z)||Z===Function.prototype)&&(Z=function(){throw new nt("Incorrect invocation")},et))for(mt in yt)h[mt]&&D(h[mt],Z);if((!et||!J||J===q)&&(J=Z.prototype,et))for(mt in yt)h[mt]&&D(h[mt].prototype,J);if(et&&C(Y)!==J&&D(Y,J),d&&!T(J,rt)){lt=!0,I(J,rt,{configurable:!0,get:function(){return y(this)?this[_]:void 0}});for(mt in yt)h[mt]&&E(h[mt],_,mt)}x.exports={NATIVE_ARRAY_BUFFER_VIEWS:et,TYPED_ARRAY_TAG:lt&&_,aTypedArray:kt,aTypedArrayConstructor:me,exportTypedArrayMethod:ge,exportTypedArrayStaticMethod:ae,getTypedArrayConstructor:Xt,isView:Dt,isTypedArray:Qt,TypedArray:Z,TypedArrayPrototype:J}},function(x,b,r){var u=r(3),d=r(85),h=r(7),p=r(208),y=r(46),T=r(60),$=r(64),A=p.ArrayBuffer,E=p.DataView,R=E.prototype,I=d(A.prototype.slice),O=d(R.getUint8),C=d(R.setUint8),D=h(function(){return!new A(2).slice(1,void 0).byteLength});u({target:"ArrayBuffer",proto:!0,unsafe:!0,forced:D},{slice:function(F,z){if(I&&z===void 0)return I(y(this),F);for(var U=y(this).byteLength,j=T(F,U),G=T(z===void 0?U:z,U),B=new A($(G-j)),V=new E(this),Y=new E(B),Z=0;j>>15,O=R>>>10&p,C=R&y;return O===p?C===0?I===0?1/0:-1/0:NaN:O===0?C*(I===0?T:-T):h(2,O-15)*(I===0?1+C*$:-1-C*$)},E=d(DataView.prototype.getUint16);u({target:"DataView",proto:!0},{getFloat16:function(I){var O=E(this,I,arguments.length>1?arguments[1]:!1);return A(O)}})},function(x,b,r){var u=r(3),d=r(14),h=r(225),p=r(212),y=r(226),T=r(216),$=Math.pow,A=65520,E=61005353927612305e-21,R=16777216,I=1024,O=function(D){if(D!==D)return 32256;if(D===0)return(1/D===-1/0)<<15;var M=D<0;if(M&&(D=-D),D>=A)return M<<15|31744;if(D2?arguments[2]:!1)}})},function(x,b,r){var u=r(69),d=TypeError;x.exports=function(h){if(u(h)==="DataView")return h;throw new d("Argument is not a DataView")}},function(x){var b=Math.log,r=Math.LN2;x.exports=Math.log2||function(d){return b(d)/r}},function(x,b,r){var u=r(6),d=r(77),h=r(228),p=ArrayBuffer.prototype;u&&!("detached"in p)&&d(p,"detached",{configurable:!0,get:function(){return h(this)}})},function(x,b,r){var u=r(4),d=r(209),h=r(229),p=u.DataView;x.exports=function(y){if(!d||h(y)!==0)return!1;try{return new p(y),!1}catch(T){return!0}}},function(x,b,r){var u=r(4),d=r(114),h=r(15),p=u.ArrayBuffer,y=u.TypeError;x.exports=p&&d(p.prototype,"byteLength","get")||function(T){if(h(T)!=="ArrayBuffer")throw new y("ArrayBuffer expected");return T.byteLength}},function(x,b,r){var u=r(3),d=r(231);d&&u({target:"ArrayBuffer",proto:!0},{transfer:function(){return d(this,arguments.length?arguments[0]:void 0,!0)}})},function(x,b,r){var u=r(4),d=r(14),h=r(114),p=r(212),y=r(232),T=r(229),$=r(233),A=r(235),E=u.structuredClone,R=u.ArrayBuffer,I=u.DataView,O=Math.min,C=R.prototype,D=I.prototype,M=d(C.slice),F=h(C,"resizable","get"),z=h(C,"maxByteLength","get"),U=d(D.getInt8),j=d(D.setInt8);x.exports=(A||$)&&function(G,B,V){var Y=T(G),Z=B===void 0?Y:p(B),J=!F||!F(G),q;if(y(G),A&&(G=E(G,{transfer:[G]}),Y===Z&&(V||J)))return G;if(Y>=Z&&(!V||J))q=M(G,0,Z);else{var nt=V&&!J&&z?{maxByteLength:z(G)}:void 0;q=new R(Z,nt);for(var rt=new I(G),_=new I(q),tt=O(Z,Y),et=0;et92||p==="NODE"&&h>94||p==="BROWSER"&&h>97)return!1;var T=new ArrayBuffer(8),$=y(T,{transfer:[T]});return T.byteLength!==0||$.byteLength!==8})},function(x,b,r){var u=r(3),d=r(231);d&&u({target:"ArrayBuffer",proto:!0},{transferToFixedLength:function(){return d(this,arguments.length?arguments[0]:void 0,!1)}})},function(x,b,r){var u=r(3),d=r(14),h=r(7),p=h(function(){return new Date(16e11).getYear()!==120}),y=d(Date.prototype.getFullYear);u({target:"Date",proto:!0,forced:p},{getYear:function(){return y(this)-1900}})},function(x,b,r){var u=r(3),d=r(14),h=Date,p=d(h.prototype.getTime);u({target:"Date",stat:!0},{now:function(){return p(new h)}})},function(x,b,r){var u=r(3),d=r(14),h=r(61),p=Date.prototype,y=d(p.getTime),T=d(p.setFullYear);u({target:"Date",proto:!0},{setYear:function(A){y(this);var E=h(A),R=E>=0&&E<=99?E+1900:E;return T(this,R)}})},function(x,b,r){var u=r(3);u({target:"Date",proto:!0},{toGMTString:Date.prototype.toUTCString})},function(x,b,r){var u=r(3),d=r(242);u({target:"Date",proto:!0,forced:Date.prototype.toISOString!==d},{toISOString:d})},function(x,b,r){var u=r(14),d=r(7),h=r(243).start,p=RangeError,y=isFinite,T=Math.abs,$=Date.prototype,A=$.toISOString,E=u($.getTime),R=u($.getUTCDate),I=u($.getUTCFullYear),O=u($.getUTCHours),C=u($.getUTCMilliseconds),D=u($.getUTCMinutes),M=u($.getUTCMonth),F=u($.getUTCSeconds);x.exports=d(function(){return A.call(new Date(-50000000000001))!=="0385-07-25T07:06:39.999Z"})||!d(function(){A.call(new Date(NaN))})?function(){if(!y(E(this)))throw new p("Invalid time value");var U=this,j=I(U),G=C(U),B=j<0?"-":j>9999?"+":"";return B+h(T(j),B?6:4,0)+"-"+h(M(U)+1,2,0)+"-"+h(R(U),2,0)+"T"+h(O(U),2,0)+":"+h(D(U),2,0)+":"+h(F(U),2,0)+"."+h(G,3,0)+"Z"}:A},function(x,b,r){var u=r(14),d=r(64),h=r(68),p=r(244),y=r(16),T=u(p),$=u("".slice),A=Math.ceil,E=function(R){return function(I,O,C){var D=h(y(I)),M=d(O),F=D.length,z=C===void 0?" ":h(C),U,j;return M<=F||z===""?D:(U=M-F,j=T(z,A(U/z.length)),j.length>U&&(j=$(j,0,U)),R?D+j:j+D)}};x.exports={start:E(!1),end:E(!0)}},function(x,b,r){var u=r(61),d=r(68),h=r(16),p=RangeError;x.exports=function(T){var $=d(h(this)),A="",E=u(T);if(E<0||E===1/0)throw new p("Wrong number of repetitions");for(;E>0;(E>>>=1)&&($+=$))E&1&&(A+=$);return A}},function(x,b,r){var u=r(3),d=r(7),h=r(39),p=r(19),y=d(function(){return new Date(NaN).toJSON()!==null||Date.prototype.toJSON.call({toISOString:function(){return 1}})!==1});u({target:"Date",proto:!0,arity:1,forced:y},{toJSON:function($){var A=h(this),E=p(A,"number");return typeof E=="number"&&!isFinite(E)?null:A.toISOString()}})},function(x,b,r){var u=r(38),d=r(47),h=r(247),p=r(33),y=p("toPrimitive"),T=Date.prototype;u(T,y)||d(T,y,h)},function(x,b,r){var u=r(46),d=r(32),h=TypeError;x.exports=function(p){if(u(this),p==="string"||p==="default")p="string";else if(p!=="number")throw new h("Incorrect hint");return d(this,p)}},function(x,b,r){var u=r(14),d=r(47),h=Date.prototype,p="Invalid Date",y="toString",T=u(h[y]),$=u(h.getTime);String(new Date(NaN))!==p&&d(h,y,function(){var E=$(this);return E===E?T(this):p})},function(x,b,r){var u=r(3),d=r(14),h=r(68),p=d("".charAt),y=d("".charCodeAt),T=d(/./.exec),$=d(1 .toString),A=d("".toUpperCase),E=/[\w*+\-./@]/,R=function(I,O){for(var C=$(I,16);C.length1?arguments[1]:void 0),_;_=_?_.next:nt.first;)for(rt(_.value,_.key,this);_&&_.removed;)_=_.previous},has:function(q){return!!Z(this,q)}}),h(B,U?{get:function(q){var nt=Z(this,q);return nt&&nt.value},set:function(q,nt){return Y(this,q===0?0:q,nt)}}:{add:function(q){return Y(this,q=q===0?0:q,q)}}),I&&d(B,"size",{configurable:!0,get:function(){return V(this).size}}),G},setStrong:function(F,z,U){var j=z+" Iterator",G=M(z),B=M(j);A(F,z,function(V,Y){D(this,{type:j,target:V,state:G(V),kind:Y,last:null})},function(){for(var V=B(this),Y=V.kind,Z=V.last;Z&&Z.removed;)Z=Z.previous;return!V.target||!(V.last=Z=Z?Z.next:V.state.first)?(V.target=null,E(void 0,!0)):E(Y==="keys"?Z.key:Y==="values"?Z.value:[Z.key,Z.value],!1)},U?"entries":"values",!U,!0),R(z)}}},function(x,b,r){var u=r(3),d=r(14),h=r(30),p=r(16),y=r(130),T=r(284),$=r(36),A=r(7),E=T.Map,R=T.has,I=T.get,O=T.set,C=d([].push),D=$||A(function(){return E.groupBy("ab",function(M){return M}).get("a").length!==1});u({target:"Map",stat:!0,forced:$||D},{groupBy:function(F,z){p(F),h(z);var U=new E,j=0;return y(F,function(G){var B=z(G,j++);R(U,B)?C(I(U,B),G):O(U,B,[G])}),U}})},function(x,b,r){var u=r(14),d=Map.prototype;x.exports={Map,set:u(d.set),get:u(d.get),has:u(d.has),remove:u(d.delete),proto:d}},function(x,b,r){var u=r(3),d=r(286),h=Math.acosh,p=Math.log,y=Math.sqrt,T=Math.LN2,$=!h||Math.floor(h(Number.MAX_VALUE))!==710||h(1/0)!==1/0;u({target:"Math",stat:!0,forced:$},{acosh:function(E){var R=+E;return R<1?NaN:R>9490626562425156e-8?p(R)+T:d(R-1+y(R-1)*y(R+1))}})},function(x){var b=Math.log;x.exports=Math.log1p||function(u){var d=+u;return d>-1e-8&&d<1e-8?d-d*d/2:b(1+d)}},function(x,b,r){var u=r(3),d=Math.asinh,h=Math.log,p=Math.sqrt;function y($){var A=+$;return!isFinite(A)||A===0?A:A<0?-y(-A):h(A+p(A*A+1))}var T=!(d&&1/d(0)>0);u({target:"Math",stat:!0,forced:T},{asinh:y})},function(x,b,r){var u=r(3),d=Math.atanh,h=Math.log,p=!(d&&1/d(-0)<0);u({target:"Math",stat:!0,forced:p},{atanh:function(T){var $=+T;return $===0?$:h((1+$)/(1-$))/2}})},function(x,b,r){var u=r(3),d=r(215),h=Math.abs,p=Math.pow;u({target:"Math",stat:!0},{cbrt:function(T){var $=+T;return d($)*p(h($),.3333333333333333)}})},function(x,b,r){var u=r(3),d=Math.floor,h=Math.log,p=Math.LOG2E;u({target:"Math",stat:!0},{clz32:function(T){var $=T>>>0;return $?31-d(h($+.5)*p):32}})},function(x,b,r){var u=r(3),d=r(292),h=Math.cosh,p=Math.abs,y=Math.E,T=!h||h(710)===1/0;u({target:"Math",stat:!0,forced:T},{cosh:function(A){var E=d(p(A)-1)+1;return(E+1/(E*y*y))*(y/2)}})},function(x){var b=Math.expm1,r=Math.exp;x.exports=!b||b(10)>22025.465794806718||b(10)<22025.465794806718||b(-2e-17)!==-2e-17?function(d){var h=+d;return h===0?h:h>-1e-6&&h<1e-6?h+h*h/2:r(h)-1}:b},function(x,b,r){var u=r(3),d=r(292);u({target:"Math",stat:!0,forced:d!==Math.expm1},{expm1:d})},function(x,b,r){var u=r(3),d=r(213);u({target:"Math",stat:!0},{fround:d})},function(x,b,r){var u=r(3),d=r(214),h=.0009765625,p=65504,y=6103515625e-14;u({target:"Math",stat:!0},{f16round:function($){return d($,h,p,y)}})},function(x,b,r){var u=r(3),d=Math.hypot,h=Math.abs,p=Math.sqrt,y=!!d&&d(1/0,NaN)!==1/0;u({target:"Math",stat:!0,arity:2,forced:y},{hypot:function($,A){for(var E=0,R=0,I=arguments.length,O=0,C,D;R0?(D=C/O,E+=D*D):E+=C;return O===1/0?1/0:O*p(E)}})},function(x,b,r){var u=r(3),d=r(7),h=Math.imul,p=d(function(){return h(4294967295,5)!==-5||h.length!==2});u({target:"Math",stat:!0,forced:p},{imul:function(T,$){var A=65535,E=+T,R=+$,I=A&E,O=A&R;return 0|I*O+((A&E>>>16)*O+I*(A&R>>>16)<<16>>>0)}})},function(x,b,r){var u=r(3),d=r(299);u({target:"Math",stat:!0},{log10:d})},function(x){var b=Math.log,r=Math.LOG10E;x.exports=Math.log10||function(d){return b(d)*r}},function(x,b,r){var u=r(3),d=r(286);u({target:"Math",stat:!0},{log1p:d})},function(x,b,r){var u=r(3),d=r(226);u({target:"Math",stat:!0},{log2:d})},function(x,b,r){var u=r(3),d=r(215);u({target:"Math",stat:!0},{sign:d})},function(x,b,r){var u=r(3),d=r(7),h=r(292),p=Math.abs,y=Math.exp,T=Math.E,$=d(function(){return Math.sinh(-2e-17)!==-2e-17});u({target:"Math",stat:!0,forced:$},{sinh:function(E){var R=+E;return p(R)<1?(h(R)-h(-R))/2:(y(R-1)-y(-R-1))*(T/2)}})},function(x,b,r){var u=r(3),d=r(292),h=Math.exp;u({target:"Math",stat:!0},{tanh:function(y){var T=+y,$=d(T),A=d(-T);return $===1/0?1:A===1/0?-1:($-A)/(h(T)+h(-T))}})},function(x,b,r){var u=r(82);u(Math,"Math",!0)},function(x,b,r){var u=r(3),d=r(62);u({target:"Math",stat:!0},{trunc:d})},function(x,b,r){var u=r(3),d=r(36),h=r(6),p=r(4),y=r(80),T=r(14),$=r(67),A=r(38),E=r(118),R=r(24),I=r(22),O=r(19),C=r(7),D=r(57).f,M=r(5).f,F=r(44).f,z=r(308),U=r(309).trim,j="Number",G=p[j],B=y[j],V=G.prototype,Y=p.TypeError,Z=T("".slice),J=T("".charCodeAt),q=function(lt){var mt=O(lt,"number");return typeof mt=="bigint"?mt:nt(mt)},nt=function(lt){var mt=O(lt,"number"),gt,xt,yt,Ut,Dt,Xt,Qt,kt;if(I(mt))throw new Y("Cannot convert a Symbol value to a number");if(typeof mt=="string"&&mt.length>2){if(mt=U(mt),gt=J(mt,0),gt===43||gt===45){if(xt=J(mt,2),xt===88||xt===120)return NaN}else if(gt===48){switch(J(mt,1)){case 66:case 98:yt=2,Ut=49;break;case 79:case 111:yt=8,Ut=55;break;default:return+mt}for(Dt=Z(mt,2),Xt=Dt.length,Qt=0;QtUt)return NaN;return parseInt(Dt,yt)}}return+mt},rt=$(j,!G(" 0o1")||!G("0b1")||G("+0x1")),_=function(lt){return R(V,lt)&&C(function(){z(lt)})},tt=function(mt){var gt=arguments.length<1?0:G(q(mt));return _(this)?E(Object(gt),this,tt):gt};tt.prototype=V,rt&&!d&&(V.constructor=tt),u({global:!0,constructor:!0,wrap:!0,forced:rt},{Number:tt});var et=function(lt,mt){for(var gt=h?D(mt):"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,isFinite,isInteger,isNaN,isSafeInteger,parseFloat,parseInt,fromString,range".split(","),xt=0,yt;gt.length>xt;xt++)A(mt,yt=gt[xt])&&!A(lt,yt)&&F(lt,yt,M(mt,yt))};d&&B&&et(y[j],B),(rt||d)&&et(y[j],G)},function(x,b,r){var u=r(14);x.exports=u(1 .valueOf)},function(x,b,r){var u=r(14),d=r(16),h=r(68),p=r(310),y=u("".replace),T=RegExp("^["+p+"]+"),$=RegExp("(^|[^"+p+"])["+p+"]+$"),A=function(E){return function(R){var I=h(d(R));return E&1&&(I=y(I,T,"")),E&2&&(I=y(I,$,"$1")),I}};x.exports={start:A(1),end:A(2),trim:A(3)}},function(x){x.exports=` +\v\f\r \xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF`},function(x,b,r){var u=r(3);u({target:"Number",stat:!0,nonConfigurable:!0,nonWritable:!0},{EPSILON:Math.pow(2,-52)})},function(x,b,r){var u=r(3),d=r(313);u({target:"Number",stat:!0},{isFinite:d})},function(x,b,r){var u=r(4),d=u.isFinite;x.exports=Number.isFinite||function(p){return typeof p=="number"&&d(p)}},function(x,b,r){var u=r(3),d=r(315);u({target:"Number",stat:!0},{isInteger:d})},function(x,b,r){var u=r(20),d=Math.floor;x.exports=Number.isInteger||function(p){return!u(p)&&isFinite(p)&&d(p)===p}},function(x,b,r){var u=r(3);u({target:"Number",stat:!0},{isNaN:function(h){return h!==h}})},function(x,b,r){var u=r(3),d=r(315),h=Math.abs;u({target:"Number",stat:!0},{isSafeInteger:function(y){return d(y)&&h(y)<=9007199254740991}})},function(x,b,r){var u=r(3);u({target:"Number",stat:!0,nonConfigurable:!0,nonWritable:!0},{MAX_SAFE_INTEGER:9007199254740991})},function(x,b,r){var u=r(3);u({target:"Number",stat:!0,nonConfigurable:!0,nonWritable:!0},{MIN_SAFE_INTEGER:-9007199254740991})},function(x,b,r){var u=r(3),d=r(321);u({target:"Number",stat:!0,forced:Number.parseFloat!==d},{parseFloat:d})},function(x,b,r){var u=r(4),d=r(7),h=r(14),p=r(68),y=r(309).trim,T=r(310),$=h("".charAt),A=u.parseFloat,E=u.Symbol,R=E&&E.iterator,I=1/A(T+"-0")!==-1/0||R&&!d(function(){A(Object(R))});x.exports=I?function(C){var D=y(p(C)),M=A(D);return M===0&&$(D,0)==="-"?-0:M}:A},function(x,b,r){var u=r(3),d=r(323);u({target:"Number",stat:!0,forced:Number.parseInt!==d},{parseInt:d})},function(x,b,r){var u=r(4),d=r(7),h=r(14),p=r(68),y=r(309).trim,T=r(310),$=u.parseInt,A=u.Symbol,E=A&&A.iterator,R=/^[+-]?0x/i,I=h(R.exec),O=$(T+"08")!==8||$(T+"0x16")!==22||E&&!d(function(){$(Object(E))});x.exports=O?function(D,M){var F=y(p(D));return $(F,M>>>0||(I(R,F)?16:10))}:$},function(x,b,r){var u=r(3),d=r(14),h=r(61),p=r(308),y=r(244),T=r(299),$=r(7),A=RangeError,E=String,R=isFinite,I=Math.abs,O=Math.floor,C=Math.pow,D=Math.round,M=d(1 .toExponential),F=d(y),z=d("".slice),U=M(-69e-12,4)==="-6.9000e-11"&&M(1.255,2)==="1.25e+0"&&M(12345,3)==="1.235e+4"&&M(25,0)==="3e+1",j=function(){return $(function(){M(1,1/0)})&&$(function(){M(1,-1/0)})},G=function(){return!$(function(){M(1/0,1/0),M(NaN,1/0)})},B=!U||!j()||!G();u({target:"Number",proto:!0,forced:B},{toExponential:function(Y){var Z=p(this);if(Y===void 0)return M(Z);var J=h(Y);if(!R(Z))return String(Z);if(J<0||J>20)throw new A("Incorrect fraction digits");if(U)return M(Z,J);var q="",nt,rt,_,tt;if(Z<0&&(q="-",Z=-Z),Z===0)rt=0,nt=F("0",J+1);else{var et=T(Z);rt=O(et);var lt=C(10,rt-J),mt=D(Z/lt);2*Z>=(2*mt+1)*lt&&(mt+=1),mt>=C(10,J+1)&&(mt/=10,rt+=1),nt=E(mt)}return J!==0&&(nt=z(nt,0,1)+"."+z(nt,1)),rt===0?(_="+",tt="0"):(_=rt>0?"+":"-",tt=E(I(rt))),nt+="e"+_+tt,q+nt}})},function(x,b,r){var u=r(3),d=r(14),h=r(61),p=r(308),y=r(244),T=r(7),$=RangeError,A=String,E=Math.floor,R=d(y),I=d("".slice),O=d(1 .toFixed),C=function(j,G,B){return G===0?B:G%2===1?C(j,G-1,B*j):C(j*j,G/2,B)},D=function(j){for(var G=0,B=j;B>=4096;)G+=12,B/=4096;for(;B>=2;)G+=1,B/=2;return G},M=function(j,G,B){for(var V=-1,Y=B;++V<6;)Y+=G*j[V],j[V]=Y%1e7,Y=E(Y/1e7)},F=function(j,G){for(var B=6,V=0;--B>=0;)V+=j[B],j[B]=E(V/G),V=V%G*1e7},z=function(j){for(var G=6,B="";--G>=0;)if(B!==""||G===0||j[G]!==0){var V=A(j[G]);B=B===""?V:B+R("0",7-V.length)+V}return B},U=T(function(){return O(8e-5,3)!=="0.000"||O(.9,0)!=="1"||O(1.255,2)!=="1.25"||O(0xde0b6b3a7640080,0)!=="1000000000000000128"})||!T(function(){O({})});u({target:"Number",proto:!0,forced:U},{toFixed:function(G){var B=p(this),V=h(G),Y=[0,0,0,0,0,0],Z="",J="0",q,nt,rt,_;if(V<0||V>20)throw new $("Incorrect fraction digits");if(B!==B)return"NaN";if(B<=-1e21||B>=1e21)return A(B);if(B<0&&(Z="-",B=-B),B>1e-21)if(q=D(B*C(2,69,1))-69,nt=q<0?B*C(2,-q,1):B/C(2,q,1),nt*=4503599627370496,q=52-q,q>0){for(M(Y,0,nt),rt=V;rt>=7;)M(Y,1e7,0),rt-=7;for(M(Y,C(10,rt,1),0),rt=q-1;rt>=23;)F(Y,8388608),rt-=23;F(Y,1<0?(_=J.length,J=Z+(_<=V?"0."+R("0",V-_)+J:I(J,0,_-V)+"."+I(J,_-V))):J=Z+J,J}})},function(x,b,r){var u=r(3),d=r(14),h=r(7),p=r(308),y=d(1 .toPrecision),T=h(function(){return y(1,void 0)!=="1"})||!h(function(){y({})});u({target:"Number",proto:!0,forced:T},{toPrecision:function(A){return A===void 0?y(p(this)):y(p(this),A)}})},function(x,b,r){var u=r(3),d=r(328);u({target:"Object",stat:!0,arity:2,forced:Object.assign!==d},{assign:d})},function(x,b,r){var u=r(6),d=r(14),h=r(8),p=r(7),y=r(73),T=r(66),$=r(10),A=r(39),E=r(13),R=Object.assign,I=Object.defineProperty,O=d([].concat);x.exports=!R||p(function(){if(u&&R({b:1},R(I({},"a",{enumerable:!0,get:function(){I(this,"b",{value:3,enumerable:!1})}}),{b:2})).b!==1)return!0;var C={},D={},M=Symbol("assign detection"),F="abcdefghijklmnopqrst";return C[M]=7,F.split("").forEach(function(z){D[z]=z}),R({},C)[M]!==7||y(R({},D)).join("")!==F})?function(D,M){for(var F=A(D),z=arguments.length,U=1,j=T.f,G=$.f;z>U;)for(var B=E(arguments[U++]),V=j?O(y(B),j(B)):y(B),Y=V.length,Z=0,J;Y>Z;)J=V[Z++],(!u||h(G,B,J))&&(F[J]=B[J]);return F}:R},function(x,b,r){var u=r(3),d=r(6),h=r(71);u({target:"Object",stat:!0,sham:!d},{create:h})},function(x,b,r){var u=r(3),d=r(6),h=r(331),p=r(30),y=r(39),T=r(44);d&&u({target:"Object",proto:!0,forced:h},{__defineGetter__:function(A,E){T.f(y(this),A,{get:p(E),enumerable:!0,configurable:!0})}})},function(x,b,r){var u=r(36),d=r(4),h=r(7),p=r(192);x.exports=u||!h(function(){if(!(p&&p<535)){var y=Math.random();__defineSetter__.call(null,y,function(){}),delete d[y]}})},function(x,b,r){var u=r(3),d=r(6),h=r(72).f;u({target:"Object",stat:!0,forced:Object.defineProperties!==h,sham:!d},{defineProperties:h})},function(x,b,r){var u=r(3),d=r(6),h=r(44).f;u({target:"Object",stat:!0,forced:Object.defineProperty!==h,sham:!d},{defineProperty:h})},function(x,b,r){var u=r(3),d=r(6),h=r(331),p=r(30),y=r(39),T=r(44);d&&u({target:"Object",proto:!0,forced:h},{__defineSetter__:function(A,E){T.f(y(this),A,{set:p(E),enumerable:!0,configurable:!0})}})},function(x,b,r){var u=r(3),d=r(336).entries;u({target:"Object",stat:!0},{entries:function(p){return d(p)}})},function(x,b,r){var u=r(6),d=r(7),h=r(14),p=r(128),y=r(73),T=r(12),$=r(10).f,A=h($),E=h([].push),R=u&&d(function(){var O=Object.create(null);return O[2]=2,!A(O,2)}),I=function(O){return function(C){for(var D=T(C),M=y(D),F=R&&p(D)===null,z=M.length,U=0,j=[],G;z>U;)G=M[U++],(!u||(F?G in D:A(D,G)))&&E(j,O?[G,D[G]]:D[G]);return j}};x.exports={entries:I(!0),values:I(!1)}},function(x,b,r){var u=r(3),d=r(281),h=r(7),p=r(20),y=r(278).onFreeze,T=Object.freeze,$=h(function(){T(1)});u({target:"Object",stat:!0,forced:$,sham:!d},{freeze:function(E){return T&&p(E)?T(y(E)):E}})},function(x,b,r){var u=r(3),d=r(130),h=r(141);u({target:"Object",stat:!0},{fromEntries:function(y){var T={};return d(y,function($,A){h(T,$,A)},{AS_ENTRIES:!0}),T}})},function(x,b,r){var u=r(3),d=r(7),h=r(12),p=r(5).f,y=r(6),T=!y||d(function(){p(1)});u({target:"Object",stat:!0,forced:T,sham:!y},{getOwnPropertyDescriptor:function(A,E){return p(h(A),E)}})},function(x,b,r){var u=r(3),d=r(6),h=r(56),p=r(12),y=r(5),T=r(141);u({target:"Object",stat:!0,sham:!d},{getOwnPropertyDescriptors:function(A){for(var E=p(A),R=y.f,I=h(E),O={},C=0,D,M;I.length>C;)M=R(E,D=I[C++]),M!==void 0&&T(O,D,M);return O}})},function(x,b,r){var u=r(3),d=r(7),h=r(75).f,p=d(function(){return!Object.getOwnPropertyNames(1)});u({target:"Object",stat:!0,forced:p},{getOwnPropertyNames:h})},function(x,b,r){var u=r(3),d=r(7),h=r(39),p=r(128),y=r(129),T=d(function(){p(1)});u({target:"Object",stat:!0,forced:T,sham:!y},{getPrototypeOf:function(A){return p(h(A))}})},function(x,b,r){var u=r(3),d=r(23),h=r(14),p=r(30),y=r(16),T=r(18),$=r(130),A=r(7),E=Object.groupBy,R=d("Object","create"),I=h([].push),O=!E||A(function(){return E("ab",function(C){return C}).a.length!==1});u({target:"Object",stat:!0,forced:O},{groupBy:function(D,M){y(D),p(M);var F=R(null),z=0;return $(D,function(U){var j=T(M(U,z++));j in F?I(F[j],U):F[j]=[U]}),F}})},function(x,b,r){var u=r(3),d=r(38);u({target:"Object",stat:!0},{hasOwn:d})},function(x,b,r){var u=r(3),d=r(346);u({target:"Object",stat:!0},{is:d})},function(x){x.exports=Object.is||function(r,u){return r===u?r!==0||1/r===1/u:r!==r&&u!==u}},function(x,b,r){var u=r(3),d=r(279);u({target:"Object",stat:!0,forced:Object.isExtensible!==d},{isExtensible:d})},function(x,b,r){var u=r(3),d=r(7),h=r(20),p=r(15),y=r(280),T=Object.isFrozen,$=y||d(function(){T(1)});u({target:"Object",stat:!0,forced:$},{isFrozen:function(E){return!h(E)||y&&p(E)==="ArrayBuffer"?!0:T?T(E):!1}})},function(x,b,r){var u=r(3),d=r(7),h=r(20),p=r(15),y=r(280),T=Object.isSealed,$=y||d(function(){T(1)});u({target:"Object",stat:!0,forced:$},{isSealed:function(E){return!h(E)||y&&p(E)==="ArrayBuffer"?!0:T?T(E):!1}})},function(x,b,r){var u=r(3),d=r(39),h=r(73),p=r(7),y=p(function(){h(1)});u({target:"Object",stat:!0,forced:y},{keys:function($){return h(d($))}})},function(x,b,r){var u=r(3),d=r(6),h=r(331),p=r(39),y=r(18),T=r(128),$=r(5).f;d&&u({target:"Object",proto:!0,forced:h},{__lookupGetter__:function(E){var R=p(this),I=y(E),O;do if(O=$(R,I))return O.get;while(R=T(R))}})},function(x,b,r){var u=r(3),d=r(6),h=r(331),p=r(39),y=r(18),T=r(128),$=r(5).f;d&&u({target:"Object",proto:!0,forced:h},{__lookupSetter__:function(E){var R=p(this),I=y(E),O;do if(O=$(R,I))return O.set;while(R=T(R))}})},function(x,b,r){var u=r(3),d=r(20),h=r(278).onFreeze,p=r(281),y=r(7),T=Object.preventExtensions,$=y(function(){T(1)});u({target:"Object",stat:!0,forced:$,sham:!p},{preventExtensions:function(E){return T&&d(E)?T(h(E)):E}})},function(x,b,r){var u=r(6),d=r(77),h=r(20),p=r(116),y=r(39),T=r(16),$=Object.getPrototypeOf,A=Object.setPrototypeOf,E=Object.prototype,R="__proto__";if(u&&$&&A&&!(R in E))try{d(E,R,{configurable:!0,get:function(){return $(y(this))},set:function(O){var C=T(this);p(O)&&h(C)&&A(C,O)}})}catch(I){}},function(x,b,r){var u=r(3),d=r(20),h=r(278).onFreeze,p=r(281),y=r(7),T=Object.seal,$=y(function(){T(1)});u({target:"Object",stat:!0,forced:$,sham:!p},{seal:function(E){return T&&d(E)?T(h(E)):E}})},function(x,b,r){var u=r(3),d=r(113);u({target:"Object",stat:!0},{setPrototypeOf:d})},function(x,b,r){var u=r(70),d=r(47),h=r(358);u||d(Object.prototype,"toString",h,{unsafe:!0})},function(x,b,r){var u=r(70),d=r(69);x.exports=u?{}.toString:function(){return"[object "+d(this)+"]"}},function(x,b,r){var u=r(3),d=r(336).values;u({target:"Object",stat:!0},{values:function(p){return d(p)}})},function(x,b,r){var u=r(3),d=r(321);u({global:!0,forced:parseFloat!==d},{parseFloat:d})},function(x,b,r){var u=r(3),d=r(323);u({global:!0,forced:parseInt!==d},{parseInt:d})},function(x,b,r){r(363),r(379),r(381),r(382),r(383),r(384)},function(x,b,r){var u=r(3),d=r(36),h=r(182),p=r(4),y=r(8),T=r(47),$=r(113),A=r(82),E=r(194),R=r(30),I=r(21),O=r(20),C=r(211),D=r(364),M=r(366).set,F=r(369),z=r(374),U=r(375),j=r(371),G=r(51),B=r(376),V=r(377),Y=r(378),Z="Promise",J=V.CONSTRUCTOR,q=V.REJECTION_EVENT,nt=V.SUBCLASSING,rt=G.getterFor(Z),_=G.set,tt=B&&B.prototype,et=B,lt=tt,mt=p.TypeError,gt=p.document,xt=p.process,yt=Y.f,Ut=yt,Dt=!!(gt&>.createEvent&&p.dispatchEvent),Xt="unhandledrejection",Qt="rejectionhandled",kt=0,me=1,ge=2,ae=1,Mt=2,Ht,re,se,ee,fe=function(Tt){var qt;return O(Tt)&&I(qt=Tt.then)?qt:!1},Pe=function(Tt,qt){var te=qt.value,Zt=qt.state===me,Yt=Zt?Tt.ok:Tt.fail,Ye=Tt.resolve,Ze=Tt.reject,ut=Tt.domain,It,Pt,Ct;try{Yt?(Zt||(qt.rejection===Mt&&Te(qt),qt.rejection=ae),Yt===!0?It=te:(ut&&ut.enter(),It=Yt(te),ut&&(ut.exit(),Ct=!0)),It===Tt.promise?Ze(new mt("Promise-chain cycle")):(Pt=fe(It))?y(Pt,It,Ye,Ze):Ye(It)):Ze(te)}catch(Nt){ut&&!Ct&&ut.exit(),Ze(Nt)}},Me=function(Tt,qt){Tt.notified||(Tt.notified=!0,F(function(){for(var te=Tt.reactions,Zt;Zt=te.get();)Pe(Zt,Tt);Tt.notified=!1,qt&&!Tt.rejection&&ce(Tt)}))},$e=function(Tt,qt,te){var Zt,Yt;Dt?(Zt=gt.createEvent("Event"),Zt.promise=qt,Zt.reason=te,Zt.initEvent(Tt,!1,!0),p.dispatchEvent(Zt)):Zt={promise:qt,reason:te},!q&&(Yt=p["on"+Tt])?Yt(Zt):Tt===Xt&&z("Unhandled promise rejection",te)},ce=function(Tt){y(M,p,function(){var qt=Tt.facade,te=Tt.value,Zt=Ae(Tt),Yt;if(Zt&&(Yt=U(function(){h?xt.emit("unhandledRejection",te,qt):$e(Xt,qt,te)}),Tt.rejection=h||Ae(Tt)?Mt:ae,Yt.error))throw Yt.value})},Ae=function(Tt){return Tt.rejection!==ae&&!Tt.parent},Te=function(Tt){y(M,p,function(){var qt=Tt.facade;h?xt.emit("rejectionHandled",qt):$e(Qt,qt,Tt.value)})},de=function(Tt,qt,te){return function(Zt){Tt(qt,Zt,te)}},bt=function(Tt,qt,te){Tt.done||(Tt.done=!0,te&&(Tt=te),Tt.value=qt,Tt.state=ge,Me(Tt,!0))},Ft=function(Tt,qt,te){if(!Tt.done){Tt.done=!0,te&&(Tt=te);try{if(Tt.facade===qt)throw new mt("Promise can't be resolved itself");var Zt=fe(qt);Zt?F(function(){var Yt={done:!1};try{y(Zt,qt,de(Ft,Yt,Tt),de(bt,Yt,Tt))}catch(Ye){bt(Yt,Ye,Tt)}}):(Tt.value=qt,Tt.state=me,Me(Tt,!1))}catch(Yt){bt({done:!1},Yt,Tt)}}};if(J&&(et=function(qt){C(this,lt),R(qt),y(Ht,this);var te=rt(this);try{qt(de(Ft,te),de(bt,te))}catch(Zt){bt(te,Zt)}},lt=et.prototype,Ht=function(qt){_(this,{type:Z,done:!1,notified:!1,parent:!1,reactions:new j,rejection:!1,state:kt,value:null})},Ht.prototype=T(lt,"then",function(qt,te){var Zt=rt(this),Yt=yt(D(this,et));return Zt.parent=!0,Yt.ok=I(qt)?qt:!0,Yt.fail=I(te)&&te,Yt.domain=h?xt.domain:void 0,Zt.state===kt?Zt.reactions.add(Yt):F(function(){Pe(Yt,Zt)}),Yt.promise}),re=function(){var Tt=new Ht,qt=rt(Tt);this.promise=Tt,this.resolve=de(Ft,qt),this.reject=de(bt,qt)},Y.f=yt=function(Tt){return Tt===et||Tt===se?new re(Tt):Ut(Tt)},!d&&I(B)&&tt!==Object.prototype)){ee=tt.then,nt||T(tt,"then",function(qt,te){var Zt=this;return new et(function(Yt,Ye){y(ee,Zt,Yt,Ye)}).then(qt,te)},{unsafe:!0});try{delete tt.constructor}catch(Tt){}$&&$(tt,lt)}u({global:!0,constructor:!0,wrap:!0,forced:J},{Promise:et}),A(et,Z,!1,!0),E(Z)},function(x,b,r){var u=r(46),d=r(365),h=r(17),p=r(33),y=p("species");x.exports=function(T,$){var A=u(T).constructor,E;return A===void 0||h(E=u(A)[y])?$:d(E)}},function(x,b,r){var u=r(89),d=r(31),h=TypeError;x.exports=function(p){if(u(p))return p;throw new h(d(p)+" is not a constructor")}},function(x,b,r){var u=r(4),d=r(94),h=r(84),p=r(21),y=r(38),T=r(7),$=r(74),A=r(76),E=r(42),R=r(367),I=r(368),O=r(182),C=u.setImmediate,D=u.clearImmediate,M=u.process,F=u.Dispatch,z=u.Function,U=u.MessageChannel,j=u.String,G=0,B={},V="onreadystatechange",Y,Z,J,q;T(function(){Y=u.location});var nt=function(et){if(y(B,et)){var lt=B[et];delete B[et],lt()}},rt=function(et){return function(){nt(et)}},_=function(et){nt(et.data)},tt=function(et){u.postMessage(j(et),Y.protocol+"//"+Y.host)};(!C||!D)&&(C=function(lt){R(arguments.length,1);var mt=p(lt)?lt:z(lt),gt=A(arguments,1);return B[++G]=function(){d(mt,void 0,gt)},Z(G),G},D=function(lt){delete B[lt]},O?Z=function(et){M.nextTick(rt(et))}:F&&F.now?Z=function(et){F.now(rt(et))}:U&&!I?(J=new U,q=J.port2,J.port1.onmessage=_,Z=h(q.postMessage,q)):u.addEventListener&&p(u.postMessage)&&!u.importScripts&&Y&&Y.protocol!=="file:"&&!T(tt)?(Z=tt,u.addEventListener("message",_,!1)):V in E("script")?Z=function(et){$.appendChild(E("script"))[V]=function(){$.removeChild(this),nt(et)}}:Z=function(et){setTimeout(rt(et),0)}),x.exports={set:C,clear:D}},function(x){var b=TypeError;x.exports=function(r,u){if(r1?p(arguments,1):[],C=y.f(this),D=$(function(){return h(T(I),void 0,O)});return(D.error?C.reject:C.resolve)(D.value),C.promise}})},function(x,b,r){var u=r(3),d=r(378);u({target:"Promise",stat:!0},{withResolvers:function(){var p=d.f(this);return{promise:p.promise,resolve:p.resolve,reject:p.reject}}})},function(x,b,r){var u=r(3),d=r(94),h=r(30),p=r(46),y=r(7),T=!y(function(){Reflect.apply(function(){})});u({target:"Reflect",stat:!0,forced:T},{apply:function(A,E,R){return d(h(A),E,p(R))}})},function(x,b,r){var u=r(3),d=r(23),h=r(94),p=r(251),y=r(365),T=r(46),$=r(20),A=r(71),E=r(7),R=d("Reflect","construct"),I=Object.prototype,O=[].push,C=E(function(){function F(){}return!(R(function(){},[],F)instanceof F)}),D=!E(function(){R(function(){})}),M=C||D;u({target:"Reflect",stat:!0,forced:M,sham:M},{construct:function(z,U){y(z),T(U);var j=arguments.length<3?z:y(arguments[2]);if(D&&!C)return R(z,U,j);if(z===j){switch(U.length){case 0:return new z;case 1:return new z(U[0]);case 2:return new z(U[0],U[1]);case 3:return new z(U[0],U[1],U[2]);case 4:return new z(U[0],U[1],U[2],U[3])}var G=[null];return h(O,G,U),new(h(p,z,G))}var B=j.prototype,V=A($(B)?B:I),Y=h(z,V,U);return $(Y)?Y:V}})},function(x,b,r){var u=r(3),d=r(6),h=r(46),p=r(18),y=r(44),T=r(7),$=T(function(){Reflect.defineProperty(y.f({},1,{value:1}),1,{value:2})});u({target:"Reflect",stat:!0,forced:$,sham:!d},{defineProperty:function(E,R,I){h(E);var O=p(R);h(I);try{return y.f(E,O,I),!0}catch(C){return!1}}})},function(x,b,r){var u=r(3),d=r(46),h=r(5).f;u({target:"Reflect",stat:!0},{deleteProperty:function(y,T){var $=h(d(y),T);return $&&!$.configurable?!1:delete y[T]}})},function(x,b,r){var u=r(3),d=r(8),h=r(20),p=r(46),y=r(396),T=r(5),$=r(128);function A(E,R){var I=arguments.length<3?E:arguments[2],O,C;if(p(E)===I)return E[R];if(O=T.f(E,R),O)return y(O)?O.value:O.get===void 0?void 0:d(O.get,I);if(h(C=$(E)))return A(C,R,I)}u({target:"Reflect",stat:!0},{get:A})},function(x,b,r){var u=r(38);x.exports=function(d){return d!==void 0&&(u(d,"value")||u(d,"writable"))}},function(x,b,r){var u=r(3),d=r(6),h=r(46),p=r(5);u({target:"Reflect",stat:!0,sham:!d},{getOwnPropertyDescriptor:function(T,$){return p.f(h(T),$)}})},function(x,b,r){var u=r(3),d=r(46),h=r(128),p=r(129);u({target:"Reflect",stat:!0,sham:!p},{getPrototypeOf:function(T){return h(d(T))}})},function(x,b,r){var u=r(3);u({target:"Reflect",stat:!0},{has:function(h,p){return p in h}})},function(x,b,r){var u=r(3),d=r(46),h=r(279);u({target:"Reflect",stat:!0},{isExtensible:function(y){return d(y),h(y)}})},function(x,b,r){var u=r(3),d=r(56);u({target:"Reflect",stat:!0},{ownKeys:d})},function(x,b,r){var u=r(3),d=r(23),h=r(46),p=r(281);u({target:"Reflect",stat:!0,sham:!p},{preventExtensions:function(T){h(T);try{var $=d("Object","preventExtensions");return $&&$(T),!0}catch(A){return!1}}})},function(x,b,r){var u=r(3),d=r(8),h=r(46),p=r(20),y=r(396),T=r(7),$=r(44),A=r(5),E=r(128),R=r(11);function I(C,D,M){var F=arguments.length<4?C:arguments[3],z=A.f(h(C),D),U,j,G;if(!z){if(p(j=E(C)))return I(j,D,M,F);z=R(0)}if(y(z)){if(z.writable===!1||!p(F))return!1;if(U=A.f(F,D)){if(U.get||U.set||U.writable===!1)return!1;U.value=M,$.f(F,D,U)}else $.f(F,D,R(0,M))}else{if(G=z.set,G===void 0)return!1;d(G,F,M)}return!0}var O=T(function(){var C=function(){},D=$.f(new C,"a",{configurable:!0});return Reflect.set(C.prototype,"a",1,D)!==!1});u({target:"Reflect",stat:!0,forced:O},{set:I})},function(x,b,r){var u=r(3),d=r(46),h=r(115),p=r(113);p&&u({target:"Reflect",stat:!0},{setPrototypeOf:function(T,$){d(T),h($);try{return p(T,$),!0}catch(A){return!1}}})},function(x,b,r){var u=r(3),d=r(4),h=r(82);u({global:!0},{Reflect:{}}),h(d.Reflect,"Reflect",!0)},function(x,b,r){var u=r(6),d=r(4),h=r(14),p=r(67),y=r(118),T=r(43),$=r(71),A=r(57).f,E=r(24),R=r(407),I=r(68),O=r(408),C=r(410),D=r(117),M=r(47),F=r(7),z=r(38),U=r(51).enforce,j=r(194),G=r(33),B=r(411),V=r(412),Y=G("match"),Z=d.RegExp,J=Z.prototype,q=d.SyntaxError,nt=h(J.exec),rt=h("".charAt),_=h("".replace),tt=h("".indexOf),et=h("".slice),lt=/^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/,mt=/a/g,gt=/a/g,xt=new Z(mt)!==mt,yt=C.MISSED_STICKY,Ut=C.UNSUPPORTED_Y,Dt=u&&(!xt||yt||B||V||F(function(){return gt[Y]=!1,Z(mt)!==mt||Z(gt)===gt||String(Z(mt,"i"))!=="/a/i"})),Xt=function(ae){for(var Mt=ae.length,Ht=0,re="",se=!1,ee;Ht<=Mt;Ht++){if(ee=rt(ae,Ht),ee==="\\"){re+=ee+rt(ae,++Ht);continue}!se&&ee==="."?re+="[\\s\\S]":(ee==="["?se=!0:ee==="]"&&(se=!1),re+=ee)}return re},Qt=function(ae){for(var Mt=ae.length,Ht=0,re="",se=[],ee=$(null),fe=!1,Pe=!1,Me=0,$e="",ce;Ht<=Mt;Ht++){if(ce=rt(ae,Ht),ce==="\\")ce+=rt(ae,++Ht);else if(ce==="]")fe=!1;else if(!fe)switch(!0){case ce==="[":fe=!0;break;case ce==="(":if(re+=ce,et(ae,Ht+1,Ht+3)==="?:")continue;nt(lt,et(ae,Ht+1))&&(Ht+=2,Pe=!0),Me++;continue;case(ce===">"&&Pe):if($e===""||z(ee,$e))throw new q("Invalid capture group name");ee[$e]=!0,se[se.length]=[$e,Me],Pe=!1,$e="";continue}Pe?$e+=ce:re+=ce}return[re,se]};if(p("RegExp",Dt)){for(var kt=function(Mt,Ht){var re=E(J,this),se=R(Mt),ee=Ht===void 0,fe=[],Pe=Mt,Me,$e,ce,Ae,Te,de;if(!re&&se&&ee&&Mt.constructor===kt)return Mt;if((se||E(J,Mt))&&(Mt=Mt.source,ee&&(Ht=O(Pe))),Mt=Mt===void 0?"":I(Mt),Ht=Ht===void 0?"":I(Ht),Pe=Mt,B&&"dotAll"in mt&&($e=!!Ht&&tt(Ht,"s")>-1,$e&&(Ht=_(Ht,/s/g,""))),Me=Ht,yt&&"sticky"in mt&&(ce=!!Ht&&tt(Ht,"y")>-1,ce&&Ut&&(Ht=_(Ht,/y/g,""))),V&&(Ae=Qt(Mt),Mt=Ae[0],fe=Ae[1]),Te=y(Z(Mt,Ht),re?this:J,kt),($e||ce||fe.length)&&(de=U(Te),$e&&(de.dotAll=!0,de.raw=kt(Xt(Mt),Me)),ce&&(de.sticky=!0),fe.length&&(de.groups=fe)),Mt!==Pe)try{T(Te,"source",Pe===""?"(?:)":Pe)}catch(bt){}return Te},me=A(Z),ge=0;me.length>ge;)D(kt,Z,me[ge++]);J.constructor=kt,kt.prototype=J,M(d,"RegExp",kt,{constructor:!0})}j("RegExp")},function(x,b,r){var u=r(20),d=r(15),h=r(33),p=h("match");x.exports=function(y){var T;return u(y)&&((T=y[p])!==void 0?!!T:d(y)==="RegExp")}},function(x,b,r){var u=r(8),d=r(38),h=r(24),p=r(409),y=RegExp.prototype;x.exports=function(T){var $=T.flags;return $===void 0&&!("flags"in y)&&!d(T,"flags")&&h(y,T)?u(p,T):$}},function(x,b,r){var u=r(46);x.exports=function(){var d=u(this),h="";return d.hasIndices&&(h+="d"),d.global&&(h+="g"),d.ignoreCase&&(h+="i"),d.multiline&&(h+="m"),d.dotAll&&(h+="s"),d.unicode&&(h+="u"),d.unicodeSets&&(h+="v"),d.sticky&&(h+="y"),h}},function(x,b,r){var u=r(7),d=r(4),h=d.RegExp,p=u(function(){var $=h("a","y");return $.lastIndex=2,$.exec("abcd")!==null}),y=p||u(function(){return!h("a","y").sticky}),T=p||u(function(){var $=h("^r","gy");return $.lastIndex=2,$.exec("str")!==null});x.exports={BROKEN_CARET:T,MISSED_STICKY:y,UNSUPPORTED_Y:p}},function(x,b,r){var u=r(7),d=r(4),h=d.RegExp;x.exports=u(function(){var p=h(".","s");return!(p.dotAll&&p.test(` +`)&&p.flags==="s")})},function(x,b,r){var u=r(7),d=r(4),h=d.RegExp;x.exports=u(function(){var p=h("(?b)","g");return p.exec("b").groups.a!=="b"||"b".replace(p,"$c")!=="bc"})},function(x,b,r){var u=r(3),d=r(14),h=r(414),p=r(38),y=r(243).start,T=r(310),$=Array,A=RegExp.escape,E=d("".charAt),R=d("".charCodeAt),I=d(1.1.toString),O=d([].join),C=/^[0-9a-z]/i,D=/^[$()*+./?[\\\]^{|}]/,M=RegExp("^[!\"#%&',\\-:;<=>@`~"+T+"]"),F=d(C.exec),z={" ":"t","\n":"n","\v":"v","\f":"f","\r":"r"},U=function(G){var B=I(R(G,0),16);return B.length<3?"\\x"+y(B,2,"0"):"\\u"+y(B,4,"0")},j=!A||A("ab")!=="\\x61b";u({target:"RegExp",stat:!0,forced:j},{escape:function(B){h(B);for(var V=B.length,Y=$(V),Z=0;Z=56320||Z+1>=V||(R(B,Z+1)&64512)!==56320?Y[Z]=U(J):(Y[Z]=J,Y[++Z]=E(B,Z))}}return O(Y,"")}})},function(x){var b=TypeError;x.exports=function(r){if(typeof r=="string")return r;throw new b("Argument is not a string")}},function(x,b,r){var u=r(6),d=r(411),h=r(15),p=r(77),y=r(51).get,T=RegExp.prototype,$=TypeError;u&&d&&p(T,"dotAll",{configurable:!0,get:function(){if(this!==T){if(h(this)==="RegExp")return!!y(this).dotAll;throw new $("Incompatible receiver, RegExp required")}}})},function(x,b,r){var u=r(3),d=r(417);u({target:"RegExp",proto:!0,forced:/./.exec!==d},{exec:d})},function(x,b,r){var u=r(8),d=r(14),h=r(68),p=r(409),y=r(410),T=r(34),$=r(71),A=r(51).get,E=r(411),R=r(412),I=T("native-string-replace",String.prototype.replace),O=RegExp.prototype.exec,C=O,D=d("".charAt),M=d("".indexOf),F=d("".replace),z=d("".slice),U=function(){var V=/a/,Y=/b*/g;return u(O,V,"a"),u(O,Y,"a"),V.lastIndex!==0||Y.lastIndex!==0}(),j=y.BROKEN_CARET,G=/()??/.exec("")[1]!==void 0,B=U||G||j||E||R;B&&(C=function(Y){var Z=this,J=A(Z),q=h(Y),nt=J.raw,rt,_,tt,et,lt,mt,gt;if(nt)return nt.lastIndex=Z.lastIndex,rt=u(C,nt,q),Z.lastIndex=nt.lastIndex,rt;var xt=J.groups,yt=j&&Z.sticky,Ut=u(p,Z),Dt=Z.source,Xt=0,Qt=q;if(yt&&(Ut=F(Ut,"y",""),M(Ut,"g")===-1&&(Ut+="g"),Qt=z(q,Z.lastIndex),Z.lastIndex>0&&(!Z.multiline||Z.multiline&&D(q,Z.lastIndex-1)!==` +`)&&(Dt="(?: "+Dt+")",Qt=" "+Qt,Xt++),_=new RegExp("^(?:"+Dt+")",Ut)),G&&(_=new RegExp("^"+Dt+"$(?!\\s)",Ut)),U&&(tt=Z.lastIndex),et=u(O,yt?_:Z,Qt),yt?et?(et.input=z(et.input,Xt),et[0]=z(et[0],Xt),et.index=Z.lastIndex,Z.lastIndex+=et[0].length):Z.lastIndex=0:U&&et&&(Z.lastIndex=Z.global?et.index+et[0].length:tt),G&&et&&et.length>1&&u(I,et[0],_,function(){for(lt=1;ltC.size?T(C.getIterator(),function(M){E(O,M)&&A(D,M)}):y(O,function(M){C.includes(M)&&A(D,M)}),D}},function(x,b,r){var u=r(3),d=r(437),h=r(433),p=!h("isDisjointFrom",function(y){return!y});u({target:"Set",proto:!0,real:!0,forced:p},{isDisjointFrom:d})},function(x,b,r){var u=r(426),d=r(427).has,h=r(431),p=r(432),y=r(429),T=r(430),$=r(135);x.exports=function(E){var R=u(this),I=p(E);if(h(R)<=I.size)return y(R,function(C){if(I.includes(C))return!1},!0)!==!1;var O=I.getIterator();return T(O,function(C){if(d(R,C))return $(O,"normal",!1)})!==!1}},function(x,b,r){var u=r(3),d=r(439),h=r(433),p=!h("isSubsetOf",function(y){return y});u({target:"Set",proto:!0,real:!0,forced:p},{isSubsetOf:d})},function(x,b,r){var u=r(426),d=r(431),h=r(429),p=r(432);x.exports=function(T){var $=u(this),A=p(T);return d($)>A.size?!1:h($,function(E){if(!A.includes(E))return!1},!0)!==!1}},function(x,b,r){var u=r(3),d=r(441),h=r(433),p=!h("isSupersetOf",function(y){return!y});u({target:"Set",proto:!0,real:!0,forced:p},{isSupersetOf:d})},function(x,b,r){var u=r(426),d=r(427).has,h=r(431),p=r(432),y=r(430),T=r(135);x.exports=function(A){var E=u(this),R=p(A);if(h(E)=0?C:O+C;return D<0||D>=O?void 0:$(I,D)}})},function(x,b,r){var u=r(3),d=r(448).codeAt;u({target:"String",proto:!0},{codePointAt:function(p){return d(this,p)}})},function(x,b,r){var u=r(14),d=r(61),h=r(68),p=r(16),y=u("".charAt),T=u("".charCodeAt),$=u("".slice),A=function(E){return function(R,I){var O=h(p(R)),C=d(I),D=O.length,M,F;return C<0||C>=D?E?"":void 0:(M=T(O,C),M<55296||M>56319||C+1===D||(F=T(O,C+1))<56320||F>57343?E?y(O,C):M:E?$(O,C,C+2):(M-55296<<10)+(F-56320)+65536)}};x.exports={codeAt:A(!1),charAt:A(!0)}},function(x,b,r){var u=r(3),d=r(85),h=r(5).f,p=r(64),y=r(68),T=r(450),$=r(16),A=r(451),E=r(36),R=d("".slice),I=Math.min,O=A("endsWith"),C=!E&&!O&&!!function(){var D=h(String.prototype,"endsWith");return D&&!D.writable}();u({target:"String",proto:!0,forced:!C&&!O},{endsWith:function(M){var F=y($(this));T(M);var z=arguments.length>1?arguments[1]:void 0,U=F.length,j=z===void 0?U:I(p(z),U),G=y(M);return R(F,j-G.length,j)===G}})},function(x,b,r){var u=r(407),d=TypeError;x.exports=function(h){if(u(h))throw new d("The method doesn't accept regular expressions");return h}},function(x,b,r){var u=r(33),d=u("match");x.exports=function(h){var p=/./;try{"/./"[h](p)}catch(y){try{return p[d]=!1,"/./"[h](p)}catch(T){}}return!1}},function(x,b,r){var u=r(3),d=r(14),h=r(60),p=RangeError,y=String.fromCharCode,T=String.fromCodePoint,$=d([].join),A=!!T&&T.length!==1;u({target:"String",stat:!0,arity:1,forced:A},{fromCodePoint:function(R){for(var I=[],O=arguments.length,C=0,D;O>C;){if(D=+arguments[C++],h(D,1114111)!==D)throw new p(D+" is not a valid code point");I[C]=D<65536?y(D):y(((D-=65536)>>10)+55296,D%1024+56320)}return $(I,"")}})},function(x,b,r){var u=r(3),d=r(14),h=r(450),p=r(16),y=r(68),T=r(451),$=d("".indexOf);u({target:"String",proto:!0,forced:!T("includes")},{includes:function(E){return!!~$(y(p(this)),y(h(E)),arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(14),h=r(16),p=r(68),y=d("".charCodeAt);u({target:"String",proto:!0},{isWellFormed:function(){for(var $=p(h(this)),A=$.length,E=0;E=56320||++E>=A||(y($,E)&64512)!==56320))return!1}return!0}})},function(x,b,r){var u=r(448).charAt,d=r(68),h=r(51),p=r(169),y=r(172),T="String Iterator",$=h.set,A=h.getterFor(T);p(String,"String",function(E){$(this,{type:T,string:d(E),index:0})},function(){var R=A(this),I=R.string,O=R.index,C;return O>=I.length?y(void 0,!0):(C=u(I,O),R.index+=C.length,y(C,!1))})},function(x,b,r){var u=r(8),d=r(457),h=r(46),p=r(17),y=r(64),T=r(68),$=r(16),A=r(29),E=r(458),R=r(459);d("match",function(I,O,C){return[function(M){var F=$(this),z=p(M)?void 0:A(M,I);return z?u(z,M,F):new RegExp(M)[I](T(F))},function(D){var M=h(this),F=T(D),z=C(O,M,F);if(z.done)return z.value;if(!M.global)return R(M,F);var U=M.unicode;M.lastIndex=0;for(var j=[],G=0,B;(B=R(M,F))!==null;){var V=T(B[0]);j[G]=V,V===""&&(M.lastIndex=E(F,y(M.lastIndex),U)),G++}return G===0?null:j}]})},function(x,b,r){r(416);var u=r(8),d=r(47),h=r(417),p=r(7),y=r(33),T=r(43),$=y("species"),A=RegExp.prototype;x.exports=function(E,R,I,O){var C=y(E),D=!p(function(){var U={};return U[C]=function(){return 7},""[E](U)!==7}),M=D&&!p(function(){var U=!1,j=/a/;return E==="split"&&(j={},j.constructor={},j.constructor[$]=function(){return j},j.flags="",j[C]=/./[C]),j.exec=function(){return U=!0,null},j[C](""),!U});if(!D||!M||I){var F=/./[C],z=R(C,""[E],function(U,j,G,B,V){var Y=j.exec;return Y===h||Y===A.exec?D&&!V?{done:!0,value:u(F,j,G,B)}:{done:!0,value:u(U,G,j,B)}:{done:!1}});d(String.prototype,E,z[0]),d(A,C,z[1])}O&&T(A[C],"sham",!0)}},function(x,b,r){var u=r(448).charAt;x.exports=function(d,h,p){return h+(p?u(d,h).length:1)}},function(x,b,r){var u=r(8),d=r(46),h=r(21),p=r(15),y=r(417),T=TypeError;x.exports=function($,A){var E=$.exec;if(h(E)){var R=u(E,$,A);return R!==null&&d(R),R}if(p($)==="RegExp")return u(y,$,A);throw new T("RegExp#exec called on incompatible receiver")}},function(x,b,r){var u=r(3),d=r(8),h=r(85),p=r(170),y=r(172),T=r(16),$=r(64),A=r(68),E=r(46),R=r(17),I=r(15),O=r(407),C=r(408),D=r(29),M=r(47),F=r(7),z=r(33),U=r(364),j=r(458),G=r(459),B=r(51),V=r(36),Y=z("matchAll"),Z="RegExp String",J=Z+" Iterator",q=B.set,nt=B.getterFor(J),rt=RegExp.prototype,_=TypeError,tt=h("".indexOf),et=h("".matchAll),lt=!!et&&!F(function(){et("a",/./)}),mt=p(function(yt,Ut,Dt,Xt){q(this,{type:J,regexp:yt,string:Ut,global:Dt,unicode:Xt,done:!1})},Z,function(){var yt=nt(this);if(yt.done)return y(void 0,!0);var Ut=yt.regexp,Dt=yt.string,Xt=G(Ut,Dt);return Xt===null?(yt.done=!0,y(void 0,!0)):yt.global?(A(Xt[0])===""&&(Ut.lastIndex=j(Dt,$(Ut.lastIndex),yt.unicode)),y(Xt,!1)):(yt.done=!0,y(Xt,!1))}),gt=function(xt){var yt=E(this),Ut=A(xt),Dt=U(yt,RegExp),Xt=A(C(yt)),Qt,kt,me;return Qt=new Dt(Dt===RegExp?yt.source:yt,Xt),kt=!!~tt(Xt,"g"),me=!!~tt(Xt,"u"),Qt.lastIndex=$(yt.lastIndex),new mt(Qt,Ut,kt,me)};u({target:"String",proto:!0,forced:lt},{matchAll:function(yt){var Ut=T(this),Dt,Xt,Qt,kt;if(R(yt)){if(lt)return et(Ut,yt)}else{if(O(yt)&&(Dt=A(T(C(yt))),!~tt(Dt,"g")))throw new _("`.matchAll` does not allow non-global regexes");if(lt)return et(Ut,yt);if(Qt=D(yt,Y),Qt===void 0&&V&&I(yt)==="RegExp"&&(Qt=gt),Qt)return d(Qt,yt,Ut)}return Xt=A(Ut),kt=new RegExp(yt,"g"),V?d(gt,kt,Xt):kt[Y](Xt)}}),V||Y in rt||M(rt,Y,gt)},function(x,b,r){var u=r(3),d=r(243).end,h=r(462);u({target:"String",proto:!0,forced:h},{padEnd:function(y){return d(this,y,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(28);x.exports=/Version\/10(?:\.\d+){1,2}(?: [\w./]+)?(?: Mobile\/\w+)? Safari\//.test(u)},function(x,b,r){var u=r(3),d=r(243).start,h=r(462);u({target:"String",proto:!0,forced:h},{padStart:function(y){return d(this,y,arguments.length>1?arguments[1]:void 0)}})},function(x,b,r){var u=r(3),d=r(14),h=r(12),p=r(39),y=r(68),T=r(63),$=d([].push),A=d([].join);u({target:"String",stat:!0},{raw:function(R){var I=h(p(R).raw),O=T(I);if(!O)return"";for(var C=arguments.length,D=[],M=0;;){if($(D,y(I[M++])),M===O)return A(D,"");M")!=="7"});p("replace",function(_,tt,et){var lt=nt?"$":"$0";return[function(gt,xt){var yt=O(this),Ut=A(gt)?void 0:D(gt,U);return Ut?d(Ut,gt,yt,xt):d(tt,I(yt),gt,xt)},function(mt,gt){var xt=T(this),yt=I(mt);if(typeof gt=="string"&&Y(gt,lt)===-1&&Y(gt,"$<")===-1){var Ut=et(tt,xt,yt,gt);if(Ut.done)return Ut.value}var Dt=$(gt);Dt||(gt=I(gt));var Xt=xt.global,Qt;Xt&&(Qt=xt.unicode,xt.lastIndex=0);for(var kt=[],me;me=F(xt,yt),!(me===null||(V(kt,me),!Xt));){var ge=I(me[0]);ge===""&&(xt.lastIndex=C(yt,R(xt.lastIndex),Qt))}for(var ae="",Mt=0,Ht=0;Ht=Mt&&(ae+=Z(yt,Mt,se)+fe,Mt=se+re.length)}return ae+Z(yt,Mt)}]},!rt||!q||nt)},function(x,b,r){var u=r(14),d=r(39),h=Math.floor,p=u("".charAt),y=u("".replace),T=u("".slice),$=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,A=/\$([$&'`]|\d{1,2})/g;x.exports=function(E,R,I,O,C,D){var M=I+E.length,F=O.length,z=A;return C!==void 0&&(C=d(C),z=$),y(D,z,function(U,j){var G;switch(p(j,0)){case"$":return"$";case"&":return E;case"`":return T(R,0,I);case"'":return T(R,M);case"<":G=C[T(j,1,-1)];break;default:var B=+j;if(B===0)return U;if(B>F){var V=h(B/10);return V===0?U:V<=F?O[V-1]===void 0?p(j,1):O[V-1]+p(j,1):U}G=O[B-1]}return G===void 0?"":G})}},function(x,b,r){var u=r(3),d=r(8),h=r(14),p=r(16),y=r(21),T=r(17),$=r(407),A=r(68),E=r(29),R=r(408),I=r(467),O=r(33),C=r(36),D=O("replace"),M=TypeError,F=h("".indexOf),z=h("".replace),U=h("".slice),j=Math.max;u({target:"String",proto:!0},{replaceAll:function(B,V){var Y=p(this),Z,J,q,nt,rt,_,tt,et,lt,mt,gt=0,xt="";if(!T(B)){if(Z=$(B),Z&&(J=A(p(R(B))),!~F(J,"g")))throw new M("`.replaceAll` does not allow non-global regexes");if(q=E(B,D),q)return d(q,B,Y,V);if(C&&Z)return z(A(Y),B,V)}for(nt=A(Y),rt=A(B),_=y(V),_||(V=A(V)),tt=rt.length,et=j(1,tt),lt=F(nt,rt);lt!==-1;)mt=_?A(V(rt,lt,nt)):I(rt,nt,lt,[],void 0,V),xt+=U(nt,gt,lt)+mt,gt=lt+tt,lt=lt+et>nt.length?-1:F(nt,rt,lt+et);return gt1||"".split(/.?/).length;h("split",function(V,Y,Z){var J="0".split(void 0,0).length?function(q,nt){return q===void 0&&nt===0?[]:u(Y,this,q,nt)}:Y;return[function(nt,rt){var _=T(this),tt=y(nt)?void 0:I(nt,V);return tt?u(tt,nt,_,rt):u(J,R(_),nt,rt)},function(q,nt){var rt=p(this),_=R(q);if(!B){var tt=Z(J,rt,_,nt,J!==Y);if(tt.done)return tt.value}var et=$(rt,RegExp),lt=rt.unicode,mt=(rt.ignoreCase?"i":"")+(rt.multiline?"m":"")+(rt.unicode?"u":"")+(M?"g":"y"),gt=new et(M?"^(?:"+rt.source+")":rt,mt),xt=nt===void 0?F:nt>>>0;if(xt===0)return[];if(_.length===0)return O(gt,_)===null?[_]:[];for(var yt=0,Ut=0,Dt=[];Ut<_.length;){gt.lastIndex=M?0:Ut;var Xt=O(gt,M?j(_,Ut):_),Qt;if(Xt===null||(Qt=z(E(gt.lastIndex+(M?Ut:0)),_.length))===yt)Ut=A(_,Ut,lt);else{if(U(Dt,j(_,yt,Ut)),Dt.length===xt)return Dt;for(var kt=1;kt<=Xt.length-1;kt++)if(U(Dt,Xt[kt]),Dt.length===xt)return Dt;Ut=yt=Qt}}return U(Dt,j(_,yt)),Dt}]},B||!G,M)},function(x,b,r){var u=r(3),d=r(85),h=r(5).f,p=r(64),y=r(68),T=r(450),$=r(16),A=r(451),E=r(36),R=d("".slice),I=Math.min,O=A("startsWith"),C=!E&&!O&&!!function(){var D=h(String.prototype,"startsWith");return D&&!D.writable}();u({target:"String",proto:!0,forced:!C&&!O},{startsWith:function(M){var F=y($(this));T(M);var z=p(I(arguments.length>1?arguments[1]:void 0,F.length)),U=y(M);return R(F,z,z+U.length)===U}})},function(x,b,r){var u=r(3),d=r(14),h=r(16),p=r(61),y=r(68),T=d("".slice),$=Math.max,A=Math.min,E=!"".substr||"ab".substr(-1)!=="b";u({target:"String",proto:!0,forced:E},{substr:function(I,O){var C=y(h(this)),D=C.length,M=p(I),F,z;return M===1/0&&(M=0),M<0&&(M=$(D+M,0)),F=O===void 0?D:p(O),F<=0||F===1/0?"":(z=A(M+F,D),M>=z?"":T(C,M,z))}})},function(x,b,r){var u=r(3),d=r(8),h=r(14),p=r(16),y=r(68),T=r(7),$=Array,A=h("".charAt),E=h("".charCodeAt),R=h([].join),I="".toWellFormed,O="\uFFFD",C=I&&T(function(){return d(I,1)!=="1"});u({target:"String",proto:!0,forced:C},{toWellFormed:function(){var M=y(p(this));if(C)return d(I,M);for(var F=M.length,z=$(F),U=0;U=56320||U+1>=F||(E(M,U+1)&64512)!==56320?z[U]=O:(z[U]=A(M,U),z[++U]=A(M,U))}return R(z,"")}})},function(x,b,r){var u=r(3),d=r(309).trim,h=r(475);u({target:"String",proto:!0,forced:h("trim")},{trim:function(){return d(this)}})},function(x,b,r){var u=r(49).PROPER,d=r(7),h=r(310),p="\u200B\x85\u180E";x.exports=function(y){return d(function(){return!!h[y]()||p[y]()!==p||u&&h[y].name!==y})}},function(x,b,r){r(477);var u=r(3),d=r(478);u({target:"String",proto:!0,name:"trimEnd",forced:"".trimEnd!==d},{trimEnd:d})},function(x,b,r){var u=r(3),d=r(478);u({target:"String",proto:!0,name:"trimEnd",forced:"".trimRight!==d},{trimRight:d})},function(x,b,r){var u=r(309).end,d=r(475);x.exports=d("trimEnd")?function(){return u(this)}:"".trimEnd},function(x,b,r){r(480);var u=r(3),d=r(481);u({target:"String",proto:!0,name:"trimStart",forced:"".trimStart!==d},{trimStart:d})},function(x,b,r){var u=r(3),d=r(481);u({target:"String",proto:!0,name:"trimStart",forced:"".trimLeft!==d},{trimLeft:d})},function(x,b,r){var u=r(309).start,d=r(475);x.exports=d("trimStart")?function(){return u(this)}:"".trimStart},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("anchor")},{anchor:function(y){return d(this,"a","name",y)}})},function(x,b,r){var u=r(14),d=r(16),h=r(68),p=/"/g,y=u("".replace);x.exports=function(T,$,A,E){var R=h(d(T)),I="<"+$;return A!==""&&(I+=" "+A+'="'+y(h(E),p,""")+'"'),I+">"+R+""}},function(x,b,r){var u=r(7);x.exports=function(d){return u(function(){var h=""[d]('"');return h!==h.toLowerCase()||h.split('"').length>3})}},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("big")},{big:function(){return d(this,"big","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("blink")},{blink:function(){return d(this,"blink","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("bold")},{bold:function(){return d(this,"b","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("fixed")},{fixed:function(){return d(this,"tt","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("fontcolor")},{fontcolor:function(y){return d(this,"font","color",y)}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("fontsize")},{fontsize:function(y){return d(this,"font","size",y)}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("italics")},{italics:function(){return d(this,"i","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("link")},{link:function(y){return d(this,"a","href",y)}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("small")},{small:function(){return d(this,"small","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("strike")},{strike:function(){return d(this,"strike","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("sub")},{sub:function(){return d(this,"sub","","")}})},function(x,b,r){var u=r(3),d=r(483),h=r(484);u({target:"String",proto:!0,forced:h("sup")},{sup:function(){return d(this,"sup","","")}})},function(x,b,r){var u=r(498);u("Float32",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(3),d=r(4),h=r(8),p=r(6),y=r(499),T=r(219),$=r(208),A=r(211),E=r(11),R=r(43),I=r(315),O=r(64),C=r(212),D=r(500),M=r(501),F=r(18),z=r(38),U=r(69),j=r(20),G=r(22),B=r(71),V=r(24),Y=r(113),Z=r(57).f,J=r(502),q=r(83).forEach,nt=r(194),rt=r(77),_=r(44),tt=r(5),et=r(199),lt=r(51),mt=r(118),gt=lt.get,xt=lt.set,yt=lt.enforce,Ut=_.f,Dt=tt.f,Xt=d.RangeError,Qt=$.ArrayBuffer,kt=Qt.prototype,me=$.DataView,ge=T.NATIVE_ARRAY_BUFFER_VIEWS,ae=T.TYPED_ARRAY_TAG,Mt=T.TypedArray,Ht=T.TypedArrayPrototype,re=T.isTypedArray,se="BYTES_PER_ELEMENT",ee="Wrong length",fe=function(Ae,Te){rt(Ae,Te,{configurable:!0,get:function(){return gt(this)[Te]}})},Pe=function(Ae){var Te;return V(kt,Ae)||(Te=U(Ae))==="ArrayBuffer"||Te==="SharedArrayBuffer"},Me=function(Ae,Te){return re(Ae)&&!G(Te)&&Te in Ae&&I(+Te)&&Te>=0},$e=function(Te,de){return de=F(de),Me(Te,de)?E(2,Te[de]):Dt(Te,de)},ce=function(Te,de,bt){return de=F(de),Me(Te,de)&&j(bt)&&z(bt,"value")&&!z(bt,"get")&&!z(bt,"set")&&!bt.configurable&&(!z(bt,"writable")||bt.writable)&&(!z(bt,"enumerable")||bt.enumerable)?(Te[de]=bt.value,Te):Ut(Te,de,bt)};p?(ge||(tt.f=$e,_.f=ce,fe(Ht,"buffer"),fe(Ht,"byteOffset"),fe(Ht,"byteLength"),fe(Ht,"length")),u({target:"Object",stat:!0,forced:!ge},{getOwnPropertyDescriptor:$e,defineProperty:ce}),x.exports=function(Ae,Te,de){var bt=Ae.match(/\d+/)[0]/8,Ft=Ae+(de?"Clamped":"")+"Array",Tt="get"+Ae,qt="set"+Ae,te=d[Ft],Zt=te,Yt=Zt&&Zt.prototype,Ye={},Ze=function(Ct,Nt){var Et=gt(Ct);return Et.view[Tt](Nt*bt+Et.byteOffset,!0)},ut=function(Ct,Nt,Et){var ie=gt(Ct);ie.view[qt](Nt*bt+ie.byteOffset,de?M(Et):Et,!0)},It=function(Ct,Nt){Ut(Ct,Nt,{get:function(){return Ze(this,Nt)},set:function(Et){return ut(this,Nt,Et)},enumerable:!0})};ge?y&&(Zt=Te(function(Ct,Nt,Et,ie){return A(Ct,Yt),mt(function(){return j(Nt)?Pe(Nt)?ie!==void 0?new te(Nt,D(Et,bt),ie):Et!==void 0?new te(Nt,D(Et,bt)):new te(Nt):re(Nt)?et(Zt,Nt):h(J,Zt,Nt):new te(C(Nt))}(),Ct,Zt)}),Y&&Y(Zt,Mt),q(Z(te),function(Ct){Ct in Zt||R(Zt,Ct,te[Ct])}),Zt.prototype=Yt):(Zt=Te(function(Ct,Nt,Et,ie){A(Ct,Yt);var we=0,Rt=0,zt,jt,Wt;if(!j(Nt))Wt=C(Nt),jt=Wt*bt,zt=new Qt(jt);else if(Pe(Nt)){zt=Nt,Rt=D(Et,bt);var ue=Nt.byteLength;if(ie===void 0){if(ue%bt)throw new Xt(ee);if(jt=ue-Rt,jt<0)throw new Xt(ee)}else if(jt=O(ie)*bt,jt+Rt>ue)throw new Xt(ee);Wt=jt/bt}else return re(Nt)?et(Zt,Nt):h(J,Zt,Nt);for(xt(Ct,{buffer:zt,byteOffset:Rt,byteLength:jt,length:Wt,view:new me(zt)});we255?255:u&255}},function(x,b,r){var u=r(84),d=r(8),h=r(365),p=r(39),y=r(63),T=r(133),$=r(134),A=r(131),E=r(503),R=r(219).aTypedArrayConstructor,I=r(504);x.exports=function(C){var D=h(this),M=p(C),F=arguments.length,z=F>1?arguments[1]:void 0,U=z!==void 0,j=$(M),G,B,V,Y,Z,J,q,nt;if(j&&!A(j))for(q=T(M,j),nt=q.next,M=[];!(J=d(nt,q)).done;)M.push(J.value);for(U&&F>2&&(z=u(z,arguments[2])),B=y(M),V=new(R(D))(B),Y=E(V),G=0;B>G;G++)Z=U?z(M[G],G):M[G],V[G]=Y?I(Z):+Z;return V}},function(x,b,r){var u=r(69);x.exports=function(d){var h=u(d);return h==="BigInt64Array"||h==="BigUint64Array"}},function(x,b,r){var u=r(19),d=TypeError;x.exports=function(h){var p=u(h,"number");if(typeof p=="number")throw new d("Can't convert number to bigint");return BigInt(p)}},function(x,b,r){var u=r(498);u("Float64",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Int8",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Int16",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Int32",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Uint8",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Uint8",function(d){return function(p,y,T){return d(this,p,y,T)}},!0)},function(x,b,r){var u=r(498);u("Uint16",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(498);u("Uint32",function(d){return function(p,y,T){return d(this,p,y,T)}})},function(x,b,r){var u=r(219),d=r(63),h=r(61),p=u.aTypedArray,y=u.exportTypedArrayMethod;y("at",function($){var A=p(this),E=d(A),R=h($),I=R>=0?R:E+R;return I<0||I>=E?void 0:A[I]})},function(x,b,r){var u=r(14),d=r(219),h=r(144),p=u(h),y=d.aTypedArray,T=d.exportTypedArrayMethod;T("copyWithin",function(A,E){return p(y(this),A,E,arguments.length>2?arguments[2]:void 0)})},function(x,b,r){var u=r(219),d=r(83).every,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("every",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(149),h=r(504),p=r(69),y=r(8),T=r(14),$=r(7),A=u.aTypedArray,E=u.exportTypedArrayMethod,R=T("".slice),I=$(function(){var O=0;return new Int8Array(2).fill({valueOf:function(){return O++}}),O!==1});E("fill",function(C){var D=arguments.length;A(this);var M=R(p(this),0,3)==="Big"?h(C):+C;return y(d,this,M,D>1?arguments[1]:void 0,D>2?arguments[2]:void 0)},I)},function(x,b,r){var u=r(219),d=r(83).filter,h=r(518),p=u.aTypedArray,y=u.exportTypedArrayMethod;y("filter",function($){var A=d(p(this),$,arguments.length>1?arguments[1]:void 0);return h(this,A)})},function(x,b,r){var u=r(199),d=r(219).getTypedArrayConstructor;x.exports=function(h,p){return u(d(h),p)}},function(x,b,r){var u=r(219),d=r(83).find,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("find",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(83).findIndex,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("findIndex",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(154).findLast,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("findLast",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(154).findLastIndex,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("findLastIndex",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(83).forEach,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("forEach",function(T){d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(499),d=r(219).exportTypedArrayStaticMethod,h=r(502);d("from",h,u)},function(x,b,r){var u=r(219),d=r(59).includes,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("includes",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(59).indexOf,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("indexOf",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(4),d=r(7),h=r(14),p=r(219),y=r(168),T=r(33),$=T("iterator"),A=u.Uint8Array,E=h(y.values),R=h(y.keys),I=h(y.entries),O=p.aTypedArray,C=p.exportTypedArrayMethod,D=A&&A.prototype,M=!d(function(){D[$].call([1])}),F=!!D&&D.values&&D[$]===D.values&&D.values.name==="values",z=function(){return E(O(this))};C("entries",function(){return I(O(this))},M),C("keys",function(){return R(O(this))},M),C("values",z,M||!F,{name:"values"}),C($,z,M||!F,{name:"values"})},function(x,b,r){var u=r(219),d=r(14),h=u.aTypedArray,p=u.exportTypedArrayMethod,y=d([].join);p("join",function($){return y(h(this),$)})},function(x,b,r){var u=r(219),d=r(94),h=r(175),p=u.aTypedArray,y=u.exportTypedArrayMethod;y("lastIndexOf",function($){var A=arguments.length;return d(h,p(this),A>1?[$,arguments[1]]:[$])})},function(x,b,r){var u=r(219),d=r(83).map,h=u.aTypedArray,p=u.getTypedArrayConstructor,y=u.exportTypedArrayMethod;y("map",function($){return d(h(this),$,arguments.length>1?arguments[1]:void 0,function(A,E){return new(p(A))(E)})})},function(x,b,r){var u=r(219),d=r(499),h=u.aTypedArrayConstructor,p=u.exportTypedArrayStaticMethod;p("of",function(){for(var T=0,$=arguments.length,A=new(h(this))($);$>T;)A[T]=arguments[T++];return A},d)},function(x,b,r){var u=r(219),d=r(181).left,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("reduce",function(T){var $=arguments.length;return d(h(this),T,$,$>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=r(181).right,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("reduceRight",function(T){var $=arguments.length;return d(h(this),T,$,$>1?arguments[1]:void 0)})},function(x,b,r){var u=r(219),d=u.aTypedArray,h=u.exportTypedArrayMethod,p=Math.floor;h("reverse",function(){for(var T=this,$=d(T).length,A=p($/2),E=0,R;E1?arguments[1]:void 0,1),j=T(z);if(D)return d(I,this,j,U);var G=this.length,B=p(j),V=0;if(B+U>G)throw new A("Wrong length");for(;VC;)M[C]=I[C++];return M},$)},function(x,b,r){var u=r(219),d=r(83).some,h=u.aTypedArray,p=u.exportTypedArrayMethod;p("some",function(T){return d(h(this),T,arguments.length>1?arguments[1]:void 0)})},function(x,b,r){var u=r(4),d=r(85),h=r(7),p=r(30),y=r(189),T=r(219),$=r(190),A=r(191),E=r(27),R=r(192),I=T.aTypedArray,O=T.exportTypedArrayMethod,C=u.Uint16Array,D=C&&d(C.prototype.sort),M=!!D&&!(h(function(){D(new C(2),null)})&&h(function(){D(new C(2),{})})),F=!!D&&!h(function(){if(E)return E<74;if($)return $<67;if(A)return!0;if(R)return R<602;var U=new C(516),j=Array(516),G,B;for(G=0;G<516;G++)B=G%4,U[G]=515-G,j[G]=G-2*B+3;for(D(U,function(V,Y){return(V/4|0)-(Y/4|0)}),G=0;G<516;G++)if(U[G]!==j[G])return!0}),z=function(U){return function(j,G){return U!==void 0?+U(j,G)||0:G!==G?-1:j!==j?1:j===0&&G===0?1/j>0&&1/G<0?1:-1:j>G}};O("sort",function(j){return j!==void 0&&p(j),F?D(this,j):y(I(this),z(j))},!F||M)},function(x,b,r){var u=r(219),d=r(64),h=r(60),p=u.aTypedArray,y=u.getTypedArrayConstructor,T=u.exportTypedArrayMethod;T("subarray",function(A,E){var R=p(this),I=R.length,O=h(A,I),C=y(R);return new C(R.buffer,R.byteOffset+O*R.BYTES_PER_ELEMENT,d((E===void 0?I:h(E,I))-O))})},function(x,b,r){var u=r(4),d=r(94),h=r(219),p=r(7),y=r(76),T=u.Int8Array,$=h.aTypedArray,A=h.exportTypedArrayMethod,E=[].toLocaleString,R=!!T&&p(function(){E.call(new T(1))}),I=p(function(){return[1,2].toLocaleString()!==new T([1,2]).toLocaleString()})||!p(function(){T.prototype.toLocaleString.call([1,2])});A("toLocaleString",function(){return d(E,R?y($(this)):$(this),y(arguments))},I)},function(x,b,r){var u=r(197),d=r(219),h=d.aTypedArray,p=d.exportTypedArrayMethod,y=d.getTypedArrayConstructor;p("toReversed",function(){return u(h(this),y(this))})},function(x,b,r){var u=r(219),d=r(14),h=r(30),p=r(199),y=u.aTypedArray,T=u.getTypedArrayConstructor,$=u.exportTypedArrayMethod,A=d(u.TypedArrayPrototype.sort);$("toSorted",function(R){R!==void 0&&h(R);var I=y(this),O=p(T(I),I);return A(O,R)})},function(x,b,r){var u=r(219).exportTypedArrayMethod,d=r(7),h=r(4),p=r(14),y=h.Uint8Array,T=y&&y.prototype||{},$=[].toString,A=p([].join);d(function(){$.call({})})&&($=function(){return A(this)});var E=T.toString!==$;u("toString",$,E)},function(x,b,r){var u=r(206),d=r(219),h=r(503),p=r(61),y=r(504),T=d.aTypedArray,$=d.getTypedArrayConstructor,A=d.exportTypedArrayMethod,E=!!function(){try{new Int8Array(1).with(2,{valueOf:function(){throw 8}})}catch(R){return R===8}}();A("with",function(R,I){var O=T(this),C=p(R),D=h(O)?y(I):+I;return u(O,$(O),C,D)},!E)},function(x,b,r){var u=r(3),d=r(14),h=r(68),p=String.fromCharCode,y=d("".charAt),T=d(/./.exec),$=d("".slice),A=/^[\da-f]{2}$/i,E=/^[\da-f]{4}$/i;u({global:!0},{unescape:function(I){for(var O=h(I),C="",D=O.length,M=0,F,z;M>(-2*_&6)));return nt}})},function(x){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",r=b+"+/",u=b+"-_",d=function(h){for(var p={},y=0;y<64;y++)p[h.charAt(y)]=y;return p};x.exports={i2c:r,c2i:d(r),i2cUrl:u,c2iUrl:d(u)}},function(x,b,r){var u=r(3),d=r(4),h=r(23),p=r(14),y=r(8),T=r(7),$=r(68),A=r(367),E=r(552).i2c,R=h("btoa"),I=p("".charAt),O=p("".charCodeAt),C=!!R&&!T(function(){return R("hi")!=="aGk="}),D=C&&!T(function(){R()}),M=C&&T(function(){return R(null)!=="bnVsbA=="}),F=C&&R.length!==1;u({global:!0,bind:!0,enumerable:!0,forced:!C||D||M||F},{btoa:function(U){if(A(arguments.length,1),C)return y(R,d,$(U));for(var j=$(U),G="",B=0,V=E,Y,Z;I(j,B)||(V="=",B%1);){if(Z=O(j,B+=.75),Z>255)throw new(h("DOMException"))("The string contains characters outside of the Latin1 range","InvalidCharacterError");Y=Y<<8|Z,G+=I(V,63&Y>>8-B%1*8)}return G}})},function(x,b,r){var u=r(4),d=r(555),h=r(556),p=r(160),y=r(43),T=function(A){if(A&&A.forEach!==p)try{y(A,"forEach",p)}catch(E){A.forEach=p}};for(var $ in d)d[$]&&T(u[$]&&u[$].prototype);T(h)},function(x){x.exports={CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0}},function(x,b,r){var u=r(42),d=u("span").classList,h=d&&d.constructor&&d.constructor.prototype;x.exports=h===Object.prototype?void 0:h},function(x,b,r){var u=r(4),d=r(555),h=r(556),p=r(168),y=r(43),T=r(82),$=r(33),A=$("iterator"),E=p.values,R=function(O,C){if(O){if(O[A]!==E)try{y(O,A,E)}catch(M){O[A]=E}if(T(O,C,!0),d[C]){for(var D in p)if(O[D]!==p[D])try{y(O,D,p[D])}catch(M){O[D]=p[D]}}}};for(var I in d)R(u[I]&&u[I].prototype,I);R(h,"DOMTokenList")},function(x,b,r){var u=r(3),d=r(23),h=r(234),p=r(7),y=r(71),T=r(11),$=r(44).f,A=r(47),E=r(77),R=r(38),I=r(211),O=r(46),C=r(125),D=r(119),M=r(559),F=r(122),z=r(51),U=r(6),j=r(36),G="DOMException",B="DATA_CLONE_ERR",V=d("Error"),Y=d(G)||function(){try{var Mt=d("MessageChannel")||h("worker_threads").MessageChannel;new Mt().port1.postMessage(new WeakMap)}catch(Ht){if(Ht.name===B&&Ht.code===25)return Ht.constructor}}(),Z=Y&&Y.prototype,J=V.prototype,q=z.set,nt=z.getterFor(G),rt="stack"in new V(G),_=function(Mt){return R(M,Mt)&&M[Mt].m?M[Mt].c:0},tt=function(){I(this,et);var Ht=arguments.length,re=D(Ht<1?void 0:arguments[0]),se=D(Ht<2?void 0:arguments[1],"Error"),ee=_(se);if(q(this,{type:G,name:se,message:re,code:ee}),U||(this.name=se,this.message=re,this.code=ee),rt){var fe=new V(re);fe.name=G,$(this,"stack",T(1,F(fe.stack,1)))}},et=tt.prototype=y(J),lt=function(Mt){return{enumerable:!0,configurable:!0,get:Mt}},mt=function(Mt){return lt(function(){return nt(this)[Mt]})};U&&(E(et,"code",mt("code")),E(et,"message",mt("message")),E(et,"name",mt("name"))),$(et,"constructor",T(1,tt));var gt=p(function(){return!(new Y instanceof V)}),xt=gt||p(function(){return J.toString!==C||String(new Y(1,2))!=="2: 1"}),yt=gt||p(function(){return new Y(1,"DataCloneError").code!==25}),Ut=gt||Y[B]!==25||Z[B]!==25,Dt=j?xt||yt||Ut:gt;u({global:!0,constructor:!0,forced:Dt},{DOMException:Dt?tt:Y});var Xt=d(G),Qt=Xt.prototype;xt&&(j||Y===Xt)&&A(Qt,"toString",C),yt&&U&&Y===Xt&&E(Qt,"code",lt(function(){return _(O(this).name)}));for(var kt in M)if(R(M,kt)){var me=M[kt],ge=me.s,ae=T(6,me.c);R(Xt,ge)||$(Xt,ge,ae),R(Qt,ge)||$(Qt,ge,ae)}},function(x){x.exports={IndexSizeError:{s:"INDEX_SIZE_ERR",c:1,m:1},DOMStringSizeError:{s:"DOMSTRING_SIZE_ERR",c:2,m:0},HierarchyRequestError:{s:"HIERARCHY_REQUEST_ERR",c:3,m:1},WrongDocumentError:{s:"WRONG_DOCUMENT_ERR",c:4,m:1},InvalidCharacterError:{s:"INVALID_CHARACTER_ERR",c:5,m:1},NoDataAllowedError:{s:"NO_DATA_ALLOWED_ERR",c:6,m:0},NoModificationAllowedError:{s:"NO_MODIFICATION_ALLOWED_ERR",c:7,m:1},NotFoundError:{s:"NOT_FOUND_ERR",c:8,m:1},NotSupportedError:{s:"NOT_SUPPORTED_ERR",c:9,m:1},InUseAttributeError:{s:"INUSE_ATTRIBUTE_ERR",c:10,m:1},InvalidStateError:{s:"INVALID_STATE_ERR",c:11,m:1},SyntaxError:{s:"SYNTAX_ERR",c:12,m:1},InvalidModificationError:{s:"INVALID_MODIFICATION_ERR",c:13,m:1},NamespaceError:{s:"NAMESPACE_ERR",c:14,m:1},InvalidAccessError:{s:"INVALID_ACCESS_ERR",c:15,m:1},ValidationError:{s:"VALIDATION_ERR",c:16,m:0},TypeMismatchError:{s:"TYPE_MISMATCH_ERR",c:17,m:1},SecurityError:{s:"SECURITY_ERR",c:18,m:1},NetworkError:{s:"NETWORK_ERR",c:19,m:1},AbortError:{s:"ABORT_ERR",c:20,m:1},URLMismatchError:{s:"URL_MISMATCH_ERR",c:21,m:1},QuotaExceededError:{s:"QUOTA_EXCEEDED_ERR",c:22,m:1},TimeoutError:{s:"TIMEOUT_ERR",c:23,m:1},InvalidNodeTypeError:{s:"INVALID_NODE_TYPE_ERR",c:24,m:1},DataCloneError:{s:"DATA_CLONE_ERR",c:25,m:1}}},function(x,b,r){var u=r(3),d=r(4),h=r(23),p=r(11),y=r(44).f,T=r(38),$=r(211),A=r(118),E=r(119),R=r(559),I=r(122),O=r(6),C=r(36),D="DOMException",M=h("Error"),F=h(D),z=function(){$(this,U);var tt=arguments.length,et=E(tt<1?void 0:arguments[0]),lt=E(tt<2?void 0:arguments[1],"Error"),mt=new F(et,lt),gt=new M(et);return gt.name=D,y(mt,"stack",p(1,I(gt.stack,1))),A(mt,this,z),mt},U=z.prototype=F.prototype,j="stack"in new M(D),G="stack"in new F(1,2),B=F&&O&&Object.getOwnPropertyDescriptor(d,D),V=!!B&&!(B.writable&&B.configurable),Y=j&&!V&&!G;u({global:!0,constructor:!0,forced:C||Y},{DOMException:Y?z:F});var Z=h(D),J=Z.prototype;if(J.constructor!==Z){C||y(J,"constructor",p(1,Z));for(var q in R)if(T(R,q)){var nt=R[q],rt=nt.s;T(Z,rt)||y(Z,rt,p(6,nt.c))}}},function(x,b,r){var u=r(23),d=r(82),h="DOMException";d(u(h),h)},function(x,b,r){r(563),r(564)},function(x,b,r){var u=r(3),d=r(4),h=r(366).clear;u({global:!0,bind:!0,enumerable:!0,forced:d.clearImmediate!==h},{clearImmediate:h})},function(x,b,r){var u=r(3),d=r(4),h=r(366).set,p=r(565),y=d.setImmediate?p(h,!1):h;u({global:!0,bind:!0,enumerable:!0,forced:d.setImmediate!==y},{setImmediate:y})},function(x,b,r){var u=r(4),d=r(94),h=r(21),p=r(183),y=r(28),T=r(76),$=r(367),A=u.Function,E=/MSIE .\./.test(y)||p==="BUN"&&function(){var R=u.Bun.version.split(".");return R.length<3||R[0]==="0"&&(R[1]<3||R[1]==="3"&&R[2]==="0")}();x.exports=function(R,I){var O=I?2:1;return E?function(C,D){var M=$(arguments.length,1)>O,F=h(C)?C:A(C),z=M?T(arguments,O):[],U=M?function(){d(F,this,z)}:F;return I?R(U,D):R(U)}:R}},function(x,b,r){var u=r(3),d=r(4),h=r(369),p=r(30),y=r(367),T=r(7),$=r(6),A=T(function(){return $&&Object.getOwnPropertyDescriptor(d,"queueMicrotask").value.length!==1});u({global:!0,enumerable:!0,dontCallGetSet:!0,forced:A},{queueMicrotask:function(R){y(arguments.length,1),h(p(R))}})},function(x,b,r){var u=r(3),d=r(4),h=r(77),p=r(6),y=TypeError,T=Object.defineProperty,$=d.self!==d;try{if(p){var A=Object.getOwnPropertyDescriptor(d,"self");($||!A||!A.get||!A.enumerable)&&h(d,"self",{get:function(){return d},set:function(R){if(this!==d)throw new y("Illegal invocation");T(d,"self",{value:R,writable:!0,configurable:!0,enumerable:!0})},configurable:!0,enumerable:!0})}else u({global:!0,simple:!0,forced:$},{self:d})}catch(E){}},function(x,b,r){var u=r(36),d=r(3),h=r(4),p=r(23),y=r(14),T=r(7),$=r(40),A=r(21),E=r(89),R=r(17),I=r(20),O=r(22),C=r(130),D=r(46),M=r(69),F=r(38),z=r(141),U=r(43),j=r(63),G=r(367),B=r(408),V=r(284),Y=r(427),Z=r(429),J=r(233),q=r(123),nt=r(235),rt=h.Object,_=h.Array,tt=h.Date,et=h.Error,lt=h.TypeError,mt=h.PerformanceMark,gt=p("DOMException"),xt=V.Map,yt=V.has,Ut=V.get,Dt=V.set,Xt=Y.Set,Qt=Y.add,kt=Y.has,me=p("Object","keys"),ge=y([].push),ae=y((!0).valueOf),Mt=y(1 .valueOf),Ht=y("".valueOf),re=y(tt.prototype.getTime),se=$("structuredClone"),ee="DataCloneError",fe="Transferring",Pe=function(ut){return!T(function(){var It=new h.Set([7]),Pt=ut(It),Ct=ut(rt(7));return Pt===It||!Pt.has(7)||!I(Ct)||+Ct!=7})&&ut},Me=function(ut,It){return!T(function(){var Pt=new It,Ct=ut({a:Pt,b:Pt});return!(Ct&&Ct.a===Ct.b&&Ct.a instanceof It&&Ct.a.stack===Pt.stack)})},$e=function(ut){return!T(function(){var It=ut(new h.AggregateError([1],se,{cause:3}));return It.name!=="AggregateError"||It.errors[0]!==1||It.message!==se||It.cause!==3})},ce=h.structuredClone,Ae=u||!Me(ce,et)||!Me(ce,gt)||!$e(ce),Te=!ce&&Pe(function(ut){return new mt(se,{detail:ut}).detail}),de=Pe(ce)||Te,bt=function(ut){throw new gt("Uncloneable type: "+ut,ee)},Ft=function(ut,It){throw new gt((It||"Cloning")+" of "+ut+" cannot be properly polyfilled in this engine",ee)},Tt=function(ut,It){return de||Ft(It),de(ut)},qt=function(){var ut;try{ut=new h.DataTransfer}catch(It){try{ut=new h.ClipboardEvent("").clipboardData}catch(Pt){}}return ut&&ut.items&&ut.files?ut:null},te=function(ut,It,Pt){if(yt(It,ut))return Ut(It,ut);var Ct=Pt||M(ut),Nt,Et,ie,we,Rt,zt;if(Ct==="SharedArrayBuffer")de?Nt=de(ut):Nt=ut;else{var jt=h.DataView;!jt&&!A(ut.slice)&&Ft("ArrayBuffer");try{if(A(ut.slice)&&!ut.resizable)Nt=ut.slice(0);else for(Et=ut.byteLength,ie=("maxByteLength"in ut)?{maxByteLength:ut.maxByteLength}:void 0,Nt=new ArrayBuffer(Et,ie),we=new jt(ut),Rt=new jt(Nt),zt=0;zt1&&!R(arguments[1])?D(arguments[1]):void 0,Ct=Pt?Pt.transfer:void 0,Nt,Et;Ct!==void 0&&(Nt=new xt,Et=Ye(Ct,Nt));var ie=Yt(It,Nt);return Et&&Ze(Et),ie}})},function(x,b,r){r(570),r(571)},function(x,b,r){var u=r(3),d=r(4),h=r(565),p=h(d.setInterval,!0);u({global:!0,bind:!0,forced:d.setInterval!==p},{setInterval:p})},function(x,b,r){var u=r(3),d=r(4),h=r(565),p=h(d.setTimeout,!0);u({global:!0,bind:!0,forced:d.setTimeout!==p},{setTimeout:p})},function(x,b,r){r(573)},function(x,b,r){r(455);var u=r(3),d=r(6),h=r(574),p=r(4),y=r(84),T=r(14),$=r(47),A=r(77),E=r(211),R=r(38),I=r(328),O=r(162),C=r(76),D=r(448).codeAt,M=r(575),F=r(68),z=r(82),U=r(367),j=r(576),G=r(51),B=G.set,V=G.getterFor("URL"),Y=j.URLSearchParams,Z=j.getState,J=p.URL,q=p.TypeError,nt=p.parseInt,rt=Math.floor,_=Math.pow,tt=T("".charAt),et=T(/./.exec),lt=T([].join),mt=T(1 .toString),gt=T([].pop),xt=T([].push),yt=T("".replace),Ut=T([].shift),Dt=T("".split),Xt=T("".slice),Qt=T("".toLowerCase),kt=T([].unshift),me="Invalid authority",ge="Invalid scheme",ae="Invalid host",Mt="Invalid port",Ht=/[a-z]/i,re=/[\d+-.a-z]/i,se=/\d/,ee=/^0x/i,fe=/^[0-7]+$/,Pe=/^\d+$/,Me=/^[\da-f]+$/i,$e=/[\0\t\n\r #%/:<>?@[\\\]^|]/,ce=/[\0\t\n\r #/:<>?@[\\\]^|]/,Ae=/^[\u0000-\u0020]+/,Te=/(^|[^\u0000-\u0020])[\u0000-\u0020]+$/,de=/[\t\n\r]/g,bt,Ft=function(ft){var wt=Dt(ft,"."),pt,it,Ot,ye,_t,Ie,rn;if(wt.length&&wt[wt.length-1]===""&&wt.length--,pt=wt.length,pt>4)return ft;for(it=[],Ot=0;Ot1&&tt(ye,0)==="0"&&(_t=et(ee,ye)?16:8,ye=Xt(ye,_t===8?1:2)),ye==="")Ie=0;else{if(!et(_t===10?Pe:_t===8?fe:Me,ye))return ft;Ie=nt(ye,_t)}xt(it,Ie)}for(Ot=0;Ot=_(256,5-pt))return null}else if(Ie>255)return null;for(rn=gt(it),Ot=0;Ot6))return;for(Ie=0;an();){if(rn=null,Ie>0)if(an()==="."&&Ie<4)Ot++;else return;if(!et(se,an()))return;for(;et(se,an());){if(hn=nt(an(),10),rn===null)rn=hn;else{if(rn===0)return;rn=rn*10+hn}if(rn>255)return;Ot++}wt[pt]=wt[pt]*256+rn,Ie++,(Ie===2||Ie===4)&&pt++}if(Ie!==4)return;break}else if(an()===":"){if(Ot++,!an())return}else if(an())return;wt[pt++]=ye}if(it!==null)for(pn=pt-it,pt=7;pt!==0&&pn>0;)ot=wt[pt],wt[pt--]=wt[it+pn-1],wt[it+--pn]=ot;else if(pt!==8)return;return wt},qt=function(ft){for(var wt=null,pt=1,it=null,Ot=0,ye=0;ye<8;ye++)ft[ye]!==0?(Ot>pt&&(wt=it,pt=Ot),it=null,Ot=0):(it===null&&(it=ye),++Ot);return Ot>pt?it:wt},te=function(ft){var wt,pt,it,Ot;if(typeof ft=="number"){for(wt=[],pt=0;pt<4;pt++)kt(wt,ft%256),ft=rt(ft/256);return lt(wt,".")}if(typeof ft=="object"){for(wt="",it=qt(ft),pt=0;pt<8;pt++)Ot&&ft[pt]===0||(Ot&&(Ot=!1),it===pt?(wt+=pt?":":"::",Ot=!0):(wt+=mt(ft[pt],16),pt<7&&(wt+=":")));return"["+wt+"]"}return ft},Zt={},Yt=I({},Zt,{" ":1,'"':1,"<":1,">":1,"`":1}),Ye=I({},Yt,{"#":1,"?":1,"{":1,"}":1}),Ze=I({},Ye,{"/":1,":":1,";":1,"=":1,"@":1,"[":1,"\\":1,"]":1,"^":1,"|":1}),ut=function(ft,wt){var pt=D(ft,0);return pt>32&&pt<127&&!R(wt,ft)?ft:encodeURIComponent(ft)},It={ftp:21,file:null,http:80,https:443,ws:80,wss:443},Pt=function(ft,wt){var pt;return ft.length===2&&et(Ht,tt(ft,0))&&((pt=tt(ft,1))===":"||!wt&&pt==="|")},Ct=function(ft){var wt;return ft.length>1&&Pt(Xt(ft,0,2))&&(ft.length===2||(wt=tt(ft,2))==="/"||wt==="\\"||wt==="?"||wt==="#")},Nt=function(ft){return ft==="."||Qt(ft)==="%2e"},Et=function(ft){return ft=Qt(ft),ft===".."||ft==="%2e."||ft===".%2e"||ft==="%2e%2e"},ie={},we={},Rt={},zt={},jt={},Wt={},ue={},Ee={},Xe={},Je={},nn={},vn={},jn={},Hr={},Ya={},ga={},yr={},Vn={},Wa={},ir={},Wn={},va=function(ft,wt,pt){var it=F(ft),Ot,ye,_t;if(wt){if(ye=this.parse(it),ye)throw new q(ye);this.searchParams=null}else{if(pt!==void 0&&(Ot=new va(pt,!0)),ye=this.parse(it,null,Ot),ye)throw new q(ye);_t=Z(new Y),_t.bindURL(this),this.searchParams=_t}};va.prototype={type:"URL",parse:function(ft,wt,pt){var it=this,Ot=wt||ie,ye=0,_t="",Ie=!1,rn=!1,hn=!1,pn,ot,an,Fn;for(ft=F(ft),wt||(it.scheme="",it.username="",it.password="",it.host=null,it.port=null,it.path=[],it.query=null,it.fragment=null,it.cannotBeABaseURL=!1,ft=yt(ft,Ae,""),ft=yt(ft,Te,"$1")),ft=yt(ft,de,""),pn=O(ft);ye<=pn.length;){switch(ot=pn[ye],Ot){case ie:if(ot&&et(Ht,ot))_t+=Qt(ot),Ot=we;else{if(wt)return ge;Ot=Rt;continue}break;case we:if(ot&&(et(re,ot)||ot==="+"||ot==="-"||ot==="."))_t+=Qt(ot);else if(ot===":"){if(wt&&(it.isSpecial()!==R(It,_t)||_t==="file"&&(it.includesCredentials()||it.port!==null)||it.scheme==="file"&&!it.host))return;if(it.scheme=_t,wt){it.isSpecial()&&It[it.scheme]===it.port&&(it.port=null);return}_t="",it.scheme==="file"?Ot=Hr:it.isSpecial()&&pt&&pt.scheme===it.scheme?Ot=zt:it.isSpecial()?Ot=Ee:pn[ye+1]==="/"?(Ot=jt,ye++):(it.cannotBeABaseURL=!0,xt(it.path,""),Ot=Wa)}else{if(wt)return ge;_t="",Ot=Rt,ye=0;continue}break;case Rt:if(!pt||pt.cannotBeABaseURL&&ot!=="#")return ge;if(pt.cannotBeABaseURL&&ot==="#"){it.scheme=pt.scheme,it.path=C(pt.path),it.query=pt.query,it.fragment="",it.cannotBeABaseURL=!0,Ot=Wn;break}Ot=pt.scheme==="file"?Hr:Wt;continue;case zt:if(ot==="/"&&pn[ye+1]==="/")Ot=Xe,ye++;else{Ot=Wt;continue}break;case jt:if(ot==="/"){Ot=Je;break}else{Ot=Vn;continue}case Wt:if(it.scheme=pt.scheme,ot===bt)it.username=pt.username,it.password=pt.password,it.host=pt.host,it.port=pt.port,it.path=C(pt.path),it.query=pt.query;else if(ot==="/"||ot==="\\"&&it.isSpecial())Ot=ue;else if(ot==="?")it.username=pt.username,it.password=pt.password,it.host=pt.host,it.port=pt.port,it.path=C(pt.path),it.query="",Ot=ir;else if(ot==="#")it.username=pt.username,it.password=pt.password,it.host=pt.host,it.port=pt.port,it.path=C(pt.path),it.query=pt.query,it.fragment="",Ot=Wn;else{it.username=pt.username,it.password=pt.password,it.host=pt.host,it.port=pt.port,it.path=C(pt.path),it.path.length--,Ot=Vn;continue}break;case ue:if(it.isSpecial()&&(ot==="/"||ot==="\\"))Ot=Xe;else if(ot==="/")Ot=Je;else{it.username=pt.username,it.password=pt.password,it.host=pt.host,it.port=pt.port,Ot=Vn;continue}break;case Ee:if(Ot=Xe,ot!=="/"||tt(_t,ye+1)!=="/")continue;ye++;break;case Xe:if(ot!=="/"&&ot!=="\\"){Ot=Je;continue}break;case Je:if(ot==="@"){Ie&&(_t="%40"+_t),Ie=!0,an=O(_t);for(var en=0;en65535)return Mt;it.port=it.isSpecial()&&Bn===It[it.scheme]?null:Bn,_t=""}if(wt)return;Ot=yr;continue}else return Mt;break;case Hr:if(it.scheme="file",ot==="/"||ot==="\\")Ot=Ya;else if(pt&&pt.scheme==="file")switch(ot){case bt:it.host=pt.host,it.path=C(pt.path),it.query=pt.query;break;case"?":it.host=pt.host,it.path=C(pt.path),it.query="",Ot=ir;break;case"#":it.host=pt.host,it.path=C(pt.path),it.query=pt.query,it.fragment="",Ot=Wn;break;default:Ct(lt(C(pn,ye),""))||(it.host=pt.host,it.path=C(pt.path),it.shortenPath()),Ot=Vn;continue}else{Ot=Vn;continue}break;case Ya:if(ot==="/"||ot==="\\"){Ot=ga;break}pt&&pt.scheme==="file"&&!Ct(lt(C(pn,ye),""))&&(Pt(pt.path[0],!0)?xt(it.path,pt.path[0]):it.host=pt.host),Ot=Vn;continue;case ga:if(ot===bt||ot==="/"||ot==="\\"||ot==="?"||ot==="#"){if(!wt&&Pt(_t))Ot=Vn;else if(_t===""){if(it.host="",wt)return;Ot=yr}else{if(Fn=it.parseHost(_t),Fn)return Fn;if(it.host==="localhost"&&(it.host=""),wt)return;_t="",Ot=yr}continue}else _t+=ot;break;case yr:if(it.isSpecial()){if(Ot=Vn,ot!=="/"&&ot!=="\\")continue}else if(!wt&&ot==="?")it.query="",Ot=ir;else if(!wt&&ot==="#")it.fragment="",Ot=Wn;else if(ot!==bt&&(Ot=Vn,ot!=="/"))continue;break;case Vn:if(ot===bt||ot==="/"||ot==="\\"&&it.isSpecial()||!wt&&(ot==="?"||ot==="#")){if(Et(_t)?(it.shortenPath(),ot!=="/"&&!(ot==="\\"&&it.isSpecial())&&xt(it.path,"")):Nt(_t)?ot!=="/"&&!(ot==="\\"&&it.isSpecial())&&xt(it.path,""):(it.scheme==="file"&&!it.path.length&&Pt(_t)&&(it.host&&(it.host=""),_t=tt(_t,0)+":"),xt(it.path,_t)),_t="",it.scheme==="file"&&(ot===bt||ot==="?"||ot==="#"))for(;it.path.length>1&&it.path[0]==="";)Ut(it.path);ot==="?"?(it.query="",Ot=ir):ot==="#"&&(it.fragment="",Ot=Wn)}else _t+=ut(ot,Ye);break;case Wa:ot==="?"?(it.query="",Ot=ir):ot==="#"?(it.fragment="",Ot=Wn):ot!==bt&&(it.path[0]+=ut(ot,Zt));break;case ir:!wt&&ot==="#"?(it.fragment="",Ot=Wn):ot!==bt&&(ot==="'"&&it.isSpecial()?it.query+="%27":ot==="#"?it.query+="%23":it.query+=ut(ot,Zt));break;case Wn:ot!==bt&&(it.fragment+=ut(ot,Yt));break}ye++}},parseHost:function(ft){var wt,pt,it;if(tt(ft,0)==="["){if(tt(ft,ft.length-1)!=="]"||(wt=Tt(Xt(ft,1,-1)),!wt))return ae;this.host=wt}else if(this.isSpecial()){if(ft=M(ft),et($e,ft)||(wt=Ft(ft),wt===null))return ae;this.host=wt}else{if(et(ce,ft))return ae;for(wt="",pt=O(ft),it=0;it1?arguments[1]:void 0,Ot=B(pt,new va(wt,!1,it));d||(pt.href=Ot.serialize(),pt.origin=Ot.getOrigin(),pt.protocol=Ot.getProtocol(),pt.username=Ot.getUsername(),pt.password=Ot.getPassword(),pt.host=Ot.getHost(),pt.hostname=Ot.getHostname(),pt.port=Ot.getPort(),pt.pathname=Ot.getPathname(),pt.search=Ot.getSearch(),pt.searchParams=Ot.getSearchParams(),pt.hash=Ot.getHash())},xn=xr.prototype,Mn=function(ft,wt){return{get:function(){return V(this)[ft]()},set:wt&&function(pt){return V(this)[wt](pt)},configurable:!0,enumerable:!0}};if(d&&(A(xn,"href",Mn("serialize","setHref")),A(xn,"origin",Mn("getOrigin")),A(xn,"protocol",Mn("getProtocol","setProtocol")),A(xn,"username",Mn("getUsername","setUsername")),A(xn,"password",Mn("getPassword","setPassword")),A(xn,"host",Mn("getHost","setHost")),A(xn,"hostname",Mn("getHostname","setHostname")),A(xn,"port",Mn("getPort","setPort")),A(xn,"pathname",Mn("getPathname","setPathname")),A(xn,"search",Mn("getSearch","setSearch")),A(xn,"searchParams",Mn("getSearchParams")),A(xn,"hash",Mn("getHash","setHash"))),$(xn,"toJSON",function(){return V(this).serialize()},{enumerable:!0}),$(xn,"toString",function(){return V(this).serialize()},{enumerable:!0}),J){var Ka=J.createObjectURL,Za=J.revokeObjectURL;Ka&&$(xr,"createObjectURL",y(Ka,J)),Za&&$(xr,"revokeObjectURL",y(Za,J))}z(xr,"URL"),u({global:!0,constructor:!0,forced:!h,sham:!d},{URL:xr})},function(x,b,r){var u=r(7),d=r(33),h=r(6),p=r(36),y=d("iterator");x.exports=!u(function(){var T=new URL("b?a=1&b=2&c=3","https://a"),$=T.searchParams,A=new URLSearchParams("a=1&a=2&b=3"),E="";return T.pathname="c%20d",$.forEach(function(R,I){$.delete("b"),E+=I+R}),A.delete("a",2),A.delete("b",void 0),p&&(!T.toJSON||!A.has("a",1)||A.has("a",2)||!A.has("a",void 0)||A.has("b"))||!$.size&&(p||!h)||!$.sort||T.href!=="https://a/c%20d?a=1&c=3"||$.get("c")!=="3"||String(new URLSearchParams("?a=1"))!=="a=1"||!$[y]||new URL("https://a@b").username!=="a"||new URLSearchParams(new URLSearchParams("a=b")).get("a")!=="b"||new URL("https://\u0442\u0435\u0441\u0442").host!=="xn--e1aybc"||new URL("https://a#\u0431").hash!=="#%D0%B1"||E!=="a1c3"||new URL("https://x",void 0).host!=="x"})},function(x,b,r){var u=r(14),d=2147483647,h=36,p=1,y=26,T=38,$=700,A=72,E=128,R="-",I=/[^\0-\u007E]/,O=/[.\u3002\uFF0E\uFF61]/g,C="Overflow: input needs wider integers to process",D=h-p,M=RangeError,F=u(O.exec),z=Math.floor,U=String.fromCharCode,j=u("".charCodeAt),G=u([].join),B=u([].push),V=u("".replace),Y=u("".split),Z=u("".toLowerCase),J=function(_){for(var tt=[],et=0,lt=_.length;et=55296&&mt<=56319&&et>1,_+=z(_/tt);_>D*y>>1;)_=z(_/D),lt+=h;return z(lt+(D+1)*_/(_+T))},rt=function(_){var tt=[];_=J(_);var et=_.length,lt=E,mt=0,gt=A,xt,yt;for(xt=0;xt<_.length;xt++)yt=_[xt],yt<128&&B(tt,U(yt));var Ut=tt.length,Dt=Ut;for(Ut&&B(tt,R);Dt=lt&&ytz((d-mt)/Qt))throw new M(C);for(mt+=(Xt-lt)*Qt,lt=Xt,xt=0;xt<_.length;xt++){if(yt=_[xt],ytd)throw new M(C);if(yt===lt){for(var kt=mt,me=h;;){var ge=me<=gt?p:me>=gt+y?y:me-gt;if(kt0&&(Rt&jt)!==0;jt>>=1)zt++;return zt},qt=function(Rt){var zt=null;switch(Rt.length){case 1:zt=Rt[0];break;case 2:zt=(Rt[0]&31)<<6|Rt[1]&63;break;case 3:zt=(Rt[0]&15)<<12|(Rt[1]&63)<<6|Rt[2]&63;break;case 4:zt=(Rt[0]&7)<<18|(Rt[1]&63)<<12|(Rt[2]&63)<<6|Rt[3]&63;break}return zt>1114111?null:zt},te=function(Rt){Rt=fe(Rt,Te," ");for(var zt=Rt.length,jt="",Wt=0;Wtzt){jt+="%",Wt++;continue}var Ee=Ft(Rt,Wt+1);if(Ee!==Ee){jt+=ue,Wt++;continue}Wt+=2;var Xe=Tt(Ee);if(Xe===0)ue=ae(Ee);else{if(Xe===1||Xe>4){jt+=de,Wt++;continue}for(var Je=[Ee],nn=1;nnzt||re(Rt,Wt)!=="%"));){var vn=Ft(Rt,Wt+1);if(vn!==vn){Wt+=3;break}if(vn>191||vn<128)break;ee(Je,vn),Wt+=2,nn++}if(Je.length!==Xe){jt+=de;continue}var jn=qt(Je);jn===null?jt+=de:ue=Mt(jn)}}jt+=ue,Wt++}return jt},Zt=/[!'()~]|%20/g,Yt={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"},Ye=function(Rt){return Yt[Rt]},Ze=function(Rt){return fe(ge(Rt),Zt,Ye)},ut=C(function(zt,jt){gt(this,{type:mt,target:xt(zt).entries,index:0,kind:jt})},lt,function(){var zt=yt(this),jt=zt.target,Wt=zt.index++;if(!jt||Wt>=jt.length)return zt.target=null,nt(void 0,!0);var ue=jt[Wt];switch(zt.kind){case"keys":return nt(ue.key,!1);case"values":return nt(ue.value,!1)}return nt([ue.key,ue.value],!1)},!0),It=function(Rt){this.entries=[],this.url=null,Rt!==void 0&&(B(Rt)?this.parseObject(Rt):this.parseQuery(typeof Rt=="string"?re(Rt,0)==="?"?ce(Rt,1):Rt:V(Rt)))};It.prototype={type:lt,bindURL:function(Rt){this.url=Rt,this.update()},parseObject:function(Rt){var zt=this.entries,jt=q(Rt),Wt,ue,Ee,Xe,Je,nn,vn;if(jt)for(Wt=J(Rt,jt),ue=Wt.next;!(Ee=y(ue,Wt)).done;){if(Xe=J(G(Ee.value)),Je=Xe.next,(nn=y(Je,Xe)).done||(vn=y(Je,Xe)).done||!y(Je,Xe).done)throw new me("Expected sequence with length 2");ee(zt,{key:V(nn.value),value:V(vn.value)})}else for(var jn in Rt)z(Rt,jn)&&ee(zt,{key:jn,value:V(Rt[jn])})},parseQuery:function(Rt){if(Rt)for(var zt=this.entries,jt=$e(Rt,"&"),Wt=0,ue,Ee;Wt0?arguments[0]:void 0,jt=gt(this,new It(zt));$||(this.size=jt.entries.length)},Ct=Pt.prototype;if(I(Ct,{append:function(zt,jt){var Wt=xt(this);rt(arguments.length,2),ee(Wt.entries,{key:V(zt),value:V(jt)}),$||this.length++,Wt.updateURL()},delete:function(Rt){for(var zt=xt(this),jt=rt(arguments.length,1),Wt=zt.entries,ue=V(Rt),Ee=jt<2?void 0:arguments[1],Xe=Ee===void 0?Ee:V(Ee),Je=0;JeWt.key?1:-1}),zt.updateURL()},forEach:function(zt){for(var jt=xt(this).entries,Wt=U(zt,arguments.length>1?arguments[1]:void 0),ue=0,Ee;ue1?ie(arguments[1]):{})}}),F(Dt)){var we=function(zt){return M(this,Qt),new Dt(zt,arguments.length>1?ie(arguments[1]):{})};Qt.constructor=we,we.prototype=Qt,u({global:!0,constructor:!0,dontCallGetSet:!0,forced:!0},{Request:we})}}x.exports={URLSearchParams:Pt,getState:xt}},function(x,b,r){var u=r(3),d=r(23),h=r(7),p=r(367),y=r(68),T=r(574),$=d("URL"),A=T&&h(function(){$.canParse()}),E=h(function(){return $.canParse.length!==1});u({target:"URL",stat:!0,forced:!A||E},{canParse:function(I){var O=p(arguments.length,1),C=y(I),D=O<2||arguments[1]===void 0?void 0:y(arguments[1]);try{return!!new $(C,D)}catch(M){return!1}}})},function(x,b,r){var u=r(3),d=r(23),h=r(367),p=r(68),y=r(574),T=d("URL");u({target:"URL",stat:!0,forced:!y},{parse:function(A){var E=h(arguments.length,1),R=p(A),I=E<2||arguments[1]===void 0?void 0:p(arguments[1]);try{return new T(R,I)}catch(O){return null}}})},function(x,b,r){var u=r(3),d=r(8);u({target:"URL",proto:!0,enumerable:!0},{toJSON:function(){return d(URL.prototype.toString,this)}})},function(x,b,r){r(576)},function(x,b,r){var u=r(47),d=r(14),h=r(68),p=r(367),y=URLSearchParams,T=y.prototype,$=d(T.append),A=d(T.delete),E=d(T.forEach),R=d([].push),I=new y("a=1&a=2&b=3");I.delete("a",1),I.delete("b",void 0),I+""!="a=2"&&u(T,"delete",function(O){var C=arguments.length,D=C<2?void 0:arguments[1];if(C&&D===void 0)return A(this,O);var M=[];E(this,function(Y,Z){R(M,{key:Z,value:Y})}),p(C,1);for(var F=h(O),z=h(D),U=0,j=0,G=!1,B=M.length,V;U=W&&(W=X+1);!(k=L[W])&&++W=0;)(s=a[i])&&(o&&s.compareDocumentPosition(o)^4&&o.parentNode.insertBefore(s,o),o=s);return this}function xt(t){t||(t=yt);function e(v,m){return v&&m?t(v.__data__,m.__data__):!v-!m}for(var n=this._groups,a=n.length,i=new Array(a),o=0;oe?1:t>=e?0:NaN}function Ut(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this}function Dt(){return Array.from(this)}function Xt(){for(var t=this._groups,e=0,n=t.length;e=0&&(e=t.slice(0,n))!=="xmlns"&&(t=t.slice(n+1)),ae.hasOwnProperty(e)?{space:ae[e],local:t}:t}function Ht(t){return function(){this.removeAttribute(t)}}function re(t){return function(){this.removeAttributeNS(t.space,t.local)}}function se(t,e){return function(){this.setAttribute(t,e)}}function ee(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function fe(t,e){return function(){var n=e.apply(this,arguments);n==null?this.removeAttribute(t):this.setAttribute(t,n)}}function Pe(t,e){return function(){var n=e.apply(this,arguments);n==null?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function Me(t,e){var n=Mt(t);if(arguments.length<2){var a=this.node();return n.local?a.getAttributeNS(n.space,n.local):a.getAttribute(n)}return this.each((e==null?n.local?re:Ht:typeof e=="function"?n.local?Pe:fe:n.local?ee:se)(n,e))}function $e(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function ce(t){return function(){this.style.removeProperty(t)}}function Ae(t,e,n){return function(){this.style.setProperty(t,e,n)}}function Te(t,e,n){return function(){var a=e.apply(this,arguments);a==null?this.style.removeProperty(t):this.style.setProperty(t,a,n)}}function de(t,e,n){return arguments.length>1?this.each((e==null?ce:typeof e=="function"?Te:Ae)(t,e,n==null?"":n)):bt(this.node(),t)}function bt(t,e){return t.style.getPropertyValue(e)||$e(t).getComputedStyle(t,null).getPropertyValue(e)}function Ft(t){return function(){delete this[t]}}function Tt(t,e){return function(){this[t]=e}}function qt(t,e){return function(){var n=e.apply(this,arguments);n==null?delete this[t]:this[t]=n}}function te(t,e){return arguments.length>1?this.each((e==null?Ft:typeof e=="function"?qt:Tt)(t,e)):this.node()[t]}function Zt(t){return t.trim().split(/^|\s+/)}function Yt(t){return t.classList||new Ye(t)}function Ye(t){this._node=t,this._names=Zt(t.getAttribute("class")||"")}Ye.prototype={add:function(t){var e=this._names.indexOf(t);e<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var e=this._names.indexOf(t);e>=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function Ze(t,e){for(var n=Yt(t),a=-1,i=e.length;++a=0&&(n=e.slice(a+1),e=e.slice(0,a)),{type:e,name:n}})}function Ka(t){return function(){var e=this.__on;if(e){for(var n=0,a=-1,i=e.length,o;n(t(o=new Date(+o)),o),i.ceil=o=>(t(o=new Date(o-1)),e(o,1),t(o),o),i.round=o=>{const s=i(o),l=i.ceil(o);return o-s(e(o=new Date(+o),s==null?1:Math.floor(s)),o),i.range=(o,s,l)=>{const c=[];if(o=i.ceil(o),l=l==null?1:Math.floor(l),!(o0))return c;let f;do c.push(f=new Date(+o)),e(o,l),t(o);while(fen(s=>{if(s>=s)for(;t(s),!o(s);)s.setTime(s-1)},(s,l)=>{if(s>=s)if(l<0)for(;++l<=0;)for(;e(s,-1),!o(s););else for(;--l>=0;)for(;e(s,1),!o(s););}),n&&(i.count=(o,s)=>(an.setTime(+o),Fn.setTime(+s),t(an),t(Fn),Math.floor(n(an,Fn))),i.every=o=>(o=Math.floor(o),!isFinite(o)||!(o>0)?null:o>1?i.filter(a?s=>a(s)%o===0:s=>i.count(0,s)%o===0):i)),i}const Gn=1e3,In=Gn*60,Bn=In*60,or=Bn*24,to=or*7,Ps=or*30,eo=or*365;function Rr(t){return en(e=>{e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)},(e,n)=>{e.setDate(e.getDate()+n*7)},(e,n)=>(n-e-(n.getTimezoneOffset()-e.getTimezoneOffset())*In)/to)}const Ja=Rr(0),Qa=Rr(1),Rf=Rr(2),If=Rr(3),Yr=Rr(4),Of=Rr(5),Cf=Rr(6),I0=Ja.range,O0=Qa.range,C0=Rf.range,P0=If.range,w0=Yr.range,M0=Of.range,D0=Cf.range;function Ir(t){return en(e=>{e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCDate(e.getUTCDate()+n*7)},(e,n)=>(n-e)/to)}const ka=Ir(0),qa=Ir(1),Pf=Ir(2),wf=Ir(3),Wr=Ir(4),Mf=Ir(5),Df=Ir(6),L0=ka.range,N0=qa.range,F0=Pf.range,B0=wf.range,U0=Wr.range,z0=Mf.range,j0=Df.range,pa=en(t=>t.setHours(0,0,0,0),(t,e)=>t.setDate(t.getDate()+e),(t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*In)/or,t=>t.getDate()-1),V0=pa.range,_a=en(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/or,t=>t.getUTCDate()-1),G0=_a.range,ws=en(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/or,t=>Math.floor(t/or)),X0=ws.range,sr=en(t=>{t.setMonth(0,1),t.setHours(0,0,0,0)},(t,e)=>{t.setFullYear(t.getFullYear()+e)},(t,e)=>e.getFullYear()-t.getFullYear(),t=>t.getFullYear());sr.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:en(e=>{e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)},(e,n)=>{e.setFullYear(e.getFullYear()+n*t)});const H0=sr.range,lr=en(t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCFullYear(t.getUTCFullYear()+e)},(t,e)=>e.getUTCFullYear()-t.getUTCFullYear(),t=>t.getUTCFullYear());lr.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:en(e=>{e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCFullYear(e.getUTCFullYear()+n*t)});const Y0=lr.range;function no(t){if(0<=t.y&&t.y<100){var e=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return e.setFullYear(t.y),e}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function ro(t){if(0<=t.y&&t.y<100){var e=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return e.setUTCFullYear(t.y),e}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function ma(t,e,n){return{y:t,m:e,d:n,H:0,M:0,S:0,L:0}}function Lf(t){var e=t.dateTime,n=t.date,a=t.time,i=t.periods,o=t.days,s=t.shortDays,l=t.months,c=t.shortMonths,f=ya(i),g=xa(i),v=ya(o),m=xa(o),S=ya(s),P=xa(s),N=ya(l),L=xa(l),w=ya(c),X=xa(c),W={a:At,A:Gt,b:Bt,B:Kt,c:null,d:Bs,e:Bs,f:rd,g:hd,G:vd,H:td,I:ed,j:nd,L:Us,m:ad,M:id,p:ne,q:le,Q:Hs,s:Ys,S:od,u:sd,U:ld,V:cd,w:ud,W:fd,x:null,X:null,y:dd,Y:gd,Z:pd,"%":Xs},H={a:be,A:Oe,b:Ce,B:He,c:null,d:js,e:js,f:Td,g:Pd,G:Md,H:md,I:yd,j:xd,L:Vs,m:$d,M:Sd,p:Fe,q:dn,Q:Hs,s:Ys,S:Ad,u:Ed,U:bd,V:Rd,w:Id,W:Od,x:null,X:null,y:Cd,Y:wd,Z:Dd,"%":Xs},k={a:dt,A:st,b:Vt,B:vt,c:Q,d:Ns,e:Ns,f:Qf,g:Ls,G:Ds,H:Fs,I:Fs,j:Wf,L:Jf,m:Yf,M:Kf,p:$t,q:Hf,Q:qf,s:_f,S:Zf,u:zf,U:jf,V:Vf,w:Uf,W:Gf,x:St,X:ct,y:Ls,Y:Ds,Z:Xf,"%":kf};W.x=K(n,W),W.X=K(a,W),W.c=K(e,W),H.x=K(n,H),H.X=K(a,H),H.c=K(e,H);function K(Jt,xe){return function(Re){var Lt=[],un=-1,Ge=0,Pn=Jt.length,wn,pe,fn;for(Re instanceof Date||(Re=new Date(+Re));++un53)return null;"w"in Lt||(Lt.w=1),"Z"in Lt?(Ge=ro(ma(Lt.y,0,1)),Pn=Ge.getUTCDay(),Ge=Pn>4||Pn===0?qa.ceil(Ge):qa(Ge),Ge=_a.offset(Ge,(Lt.V-1)*7),Lt.y=Ge.getUTCFullYear(),Lt.m=Ge.getUTCMonth(),Lt.d=Ge.getUTCDate()+(Lt.w+6)%7):(Ge=no(ma(Lt.y,0,1)),Pn=Ge.getDay(),Ge=Pn>4||Pn===0?Qa.ceil(Ge):Qa(Ge),Ge=pa.offset(Ge,(Lt.V-1)*7),Lt.y=Ge.getFullYear(),Lt.m=Ge.getMonth(),Lt.d=Ge.getDate()+(Lt.w+6)%7)}else("W"in Lt||"U"in Lt)&&("w"in Lt||(Lt.w="u"in Lt?Lt.u%7:"W"in Lt?1:0),Pn="Z"in Lt?ro(ma(Lt.y,0,1)).getUTCDay():no(ma(Lt.y,0,1)).getDay(),Lt.m=0,Lt.d="W"in Lt?(Lt.w+6)%7+Lt.W*7-(Pn+5)%7:Lt.w+Lt.U*7-(Pn+6)%7);return"Z"in Lt?(Lt.H+=Lt.Z/100|0,Lt.M+=Lt.Z%100,ro(Lt)):no(Lt)}}function ht(Jt,xe,Re,Lt){for(var un=0,Ge=xe.length,Pn=Re.length,wn,pe;un=Pn)return-1;if(wn=xe.charCodeAt(un++),wn===37){if(wn=xe.charAt(un++),pe=k[wn in Ms?xe.charAt(un++):wn],!pe||(Lt=pe(Jt,Re,Lt))<0)return-1}else if(wn!=Re.charCodeAt(Lt++))return-1}return Lt}function $t(Jt,xe,Re){var Lt=f.exec(xe.slice(Re));return Lt?(Jt.p=g.get(Lt[0].toLowerCase()),Re+Lt[0].length):-1}function dt(Jt,xe,Re){var Lt=S.exec(xe.slice(Re));return Lt?(Jt.w=P.get(Lt[0].toLowerCase()),Re+Lt[0].length):-1}function st(Jt,xe,Re){var Lt=v.exec(xe.slice(Re));return Lt?(Jt.w=m.get(Lt[0].toLowerCase()),Re+Lt[0].length):-1}function Vt(Jt,xe,Re){var Lt=w.exec(xe.slice(Re));return Lt?(Jt.m=X.get(Lt[0].toLowerCase()),Re+Lt[0].length):-1}function vt(Jt,xe,Re){var Lt=N.exec(xe.slice(Re));return Lt?(Jt.m=L.get(Lt[0].toLowerCase()),Re+Lt[0].length):-1}function Q(Jt,xe,Re){return ht(Jt,e,xe,Re)}function St(Jt,xe,Re){return ht(Jt,n,xe,Re)}function ct(Jt,xe,Re){return ht(Jt,a,xe,Re)}function At(Jt){return s[Jt.getDay()]}function Gt(Jt){return o[Jt.getDay()]}function Bt(Jt){return c[Jt.getMonth()]}function Kt(Jt){return l[Jt.getMonth()]}function ne(Jt){return i[+(Jt.getHours()>=12)]}function le(Jt){return 1+~~(Jt.getMonth()/3)}function be(Jt){return s[Jt.getUTCDay()]}function Oe(Jt){return o[Jt.getUTCDay()]}function Ce(Jt){return c[Jt.getUTCMonth()]}function He(Jt){return l[Jt.getUTCMonth()]}function Fe(Jt){return i[+(Jt.getUTCHours()>=12)]}function dn(Jt){return 1+~~(Jt.getUTCMonth()/3)}return{format:function(Jt){var xe=K(Jt+="",W);return xe.toString=function(){return Jt},xe},parse:function(Jt){var xe=at(Jt+="",!1);return xe.toString=function(){return Jt},xe},utcFormat:function(Jt){var xe=K(Jt+="",H);return xe.toString=function(){return Jt},xe},utcParse:function(Jt){var xe=at(Jt+="",!0);return xe.toString=function(){return Jt},xe}}}var Ms={"-":"",_:" ",0:"0"},mn=/^\s*\d+/,Nf=/^%/,Ff=/[\\^$*+?|[\]().{}]/g;function Ne(t,e,n){var a=t<0?"-":"",i=(a?-t:t)+"",o=i.length;return a+(o[e.toLowerCase(),n]))}function Uf(t,e,n){var a=mn.exec(e.slice(n,n+1));return a?(t.w=+a[0],n+a[0].length):-1}function zf(t,e,n){var a=mn.exec(e.slice(n,n+1));return a?(t.u=+a[0],n+a[0].length):-1}function jf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.U=+a[0],n+a[0].length):-1}function Vf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.V=+a[0],n+a[0].length):-1}function Gf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.W=+a[0],n+a[0].length):-1}function Ds(t,e,n){var a=mn.exec(e.slice(n,n+4));return a?(t.y=+a[0],n+a[0].length):-1}function Ls(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.y=+a[0]+(+a[0]>68?1900:2e3),n+a[0].length):-1}function Xf(t,e,n){var a=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return a?(t.Z=a[1]?0:-(a[2]+(a[3]||"00")),n+a[0].length):-1}function Hf(t,e,n){var a=mn.exec(e.slice(n,n+1));return a?(t.q=a[0]*3-3,n+a[0].length):-1}function Yf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.m=a[0]-1,n+a[0].length):-1}function Ns(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.d=+a[0],n+a[0].length):-1}function Wf(t,e,n){var a=mn.exec(e.slice(n,n+3));return a?(t.m=0,t.d=+a[0],n+a[0].length):-1}function Fs(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.H=+a[0],n+a[0].length):-1}function Kf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.M=+a[0],n+a[0].length):-1}function Zf(t,e,n){var a=mn.exec(e.slice(n,n+2));return a?(t.S=+a[0],n+a[0].length):-1}function Jf(t,e,n){var a=mn.exec(e.slice(n,n+3));return a?(t.L=+a[0],n+a[0].length):-1}function Qf(t,e,n){var a=mn.exec(e.slice(n,n+6));return a?(t.L=Math.floor(a[0]/1e3),n+a[0].length):-1}function kf(t,e,n){var a=Nf.exec(e.slice(n,n+1));return a?n+a[0].length:-1}function qf(t,e,n){var a=mn.exec(e.slice(n));return a?(t.Q=+a[0],n+a[0].length):-1}function _f(t,e,n){var a=mn.exec(e.slice(n));return a?(t.s=+a[0],n+a[0].length):-1}function Bs(t,e){return Ne(t.getDate(),e,2)}function td(t,e){return Ne(t.getHours(),e,2)}function ed(t,e){return Ne(t.getHours()%12||12,e,2)}function nd(t,e){return Ne(1+pa.count(sr(t),t),e,3)}function Us(t,e){return Ne(t.getMilliseconds(),e,3)}function rd(t,e){return Us(t,e)+"000"}function ad(t,e){return Ne(t.getMonth()+1,e,2)}function id(t,e){return Ne(t.getMinutes(),e,2)}function od(t,e){return Ne(t.getSeconds(),e,2)}function sd(t){var e=t.getDay();return e===0?7:e}function ld(t,e){return Ne(Ja.count(sr(t)-1,t),e,2)}function zs(t){var e=t.getDay();return e>=4||e===0?Yr(t):Yr.ceil(t)}function cd(t,e){return t=zs(t),Ne(Yr.count(sr(t),t)+(sr(t).getDay()===4),e,2)}function ud(t){return t.getDay()}function fd(t,e){return Ne(Qa.count(sr(t)-1,t),e,2)}function dd(t,e){return Ne(t.getFullYear()%100,e,2)}function hd(t,e){return t=zs(t),Ne(t.getFullYear()%100,e,2)}function gd(t,e){return Ne(t.getFullYear()%1e4,e,4)}function vd(t,e){var n=t.getDay();return t=n>=4||n===0?Yr(t):Yr.ceil(t),Ne(t.getFullYear()%1e4,e,4)}function pd(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+Ne(e/60|0,"0",2)+Ne(e%60,"0",2)}function js(t,e){return Ne(t.getUTCDate(),e,2)}function md(t,e){return Ne(t.getUTCHours(),e,2)}function yd(t,e){return Ne(t.getUTCHours()%12||12,e,2)}function xd(t,e){return Ne(1+_a.count(lr(t),t),e,3)}function Vs(t,e){return Ne(t.getUTCMilliseconds(),e,3)}function Td(t,e){return Vs(t,e)+"000"}function $d(t,e){return Ne(t.getUTCMonth()+1,e,2)}function Sd(t,e){return Ne(t.getUTCMinutes(),e,2)}function Ad(t,e){return Ne(t.getUTCSeconds(),e,2)}function Ed(t){var e=t.getUTCDay();return e===0?7:e}function bd(t,e){return Ne(ka.count(lr(t)-1,t),e,2)}function Gs(t){var e=t.getUTCDay();return e>=4||e===0?Wr(t):Wr.ceil(t)}function Rd(t,e){return t=Gs(t),Ne(Wr.count(lr(t),t)+(lr(t).getUTCDay()===4),e,2)}function Id(t){return t.getUTCDay()}function Od(t,e){return Ne(qa.count(lr(t)-1,t),e,2)}function Cd(t,e){return Ne(t.getUTCFullYear()%100,e,2)}function Pd(t,e){return t=Gs(t),Ne(t.getUTCFullYear()%100,e,2)}function wd(t,e){return Ne(t.getUTCFullYear()%1e4,e,4)}function Md(t,e){var n=t.getUTCDay();return t=n>=4||n===0?Wr(t):Wr.ceil(t),Ne(t.getUTCFullYear()%1e4,e,4)}function Dd(){return"+0000"}function Xs(){return"%"}function Hs(t){return+t}function Ys(t){return Math.floor(+t/1e3)}var Kr,ao,Ws,io,Ks;Ld({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});function Ld(t){return Kr=Lf(t),ao=Kr.format,Ws=Kr.parse,io=Kr.utcFormat,Ks=Kr.utcParse,Kr}var Nd=Object.defineProperty,Zs=Object.getOwnPropertySymbols,Fd=Object.prototype.hasOwnProperty,Bd=Object.prototype.propertyIsEnumerable,Js=(t,e,n)=>e in t?Nd(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,ke=(t,e)=>{for(var n in e||(e={}))Fd.call(e,n)&&Js(t,n,e[n]);if(Zs)for(var n of Zs(e))Bd.call(e,n)&&Js(t,n,e[n]);return t};const Se={button:"bb-button",chart:"bb-chart",empty:"bb-empty",main:"bb-main",target:"bb-target",EXPANDED:"_expanded_"},Ve={arc:"bb-arc",arcLabelLine:"bb-arc-label-line",arcRange:"bb-arc-range",arcs:"bb-arcs",chartArc:"bb-chart-arc",chartArcs:"bb-chart-arcs",chartArcsBackground:"bb-chart-arcs-background",chartArcsTitle:"bb-chart-arcs-title",needle:"bb-needle"},ti={area:"bb-area",areas:"bb-areas"},Tn={axis:"bb-axis",axisX:"bb-axis-x",axisXLabel:"bb-axis-x-label",axisY:"bb-axis-y",axisY2:"bb-axis-y2",axisY2Label:"bb-axis-y2-label",axisYLabel:"bb-axis-y-label",axisXTooltip:"bb-axis-x-tooltip",axisYTooltip:"bb-axis-y-tooltip",axisY2Tooltip:"bb-axis-y2-tooltip"},Kn={bar:"bb-bar",bars:"bb-bars",chartBar:"bb-chart-bar",chartBars:"bb-chart-bars"},cr={candlestick:"bb-candlestick",candlesticks:"bb-candlesticks",chartCandlestick:"bb-chart-candlestick",chartCandlesticks:"bb-chart-candlesticks",valueDown:"bb-value-down",valueUp:"bb-value-up"},$n={chartCircles:"bb-chart-circles",circle:"bb-circle",circles:"bb-circles"},oo={colorPattern:"bb-color-pattern",colorScale:"bb-colorscale"},Or={dragarea:"bb-dragarea",INCLUDED:"_included_"},Ta={funnel:"bb-funnel",chartFunnel:"bb-chart-funnel",chartFunnels:"bb-chart-funnels",funnelBackground:"bb-funnel-background"},Un={chartArcsGaugeMax:"bb-chart-arcs-gauge-max",chartArcsGaugeMin:"bb-chart-arcs-gauge-min",chartArcsGaugeUnit:"bb-chart-arcs-gauge-unit",chartArcsGaugeTitle:"bb-chart-arcs-gauge-title",gaugeValue:"bb-gauge-value"},We={legend:"bb-legend",legendBackground:"bb-legend-background",legendItem:"bb-legend-item",legendItemEvent:"bb-legend-item-event",legendItemHidden:"bb-legend-item-hidden",legendItemPoint:"bb-legend-item-point",legendItemTile:"bb-legend-item-tile"},ur={chartLine:"bb-chart-line",chartLines:"bb-chart-lines",line:"bb-line",lines:"bb-lines"},Zn={eventRect:"bb-event-rect",eventRects:"bb-event-rects",eventRectsMultiple:"bb-event-rects-multiple",eventRectsSingle:"bb-event-rects-single"},qe={focused:"bb-focused",defocused:"bb-defocused",legendItemFocused:"bb-legend-item-focused",xgridFocus:"bb-xgrid-focus",ygridFocus:"bb-ygrid-focus"},on={grid:"bb-grid",gridLines:"bb-grid-lines",xgrid:"bb-xgrid",xgridLine:"bb-xgrid-line",xgridLines:"bb-xgrid-lines",xgrids:"bb-xgrids",ygrid:"bb-ygrid",ygridLine:"bb-ygrid-line",ygridLines:"bb-ygrid-lines",ygrids:"bb-ygrids"},Tr={level:"bb-level",levels:"bb-levels"},Qs={chartRadar:"bb-chart-radar",chartRadars:"bb-chart-radars"},$a={region:"bb-region",regions:"bb-regions"},tn={selectedCircle:"bb-selected-circle",selectedCircles:"bb-selected-circles",SELECTED:"_selected_"},sn={shape:"bb-shape",shapes:"bb-shapes"},ks={brush:"bb-brush",subchart:"bb-subchart"},On={chartText:"bb-chart-text",chartTexts:"bb-chart-texts",text:"bb-text",texts:"bb-texts",title:"bb-title",TextOverlapping:"text-overlapping"},ei={tooltip:"bb-tooltip",tooltipContainer:"bb-tooltip-container",tooltipName:"bb-tooltip-name"},qs={treemap:"bb-treemap",chartTreemap:"bb-chart-treemap",chartTreemaps:"bb-chart-treemaps"},so={buttonZoomReset:"bb-zoom-reset",zoomBrush:"bb-zoom-brush"};var Ue=ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke(ke({},Se),Ve),ti),Tn),Kn),cr),$n),oo),Or),Un),We),ur),Zn),qe),Ta),on),Qs),$a),tn),sn),ks),On),ei),qs),so),Ud={boost_useCssRule:!1,boost_useWorker:!1},zd={color_pattern:[],color_tiles:void 0,color_threshold:{},color_onover:void 0},jd={legend_contents_bindto:void 0,legend_contents_template:"{=TITLE}",legend_equally:!1,legend_hide:!1,legend_inset_anchor:"top-left",legend_inset_x:10,legend_inset_y:0,legend_inset_step:void 0,legend_item_interaction:!0,legend_item_dblclick:!1,legend_item_onclick:void 0,legend_item_onover:void 0,legend_item_onout:void 0,legend_item_tile_width:10,legend_item_tile_height:10,legend_item_tile_r:5,legend_item_tile_type:"rectangle",legend_format:void 0,legend_padding:0,legend_position:"bottom",legend_show:!0,legend_tooltip:!1,legend_usePoint:!1},Vd={bindto:"#chart",background:{},clipPath:!0,svg_classname:void 0,size_width:void 0,size_height:void 0,padding:!0,padding_mode:void 0,padding_left:void 0,padding_right:void 0,padding_top:void 0,padding_bottom:void 0,resize_auto:!0,resize_timer:!0,onclick:void 0,onover:void 0,onout:void 0,onresize:void 0,onresized:void 0,onbeforeinit:void 0,oninit:void 0,onafterinit:void 0,onrendered:void 0,transition_duration:250,plugins:[],render:{},regions:[]},Gd={title_text:void 0,title_padding:{top:0,right:0,bottom:0,left:0},title_position:"center"},Xd={tooltip_show:!0,tooltip_doNotHide:!1,tooltip_grouped:!0,tooltip_format_title:void 0,tooltip_format_name:void 0,tooltip_format_value:void 0,tooltip_position:void 0,tooltip_contents:{},tooltip_init_show:!1,tooltip_init_x:0,tooltip_init_position:void 0,tooltip_linked:!1,tooltip_linked_name:"",tooltip_onshow:()=>{},tooltip_onhide:()=>{},tooltip_onshown:()=>{},tooltip_onhidden:()=>{},tooltip_order:null},Hd={data_x:void 0,data_idConverter:t=>t,data_names:{},data_classes:{},data_type:void 0,data_types:{},data_order:"desc",data_groups:[],data_groupsZeroAs:"positive",data_color:void 0,data_colors:{},data_labels:{},data_labels_backgroundColors:void 0,data_labels_colors:void 0,data_labels_position:{},data_hide:!1,data_filter:void 0,data_onclick:()=>{},data_onover:()=>{},data_onout:()=>{},data_onshown:void 0,data_onhidden:void 0,data_onmin:void 0,data_onmax:void 0,data_url:void 0,data_headers:void 0,data_json:void 0,data_rows:void 0,data_columns:void 0,data_mimeType:"csv",data_keys:void 0,data_empty_label_text:""},Yd={interaction_enabled:!0,interaction_brighten:!0,interaction_inputType_mouse:!0,interaction_inputType_touch:{},interaction_onout:!0},Wd={value:()=>{}};function _s(){for(var t=0,e=arguments.length,n={},a;t=0&&(a=n.slice(i+1),n=n.slice(0,i)),n&&!e.hasOwnProperty(n))throw new Error("unknown type: "+n);return{type:n,name:a}})}ni.prototype=_s.prototype={constructor:ni,on:function(t,e){var n=this._,a=Kd(t+"",n),i,o=-1,s=a.length;if(arguments.length<2){for(;++o0)for(var n=new Array(i),a=0,i,o;a>8&15|e>>4&240,e>>4&15|e&240,(e&15)<<4|e&15,1):n===8?ii(e>>24&255,e>>16&255,e>>8&255,(e&255)/255):n===4?ii(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|e&240,((e&15)<<4|e&15)/255):null):(e=kd.exec(t))?new Dn(e[1],e[2],e[3],1):(e=qd.exec(t))?new Dn(e[1]*255/100,e[2]*255/100,e[3]*255/100,1):(e=_d.exec(t))?ii(e[1],e[2],e[3],e[4]):(e=th.exec(t))?ii(e[1]*255/100,e[2]*255/100,e[3]*255/100,e[4]):(e=eh.exec(t))?ll(e[1],e[2]/100,e[3]/100,1):(e=nh.exec(t))?ll(e[1],e[2]/100,e[3]/100,e[4]):nl.hasOwnProperty(t)?il(nl[t]):t==="transparent"?new Dn(NaN,NaN,NaN,0):null}function il(t){return new Dn(t>>16&255,t>>8&255,t&255,1)}function ii(t,e,n,a){return a<=0&&(t=e=n=NaN),new Dn(t,e,n,a)}function ih(t){return t instanceof Aa||(t=Cr(t)),t?(t=t.rgb(),new Dn(t.r,t.g,t.b,t.opacity)):new Dn}function oi(t,e,n,a){return arguments.length===1?ih(t):new Dn(t,e,n,a==null?1:a)}function Dn(t,e,n,a){this.r=+t,this.g=+e,this.b=+n,this.opacity=+a}fo(Dn,oi,el(Aa,{brighter(t){return t=t==null?ai:Math.pow(ai,t),new Dn(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=t==null?Ea:Math.pow(Ea,t),new Dn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new Dn(Pr(this.r),Pr(this.g),Pr(this.b),si(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:ol,formatHex:ol,formatHex8:oh,formatRgb:sl,toString:sl}));function ol(){return`#${wr(this.r)}${wr(this.g)}${wr(this.b)}`}function oh(){return`#${wr(this.r)}${wr(this.g)}${wr(this.b)}${wr((isNaN(this.opacity)?1:this.opacity)*255)}`}function sl(){const t=si(this.opacity);return`${t===1?"rgb(":"rgba("}${Pr(this.r)}, ${Pr(this.g)}, ${Pr(this.b)}${t===1?")":`, ${t})`}`}function si(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function Pr(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function wr(t){return t=Pr(t),(t<16?"0":"")+t.toString(16)}function ll(t,e,n,a){return a<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new Jn(t,e,n,a)}function cl(t){if(t instanceof Jn)return new Jn(t.h,t.s,t.l,t.opacity);if(t instanceof Aa||(t=Cr(t)),!t)return new Jn;if(t instanceof Jn)return t;t=t.rgb();var e=t.r/255,n=t.g/255,a=t.b/255,i=Math.min(e,n,a),o=Math.max(e,n,a),s=NaN,l=o-i,c=(o+i)/2;return l?(e===o?s=(n-a)/l+(n0&&c<1?0:s,new Jn(s,l,c,t.opacity)}function sh(t,e,n,a){return arguments.length===1?cl(t):new Jn(t,e,n,a==null?1:a)}function Jn(t,e,n,a){this.h=+t,this.s=+e,this.l=+n,this.opacity=+a}fo(Jn,sh,el(Aa,{brighter(t){return t=t==null?ai:Math.pow(ai,t),new Jn(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=t==null?Ea:Math.pow(Ea,t),new Jn(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+(this.h<0)*360,e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,a=n+(n<.5?n:1-n)*e,i=2*n-a;return new Dn(ho(t>=240?t-240:t+120,i,a),ho(t,i,a),ho(t<120?t+240:t-120,i,a),this.opacity)},clamp(){return new Jn(ul(this.h),li(this.s),li(this.l),si(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const t=si(this.opacity);return`${t===1?"hsl(":"hsla("}${ul(this.h)}, ${li(this.s)*100}%, ${li(this.l)*100}%${t===1?")":`, ${t})`}`}}));function ul(t){return t=(t||0)%360,t<0?t+360:t}function li(t){return Math.max(0,Math.min(1,t||0))}function ho(t,e,n){return(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)*255}function fl(t,e,n,a,i){var o=t*t,s=o*t;return((1-3*t+3*o-s)*e+(4-6*o+3*s)*n+(1+3*t+3*o-3*s)*a+s*i)/6}function lh(t){var e=t.length-1;return function(n){var a=n<=0?n=0:n>=1?(n=1,e-1):Math.floor(n*e),i=t[a],o=t[a+1],s=a>0?t[a-1]:2*i-o,l=a()=>t;function dl(t,e){return function(n){return t+n*e}}function uh(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(a){return Math.pow(t+a*e,n)}}function W0(t,e){var n=e-t;return n?dl(t,n>180||n<-180?n-360*Math.round(n/360):n):ci(isNaN(t)?e:t)}function fh(t){return(t=+t)==1?hl:function(e,n){return n-e?uh(e,n,t):ci(isNaN(e)?n:e)}}function hl(t,e){var n=e-t;return n?dl(t,n):ci(isNaN(t)?e:t)}var ui=function t(e){var n=fh(e);function a(i,o){var s=n((i=oi(i)).r,(o=oi(o)).r),l=n(i.g,o.g),c=n(i.b,o.b),f=hl(i.opacity,o.opacity);return function(g){return i.r=s(g),i.g=l(g),i.b=c(g),i.opacity=f(g),i+""}}return a.gamma=t,a}(1);function gl(t){return function(e){var n=e.length,a=new Array(n),i=new Array(n),o=new Array(n),s,l;for(s=0;sn&&(o=e.slice(n,o),l[s]?l[s]+=o:l[++s]=o),(a=a[0])===(i=i[0])?l[s]?l[s]+=i:l[++s]=i:(l[++s]=null,c.push({i:s,x:Qn(a,i)})),n=vo.lastIndex;return n=0&&t._call.call(void 0,e),t=t._next;--kr}function Sl(){Mr=(di=Ca.now())+hi,kr=Ra=0;try{yh()}finally{kr=0,Th(),Mr=0}}function xh(){var t=Ca.now(),e=t-di;e>xl&&(hi-=e,di=t)}function Th(){for(var t,e=fi,n,a=1/0;e;)e._call?(a>e._time&&(a=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:fi=n);Oa=t,mo(a)}function mo(t){if(!kr){Ra&&(Ra=clearTimeout(Ra));var e=t-Mr;e>24?(t<1/0&&(Ra=setTimeout(Sl,t-Ca.now()-hi)),Ia&&(Ia=clearInterval(Ia))):(Ia||(di=Ca.now(),Ia=setInterval(xh,xl)),kr=1,Tl(Sl))}}function Al(t,e,n){var a=new gi;return e=e==null?0:+e,a.restart(i=>{a.stop(),t(i+e)},e,n),a}var $h=ri("start","end","cancel","interrupt"),Sh=[],El=0,bl=1,yo=2,vi=3,Rl=4,xo=5,pi=6;function mi(t,e,n,a,i,o){var s=t.__transition;if(!s)t.__transition={};else if(n in s)return;Ah(t,n,{name:e,index:a,group:i,on:$h,tween:Sh,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:El})}function To(t,e){var n=kn(t,e);if(n.state>El)throw new Error("too late; already scheduled");return n}function er(t,e){var n=kn(t,e);if(n.state>vi)throw new Error("too late; already running");return n}function kn(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function Ah(t,e,n){var a=t.__transition,i;a[e]=n,n.timer=$l(o,0,n.time);function o(f){n.state=bl,n.timer.restart(s,n.delay,n.time),n.delay<=f&&s(f-n.delay)}function s(f){var g,v,m,S;if(n.state!==bl)return c();for(g in a)if(S=a[g],S.name===n.name){if(S.state===vi)return Al(s);S.state===Rl?(S.state=pi,S.timer.stop(),S.on.call("interrupt",t,t.__data__,S.index,S.group),delete a[g]):+gyo&&a.state180?g+=360:g-f>180&&(f+=360),m.push({i:v.push(i(v)+"rotate(",null,a)-2,x:Qn(f,g)})):g&&v.push(i(v)+"rotate("+g+a)}function l(f,g,v,m){f!==g?m.push({i:v.push(i(v)+"skewX(",null,a)-2,x:Qn(f,g)}):g&&v.push(i(v)+"skewX("+g+a)}function c(f,g,v,m,S,P){if(f!==v||g!==m){var N=S.push(i(S)+"scale(",null,",",null,")");P.push({i:N-4,x:Qn(f,v)},{i:N-2,x:Qn(g,m)})}else(v!==1||m!==1)&&S.push(i(S)+"scale("+v+","+m+")")}return function(f,g){var v=[],m=[];return f=t(f),g=t(g),o(f.translateX,f.translateY,g.translateX,g.translateY,v,m),s(f.rotate,g.rotate,v,m),l(f.skewX,g.skewX,v,m),c(f.scaleX,f.scaleY,g.scaleX,g.scaleY,v,m),f=g=null,function(S){for(var P=-1,N=m.length,L;++P=0&&(e=e.slice(0,n)),!e||e==="start"})}function rg(t,e,n){var a,i,o=ng(e)?To:er;return function(){var s=o(this,t),l=s.on;l!==a&&(i=(a=l).copy()).on(e,n),s.on=i}}function ag(t,e){var n=this._id;return arguments.length<2?kn(this.node(),n).on.on(t):this.each(rg(n,t,e))}function ig(t){return function(){var e=this.parentNode;for(var n in this.__transition)if(+n!==t)return;e&&e.removeChild(this)}}function og(){return this.on("end.remove",ig(this._id))}function sg(t){var e=this._name,n=this._id;typeof t!="function"&&(t=p(t));for(var a=this._groups,i=a.length,o=new Array(i),s=0;s()=>t;function Mg(t,{sourceEvent:e,target:n,selection:a,mode:i,dispatch:o}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:e,enumerable:!0,configurable:!0},target:{value:n,enumerable:!0,configurable:!0},selection:{value:a,enumerable:!0,configurable:!0},mode:{value:i,enumerable:!0,configurable:!0},_:{value:o}})}function Dg(t){t.stopImmediatePropagation()}function Eo(t){t.preventDefault(),t.stopImmediatePropagation()}var Ll={name:"drag"},bo={name:"space"},_r={name:"handle"},ta={name:"center"};const{abs:Nl,max:Sn,min:An}=Math;function Fl(t){return[+t[0],+t[1]]}function Ro(t){return[Fl(t[0]),Fl(t[1])]}var xi={name:"x",handles:["w","e"].map(Pa),input:function(t,e){return t==null?null:[[+t[0],e[0][1]],[+t[1],e[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Ti={name:"y",handles:["n","s"].map(Pa),input:function(t,e){return t==null?null:[[e[0][0],+t[0]],[e[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Lg={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(Pa),input:function(t){return t==null?null:Ro(t)},output:function(t){return t}},hr={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Bl={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},Ul={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},Ng={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},Fg={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function Pa(t){return{type:t}}function Bg(t){return!t.ctrlKey&&!t.button}function Ug(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?(t=t.viewBox.baseVal,[[t.x,t.y],[t.x+t.width,t.y+t.height]]):[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function zg(){return navigator.maxTouchPoints||"ontouchstart"in this}function Io(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function jg(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function zl(t){var e=t.__brush;return e?e.dim.output(e.selection):null}function Vg(){return Oo(xi)}function Gg(){return Oo(Ti)}function q0(){return Oo(Lg)}function Oo(t){var e=Ug,n=Bg,a=zg,i=!0,o=ri("start","brush","end"),s=6,l;function c(L){var w=L.property("__brush",N).selectAll(".overlay").data([Pa("overlay")]);w.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",hr.overlay).merge(w).each(function(){var W=Io(this).extent;ot(this).attr("x",W[0][0]).attr("y",W[0][1]).attr("width",W[1][0]-W[0][0]).attr("height",W[1][1]-W[0][1])}),L.selectAll(".selection").data([Pa("selection")]).enter().append("rect").attr("class","selection").attr("cursor",hr.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var X=L.selectAll(".handle").data(t.handles,function(W){return W.type});X.exit().remove(),X.enter().append("rect").attr("class",function(W){return"handle handle--"+W.type}).attr("cursor",function(W){return hr[W.type]}),L.each(f).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",m).filter(a).on("touchstart.brush",m).on("touchmove.brush",S).on("touchend.brush touchcancel.brush",P).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}c.move=function(L,w,X){L.tween?L.on("start.brush",function(W){g(this,arguments).beforestart().start(W)}).on("interrupt.brush end.brush",function(W){g(this,arguments).end(W)}).tween("brush",function(){var W=this,H=W.__brush,k=g(W,arguments),K=H.selection,at=t.input(typeof w=="function"?w.apply(this,arguments):w,H.extent),ht=Qr(K,at);function $t(dt){H.selection=dt===1&&at===null?null:ht(dt),f.call(W),k.brush()}return K!==null&&at!==null?$t:$t(1)}):L.each(function(){var W=this,H=arguments,k=W.__brush,K=t.input(typeof w=="function"?w.apply(W,H):w,k.extent),at=g(W,H).beforestart();qr(W),k.selection=K===null?null:K,f.call(W),at.start(X).brush(X).end(X)})},c.clear=function(L,w){c.move(L,null,w)};function f(){var L=ot(this),w=Io(this).selection;w?(L.selectAll(".selection").style("display",null).attr("x",w[0][0]).attr("y",w[0][1]).attr("width",w[1][0]-w[0][0]).attr("height",w[1][1]-w[0][1]),L.selectAll(".handle").style("display",null).attr("x",function(X){return X.type[X.type.length-1]==="e"?w[1][0]-s/2:w[0][0]-s/2}).attr("y",function(X){return X.type[0]==="s"?w[1][1]-s/2:w[0][1]-s/2}).attr("width",function(X){return X.type==="n"||X.type==="s"?w[1][0]-w[0][0]+s:s}).attr("height",function(X){return X.type==="e"||X.type==="w"?w[1][1]-w[0][1]+s:s})):L.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function g(L,w,X){var W=L.__brush.emitter;return W&&(!X||!W.clean)?W:new v(L,w,X)}function v(L,w,X){this.that=L,this.args=w,this.state=L.__brush,this.active=0,this.clean=X}v.prototype={beforestart:function(){return++this.active===1&&(this.state.emitter=this,this.starting=!0),this},start:function(L,w){return this.starting?(this.starting=!1,this.emit("start",L,w)):this.emit("brush",L),this},brush:function(L,w){return this.emit("brush",L,w),this},end:function(L,w){return--this.active===0&&(delete this.state.emitter,this.emit("end",L,w)),this},emit:function(L,w,X){var W=ot(this.that).datum();o.call(L,this.that,new Mg(L,{sourceEvent:w,target:c,selection:t.output(this.state.selection),mode:X,dispatch:o}),W)}};function m(L){if(l&&!L.touches||!n.apply(this,arguments))return;var w=this,X=L.target.__data__.type,W=(i&&L.metaKey?X="overlay":X)==="selection"?Ll:i&&L.altKey?ta:_r,H=t===Ti?null:Ng[X],k=t===xi?null:Fg[X],K=Io(w),at=K.extent,ht=K.selection,$t=at[0][0],dt,st,Vt=at[0][1],vt,Q,St=at[1][0],ct,At,Gt=at[1][1],Bt,Kt,ne=0,le=0,be,Oe=H&&k&&i&&L.shiftKey,Ce,He,Fe=Array.from(L.touches||[L],pe=>{const fn=pe.identifier;return pe=Xn(pe,w),pe.point0=pe.slice(),pe.identifier=fn,pe});qr(w);var dn=g(w,arguments,!0).beforestart();if(X==="overlay"){ht&&(be=!0);const pe=[Fe[0],Fe[1]||Fe[0]];K.selection=ht=[[dt=t===Ti?$t:An(pe[0][0],pe[1][0]),vt=t===xi?Vt:An(pe[0][1],pe[1][1])],[ct=t===Ti?St:Sn(pe[0][0],pe[1][0]),Bt=t===xi?Gt:Sn(pe[0][1],pe[1][1])]],Fe.length>1&&un(L)}else dt=ht[0][0],vt=ht[0][1],ct=ht[1][0],Bt=ht[1][1];st=dt,Q=vt,At=ct,Kt=Bt;var Jt=ot(w).attr("pointer-events","none"),xe=Jt.selectAll(".overlay").attr("cursor",hr[X]);if(L.touches)dn.moved=Lt,dn.ended=Ge;else{var Re=ot(L.view).on("mousemove.brush",Lt,!0).on("mouseup.brush",Ge,!0);i&&Re.on("keydown.brush",Pn,!0).on("keyup.brush",wn,!0),co(L.view)}f.call(w),dn.start(L,W.name);function Lt(pe){for(const fn of pe.changedTouches||[pe])for(const Ga of Fe)Ga.identifier===fn.identifier&&(Ga.cur=Xn(fn,w));if(Oe&&!Ce&&!He&&Fe.length===1){const fn=Fe[0];Nl(fn.cur[0]-fn[0])>Nl(fn.cur[1]-fn[1])?He=!0:Ce=!0}for(const fn of Fe)fn.cur&&(fn[0]=fn.cur[0],fn[1]=fn.cur[1]);be=!0,Eo(pe),un(pe)}function un(pe){const fn=Fe[0],Ga=fn.point0;var br;switch(ne=fn[0]-Ga[0],le=fn[1]-Ga[1],W){case bo:case Ll:{H&&(ne=Sn($t-dt,An(St-ct,ne)),st=dt+ne,At=ct+ne),k&&(le=Sn(Vt-vt,An(Gt-Bt,le)),Q=vt+le,Kt=Bt+le);break}case _r:{Fe[1]?(H&&(st=Sn($t,An(St,Fe[0][0])),At=Sn($t,An(St,Fe[1][0])),H=1),k&&(Q=Sn(Vt,An(Gt,Fe[0][1])),Kt=Sn(Vt,An(Gt,Fe[1][1])),k=1)):(H<0?(ne=Sn($t-dt,An(St-dt,ne)),st=dt+ne,At=ct):H>0&&(ne=Sn($t-ct,An(St-ct,ne)),st=dt,At=ct+ne),k<0?(le=Sn(Vt-vt,An(Gt-vt,le)),Q=vt+le,Kt=Bt):k>0&&(le=Sn(Vt-Bt,An(Gt-Bt,le)),Q=vt,Kt=Bt+le));break}case ta:{H&&(st=Sn($t,An(St,dt-ne*H)),At=Sn($t,An(St,ct+ne*H))),k&&(Q=Sn(Vt,An(Gt,vt-le*k)),Kt=Sn(Vt,An(Gt,Bt+le*k)));break}}At0&&(dt=st-ne),k<0?Bt=Kt-le:k>0&&(vt=Q-le),W=bo,xe.attr("cursor",hr.selection),un(pe));break}default:return}Eo(pe)}function wn(pe){switch(pe.keyCode){case 16:{Oe&&(Ce=He=Oe=!1,un(pe));break}case 18:{W===ta&&(H<0?ct=At:H>0&&(dt=st),k<0?Bt=Kt:k>0&&(vt=Q),W=_r,un(pe));break}case 32:{W===bo&&(pe.altKey?(H&&(ct=At-ne*H,dt=st+ne*H),k&&(Bt=Kt-le*k,vt=Q+le*k),W=ta):(H<0?ct=At:H>0&&(dt=st),k<0?Bt=Kt:k>0&&(vt=Q),W=_r),xe.attr("cursor",hr[X]),un(pe));break}default:return}Eo(pe)}}function S(L){g(this,arguments).moved(L)}function P(L){g(this,arguments).ended(L)}function N(){var L=this.__brush||{selection:null};return L.extent=Ro(e.apply(this,arguments)),L.dim=t,L}return c.extent=function(L){return arguments.length?(e=typeof L=="function"?L:Ao(Ro(L)),c):e},c.filter=function(L){return arguments.length?(n=typeof L=="function"?L:Ao(!!L),c):n},c.touchable=function(L){return arguments.length?(a=typeof L=="function"?L:Ao(!!L),c):a},c.handleSize=function(L){return arguments.length?(s=+L,c):s},c.keyModifiers=function(L){return arguments.length?(i=!!L,c):i},c.on=function(){var L=o.on.apply(o,arguments);return L===o?c:L},c}function Xg(){return typeof globalThis=="object"&&globalThis!==null&&globalThis.Object===Object&&globalThis||typeof global=="object"&&global!==null&&global.Object===Object&&global||typeof self=="object"&&self!==null&&self.Object===Object&&self||Function("return this")()}function Hg(t){const e=typeof(t==null?void 0:t.requestAnimationFrame)=="function"&&typeof(t==null?void 0:t.cancelAnimationFrame)=="function",n=typeof(t==null?void 0:t.requestIdleCallback)=="function"&&typeof(t==null?void 0:t.cancelIdleCallback)=="function",a=o=>setTimeout(o,1),i=o=>clearTimeout(o);return[e?t.requestAnimationFrame:a,e?t.cancelAnimationFrame:i,n?t.requestIdleCallback:a,n?t.cancelIdleCallback:i]}const Ke=Xg(),gn=Ke==null?void 0:Ke.document,[Yg,_0,jl,t1]=Hg(Ke);var Wg=Object.defineProperty,Vl=Object.getOwnPropertySymbols,Kg=Object.prototype.hasOwnProperty,Zg=Object.prototype.propertyIsEnumerable,Gl=(t,e,n)=>e in t?Wg(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,Xl=(t,e)=>{for(var n in e||(e={}))Kg.call(e,n)&&Gl(t,n,e[n]);if(Vl)for(var n of Vl(e))Zg.call(e,n)&&Gl(t,n,e[n]);return t};const De=t=>t||t===0,ve=t=>typeof t=="function",ze=t=>typeof t=="string",he=t=>typeof t=="number",ln=t=>typeof t=="undefined",Qe=t=>typeof t!="undefined",Co=t=>typeof t=="boolean",Jg=t=>Math.ceil(t/10)*10,$i=t=>Math.ceil(t)+.5,Dr=t=>t[1]-t[0],nr=t=>typeof t=="object",qn=t=>ln(t)||t===null||ze(t)&&t.length===0||nr(t)&&!(t instanceof Date)&&Object.keys(t).length===0||he(t)&&isNaN(t),cn=t=>!qn(t),je=t=>Array.isArray(t),Be=t=>t&&!(t!=null&&t.nodeType)&&nr(t)&&!je(t);function $r(t,e,n){return Qe(t[e])?t[e]:n}function Qg(t,e){let n=!1;return Object.keys(t).forEach(a=>t[a]===e&&(n=!0)),n}function _e(t,e,...n){const a=ve(t);return a&&t.call(e,...n),a}function Si(t,e){let n=0;const a=function(...i){!--n&&e.apply(this,...i)};"duration"in t?t.each(()=>++n).on("end",a):(++n,t.call(a))}function Po(t){return ze(t)?t.replace(/<(script|img)?/ig,"<").replace(/(script)?>/ig,">"):t}function wa(t,e,n=[-1,1],a=!1){if(!(!t||!ze(e)))if(e.indexOf(` +`)===-1)t.text(e);else{const i=[t.text(),e].map(o=>o.replace(/[\s\n]/g,""));if(i[0]!==i[1]){const o=e.split(` +`),s=a?o.length-1:1;t.html(""),o.forEach((l,c)=>{t.append("tspan").attr("x",0).attr("dy",`${c===0?n[0]*s:n[1]}em`).text(l)})}}}function Hl(t){const{x:e,y:n,width:a,height:i}=t.getBBox();return[{x:e,y:n+i},{x:e,y:n},{x:e+a,y:n},{x:e+a,y:n+i}]}function Yl(t){const{width:e,height:n}=t.getBoundingClientRect(),a=Hl(t),i=a[0].x,o=Math.min(a[0].y,a[1].y);return{x:i,y:o,width:e,height:n}}function Hn(t,e){var n;const a=t&&((n=t.touches||t.sourceEvent&&t.sourceEvent.touches)==null?void 0:n[0]);let i=[0,0];try{i=Xn(a||t,e)}catch(o){}return i.map(o=>isNaN(o)?0:o)}function Wl(t){const{event:e,$el:n}=t,a=n.subchart.main||n.main;let i;return e&&e.type==="brush"?i=e.selection:a&&(i=a.select(".bb-brush").node())&&(i=zl(i)),i}function Ma(t){return!("rect"in t)||"rect"in t&&t.hasAttribute("width")&&t.rect.width!==+t.getAttribute("width")?t.rect=t.getBoundingClientRect():t.rect}function gr(t=!0,e=0,n=1e4){const a=Ke.crypto||Ke.msCrypto,i=a?e+a.getRandomValues(new Uint32Array(1))[0]%(n-e+1):Math.floor(Math.random()*(n-e)+e);return t?String(i):i}function wo(t,e,n,a,i){if(n>a)return-1;const o=Math.floor((n+a)/2);let{x:s,w:l=0}=t[o];return i&&(s=t[o].y,l=t[o].h),e>=s&&e<=s+l?o:e{if(Be(n)&&n.constructor){const a=new n.constructor;for(const i in n)a[i]=e(n[i]);return a}return n};return t.map(n=>e(n)).reduce((n,a)=>Xl(Xl({},n),a))}function yn(t={},e){je(e)&&e.forEach(n=>yn(t,n));for(const n in e)/^\d+$/.test(n)||n in t||(t[n]=e[n]);return t}const Cn=t=>t.charAt(0).toUpperCase()+t.slice(1);function qg(t,e="-"){return t.split(e).map((n,a)=>a?n.charAt(0).toUpperCase()+n.slice(1).toLowerCase():n.toLowerCase()).join("")}const Lr=t=>[].slice.call(t);function _g(t,e,n){const{rootSelector:a="",sheet:i}=t,s=`${a} ${(l=>l.replace(/\s?(bb-)/g,".$1").replace(/\.+/g,"."))(e)} {${n.join(";")}}`;return i[i.insertRule?"insertRule":"addRule"](s,i.cssRules.length)}function tv(t){let e=[];return t.forEach(n=>{var a;try{n.cssRules&&n.cssRules.length&&(e=e.concat(Lr(n.cssRules)))}catch(i){(a=Ke.console)==null||a.warn(`Error while reading rules from ${n.href}: ${i.toString()}`)}}),e}function Zl(t){var e,n,a,i,o,s;return{x:((n=(e=Ke.pageXOffset)!=null?e:Ke.scrollX)!=null?n:0)+((a=t.scrollLeft)!=null?a:0),y:((o=(i=Ke.pageYOffset)!=null?i:Ke.scrollY)!=null?o:0)+((s=t.scrollTop)!=null?s:0)}}function Ai(t,e=0,n=0,a=!0){const i=new DOMPoint(e,n),o=t.getScreenCTM(),s=i.matrixTransform(a?o==null?void 0:o.inverse():o);if(a===!1){const l=t.getBoundingClientRect();s.x-=l.x,s.y-=l.y}return s}function Jl(t){const e=t?t.transform:null,n=e&&e.baseVal;return n&&n.numberOfItems?n.getItem(0).matrix:{a:0,b:0,c:0,d:0,e:0,f:0}}function Mo(t){const e=t[0]instanceof Date,n=(e?t.map(Number):t).filter((a,i,o)=>o.indexOf(a)===i);return e?n.map(a=>new Date(a)):n}function Do(t){return t&&t.length?t.reduce((e,n)=>e.concat(n)):[]}function ea(t,...e){if(!e.length||e.length===1&&!e[0])return t;const n=e.shift();return Be(t)&&Be(n)&&Object.keys(n).forEach(a=>{if(!/^(__proto__|constructor|prototype)$/i.test(a)){const i=n[a];Be(i)?(!t[a]&&(t[a]={}),t[a]=ea(t[a],i)):t[a]=je(i)?i.concat():i}}),ea(t,...e)}function na(t,e=!0){let n;return t[0]instanceof Date?n=e?(a,i)=>a-i:(a,i)=>i-a:e&&!t.every(isNaN)?n=(a,i)=>a-i:e||(n=(a,i)=>a>i&&-1||acn(a));return n.length?he(n[0])?n=Math[t](...n):n[0]instanceof Date&&(n=na(n,t==="min")[0]):n=void 0,n}const Ei=(t,e,n=1)=>{const a=[],i=Math.max(0,Math.ceil((e-t)/n))|0;for(let o=t;o{const t=()=>({bubbles:!1,cancelable:!1,screenX:0,screenY:0,clientX:0,clientY:0});try{return new MouseEvent("t"),(e,n,a=t())=>{e.dispatchEvent(new MouseEvent(n,a))}}catch(e){return(n,a,i=t())=>{const o=gn.createEvent("MouseEvent");o.initMouseEvent(a,i.bubbles,i.cancelable,Ke,0,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),n.dispatchEvent(o)}}})(),touch:(t,e,n)=>{const a=new Touch(ea({identifier:Date.now(),target:t,radiusX:2.5,radiusY:2.5,rotationAngle:10,force:.5},n));t.dispatchEvent(new TouchEvent(e,{cancelable:!0,bubbles:!0,shiftKey:!0,touches:[a],targetTouches:[],changedTouches:[a]}))}};function bi(t,e){let n=t;for(const a in e)n=n.replace(new RegExp(`{=${a}}`,"g"),e[a]);return n}function Yn(t){var e;let n;if(t instanceof Date)n=t;else if(ze(t)){const{config:a,format:i}=this;n=(e=i.dataTime(a.data_xFormat)(t))!=null?e:new Date(t)}else he(t)&&!isNaN(t)&&(n=new Date(+t));return(!n||isNaN(+n))&&console&&console.error&&console.error(`Failed to parse x '${t}' to Date object`),n}function Lo(t){const e=t.attr("viewBox");return e?/(\d+(\.\d+)?){3}/.test(e):!1}function nv(t,e,n=!1){const a=!!t.node;let i=!1;for(const[o,s]of Object.entries(e))if(i=a?t.style(o)===s:t.style[o]===s,n===!1&&i)break;return i}function Da(){var t,e;return((t=gn)==null?void 0:t.hidden)===!1||((e=gn)==null?void 0:e.visibilityState)==="visible"}function rv(t,e){const{DocumentTouch:n,matchMedia:a,navigator:i}=Ke,o=a==null?void 0:a("(pointer:coarse)").matches;let s=!1;if(e)if(i&&"maxTouchPoints"in i)s=i.maxTouchPoints>0;else if("ontouchmove"in Ke||n&&gn instanceof n)s=!0;else if(o)s=!0;else{const c=i.userAgent;s=/\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(c)||/\b(Android|Windows Phone|iPad|iPod)\b/i.test(c)}return t&&!o&&(a==null?void 0:a("(pointer:fine)").matches)&&"mouse"||s&&"touch"||"mouse"}function Ql(t,e){e()===!1?Yg(()=>Ql(t,e)):t()}var av=Object.defineProperty,kl=Object.getOwnPropertySymbols,iv=Object.prototype.hasOwnProperty,ov=Object.prototype.propertyIsEnumerable,No=(t,e,n)=>e in t?av(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,ql=(t,e)=>{for(var n in e||(e={}))iv.call(e,n)&&No(t,n,e[n]);if(kl)for(var n of kl(e))ov.call(e,n)&&No(t,n,e[n]);return t},sv=(t,e,n)=>No(t,typeof e!="symbol"?e+"":e,n);const _l=class bf{static setOptions(e){this.data=e.reduce((n,a)=>ql(ql({},n),a),this.data)}constructor(){return kg(Vd,Ud,Hd,zd,Yd,jd,Gd,Xd,bf.data)}};sv(_l,"data",{});let Nr=_l;class lv{constructor(){return{chart:null,main:null,svg:null,axis:{x:null,y:null,y2:null,subX:null},axisTooltip:{x:null,y:null,y2:null},defs:null,tooltip:null,legend:null,title:null,subchart:{main:null,bar:null,line:null,area:null},arcs:null,bar:null,candlestick:null,line:null,area:null,circle:null,radar:null,text:null,grid:{main:null,x:null,y:null},gridLines:{main:null,x:null,y:null},region:{main:null,list:null},eventRect:null,zoomResetBtn:null}}}class cv{constructor(){return{width:0,width2:0,height:0,height2:0,margin:{top:0,bottom:0,left:0,right:0},margin2:{top:0,bottom:0,left:0,right:0},margin3:{top:0,bottom:0,left:0,right:0},arcWidth:0,arcHeight:0,xAxisHeight:0,hasAxis:!1,hasFunnel:!1,hasRadar:!1,hasTreemap:!1,cssRule:{},current:{domain:void 0,width:0,height:0,dataMax:0,maxTickSize:{x:{width:0,height:0,ticks:[],clipPath:0,domain:""},y:{width:0,height:0,domain:""},y2:{width:0,height:0,domain:""}},types:[],needle:void 0},isLegendRight:!1,isLegendInset:!1,isLegendTop:!1,isLegendLeft:!1,legendStep:0,legendItemWidth:0,legendItemHeight:0,legendHasRendered:!1,eventReceiver:{currentIdx:-1,rect:{},data:[],coords:[]},axis:{x:{padding:{left:0,right:0},tickCount:0}},rotatedPadding:{left:30,right:0,top:5},withoutFadeIn:{},inputType:"",datetimeId:"",clip:{id:"",idXAxis:"",idYAxis:"",idXAxisTickTexts:"",idGrid:"",idSubchart:"",path:"",pathXAxis:"",pathYAxis:"",pathXAxisTickTexts:"",pathGrid:""},event:null,dragStart:null,dragging:!1,flowing:!1,cancelClick:!1,mouseover:!1,rendered:!1,transiting:!1,redrawing:!1,resizing:!1,toggling:!1,zooming:!1,hasNegativeValue:!1,hasPositiveValue:!0,orgAreaOpacity:"0.2",orgConfig:{},hiddenTargetIds:[],hiddenLegendIds:[],focusedTargetIds:[],defocusedTargetIds:[],radius:0,innerRadius:0,outerRadius:void 0,innerRadiusRatio:0,gaugeArcWidth:0,radiusExpanded:0,xgridAttr:{x1:null,x2:null,y1:null,y2:null}}}}const tc={element:lv,state:cv};class uv{constructor(){Object.keys(tc).forEach(e=>{this[e]=new tc[e]})}getStore(e){return this[e]}}var fv=Object.defineProperty,dv=(t,e,n)=>e in t?fv(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,hv=(t,e,n)=>dv(t,typeof e!="symbol"?e+"":e,n);const Ln={bubbleBaseLength:"$baseLength",colorPattern:"__colorPattern__",dataMinMax:"$dataMinMax",dataTotalSum:"$dataTotalSum",dataTotalPerIndex:"$totalPerIndex",legendItemTextBox:"legendItemTextBox",radarPoints:"$radarPoints",radarTextWidth:"$radarTextWidth",setOverOut:"setOverOut",callOverOutForTouch:"callOverOutForTouch",textRect:"textRect"};class gv{constructor(){hv(this,"cache",{})}add(e,n,a=!1){return this.cache[e]=a?this.cloneTarget(n):n,this.cache[e]}remove(e){(ze(e)?[e]:e).forEach(n=>delete this.cache[n])}get(e,n=!1){if(n&&Array.isArray(e)){const a=[];for(let i=0,o;o=e[i];i++)o in this.cache&&a.push(this.cloneTarget(this.cache[o]));return a}else{const a=this.cache[e];return De(a)?a:null}}reset(e){const n=this;for(const a in n.cache)(e||/^\$/.test(a))&&(n.cache[a]=null)}cloneTarget(e){return{id:e.id,id_org:e.id_org,values:e.values.map(n=>({x:n.x,value:n.value,id:n.id}))}}}const oe={AREA:"area",AREA_LINE_RANGE:"area-line-range",AREA_SPLINE:"area-spline",AREA_SPLINE_RANGE:"area-spline-range",AREA_STEP:"area-step",AREA_STEP_RANGE:"area-step-range",BAR:"bar",BUBBLE:"bubble",CANDLESTICK:"candlestick",DONUT:"donut",FUNNEL:"funnel",GAUGE:"gauge",LINE:"line",PIE:"pie",POLAR:"polar",RADAR:"radar",SCATTER:"scatter",SPLINE:"spline",STEP:"step",TREEMAP:"treemap"},Fo={AREA:"initArea",AREA_LINE_RANGE:"initArea",AREA_SPLINE:"initArea",AREA_SPLINE_RANGE:"initArea",AREA_STEP:"initArea",AREA_STEP_RANGE:"initArea",BAR:"initBar",BUBBLE:"initCircle",CANDLESTICK:"initCandlestick",DONUT:"initArc",FUNNEL:"initFunnel",GAUGE:"initArc",LINE:"initLine",PIE:"initArc",POLAR:"initPolar",RADAR:"initCircle",SCATTER:"initCircle",SPLINE:"initLine",STEP:"initLine",TREEMAP:"initTreemap"},Sr={Area:[oe.AREA,oe.AREA_SPLINE,oe.AREA_SPLINE_RANGE,oe.AREA_LINE_RANGE,oe.AREA_STEP,oe.AREA_STEP_RANGE],AreaRange:[oe.AREA_SPLINE_RANGE,oe.AREA_LINE_RANGE,oe.AREA_STEP_RANGE],Arc:[oe.PIE,oe.DONUT,oe.GAUGE,oe.POLAR,oe.RADAR],Line:[oe.LINE,oe.SPLINE,oe.AREA,oe.AREA_SPLINE,oe.AREA_SPLINE_RANGE,oe.AREA_LINE_RANGE,oe.STEP,oe.AREA_STEP,oe.AREA_STEP_RANGE],Step:[oe.STEP,oe.AREA_STEP,oe.AREA_STEP_RANGE],Spline:[oe.SPLINE,oe.AREA_SPLINE,oe.AREA_SPLINE_RANGE]};function vv(t){const e=t,{config:n}=e;let a="";if(qn(n.data_type||n.data_types)&&!e[Fo.LINE])a="line";else for(const i in Fo){const o=oe[i];if(e.hasType(o)&&!e[Fo[i]]){a=o;break}}a&&pv(`Please, make sure if %c${qg(a)}`,"module has been imported and specified correctly.","https://github.com/naver/billboard.js/wiki/CHANGELOG-v2#modularization-by-its-functionality")}function pv(t,e,n){var a;const i="[billboard.js]";if((a=Ke.console)==null?void 0:a.error){const s=e?["background:red;color:white;display:block;font-size:15px",e]:[];console.error(`\u274C ${i} ${t}`,"background:red;color:white;display:block;font-size:15px",...s),n&&console.info("%c\u2139\uFE0F","font-size:15px",n)}throw Error(`${i} ${t.replace(/\%c([a-z-]+)/i,"'$1' ")} ${e!=null?e:""}`)}const{setTimeout:mv,clearTimeout:yv}=Ke;function xv(t){const e=[];let n;const a=function(){a.clear(),t===!1?jl(()=>{e.forEach(i=>i())},{timeout:200}):n=mv(()=>{e.forEach(i=>i())},he(t)?t:200)};return a.clear=()=>{n&&(yv(n),n=null)},a.add=i=>e.push(i),a.remove=i=>e.splice(e.indexOf(i),1),a}function ec(){let t=[];const e=function(n,a){function i(){var o;let s=0;for(let l=0,c;c=t[l];l++){if(c===!0||(o=c.empty)!=null&&o.call(c)){s++;continue}if(Da()===!1){s=t.length;break}try{c.transition()}catch(f){s++}}return s===t.length}Ql(()=>{a==null||a()},i)};return e.add=function(n){je(n)?t=t.concat(n):t.push(n)},e}const Bo={};function Tv(t,e){var n;const a=t.toString(),i=a.replace(/(function|[\s\W\n])/g,"").substring(0,15);return i in Bo||(Bo[i]=new Ke.Blob([`${(n=e==null?void 0:e.map(String).join(";"))!=null?n:""} + + self.onmessage=function({data}) { + const result = (${a}).apply(null, data); + self.postMessage(result); + };`],{type:"text/javascript"})),Ke.URL.createObjectURL(Bo[i])}function $v(t){const e=new Ke.Worker(t);return e.onerror=function(n){console.error?console.error(n):console.log(n)},e}function Uo(t=!0,e,n,a){let i=function(...o){const s=e(...o);n(s)};if(Ke.Worker&&t){const o=Tv(e,a),s=$v(o);i=function(...l){s.postMessage(l),s.onmessage=function(c){return Ke.URL.revokeObjectURL(o),n(c.data)}}}return i}var nc={},zo={},jo=34,La=10,Vo=13;function rc(t){return new Function("d","return {"+t.map(function(e,n){return JSON.stringify(e)+": d["+n+'] || ""'}).join(",")+"}")}function Sv(t,e){var n=rc(t);return function(a,i){return e(n(a),i,t)}}function ac(t){var e=Object.create(null),n=[];return t.forEach(function(a){for(var i in a)i in e||n.push(e[i]=i)}),n}function Nn(t,e){var n=t+"",a=n.length;return a9999?"+"+Nn(t,6):Nn(t,4)}function Ev(t){var e=t.getUTCHours(),n=t.getUTCMinutes(),a=t.getUTCSeconds(),i=t.getUTCMilliseconds();return isNaN(t)?"Invalid Date":Av(t.getUTCFullYear(),4)+"-"+Nn(t.getUTCMonth()+1,2)+"-"+Nn(t.getUTCDate(),2)+(i?"T"+Nn(e,2)+":"+Nn(n,2)+":"+Nn(a,2)+"."+Nn(i,3)+"Z":a?"T"+Nn(e,2)+":"+Nn(n,2)+":"+Nn(a,2)+"Z":n||e?"T"+Nn(e,2)+":"+Nn(n,2)+"Z":"")}function ic(t){var e=new RegExp('["'+t+` +\r]`),n=t.charCodeAt(0);function a(v,m){var S,P,N=i(v,function(L,w){if(S)return S(L,w-1);P=L,S=m?Sv(L,m):rc(L)});return N.columns=P||[],N}function i(v,m){var S=[],P=v.length,N=0,L=0,w,X=P<=0,W=!1;v.charCodeAt(P-1)===La&&--P,v.charCodeAt(P-1)===Vo&&--P;function H(){if(X)return zo;if(W)return W=!1,nc;var K,at=N,ht;if(v.charCodeAt(at)===jo){for(;N++=P?X=!0:(ht=v.charCodeAt(N++))===La?W=!0:ht===Vo&&(W=!0,v.charCodeAt(N)===La&&++N),v.slice(at+1,K-1).replace(/""/g,'"')}for(;N0){if(typeof e[s-1]=="undefined"&&(e[s-1]={}),typeof o=="undefined")throw new Error(`Source data is missing a component at (${a}, ${s})!`);e[s-1][i]=o}})}),e}function Xo(t){const e=t[0],n=[];return t.forEach(function(a,i){if(i>0){const o={};a.forEach(function(s,l){if(typeof s=="undefined")throw new Error(`Source data is missing a component at (${i}, ${l})!`);o[e[l]]=s}),n.push(o)}}),n}function oc(t,e){const n=[];let a,i;if(Array.isArray(t)){const o=function(s,l){if(s[l]!==void 0)return s[l];const f=l.replace(/\[(\w+)\]/g,".$1").replace(/^\./,"").split(".");let g=s;return f.some(function(v){return!(g=g&&v in g?g[v]:void 0)}),g};e.x?a=e.value.concat(e.x):a=e.value,n.push(a),t.forEach(function(s){const l=a.map(function(c){let f=o(s,c);return typeof f=="undefined"&&(f=null),f});n.push(l)}),i=Xo(n)}else Object.keys(t).forEach(function(o){var s;const l=t[o].concat();(s=l.unshift)==null||s.call(l,o),n.push(l)}),i=Go(n);return i}function Cv(t,e="csv",n,a,i){const o=new XMLHttpRequest,s={csv:Pv,tsv:wv,json:oc};o.open("GET",t),n&&Object.keys(n).forEach(function(l){o.setRequestHeader(l,n[l])}),o.onreadystatechange=function(){if(o.readyState===4)if(o.status===200){const l=o.responseText;l&&i.call(this,s[e](e==="json"?JSON.parse(l):l,a))}else throw new Error(`${t}: Something went wrong loading!`)},o.send()}function sc(t,e){const n=t.rows(e);let a;return n.length===1?(a=[{}],n[0].forEach(i=>{a[0][i]=null})):a=t.parse(e),a}function Pv(t){return sc({rows:Rv,parse:bv},t)}function wv(t){return sc({rows:Ov,parse:Iv},t)}function lc(t,e){const n=t||(e==null?void 0:e.data_keys);return n!=null&&n.x&&(e.data_x=n.x),n}var Mv={convertData(t,e){const{config:n}=this,a=n.boost_useWorker;let i=t;if(t.bindto&&(i={},["url","mimeType","headers","keys","json","keys","rows","columns"].forEach(o=>{const s=`data_${o}`;s in t&&(i[o]=t[s])})),i.url&&e)Cv(i.url,i.mimeType,i.headers,lc(i.keys,n),e);else if(i.json)Uo(a,oc,e,[Go,Xo])(i.json,lc(i.keys,n));else if(i.rows)Uo(a,Xo,e)(i.rows);else if(i.columns)Uo(a,Go,e)(i.columns);else if(t.bindto)throw Error("url or json or rows or columns is required.")},convertDataToTargets(t,e){const n=this,{axis:a,config:i,state:o}=n,s=i.data_type;let l=!1,c=!1,f=!1;a&&(l=a.isCategorized(),c=a.isTimeSeries(),f=a.isCustomX());const g=Object.keys(t[0]||{}),v=g.length?g.filter(n.isNotX,n):[],m=g.length?g.filter(n.isX,n):[];let S;v.forEach(N=>{const L=this.getXKey(N);f||c?m.indexOf(L)>=0?S=(e&&n.data.xs[N]||[]).concat(t.map(w=>w[L]).filter(De).map((w,X)=>n.generateTargetX(w,N,X))):i.data_x?S=this.getOtherTargetXs():cn(i.data_xs)&&(S=n.getXValuesOfXKey(L,n.data.targets)):S=t.map((w,X)=>X),S&&(this.data.xs[N]=S)}),v.forEach(N=>{if(!this.data.xs[N])throw new Error(`x is not defined for id = "${N}".`)});const P=v.map((N,L)=>{const w=i.data_idConverter.bind(n.api)(N),X=n.getXKey(N),W=f&&l,H=W&&t.map(at=>at.x).every(at=>i.axis_x_categories.indexOf(at)>-1),k=t.__append__,K=X===null&&k?n.api.data.values(N).length:0;return{id:w,id_org:N,values:t.map((at,ht)=>{const $t=at[X];let dt=at[N],st;return dt=dt!==null&&!isNaN(dt)&&!Be(dt)?+dt:je(dt)||Be(dt)?dt:null,(W||o.hasRadar)&&L===0&&!ln($t)?(!H&&L===0&&ht===0&&!k&&(i.axis_x_categories=[]),st=i.axis_x_categories.indexOf($t),st===-1&&(st=i.axis_x_categories.length,i.axis_x_categories.push($t))):st=n.generateTargetX($t,N,K+ht),(ln(dt)||n.data.xs[N].length<=ht)&&(st=void 0),{x:st,value:dt,id:w,index:-1}}).filter(at=>Qe(at.x))}});if(P.forEach(N=>{var L;i.data_xSort&&(N.values=N.values.sort((w,X)=>{const W=w.x||w.x===0?w.x:1/0,H=X.x||X.x===0?X.x:1/0;return W-H})),N.values.forEach((w,X)=>w.index=X),(L=n.data.xs[N.id])==null||L.sort((w,X)=>w-X)}),o.hasNegativeValue=n.hasNegativeValueInTargets(P),o.hasPositiveValue=n.hasPositiveValueInTargets(P),s&&n.isValidChartType(s)){const N=n.mapToIds(P).filter(L=>!(L in i.data_types)||!n.isValidChartType(i.data_types[L]));n.setTargetType(N,s)}return P.forEach(N=>n.cache.add(N.id_org,N,!0)),P}},Dv={isX(t){const e=this,{config:n}=e,a=n.data_x&&t===n.data_x,i=cn(n.data_xs)&&Qg(n.data_xs,t);return a||i},isNotX(t){return!this.isX(t)},isStackNormalized(){const{config:t}=this;return!!(t.data_stack_normalize&&t.data_groups.length)},isGrouped(t){const e=this.config.data_groups;return t?e.some(n=>n.indexOf(t)>=0&&n.length>1):e.length>0},getXKey(t){const e=this,{config:n}=e;return n.data_x?n.data_x:cn(n.data_xs)?n.data_xs[t]:null},getXValuesOfXKey(t,e){const n=this,a=e&&cn(e)?n.mapToIds(e):[];let i;return a.forEach(o=>{n.getXKey(o)===t&&(i=n.data.xs[o])}),i},getIndexByX(t,e){const n=this;return e?e.indexOf(ze(t)?t:+t):(n.filterByX(n.data.targets,t)[0]||{index:null}).index},getXValue(t,e){const n=this;return t in n.data.xs&&n.data.xs[t]&&De(n.data.xs[t][e])?n.data.xs[t][e]:e},getOtherTargetXs(){const t=this,e=Object.keys(t.data.xs);return e.length?t.data.xs[e[0]]:null},getOtherTargetX(t){const e=this.getOtherTargetXs();return e&&t{n.data_xs[a]=t[a]})},isMultipleX(){return!this.config.axis_x_forceAsSingle&&(cn(this.config.data_xs)||this.hasType("bubble")||this.hasType("scatter"))},addName(t){const e=this,{config:n}=e;let a;return t&&(a=n.data_names[t.id],t.name=a!==void 0?a:t.id),t},getAllValuesOnIndex(t,e=!1){const n=this;let a=n.filterTargetsToShow(n.data.targets).map(i=>n.addName(n.getValueOnIndex(i.values,t)));return e&&(a=a.filter(i=>i&&"value"in i&&De(i.value))),a},getValueOnIndex(t,e){const n=t.filter(a=>a.index===e);return n.length?n[0]:null},updateTargetX(t,e){const n=this;t.forEach(a=>{a.values.forEach((i,o)=>{i.x=n.generateTargetX(e[o],a.id,o)}),n.data.xs[a.id]=e})},updateTargetXs(t,e){const n=this;t.forEach(a=>{e[a.id]&&n.updateTargetX([a],e[a.id])})},generateTargetX(t,e,n){const a=this,{axis:i}=a;let o=i!=null&&i.isCategorized()?n:t||n;if(i!=null&&i.isTimeSeries()){const s=Yn.bind(a);o=s(t||a.getXValue(e,n))}else i!=null&&i.isCustomX()&&!(i!=null&&i.isCategorized())&&(o=De(t)?+t:a.getXValue(e,n));return o},updateXs(t){t.length&&(this.axis.xs=t.map(e=>e.x))},getPrevX(t){const e=this.axis.xs[t-1];return Qe(e)?e:null},getNextX(t){const e=this.axis.xs[t+1];return Qe(e)?e:null},getBaseValue(t){const e=this,{hasAxis:n}=e.state;let{value:a}=t;return a&&n&&(e.isAreaRangeType(t)?a=e.getRangedData(t,"mid"):e.isBubbleZType(t)&&(a=e.getBubbleZData(a,"y"))),a},getMinMaxValue(t){const e=this.getBaseValue.bind(this);let n,a;return(t||this.data.targets.map(i=>i.values)).forEach((i,o)=>{const s=i.map(e).filter(he);n=Math.min(o?n:1/0,...s),a=Math.max(o?a:-1/0,...s)}),{min:n,max:a}},getMinMaxData(){const t=this,e=Ln.dataMinMax;let n=t.cache.get(e);if(!n){const a=t.data.targets.map(l=>l.values),i=t.getMinMaxValue(a);let o=[],s=[];a.forEach(l=>{const c=t.getFilteredDataByValue(l,i.min),f=t.getFilteredDataByValue(l,i.max);c.length&&(o=o.concat(c)),f.length&&(s=s.concat(f))}),t.cache.add(e,n={min:o,max:s})}return n},getTotalPerIndex(){const t=this,e=Ln.dataTotalPerIndex;let n=t.cache.get(e);return(t.config.data_groups.length||t.isStackNormalized())&&!n&&(n=[],t.data.targets.forEach(a=>{a.values.forEach((i,o)=>{n[o]||(n[o]=0),n[o]+=he(i.value)?i.value:0})})),n},getTotalDataSum(t){const e=this,n=Ln.dataTotalSum;let a=e.cache.get(n);if(!he(a)){const i=Do(e.data.targets.map(o=>o.values)).map(o=>o.value);a=i.length?i.reduce((o,s)=>o+s):0,e.cache.add(n,a)}return t&&(a-=e.getHiddenTotalDataSum()),a},getHiddenTotalDataSum(){const t=this,{api:e,state:{hiddenTargetIds:n}}=t;let a=0;return n.length&&(a=e.data.values.bind(e)(n).reduce((i,o)=>i+o)),a},getFilteredDataByValue(t,e){return t.filter(n=>this.getBaseValue(n)===e)},getMaxDataCount(){return Math.max(...this.data.targets.map(t=>t.values.length),0)},getMaxDataCountTarget(){let t=this.filterTargetsToShow()||[];const e=t.length,n=this.config.axis_x_inverted;return e>1?(t=t.map(a=>a.values).reduce((a,i)=>a.concat(i)).map(a=>a.x),t=na(Mo(t)).map((a,i,o)=>({x:a,index:n?o.length-i-1:i}))):e&&(t=t[0].values.concat()),t},mapToIds(t){return t.map(e=>e.id)},mapToTargetIds(t){const e=this;return t?je(t)?t.concat():[t]:e.mapToIds(e.data.targets)},hasTarget(t,e){const n=this.mapToIds(t);for(let a=0,i;i=n[a];a++)if(i===e)return!0;return!1},isTargetToShow(t){return this.state.hiddenTargetIds.indexOf(t)<0},isLegendToShow(t){return this.state.hiddenLegendIds.indexOf(t)<0},filterTargetsToShow(t){const e=this;return(t||e.data.targets).filter(n=>e.isTargetToShow(n.id))},mapTargetsToUniqueXs(t){const e=this,{axis:n}=e;let a=[];return t!=null&&t.length&&(a=Mo(Do(t.map(i=>i.values.map(o=>+o.x)))),a=n!=null&&n.isTimeSeries()?a.map(i=>new Date(+i)):a.map(Number)),na(a)},addTargetIds(t,e){const{state:n}=this;(je(e)?e:[e]).forEach(i=>{n[t].indexOf(i)<0&&n[t].push(i)})},removeTargetIds(t,e){const{state:n}=this;(je(e)?e:[e]).forEach(i=>{const o=n[t].indexOf(i);o>=0&&n[t].splice(o,1)})},addHiddenTargetIds(t){this.addTargetIds("hiddenTargetIds",t)},removeHiddenTargetIds(t){this.removeTargetIds("hiddenTargetIds",t)},addHiddenLegendIds(t){this.addTargetIds("hiddenLegendIds",t)},removeHiddenLegendIds(t){this.removeTargetIds("hiddenLegendIds",t)},getValuesAsIdKeyed(t){const e=this,{hasAxis:n}=e.state,a={},i=e.isMultipleX(),o=i?e.mapTargetsToUniqueXs(t).map(s=>ze(s)?s:+s):null;return t.forEach(s=>{const l=[];s.values.filter(({value:c})=>De(c)||c===null).forEach(c=>{let{value:f}=c;f!==null&&e.isCandlestickType(c)&&(f=je(f)?f.slice(0,4):[f.open,f.high,f.low,f.close]),je(f)?l.push(...f):Be(f)&&"high"in f?l.push(...Object.values(f)):e.isBubbleZType(c)?l.push(n&&e.getBubbleZData(f,"y")):i?l[e.getIndexByX(c.x,o)]=f:l.push(f)}),a[s.id]=l}),a},checkValueInTargets(t,e){const n=Object.keys(t);let a;for(let i=0;i1},hasNegativeValueInTargets(t){return this.checkValueInTargets(t,e=>e<0)},hasPositiveValueInTargets(t){return this.checkValueInTargets(t,e=>e>0)},orderTargets(t){const e=this,n=[...t],a=e.getSortCompareFn();return a&&n.sort(a),n},getSortCompareFn(t=!1){const e=this,{config:n}=e,a=n.data_order,i=/asc/i.test(a),o=/desc/i.test(a);let s;if(i||o){const l=(f,g)=>f+Math.abs(g.value),c=f=>he(f)?f:"values"in f?f.values.reduce(l,0):f.value;s=(f,g)=>{const v=c(f),m=c(g);return t?i?v-m:m-v:i?m-v:v-m}}else ve(a)&&(s=a.bind(e.api));return s||null},filterByX(t,e){return Do(t.map(n=>n.values)).filter(n=>n.x-e===0)},filterRemoveNull(t){return t.filter(e=>De(this.getBaseValue(e)))},filterByXDomain(t,e){return t.map(n=>({id:n.id,id_org:n.id_org,values:n.values.filter(a=>e[0]<=a.x&&a.x<=e[1])}))},hasDataLabel(){const t=this.config.data_labels;return Co(t)&&t||nr(t)&&cn(t)},hasNullDataValue(t){return t.some(({value:e})=>e===null)},getDataIndexFromEvent(t){const e=this,{$el:n,config:a,state:{hasRadar:i,inputType:o,eventReceiver:{coords:s,rect:l}}}=e;let c;if(i){let f=t.target;/tspan/i.test(f.tagName)&&(f=f.parentNode);const g=ot(f).datum();c=g&&Object.keys(g).length===1?g.index:void 0}else{const f=a.axis_rotated,g=Zl(n.chart.node()),v=o==="touch"&&t.changedTouches?t.changedTouches[0]:t;let m=f?v.clientY+g.y:v.clientX+g.x;if(Lo(n.svg)){const S=[m,0];f&&S.reverse(),m=Ai(n.eventRect.node(),...S)[f?"y":"x"]}else m-=f?l.top:l.left;c=wo(s,m,0,s.length-1,f)}return c},getDataLabelLength(t,e,n){const a=this,i=[0,0],o=1.3;return a.$el.chart.select("svg").selectAll(".dummy").data([t,e]).enter().append("text").text(s=>a.dataLabelFormat(s.id)(s)).each(function(s,l){i[l]=this.getBoundingClientRect()[n]*o}).remove(),i},isNoneArc(t){return this.hasTarget(this.data.targets,t.id)},isArc(t){return"data"in t&&this.hasTarget(this.data.targets,t.data.id)},findSameXOfValues(t,e){const n=t[e].x,a=[];let i;for(i=e-1;i>=0&&n===t[i].x;i--)a.push(t[i]);for(i=e;in.findClosest(i.values,e));return n.findClosest(a,e)},findClosest(t,e){const n=this,{$el:{main:a}}=n,i=t.filter(l=>l&&De(l.value));let o,s;return i.filter(l=>n.isBarType(l.id)||n.isCandlestickType(l.id)).forEach(l=>{const c=n.isBarType(l.id)?`.${Kn.chartBar}.${Se.target}${n.getTargetSelectorSuffix(l.id)} .${Kn.bar}-${l.index}`:`.${cr.chartCandlestick}.${Se.target}${n.getTargetSelectorSuffix(l.id)} .${cr.candlestick}-${l.index} path`;!s&&n.isWithinBar(a.select(c).node())&&(s=l)}),i.filter(l=>!n.isBarType(l.id)&&!n.isCandlestickType(l.id)).forEach(l=>{const c=n.dist(l,e);o=n.getPointSensitivity(l),c{const{x:i,id:o}=a;n.push({x:i,id:o,value:a.value[0]}),n.push({x:i,id:o,value:a.value[2]})}),n},updateDataAttributes(t,e){const n=this,{config:a}=n,i=a[`data_${t}`];return ln(e)||(Object.keys(e).forEach(o=>{i[o]=e[o]}),n.redraw({withLegend:!0})),i},getRangedData(t,e="",n="areaRange"){const a=t==null?void 0:t.value;if(je(a)){if(n==="bar")return a.reduce((i,o)=>o-i);{const i={areaRange:["high","mid","low"],candlestick:["open","high","low","close","volume"]}[n].indexOf(e);return i>=0&&a?a[i]:void 0}}else if(a&&e)return a[e];return a},setRatioForGroupedData(t){const e=this,{config:n}=e;if(n.data_groups.length&&t.some(a=>e.isGrouped(a.id))){const a=i=>e.getRatio("index",i,!0);t.forEach(i=>{"values"in i?i.values.forEach(a):a(i)})}},getRatio(t,e,n=!1){const a=this,{config:i,state:o}=a,s=a.api;let l=0;if(e&&s.data.shown().length)if(l=e.ratio||e.value,t==="arc")if(a.pie.padAngle()())l=e.value/a.getTotalDataSum(!0);else{const c=i.gauge_fullCircle?a.getArcLength():a.getStartingAngle()*-2,f=a.hasType("gauge")?c:Math.PI*2;l=(e.endAngle-e.startAngle)/f}else if(t==="index"){const c=s.data.values.bind(s);let f=this.getTotalPerIndex();if(o.hiddenTargetIds.length){let v=c(o.hiddenTargetIds,!1);v.length&&(v=v.reduce((m,S)=>m.map((P,N)=>(he(P)?P:0)+S[N])),f=f.map((m,S)=>m-v[S]))}const g=f[e.index];e.ratio=he(e.value)&&f&&g?e.value/g:0,l=e.ratio}else if(t==="radar")l=parseFloat(String(Math.max(e.value,0)))/o.current.dataMax*i.radar_size_ratio;else if(t==="bar"){const f=a.getYScaleById.bind(a)(e.id).domain().reduce((g,v)=>v-g);l=f===0?0:Math.abs(a.getRangedData(e,null,t)/f)}else t==="treemap"&&(l/=a.getTotalDataSum(!0));return n&&l?l*100:l},updateDataIndexByX(t){const e=this,n=t.reduce((a,i,o)=>(a[Number(i.x)]=o,a),{});e.data.targets.forEach(a=>{a.values.forEach((i,o)=>{let s=n[Number(i.x)];s===void 0&&(s=o),i.index=s})})},isBubbleZType(t){return this.isBubbleType(t)&&(Be(t.value)&&("z"in t.value||"y"in t.value)||je(t.value)&&t.value.length>=2)},isBarRangeType(t){const e=this,{value:n}=t;return e.isBarType(t)&&je(n)&&n.length>=2&&n.every(a=>he(a))},getDataById(t){var e;const n=this.cache.get(t)||this.api.data(t);return(e=n==null?void 0:n[0])!=null?e:n}};function cc(t,e=!1){const n=this,{api:a}=n;e&&n.api.flush(!0),t==null||t.call(a)}var Lv={load(t,e){const n=this,{axis:a,data:i,org:o,scale:s}=n,{append:l}=e,c={domain:null,currentDomain:null,x:null};let f=t;f&&(e.filter&&(f=f.filter(e.filter)),(e.type||e.types)&&f.forEach(g=>{var v;const m=((v=e.types)==null?void 0:v[g.id])||e.type;n.setTargetType(g.id,m)}),i.targets.forEach(g=>{for(let v=0;v{const a=t.data||n;t.append&&(a.__append__=!0),a&&e.load(e.convertDataToTargets(a),t)}))},unload(t,e){var n;const a=this,{state:i,$el:o,$T:s}=a,l=!!((n=a.hasLegendDefsPoint)!=null&&n.call(a));let c=e,f=t;if(a.cache.reset(),c||(c=()=>{}),f=f.filter(v=>a.hasTarget(a.data.targets,v)),!f||f.length===0){c();return}const g=o.svg.selectAll(f.map(v=>a.selectorTarget(v)));s(g).style("opacity","0").remove().call(Si,c),f.forEach(v=>{var m;const S=a.getTargetSelectorSuffix(v);i.withoutFadeIn[v]=!1,o.legend&&o.legend.selectAll(`.${We.legendItem}${S}`).remove(),a.data.targets=a.data.targets.filter(P=>P.id!==v),l&&((m=o.defs)==null||m.select(`#${a.getDefsPointId(S)}`).remove())}),i.hasFunnel&&a.updateFunnel(a.data.targets),i.hasTreemap&&a.updateTargetsForTreemap(a.data.targets),a.updateTypesElements()}},Ri=t=>()=>t;function Ho(t,{sourceEvent:e,subject:n,target:a,identifier:i,active:o,x:s,y:l,dx:c,dy:f,dispatch:g}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:e,enumerable:!0,configurable:!0},subject:{value:n,enumerable:!0,configurable:!0},target:{value:a,enumerable:!0,configurable:!0},identifier:{value:i,enumerable:!0,configurable:!0},active:{value:o,enumerable:!0,configurable:!0},x:{value:s,enumerable:!0,configurable:!0},y:{value:l,enumerable:!0,configurable:!0},dx:{value:c,enumerable:!0,configurable:!0},dy:{value:f,enumerable:!0,configurable:!0},_:{value:g}})}Ho.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};function Nv(t){return!t.ctrlKey&&!t.button}function Fv(){return this.parentNode}function Bv(t,e){return e==null?{x:t.x,y:t.y}:e}function Uv(){return navigator.maxTouchPoints||"ontouchstart"in this}function uc(){var t=Nv,e=Fv,n=Bv,a=Uv,i={},o=ri("start","drag","end"),s=0,l,c,f,g,v=0;function m(H){H.on("mousedown.drag",S).filter(a).on("touchstart.drag",L).on("touchmove.drag",w,Jd).on("touchend.drag touchcancel.drag",X).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function S(H,k){if(!(g||!t.call(this,H,k))){var K=W(this,e.call(this,H,k),H,k,"mouse");K&&(ot(H.view).on("mousemove.drag",P,Sa).on("mouseup.drag",N,Sa),co(H.view),lo(H),f=!1,l=H.clientX,c=H.clientY,K("start",H))}}function P(H){if(Zr(H),!f){var k=H.clientX-l,K=H.clientY-c;f=k*k+K*K>v}i.mouse("drag",H)}function N(H){ot(H.view).on("mousemove.drag mouseup.drag",null),uo(H.view,f),Zr(H),i.mouse("end",H)}function L(H,k){if(t.call(this,H,k)){var K=H.changedTouches,at=e.call(this,H,k),ht=K.length,$t,dt;for($t=0;$ti.$el[o]).forEach(o=>{a&&i.$el[o].classed(Se.EXPANDED,!1),i.getShapeByIndex(o,e,n).classed(Se.EXPANDED,t)})},setOverOut(t,e){const n=this,{config:a,state:{hasFunnel:i,hasRadar:o,hasTreemap:s},$el:{main:l}}=n,c=Be(e);if(c||e!==-1){const f=a[t?"data_onover":"data_onout"].bind(n.api);if(a.color_onover&&n.setOverColor(t,e,c),c){const g=n.getTargetSelectorSuffix(e.id),v=i||s?`${Se.target+g} .${sn.shape}`:Ve.arc+g;f(e,l.select(`.${v}`).node())}else if(a.tooltip_grouped)t&&(o&&n.isPointFocusOnly()?n.showCircleFocus(n.getAllValuesOnIndex(e,!0)):n.setExpand(e,null,!0)),!n.isMultipleX()&&l.selectAll(`.${sn.shape}-${e}`).each(function(g){f(g,this)});else{const g=n.cache.get(Ln.setOverOut)||[],v=l.selectAll(`.${sn.shape}-${e}`).filter(function(S){return n.isWithinShape(this,S)}),m=v.filter(function(){return g.every(S=>S!==this)});if(!t||v.empty()||g.length===m.size()&&m.nodes().every((S,P)=>S!==g[P]))for(;g.length;){const S=g.pop();a.data_onout.bind(n.api)(ot(S).datum(),S)}m.each(function(){t&&(f(ot(this).datum(),this),g.push(this))}),n.cache.add(Ln.setOverOut,g)}}},callOverOutForTouch(t){const e=this,n=e.cache.get(Ln.callOverOutForTouch);(Be(t)&&n?t.id!==n.id:t!==n)&&((n||he(n))&&e.setOverOut(!1,n),(t||he(t))&&e.setOverOut(!0,t),e.cache.add(Ln.callOverOutForTouch,t))},getDraggableSelection(){const t=this,{config:e,state:n}=t;return e.interaction_enabled&&e.data_selection_draggable&&t.drag?uc().on("drag",function(a){n.event=a,t.drag(Hn(a,this))}).on("start",function(a){n.event=a,t.dragstart(Hn(a,this))}).on("end",a=>{n.event=a,t.dragend()}):()=>{}},dispatchEvent(t,e,n){var a,i,o;const s=this,{config:l,state:{eventReceiver:c,hasAxis:f,hasFunnel:g,hasRadar:v,hasTreemap:m},$el:{eventRect:S,funnel:P,radar:N,svg:L,treemap:w}}=s;let X=(o=(i=(g||m)&&c.rect||v&&N.axes.select(`.${Tn.axis}-${e} text`)||S||((a=s.getArcElementByIdOrIndex)==null?void 0:a.call(s,e)))==null?void 0:i.node)==null?void 0:o.call(i);if(X){const W=s.isMultipleX(),H=l.axis_rotated;let{width:k,left:K,top:at}=X.getBoundingClientRect();if(f&&!v&&!W){const st=c.coords[e];st?(k=st.w,K+=st.x,at+=st.y):(k=0,K=0,at=0)}let ht=K+(n?n[0]:0)+(W||H?0:k/2),$t=at+(n?n[1]:0)+(H?4:0);if(Lo(L)){const st=Ai(s.$el.eventRect.node(),ht,$t,!1);ht=st.x,$t=st.y}const dt={screenX:ht,screenY:$t,clientX:ht,clientY:$t,bubbles:v};(g||m)&&(X=(P!=null?P:w).node()),ev[/^(mouse|click)/.test(t)?"mouse":"touch"](X,t,dt)}},setDragStatus(t){this.state.dragging=t},unbindZoomEvent(){const t=this,{$el:{eventRect:e,zoomResetBtn:n}}=t;e==null||e.on(".zoom wheel.zoom .drag",null),n==null||n.on("click",null).style("display","none")},unbindAllEvents(){var t;const e=this,{$el:{arcs:n,eventRect:a,legend:i,region:o,svg:s,treemap:l},brush:c}=e,f=["wheel","click","mouseover","mousemove","mouseout","touchstart","touchmove","touchend","touchstart.eventRect","touchmove.eventRect","touchend.eventRect",".brush",".drag",".zoom","wheel.zoom","dblclick.zoom"].join(" ");[s,a,o==null?void 0:o.list,c==null?void 0:c.getSelection(),n==null?void 0:n.selectAll("path"),i==null?void 0:i.selectAll("g"),l].forEach(g=>g==null?void 0:g.on(f,null)),(t=e.unbindZoomEvent)==null||t.call(e)}},jv={categoryName(t){var e;const{axis_x_categories:n}=this.config;return(e=n==null?void 0:n[t])!=null?e:t}},Vv={generateClass(t,e){return` ${t} ${t+this.getTargetSelectorSuffix(e)}`},getClass(t,e){const n=/s$/.test(t),a=/^(area|arc|line|funnel|treemap)s?$/.test(t),i=n?"id":"index";return o=>{const s=o.data||o;return((e?this.generateClass(Ue[n?"shapes":"shape"],s[i]):"")+this.generateClass(Ue[t],s[a?"id":i])).trim()}},getChartClass(t){return e=>Ue[`chart${t}`]+this.classTarget((e.data?e.data:e).id)},generateExtraLineClass(){const e=this.config.line_classes||[],n=[];return function(a){var i;const o=a.id||((i=a.data)==null?void 0:i.id)||a;return n.indexOf(o)<0&&n.push(o),e[n.indexOf(o)%e.length]}},classRegion(t,e){return`${this.generateClass(Ue.region,e)} ${"class"in t?t.class:""}`},classTarget(t){const e=this.config.data_classes[t];let n="";return e&&(n=` ${Ue.target}-${e}`),this.generateClass(Ue.target,t)+n},classFocus(t){return this.classFocused(t)+this.classDefocused(t)},classFocused(t){return` ${this.state.focusedTargetIds.indexOf(t.id)>=0?Ue.focused:""}`},classDefocused(t){return` ${this.state.defocusedTargetIds.indexOf(t.id)>=0?Ue.defocused:""}`},getTargetSelectorSuffix(t){return(t||t===0?`-${t}`:"").replace(/[\x00-\x20\x7F-\xA0\s?!@#$%^&*()_=+,.<>'":;\[\]\/|~`{}\\]/g,"-")},selectorTarget(t,e="",n=""){const a=this.getTargetSelectorSuffix(t);return`${e}.${Ue.target+a} ${n}, ${e}.${Ue.circles+a} ${n}`},selectorTargets(t,e){const n=t||[];return n.length?n.map(a=>this.selectorTarget(a,e)):null},selectorLegend(t){return`.${Ue.legendItem+this.getTargetSelectorSuffix(t)}`},selectorLegends(t){return t!=null&&t.length?t.map(e=>this.selectorLegend(e)):null}};class fc extends Map{constructor(e,n=gc){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),e!=null)for(const[a,i]of e)this.set(a,i)}get(e){return super.get(Yo(this,e))}has(e){return super.has(Yo(this,e))}set(e,n){return super.set(dc(this,e),n)}delete(e){return super.delete(hc(this,e))}}class f1 extends Set{constructor(e,n=gc){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:n}}),e!=null)for(const a of e)this.add(a)}has(e){return super.has(Yo(this,e))}add(e){return super.add(dc(this,e))}delete(e){return super.delete(hc(this,e))}}function Yo({_intern:t,_key:e},n){const a=e(n);return t.has(a)?t.get(a):n}function dc({_intern:t,_key:e},n){const a=e(n);return t.has(a)?t.get(a):(t.set(a,n),n)}function hc({_intern:t,_key:e},n){const a=e(n);return t.has(a)&&(n=t.get(a),t.delete(a)),n}function gc(t){return t!==null&&typeof t=="object"?t.valueOf():t}function ra(t,e){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(e).domain(t);break}return this}function d1(t,e){switch(arguments.length){case 0:break;case 1:{typeof t=="function"?this.interpolator(t):this.range(t);break}default:{this.domain(t),typeof e=="function"?this.interpolator(e):this.range(e);break}}return this}const vc=Symbol("implicit");function pc(){var t=new fc,e=[],n=[],a=vc;function i(o){let s=t.get(o);if(s===void 0){if(a!==vc)return a;t.set(o,s=e.push(o)-1)}return n[s%n.length]}return i.domain=function(o){if(!arguments.length)return e.slice();e=[],t=new fc;for(const s of o)t.has(s)||t.set(s,e.push(s)-1);return i},i.range=function(o){return arguments.length?(n=Array.from(o),i):n.slice()},i.unknown=function(o){return arguments.length?(a=o,i):a},i.copy=function(){return pc(e,n).unknown(a)},ra.apply(i,arguments),i}const Gv=(t,e,n)=>{const a=ot(t.cloneNode(!0));return a.attr("id",n).insert("rect",":first-child").attr("width",a.attr("width")).attr("height",a.attr("height")).style("fill",e),{id:n,node:a.node()}};function Xv(t){const e=Ln.colorPattern,{body:n}=gn;let a=n[e];if(!a){const i=";",o=t.classed(oo.colorPattern,!0).style("background-image");t.classed(oo.colorPattern,!1),o.indexOf(i)>-1&&(a=o.replace(/url[^#]*|["'()]|(\s|%20)/g,"").split(i).map(s=>s.trim().replace(/[\"'\s]/g,"")).filter(Boolean),n[e]=a)}return a}const Hv=["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"];var Yv={generateColor(){const t=this,{$el:e,config:n}=t,a=n.data_colors,i=n.data_color,o=[];let s=cn(n.color_pattern)?n.color_pattern:pc(Xv(e.chart)||Hv).range();const l=s;if(ve(n.color_tiles)){const c=n.color_tiles.bind(t.api)(),f=s.map((g,v)=>{const m=g.replace(/[#\(\)\s,]/g,""),S=`${t.state.datetimeId}-pattern-${m}-${v}`;return Gv(c[v%c.length],g,S)});s=f.map(g=>`url(#${g.id})`),t.patterns=f}return function(c){var f;const g=c.id||((f=c.data)==null?void 0:f.id)||c,v=t.isTypeOf(g,["line","spline","step"])||!n.data_types[g];let m;return ve(a[g])?m=a[g].bind(t.api)(c):a[g]?m=a[g]:(o.indexOf(g)<0&&o.push(g),m=v?l[o.indexOf(g)%l.length]:s[o.indexOf(g)%s.length],a[g]=m),ve(i)?i.bind(t.api)(m,c):m}},generateLevelColor(){const t=this,{config:e}=t,n=e.color_pattern,a=e.color_threshold,i=a.unit==="value",o=a.max||100,s=a.values&&a.values.length?a.values:[];return cn(a)?function(l){const c=i?l:l*100/o;let f=n[n.length-1];for(let g=0,v=s.length;g{const l=`${i.datetimeId}-labels-bg${n.getTargetSelectorSuffix(s)}${ze(t)?n.getTargetSelectorSuffix(t):""}`;a.defs.append("filter").attr("x",e.x).attr("y",e.y).attr("width",e.width).attr("height",e.height).attr("id",l).html(` + `)})}},getGradienColortUrl(t){return`url(#${this.state.datetimeId}-gradient${this.getTargetSelectorSuffix(t)})`},updateLinearGradient(){const t=this,{config:e,data:{targets:n},state:{datetimeId:a},$el:{defs:i}}=t;n.forEach(o=>{const s=`${a}-gradient${t.getTargetSelectorSuffix(o.id)}`,l=t.hasPointType()&&e.point_radialGradient,c=t.isAreaType(o)&&"area"||t.isBarType(o)&&"bar";if((l||c)&&i.select(`#${s}`).empty()){const f=t.color(o),g={defs:null,stops:[]};if(l){const{cx:v=.3,cy:m=.3,r:S=.7,stops:P=[[.1,f,0],[.9,f,1]]}=l;g.stops=P,g.defs=i.append("radialGradient").attr("id",`${s}`).attr("cx",v).attr("cy",m).attr("r",S)}else{const v=e.axis_rotated,{x:m=v?[1,0]:[0,0],y:S=v?[0,0]:[0,1],stops:P=[[0,f,1],[1,f,0]]}=e[`${c}_linearGradient`];g.stops=P,g.defs=i.append("linearGradient").attr("id",`${s}`).attr("x1",m[0]).attr("x2",m[1]).attr("y1",S[0]).attr("y2",S[1])}g.stops.forEach(v=>{const[m,S,P]=v,N=ve(S)?S.bind(t.api)(o.id):S;g.defs&&g.defs.append("stop").attr("offset",m).attr("stop-color",N||f).attr("stop-opacity",P)})}})},setOverColor(t,e){const n=this,{config:a,$el:{main:i}}=n,o=a.color_onover;let s=t?o:n.color;Be(s)?s=({id:l})=>l in o?o[l]:n.color(l):ze(s)?s=()=>o:ve(o)&&(s=s.bind(n.api)),i.selectAll(Be(e)?`.${Ve.arc}${n.getTargetSelectorSuffix(e.id)}`:`.${sn.shape}-${e}`).style("fill",s)}},Wv={getYDomainMinMax(t,e){const n=this,{axis:a,config:i}=n,o=e==="min",s=i.data_groups,l=n.mapToIds(t),c=n.getValuesAsIdKeyed(t);if(s.length>0){const f=n[`has${o?"Negative":"Positive"}ValueInTargets`](t);s.forEach(g=>{const v=g.filter(m=>l.indexOf(m)>=0);if(v.length){const m=v[0],S=a.getId(m);f&&c[m]&&(c[m]=c[m].map(P=>(o?P<0:P>0)?P:0)),v.filter((P,N)=>N>0).forEach(P=>{if(c[P]){const N=a.getId(P);c[P].forEach((L,w)=>{const X=+L,W=o?X>0:X<0;N===S&&!(f&&W)&&(c[m][w]+=X)})}})}})}return _n(e,Object.keys(c).map(f=>_n(e,c[f])))},isHiddenTargetWithYDomain(t){const e=this;return e.state.hiddenTargetIds.some(n=>e.axis.getId(n)===t)},getYDomain(t,e,n){const a=this,{axis:i,config:o,scale:s}=a,l=`axis_${e}`;if(a.isStackNormalized())return[0,100];const c=(s==null?void 0:s[e])&&s[e].type==="log",f=t.filter(dt=>i.getId(dt.id)===e),g=n?a.filterByXDomain(f,n):f;if(g.length===0)return a.isHiddenTargetWithYDomain(e)?s[e].domain():e==="y2"?s.y.domain():a.getYDomain(t,"y2",n);const v=o[`${l}_min`],m=o[`${l}_max`],S=o[`${l}_center`],P=o[`${l}_inverted`],N=a.hasDataLabel()&&o.axis_rotated,L=a.hasDataLabel()&&!o.axis_rotated;let w=a.getYDomainMinMax(g,"min"),X=a.getYDomainMinMax(g,"max"),W=[oe.BAR,oe.BUBBLE,oe.SCATTER,...Sr.Line].some(dt=>{const st=dt.indexOf("area")>-1?"area":dt;return a.hasType(dt,g,!0)&&o[`${st}_zerobased`]});w=De(v)?v:De(m)?w<=m?w:m-10:w,X=De(m)?m:De(v)?v<=X?X:v+10:X,isNaN(w)&&(w=0),isNaN(X)&&(X=w),w===X&&(w<0?X=0:w=0);const H=w>=0&&X>=0,k=w<=0&&X<=0;(De(v)&&H||De(m)&&k)&&(W=!1),W&&(H&&(w=0),k&&(X=0));const K=Math.abs(X-w);let at={top:K*.1,bottom:K*.1};if(Qe(S)){const dt=Math.max(Math.abs(w),Math.abs(X));X=S+dt,w=S-dt}if(N){const dt=Dr(s.y.range()),st=a.getDataLabelLength(w,X,"width").map(Vt=>Vt/dt);["bottom","top"].forEach((Vt,vt)=>{at[Vt]+=K*(st[vt]/(1-st[0]-st[1]))})}else if(L){const dt=a.getDataLabelLength(w,X,"height");["bottom","top"].forEach((st,Vt)=>{at[st]+=a.convertPixelToScale("y",dt[Vt],K)})}at=a.getResettedPadding(at);const ht=o[`${l}_padding`];cn(ht)&&["bottom","top"].forEach(dt=>{at[dt]=i.getPadding(ht,dt,at[dt],K)}),W&&(H&&(at.bottom=w),k&&(at.top=-X));const $t=c?[w,X].map(dt=>dt<0?0:dt):[w-at.bottom,X+at.top];return P?$t.reverse():$t},getXDomainMinMax(t,e){var n;const a=this,i=a.config[`axis_x_${e}`],o=_n(e,t.map(l=>_n(e,l.values.map(c=>c.x))));let s=Be(i)?i.value:i;return s=Qe(s)&&((n=a.axis)!=null&&n.isTimeSeries())?Yn.bind(this)(s):s,Be(i)&&i.fit&&(e==="min"&&so)&&(s=void 0),Qe(s)?s:o},getXDomainPadding(t,e){const n=this,{axis:a,config:i}=n,o=i.axis_x_padding,s=a.isTimeSeries()&&e,l=Dr(t);let c;if(a.isCategorized()||s)c=0;else if(n.hasType("bar")){const v=n.getMaxDataCount();c=v>1?l/(v-1)/2:.5}else c=n.getResettedPadding(l*.01);let{left:f=c,right:g=c}=he(o)?{left:o,right:o}:o;if(o.unit==="px"){const v=Math.abs(l+l*.2);f=a.getPadding(o,"left",c,v),g=a.getPadding(o,"right",c,v)}else{const v=l+f+g;if(s&&v){const m=l/e/v;f=f/v/m,g=g/v/m}}return{left:f,right:g}},getXDomain(t){const e=this,{axis:n,config:a,scale:{x:i}}=e,o=a.axis_x_inverted,s=[e.getXDomainMinMax(t,"min"),e.getXDomainMinMax(t,"max")];let[l=0,c=0]=s;if(i.type!=="log"){const f=n.isCategorized(),g=n.isTimeSeries(),v=e.getXDomainPadding(s);let[m,S]=s;m-S===0&&!f&&(g?(m=new Date(m.getTime()*.5),S=new Date(S.getTime()*1.5)):(m=m===0?1:m*.5,S=S===0?-1:S*1.5)),(m||m===0)&&(l=g?new Date(m.getTime()-v.left):m-v.left),(S||S===0)&&(c=g?new Date(S.getTime()+v.right):S+v.right)}return o?[c,l]:[l,c]},updateXDomain(t,e,n,a,i){var o;const s=this,{config:l,org:c,scale:{x:f,subX:g}}=s,v=l.zoom_enabled;if(n&&(f.domain(i||na(s.getXDomain(t),!l.axis_x_inverted)),c.xDomain=f.domain(),g.domain(f.domain()),(o=s.brush)==null||o.scale(g)),e){const m=i||!s.brush||Kl(s)?c.xDomain:Wl(s).map(g.invert);f.domain(m)}return(n||e)&&v&&s.zoom.updateScaleExtent(),a&&f.domain(s.trimXDomain(f.orgDomain())),f.domain()},trimXDomain(t){const e=this,n=e.config.axis_x_inverted,a=e.getZoomDomain(),[i,o]=a;return(n?t[0]>=i:t[0]<=i)&&(t[1]=+t[1]+(i-t[0]),t[0]=i),(n?t[1]<=o:t[1]>=o)&&(t[0]=+t[0]-(t[1]-o),t[1]=o),t},getZoomDomain(t="zoom",e=!1){const n=this,{config:a,scale:i,org:o}=n;let[s,l]=e&&i[t]?i[t].domain():o.xDomain;return t==="zoom"&&(Qe(a.zoom_x_min)&&(s=_n("min",[s,a.zoom_x_min])),Qe(a.zoom_x_max)&&(l=_n("max",[l,a.zoom_x_max]))),[s,l]},getZoomDomainValue(t){const e=this,{config:n,axis:a}=e;if(a.isCategorized()&&Array.isArray(t)){const i=n.axis_x_inverted;return t.map((s,l)=>Number(s)+(l===0?+i:+!i))}return t},convertPixelToScale(t,e,n){const a=this,{config:i,state:o}=a,s=i.axis_rotated;let l;return t==="x"?l=s?"height":"width":l=s?"width":"height",n*(e/o[l])},withinRange(t,e=[0,0],n){const i=this.config.axis_x_inverted,[o,s]=n;if(Array.isArray(t)){const l=[...t];if(i&&l.reverse(),l[0](f===0?i?+c<=o:+c>=o:i?+c>=s:+c<=s)&&!t.every((g,v)=>g===e[v]))}return!1}};function mc(t,e,n){const{config:a}=t,i=`axis_${e}_tick_format`;return(a[i]?a[i]:t.defaultValueFormat).call(t.api,n)}var Kv={yFormat(t){return mc(this,"y",t)},y2Format(t){return mc(this,"y2",t)},getDefaultValueFormat(){const t=this,{defaultArcValueFormat:e,yFormat:n,y2Format:a}=t,i=t.hasArcType(null,["gauge","polar","radar"]);return function(o,s,l){return(i?e:t.axis&&t.axis.getId(l)==="y2"?a:n).call(t,o,s)}},defaultValueFormat(t){return je(t)?t.join("~"):De(t)?+t:""},defaultArcValueFormat(t,e){return`${(e*100).toFixed(1)}%`},defaultPolarValueFormat(t){return`${t}`},dataLabelFormat(t){const e=this,n=e.config.data_labels,a=o=>{const s="~";let l=o;return je(o)?l=o.join(s):Be(o)&&(l=Object.values(o).join(s)),l};let i=a;return ve(n.format)?i=n.format:nr(n.format)&&(n.format[t]?i=n.format[t]===!0?a:n.format[t]:i=()=>""),i.bind(e.api)}};function Ii(t){const e=this,n=e.getDataById(t);return e.levelColor?e.levelColor(n.values[0].value):e.color(n)}function Wo(t,e=!0){var n;const{config:a}=this;let i=(n=a.data_names[t])!=null?n:t;return e&&ve(a.legend_format)&&(i=a.legend_format(i,t!==i?t:void 0)),i}var Zv={initLegend(){const t=this,{config:e,$el:n}=t;t.legendItemTextBox={},t.state.legendHasRendered=!1,e.legend_show?(e.legend_contents_bindto||(n.legend=t.$el.svg.append("g").classed(We.legend,!0).attr("transform",t.getTranslate("legend"))),t.updateLegend()):t.state.hiddenLegendIds=t.mapToIds(t.data.targets)},updateLegend(t,e,n){var a;const i=this,{config:o,state:s,scale:l,$el:c}=i,f=e||{withTransform:!1,withTransitionForTransform:!1,withTransition:!1};f.withTransition=$r(f,"withTransition",!0),f.withTransitionForTransform=$r(f,"withTransitionForTransform",!0),o.legend_contents_bindto&&o.legend_contents_template?i.updateLegendTemplate():s.hasTreemap||i.updateLegendElement(t||i.mapToIds(i.data.targets),f,n),(a=c.legend)==null||a.selectAll(`.${We.legendItem}`).classed(We.legendItemHidden,function(g){const v=!i.isTargetToShow(g);return v&&(this.style.opacity=null),v}),i.updateScales(!1,!l.zoom),i.updateSvgSize(),i.transformAll(f.withTransitionForTransform,n),s.legendHasRendered=!0},updateLegendTemplate(){const t=this,{config:e,$el:n}=t,a=ot(e.legend_contents_bindto),i=e.legend_contents_template;if(!a.empty()){const o=t.mapToIds(t.data.targets),s=[];let l="";o.forEach(f=>{const g=ve(i)?i.bind(t.api)(f,t.color(f),t.api.data(f)[0].values):bi(i,{COLOR:t.color(f),TITLE:f});g&&(s.push(f),l+=g)});const c=a.html(l).selectAll(function(){return this.childNodes}).data(s);t.setLegendItem(c),n.legend=a}},updateSizeForLegend(t){const e=this,{config:n,state:{isLegendTop:a,isLegendLeft:i,isLegendRight:o,isLegendInset:s,current:l}}=e,{width:c,height:f}=t,g={top:a?e.getCurrentPaddingByDirection("top")+n.legend_inset_y+5.5:l.height-f-e.getCurrentPaddingByDirection("bottom")-n.legend_inset_y,left:i?e.getCurrentPaddingByDirection("left")+n.legend_inset_x+.5:l.width-c-e.getCurrentPaddingByDirection("right")-n.legend_inset_x+.5};e.state.margin3={top:o?0:s?g.top:l.height-f,right:NaN,bottom:0,left:o?l.width-c:s?g.left:0}},transformLegend(t){const e=this,{$el:{legend:n},$T:a}=e;a(n,t).attr("transform",e.getTranslate("legend"))},updateLegendStep(t){this.state.legendStep=t},updateLegendItemWidth(t){this.state.legendItemWidth=t},updateLegendItemHeight(t){this.state.legendItemHeight=t},updateLegendItemColor(t,e){const{legend:n}=this.$el;n&&n.select(`.${We.legendItem}-${t} line`).style("stroke",e)},getLegendWidth(){const t=this,{current:{width:e},isLegendRight:n,isLegendInset:a,legendItemWidth:i,legendStep:o}=t.state;return t.config.legend_show?n||a?i*(o+1):e:0},getLegendHeight(){var t;const e=this,{current:n,isLegendRight:a,legendItemHeight:i,legendStep:o}=e.state,s=((t=e.config.padding)==null?void 0:t.mode)==="fit";return e.config.legend_show?a?n.height:Math.max(s?10:20,i)*(o+1):0},opacityForUnfocusedLegend(t){return t.classed(We.legendItemHidden)?null:"0.3"},toggleFocusLegend(t,e){const n=this,{$el:{legend:a},$T:i}=n,o=n.mapToTargetIds(t);a&&i(a.selectAll(`.${We.legendItem}`).filter(s=>o.indexOf(s)>=0).classed(qe.legendItemFocused,e)).style("opacity",function(){return e?null:n.opacityForUnfocusedLegend.call(n,ot(this))})},revertLegend(){const t=this,{$el:{legend:e},$T:n}=t;e&&n(e.selectAll(`.${We.legendItem}`).classed(qe.legendItemFocused,!1)).style("opacity",null)},showLegend(t){const e=this,{config:n,$el:a,$T:i}=e;n.legend_show||(n.legend_show=!0,a.legend?a.legend.style("visibility",null):e.initLegend(),!e.state.legendHasRendered&&e.updateLegend()),e.removeHiddenLegendIds(t),i(a.legend.selectAll(e.selectorLegends(t)).style("visibility",null)).style("opacity",null)},hideLegend(t){const e=this,{config:n,$el:{legend:a}}=e;n.legend_show&&qn(t)&&(n.legend_show=!1,a.style("visibility","hidden")),e.addHiddenLegendIds(t),a.selectAll(e.selectorLegends(t)).style("opacity","0").style("visibility","hidden")},getLegendItemTextBox(t,e){const n=this,{cache:a,state:i}=n;let o;const s=Ln.legendItemTextBox;return t&&(o=!i.redrawing&&a.get(s)||{},o[t]||(o[t]=n.getTextRect(e,We.legendItem),a.add(s,o)),o=o[t]),o},setLegendItem(t){const e=this,{$el:n,api:a,config:i,state:o}=e,s=o.inputType==="touch",l=e.hasType("gauge"),c=i.boost_useCssRule,f=i.legend_item_interaction;t.attr("class",function(g){const v=ot(this);return(!v.empty()&&v.attr("class")||"")+e.generateClass(We.legendItem,g)}).style("visibility",g=>e.isLegendToShow(g)?null:"hidden"),i.interaction_enabled&&(c&&[[`.${We.legendItem}`,"cursor:pointer"],[`.${We.legendItem} text`,"pointer-events:none"],[`.${We.legendItemPoint} text`,"pointer-events:none"],[`.${We.legendItemTile}`,"pointer-events:none"],[`.${We.legendItemEvent}`,"fill-opacity:0"]].forEach(g=>{const[v,m]=g;e.setCssRule(!1,v,[m])(n.legend)}),t.on(f.dblclick?"dblclick":"click",f||ve(i.legend_item_onclick)?function(g,v){if(!_e(i.legend_item_onclick,a,v,!o.hiddenTargetIds.includes(v))){const{altKey:m,target:S,type:P}=g;P==="dblclick"||m?o.hiddenTargetIds.length&&S.parentNode.getAttribute("class").indexOf(We.legendItemHidden)===-1?a.show():(a.hide(),a.show(v)):(a.toggle(v),ot(this).classed(qe.legendItemFocused,!1))}s&&e.hideTooltip()}:null),!s&&t.on("mouseout",f||ve(i.legend_item_onout)?function(g,v){_e(i.legend_item_onout,a,v,!o.hiddenTargetIds.includes(v))||(ot(this).classed(qe.legendItemFocused,!1),l&&e.undoMarkOverlapped(e,`.${Un.gaugeValue}`),e.api.revert())}:null).on("mouseover",f||ve(i.legend_item_onover)?function(g,v){_e(i.legend_item_onover,a,v,!o.hiddenTargetIds.includes(v))||(ot(this).classed(qe.legendItemFocused,!0),l&&e.markOverlapped(v,e,`.${Un.gaugeValue}`),!o.transiting&&e.isTargetToShow(v)&&a.focus(v))}:null),!t.empty()&&t.on("click mouseout mouseover")&&t.style("cursor",e.getStylePropValue("pointer")))},updateLegendElement(t,e){const n=this,{config:a,state:i,$el:{legend:o},$T:s}=n,c=a.legend_item_tile_type!=="circle",f=a.legend_item_tile_r,g={width:c?a.legend_item_tile_width:f*2,height:c?a.legend_item_tile_height:f*2},v={padding:{top:4,right:10},max:{width:0,height:0},posMin:10,step:0,tileWidth:g.width+5,totalLength:0},m={offsets:{},widths:{},heights:{},margins:[0],steps:{}};let S,P,N;const L=t.filter(K=>!Qe(a.data_names[K])||a.data_names[K]!==null),w=e.withTransition,X=n.getUpdateLegendPositions(L,v,m);i.isLegendInset&&(v.step=a.legend_inset_step?a.legend_inset_step:L.length,n.updateLegendStep(v.step)),i.isLegendRight?(S=K=>v.max.width*m.steps[K],P=K=>m.margins[m.steps[K]]+m.offsets[K]):i.isLegendInset?(S=K=>v.max.width*m.steps[K]+10,P=K=>m.margins[m.steps[K]]+m.offsets[K]):(S=K=>m.margins[m.steps[K]]+m.offsets[K],P=K=>v.max.height*m.steps[K]);const W={xText:(K,at)=>S(K,at)+4+g.width,xRect:(K,at)=>S(K,at),x1Tile:(K,at)=>S(K,at)-2,x2Tile:(K,at)=>S(K,at)-2+g.width,yText:(K,at)=>P(K,at)+9,yRect:(K,at)=>P(K,at)-5,yTile:(K,at)=>P(K,at)+4};n.generateLegendItem(L,g,X,W),N=o.select(`.${We.legendBackground} rect`),i.isLegendInset&&v.max.width>0&&N.size()===0&&(N=o.insert("g",`.${We.legendItem}`).attr("class",We.legendBackground).append("rect")),a.legend_tooltip&&o.selectAll("title").data(L).text(K=>Wo.bind(n)(K,!1));const H=o.selectAll("text").data(L).text(K=>Wo.bind(n)(K)).each(function(K,at){X(this,K,at)});s(H,w).attr("x",W.xText).attr("y",W.yText);const k=o.selectAll(`rect.${We.legendItemEvent}`).data(L);s(k,w).attr("width",K=>m.widths[K]).attr("height",K=>m.heights[K]).attr("x",W.xRect).attr("y",W.yRect),n.updateLegendItemPos(L,w,W),N&&s(N,w).attr("height",n.getLegendHeight()-12).attr("width",v.max.width*(v.step+1)+10),n.updateLegendItemWidth(v.max.width),n.updateLegendItemHeight(v.max.height),n.updateLegendStep(v.step)},getUpdateLegendPositions(t,e,n){const a=this,{config:i,state:o}=a,s=o.isLegendRight||o.isLegendInset;return function(l,c,f){const g=f===0,v=f===t.length-1,m=a.getLegendItemTextBox(c,l),S=m.width+e.tileWidth+(v&&!s?0:e.padding.right)+i.legend_padding,P=m.height+e.padding.top,N=s?P:S,L=s?a.getLegendHeight():a.getLegendWidth();let w;const X=function(H,k){k||(w=(L-e.totalLength-N)/2,w=e.max.width)&&(e.max.width=S),(!e.max.height||P>=e.max.height)&&(e.max.height=P);const W=s?e.max.height:e.max.width;i.legend_equally?(Object.keys(n.widths).forEach(H=>n.widths[H]=e.max.width),Object.keys(n.heights).forEach(H=>n.heights[H]=e.max.height),w=(L-W*t.length)/2,wX(H))):X(c,!0)):X(c)}},generateLegendItem(t,e,n,a){const i=this,{config:o,state:s,$el:{legend:l}}=i,c=o.legend_usePoint,f=o.legend_item_tile_r,g=o.legend_item_tile_type,v=g!=="circle",m=s.isLegendRight||s.isLegendInset,S=-200,P=l.selectAll(`.${We.legendItem}`).data(t).enter().append("g");if(i.setLegendItem(P),o.legend_tooltip&&P.append("title").text(N=>N),P.append("text").text(N=>Wo.bind(i)(N)).each(function(N,L){n(this,N,L)}).style("pointer-events",i.getStylePropValue("none")).attr("x",m?a.xText:S).attr("y",m?S:a.yText),P.append("rect").attr("class",We.legendItemEvent).style("fill-opacity",i.getStylePropValue("0")).attr("x",m?a.xRect:S).attr("y",m?S:a.yRect),c){const N=[];P.append(L=>{const w=cn(o.point_pattern)?o.point_pattern:[o.point_type];N.indexOf(L)===-1&&N.push(L);let X=w[N.indexOf(L)%w.length];return X==="rectangle"&&(X="rect"),gn.createElementNS(ae.svg,"hasValidPointType"in i&&i.hasValidPointType(X)?X:"use")}).attr("class",We.legendItemPoint).style("fill",Ii.bind(i)).style("pointer-events",i.getStylePropValue("none")).attr("href",(L,w,X)=>{const H=X[w].nodeName.toLowerCase(),k=i.getTargetSelectorSuffix(L);return H==="use"?`#${s.datetimeId}-point${k}`:void 0})}else P.append(v?"line":g).attr("class",We.legendItemTile).style("stroke",Ii.bind(i)).style("pointer-events",i.getStylePropValue("none")).call(N=>{g==="circle"?N.attr("r",f).style("fill",Ii.bind(i)).attr("cx",m?a.x2Tile:S).attr("cy",m?S:a.yTile):v&&N.attr("stroke-width",e.height).attr("x1",m?a.x1Tile:S).attr("y1",m?S:a.yTile).attr("x2",m?a.x2Tile:S).attr("y2",m?S:a.yTile)})},updateLegendItemPos(t,e,n){const a=this,{config:i,$el:{legend:o},$T:s}=a,l=i.legend_usePoint,c=i.legend_item_tile_type,f=c!=="circle";if(l){const g=o.selectAll(`.${We.legendItemPoint}`).data(t);s(g,e).each(function(){const v=this.nodeName.toLowerCase(),m=i.point_r;let S="x",P="y",N=2,L=2.5,w=null,X=null,W=null;if(v==="circle"){const H=m*.2;S="cx",P="cy",w=m+H,N=m*2,L=-H}else if(v==="rect"){const H=m*2.5;X=H,W=H,L=3}ot(this).attr(S,H=>n.x1Tile(H)+N).attr(P,H=>n.yTile(H)-L).attr("r",w).attr("width",X).attr("height",W)})}else{const g=o.selectAll(`.${We.legendItemTile}`).data(t);s(g,e).style("stroke",Ii.bind(a)).call(v=>{c==="circle"?v.attr("cx",m=>{const S=n.x2Tile(m);return S-(S-n.x1Tile(m))/2}).attr("cy",n.yTile):f&&v.attr("x1",n.x1Tile).attr("y1",n.yTile).attr("x2",n.x2Tile).attr("y2",n.yTile)})}}},Jv={redraw(t={}){var e,n,a,i;const o=this,{config:s,state:l,$el:c}=o,{main:f,treemap:g}=c;l.redrawing=!0;const v=o.filterTargetsToShow(o.data.targets),{flow:m,initializing:S}=t,P=o.getWithOption(t),N=P.Transition?s.transition_duration:0,L=P.TransitionForExit?N:0,w=P.TransitionForAxis?N:0,X=(e=o.axis)==null?void 0:e.generateTransitions(w);o.updateSizes(S),P.Legend&&s.legend_show?(t.withTransition=!!N,!g&&o.updateLegend(o.mapToIds(o.data.targets),t,X)):P.Dimension&&o.updateDimension(!0),s.data_empty_label_text&&f.select(`text.${On.text}.${Se.empty}`).attr("x",l.width/2).attr("y",l.height/2).text(s.data_empty_label_text).style("display",v.length?"none":null),l.hasAxis?(o.axis.redrawAxis(v,P,X,m,S),o.hasGrid()&&o.updateGrid(),s.regions.length&&o.updateRegion(),["bar","candlestick","line","area"].forEach(W=>{const H=Cn(W);(/^(line|area)$/.test(W)&&o.hasTypeOf(H)||o.hasType(W))&&o[`update${H}`](P.TransitionForExit)}),c.text&&f.selectAll(`.${tn.selectedCircles}`).filter(o.isBarType.bind(o)).selectAll("circle").remove(),s.interaction_enabled&&!m&&P.EventRect&&(o.redrawEventRect(),(n=o.bindZoomEvent)==null||n.call(o))):(c.arcs&&o.redrawArc(N,L,P.Transform),c.radar&&o.redrawRadar(),c.polar&&o.redrawPolar(),c.funnel&&o.redrawFunnel(),g&&o.updateTreemap(L)),!l.resizing&&!g&&(o.hasPointType()||l.hasRadar)?o.updateCircle():(a=o.hasLegendDefsPoint)!=null&&a.call(o)&&o.data.targets.forEach(o.point("create",this)),o.hasDataLabel()&&!o.hasArcType(null,["radar"])&&o.updateText(),(i=o.redrawTitle)==null||i.call(o),S&&o.updateTypesElements(),o.generateRedrawList(v,m,N,P.Subchart),o.updateTooltipOnRedraw(),o.callPluginHook("$redraw",t,N)},generateRedrawList(t,e,n,a){const i=this,{config:o,state:s}=i,l=i.getDrawShape();s.hasAxis&&o.subchart_show&&i.redrawSubchart(a,n,l);const c=e&&i.generateFlow({targets:t,flow:e,duration:e.duration,shape:l,xv:i.xv.bind(i)}),f=(n||c)&&Da(),g=i.getRedrawList(l,e,c,f),v=()=>{c&&c(),s.redrawing=!1,_e(o.onrendered,i.api)};if(v)if(f&&g.length){const m=ec();Ml().duration(n).each(()=>{g.reduce((S,P)=>S.concat(P),[]).forEach(S=>m.add(S))}).call(m,v)}else s.transiting||v();i.mapToIds(i.data.targets).forEach(m=>{s.withoutFadeIn[m]=!0})},getRedrawList(t,e,n,a){const i=this,{config:o,state:{hasAxis:s,hasRadar:l,hasTreemap:c},$el:{grid:f}}=i,{cx:g,cy:v,xForText:m,yForText:S}=t.pos,P=[];return s&&((o.grid_x_lines.length||o.grid_y_lines.length)&&P.push(i.redrawGrid(a)),o.regions.length&&P.push(i.redrawRegion(a)),Object.keys(t.type).forEach(N=>{const L=Cn(N),w=t.type[N];(/^(area|line)$/.test(N)&&i.hasTypeOf(L)||i.hasType(N))&&P.push(i[`redraw${L}`](w,a))}),!e&&f.main&&P.push(i.updateGridFocus())),(!i.hasArcType()||l)&&cn(o.data_labels)&&o.data_labels!==!1&&P.push(i.redrawText(m,S,e,a)),(i.hasPointType()||l)&&!i.isPointFocusOnly()&&i.redrawCircle&&P.push(i.redrawCircle(g,v,a,n)),c&&P.push(i.redrawTreemap(a)),P},updateAndRedraw(t={}){const e=this,{config:n,state:a}=e;let i;t.withTransition=$r(t,"withTransition",!0),t.withTransform=$r(t,"withTransform",!1),t.withLegend=$r(t,"withLegend",!1),t.withUpdateXDomain=!0,t.withUpdateOrgXDomain=!0,t.withTransitionForExit=!1,t.withTransitionForTransform=$r(t,"withTransitionForTransform",t.withTransition),t.withLegend&&n.legend_show||(a.hasAxis&&(i=e.axis.generateTransitions(t.withTransitionForAxis?n.transition_duration:0)),e.updateScales(),e.updateSvgSize(),e.transformAll(t.withTransitionForTransform,i)),e.redraw(t,i)}};const Qv=Math.sqrt(50),kv=Math.sqrt(10),qv=Math.sqrt(2);function Oi(t,e,n){const a=(e-t)/Math.max(0,n),i=Math.floor(Math.log10(a)),o=a/Math.pow(10,i),s=o>=Qv?10:o>=kv?5:o>=qv?2:1;let l,c,f;return i<0?(f=Math.pow(10,-i)/s,l=Math.round(t*f),c=Math.round(e*f),l/fe&&--c,f=-f):(f=Math.pow(10,i)*s,l=Math.round(t/f),c=Math.round(e/f),l*fe&&--c),c0))return[];if(t===e)return[t];const a=e=i))return[];const l=o-i+1,c=new Array(l);if(a)if(s<0)for(let f=0;fe?1:t>=e?0:NaN}function _v(t,e){return t==null||e==null?NaN:et?1:e>=t?0:NaN}function Qo(t){let e,n,a;t.length!==2?(e=Ci,n=(l,c)=>Ci(t(l),c),a=(l,c)=>t(l)-c):(e=t===Ci||t===_v?t:tp,n=t,a=t);function i(l,c,f=0,g=l.length){if(f>>1;n(l[v],c)<0?f=v+1:g=v}while(f>>1;n(l[v],c)<=0?f=v+1:g=v}while(ff&&a(l[v-1],c)>-a(l[v],c)?v-1:v}return{left:i,center:s,right:o}}function tp(){return 0}function ep(t){return t===null?NaN:+t}function*h1(t,e){if(e===void 0)for(let n of t)n!=null&&(n=+n)>=n&&(yield n);else{let n=-1;for(let a of t)(a=e(a,++n,t))!=null&&(a=+a)>=a&&(yield a)}}const yc=Qo(Ci),np=yc.right,g1=yc.left,v1=Qo(ep).center;var rp=np;function ap(t,e){return t=+t,e=+e,function(n){return Math.round(t*(1-n)+e*n)}}function ip(t){return function(){return t}}function op(t){return+t}var xc=[0,1];function aa(t){return t}function ko(t,e){return(e-=t=+t)?function(n){return(n-t)/e}:ip(isNaN(e)?NaN:.5)}function sp(t,e){var n;return t>e&&(n=t,t=e,e=n),function(a){return Math.max(t,Math.min(e,a))}}function lp(t,e,n){var a=t[0],i=t[1],o=e[0],s=e[1];return i2?cp:lp,c=f=null,v}function v(m){return m==null||isNaN(m=+m)?o:(c||(c=l(t.map(a),e,n)))(a(s(m)))}return v.invert=function(m){return s(i((f||(f=l(e,t.map(a),Qn)))(m)))},v.domain=function(m){return arguments.length?(t=Array.from(m,op),g()):t.slice()},v.range=function(m){return arguments.length?(e=Array.from(m),g()):e.slice()},v.rangeRound=function(m){return e=Array.from(m),n=ap,g()},v.clamp=function(m){return arguments.length?(s=m?!0:aa,g()):s!==aa},v.interpolate=function(m){return arguments.length?(n=m,g()):n},v.unknown=function(m){return arguments.length?(o=m,v):o},function(m,S){return a=m,i=S,g()}}function Tc(){return qo()(aa,aa)}var up=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Na(t){if(!(e=up.exec(t)))throw new Error("invalid format: "+t);var e;return new _o({fill:e[1],align:e[2],sign:e[3],symbol:e[4],zero:e[5],width:e[6],comma:e[7],precision:e[8]&&e[8].slice(1),trim:e[9],type:e[10]})}Na.prototype=_o.prototype;function _o(t){this.fill=t.fill===void 0?" ":t.fill+"",this.align=t.align===void 0?">":t.align+"",this.sign=t.sign===void 0?"-":t.sign+"",this.symbol=t.symbol===void 0?"":t.symbol+"",this.zero=!!t.zero,this.width=t.width===void 0?void 0:+t.width,this.comma=!!t.comma,this.precision=t.precision===void 0?void 0:+t.precision,this.trim=!!t.trim,this.type=t.type===void 0?"":t.type+""}_o.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(this.width===void 0?"":Math.max(1,this.width|0))+(this.comma?",":"")+(this.precision===void 0?"":"."+Math.max(0,this.precision|0))+(this.trim?"~":"")+this.type};function fp(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)}function wi(t,e){if((n=(t=e?t.toExponential(e-1):t.toExponential()).indexOf("e"))<0)return null;var n,a=t.slice(0,n);return[a.length>1?a[0]+a.slice(2):a,+t.slice(n+1)]}function ia(t){return t=wi(Math.abs(t)),t?t[1]:NaN}function dp(t,e){return Math.max(0,Math.max(-8,Math.min(8,Math.floor(ia(e)/3)))*3-ia(Math.abs(t)))}function hp(t,e){return function(n,a){for(var i=n.length,o=[],s=0,l=t[0],c=0;i>0&&l>0&&(c+l+1>a&&(l=Math.max(1,a-c)),o.push(n.substring(i-=l,i+l)),!((c+=l+1)>a));)l=t[s=(s+1)%t.length];return o.reverse().join(e)}}function gp(t){return function(e){return e.replace(/[0-9]/g,function(n){return t[+n]})}}function vp(t){t:for(var e=t.length,n=1,a=-1,i;n0&&(a=0);break}return a>0?t.slice(0,a)+t.slice(i+1):t}var $c;function pp(t,e){var n=wi(t,e);if(!n)return t+"";var a=n[0],i=n[1],o=i-($c=Math.max(-8,Math.min(8,Math.floor(i/3)))*3)+1,s=a.length;return o===s?a:o>s?a+new Array(o-s+1).join("0"):o>0?a.slice(0,o)+"."+a.slice(o):"0."+new Array(1-o).join("0")+wi(t,Math.max(0,e+o-1))[0]}function Sc(t,e){var n=wi(t,e);if(!n)return t+"";var a=n[0],i=n[1];return i<0?"0."+new Array(-i).join("0")+a:a.length>i+1?a.slice(0,i+1)+"."+a.slice(i+1):a+new Array(i-a.length+2).join("0")}var Ac={"%":(t,e)=>(t*100).toFixed(e),b:t=>Math.round(t).toString(2),c:t=>t+"",d:fp,e:(t,e)=>t.toExponential(e),f:(t,e)=>t.toFixed(e),g:(t,e)=>t.toPrecision(e),o:t=>Math.round(t).toString(8),p:(t,e)=>Sc(t*100,e),r:Sc,s:pp,X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function Ec(t){return t}var bc=Array.prototype.map,Rc=["y","z","a","f","p","n","\xB5","m","","k","M","G","T","P","E","Z","Y"];function mp(t){var e=t.grouping===void 0||t.thousands===void 0?Ec:hp(bc.call(t.grouping,Number),t.thousands+""),n=t.currency===void 0?"":t.currency[0]+"",a=t.currency===void 0?"":t.currency[1]+"",i=t.decimal===void 0?".":t.decimal+"",o=t.numerals===void 0?Ec:gp(bc.call(t.numerals,String)),s=t.percent===void 0?"%":t.percent+"",l=t.minus===void 0?"\u2212":t.minus+"",c=t.nan===void 0?"NaN":t.nan+"";function f(v){v=Na(v);var m=v.fill,S=v.align,P=v.sign,N=v.symbol,L=v.zero,w=v.width,X=v.comma,W=v.precision,H=v.trim,k=v.type;k==="n"?(X=!0,k="g"):Ac[k]||(W===void 0&&(W=12),H=!0,k="g"),(L||m==="0"&&S==="=")&&(L=!0,m="0",S="=");var K=N==="$"?n:N==="#"&&/[boxX]/.test(k)?"0"+k.toLowerCase():"",at=N==="$"?a:/[%p]/.test(k)?s:"",ht=Ac[k],$t=/[defgprs%]/.test(k);W=W===void 0?6:/[gprs]/.test(k)?Math.max(1,Math.min(21,W)):Math.max(0,Math.min(20,W));function dt(st){var Vt=K,vt=at,Q,St,ct;if(k==="c")vt=ht(st)+vt,st="";else{st=+st;var At=st<0||1/st<0;if(st=isNaN(st)?c:ht(Math.abs(st),W),H&&(st=vp(st)),At&&+st==0&&P!=="+"&&(At=!1),Vt=(At?P==="("?P:l:P==="-"||P==="("?"":P)+Vt,vt=(k==="s"?Rc[8+$c/3]:"")+vt+(At&&P==="("?")":""),$t){for(Q=-1,St=st.length;++Qct||ct>57){vt=(ct===46?i+st.slice(Q+1):st.slice(Q))+vt,st=st.slice(0,Q);break}}}X&&!L&&(st=e(st,1/0));var Gt=Vt.length+st.length+vt.length,Bt=Gt>1)+Vt+st+vt+Bt.slice(Gt);break;default:st=Bt+Vt+st+vt;break}return o(st)}return dt.toString=function(){return v+""},dt}function g(v,m){var S=f((v=Na(v),v.type="f",v)),P=Math.max(-8,Math.min(8,Math.floor(ia(m)/3)))*3,N=Math.pow(10,-P),L=Rc[8+P/3];return function(w){return S(N*w)+L}}return{format:f,formatPrefix:g}}var Mi,ts,Ic;yp({thousands:",",grouping:[3],currency:["$",""]});function yp(t){return Mi=mp(t),ts=Mi.format,Ic=Mi.formatPrefix,Mi}function xp(t,e){return t=Math.abs(t),e=Math.abs(e)-t,Math.max(0,ia(e)-ia(t))+1}function Tp(t){return Math.max(0,-ia(Math.abs(t)))}function $p(t,e,n,a){var i=Jo(t,e,n),o;switch(a=Na(a==null?",f":a),a.type){case"s":{var s=Math.max(Math.abs(t),Math.abs(e));return a.precision==null&&!isNaN(o=dp(i,s))&&(a.precision=o),Ic(a,s)}case"":case"e":case"g":case"p":case"r":{a.precision==null&&!isNaN(o=xp(i,Math.max(Math.abs(t),Math.abs(e))))&&(a.precision=o-(a.type==="e"));break}case"f":case"%":{a.precision==null&&!isNaN(o=Tp(i))&&(a.precision=o-(a.type==="%")*2);break}}return ts(a)}function Oc(t){var e=t.domain;return t.ticks=function(n){var a=e();return Ko(a[0],a[a.length-1],n==null?10:n)},t.tickFormat=function(n,a){var i=e();return $p(i[0],i[i.length-1],n==null?10:n,a)},t.nice=function(n){n==null&&(n=10);var a=e(),i=0,o=a.length-1,s=a[i],l=a[o],c,f,g=10;for(l0;){if(f=Zo(s,l,n),f===c)return a[i]=s,a[o]=l,e(a);if(f>0)s=Math.floor(s/f)*f,l=Math.ceil(l/f)*f;else if(f<0)s=Math.ceil(s*f)/f,l=Math.floor(l*f)/f;else break;c=f}return t},t}function Di(){var t=Tc();return t.copy=function(){return Pi(t,Di())},ra.apply(t,arguments),Oc(t)}function Cc(t){return function(e){return Math.sign(e)*Math.log1p(Math.abs(e/t))}}function Pc(t){return function(e){return Math.sign(e)*Math.expm1(Math.abs(e))*t}}function Sp(t){var e=1,n=t(Cc(e),Pc(e));return n.constant=function(a){return arguments.length?t(Cc(e=+a),Pc(e)):e},Oc(n)}function wc(){var t=Sp(qo());return t.copy=function(){return Pi(t,wc()).constant(t.constant())},ra.apply(t,arguments)}function Mc(t,e){t=t.slice();var n=0,a=t.length-1,i=t[n],o=t[a],s;return oMath.pow(t,e)}function Ip(t){return t===Math.E?Math.log:t===10&&Math.log10||t===2&&Math.log2||(t=Math.log(t),e=>Math.log(e)/t)}function Nc(t){return(e,n)=>-t(-e,n)}function Op(t){const e=t(Dc,Lc),n=e.domain;let a=10,i,o;function s(){return i=Ip(a),o=Rp(a),n()[0]<0?(i=Nc(i),o=Nc(o),t(Ap,Ep)):t(Dc,Lc),e}return e.base=function(l){return arguments.length?(a=+l,s()):a},e.domain=function(l){return arguments.length?(n(l),s()):n()},e.ticks=l=>{const c=n();let f=c[0],g=c[c.length-1];const v=g0){for(;m<=S;++m)for(P=1;Pg)break;w.push(N)}}else for(;m<=S;++m)for(P=a-1;P>=1;--P)if(N=m>0?P/o(-m):P*o(m),!(Ng)break;w.push(N)}w.length*2{if(l==null&&(l=10),c==null&&(c=a===10?"s":","),typeof c!="function"&&(!(a%1)&&(c=Na(c)).precision==null&&(c.trim=!0),c=ts(c)),l===1/0)return c;const f=Math.max(1,a*l/e.ticks().length);return g=>{let v=g/o(Math.round(i(g)));return v*an(Mc(n(),{floor:l=>o(Math.floor(i(l))),ceil:l=>o(Math.ceil(i(l)))})),e}function Fc(){const t=Op(qo()).domain([1,10]);return t.copy=()=>Pi(t,Fc()).base(t.base()),ra.apply(t,arguments),t}const Li=en(()=>{},(t,e)=>{t.setTime(+t+e)},(t,e)=>e-t);Li.every=t=>(t=Math.floor(t),!isFinite(t)||!(t>0)?null:t>1?en(e=>{e.setTime(Math.floor(e/t)*t)},(e,n)=>{e.setTime(+e+n*t)},(e,n)=>(n-e)/t):Li);const p1=Li.range,Ur=en(t=>{t.setTime(t-t.getMilliseconds())},(t,e)=>{t.setTime(+t+e*Gn)},(t,e)=>(e-t)/Gn,t=>t.getUTCSeconds()),m1=Ur.range,es=en(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Gn)},(t,e)=>{t.setTime(+t+e*In)},(t,e)=>(e-t)/In,t=>t.getMinutes()),y1=es.range,ns=en(t=>{t.setUTCSeconds(0,0)},(t,e)=>{t.setTime(+t+e*In)},(t,e)=>(e-t)/In,t=>t.getUTCMinutes()),x1=ns.range,rs=en(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*Gn-t.getMinutes()*In)},(t,e)=>{t.setTime(+t+e*Bn)},(t,e)=>(e-t)/Bn,t=>t.getHours()),T1=rs.range,as=en(t=>{t.setUTCMinutes(0,0,0)},(t,e)=>{t.setTime(+t+e*Bn)},(t,e)=>(e-t)/Bn,t=>t.getUTCHours()),$1=as.range,is=en(t=>{t.setDate(1),t.setHours(0,0,0,0)},(t,e)=>{t.setMonth(t.getMonth()+e)},(t,e)=>e.getMonth()-t.getMonth()+(e.getFullYear()-t.getFullYear())*12,t=>t.getMonth()),S1=is.range,os=en(t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCMonth(t.getUTCMonth()+e)},(t,e)=>e.getUTCMonth()-t.getUTCMonth()+(e.getUTCFullYear()-t.getUTCFullYear())*12,t=>t.getUTCMonth()),A1=os.range;function Bc(t,e,n,a,i,o){const s=[[Ur,1,Gn],[Ur,5,5*Gn],[Ur,15,15*Gn],[Ur,30,30*Gn],[o,1,In],[o,5,5*In],[o,15,15*In],[o,30,30*In],[i,1,Bn],[i,3,3*Bn],[i,6,6*Bn],[i,12,12*Bn],[a,1,or],[a,2,2*or],[n,1,to],[e,1,Ps],[e,3,3*Ps],[t,1,eo]];function l(f,g,v){const m=gL).right(s,m);if(S===s.length)return t.every(Jo(f/eo,g/eo,v));if(S===0)return Li.every(Math.max(Jo(f,g,v),1));const[P,N]=s[m/s[S-1][2]n.axis.x.tickOffset()),i=n.config.axis_x_inverted,o=function(s){return t(s)+a()};for(const s in t)o[s]=t[s];return o.orgDomain=()=>t.domain(),o.orgScale=()=>t,n.axis.isCategorized()&&(o.domain=function(s){let l=s;return arguments.length?(t.domain(l),o):(l=this.orgDomain(),i?[l[0]+1,l[1]]:[l[0],l[1]+1])}),o},updateScales(t,e=!0){var n,a;const i=this,{axis:o,config:s,format:l,org:c,scale:f,state:{current:g,width:v,height:m,width2:S,height2:P,hasAxis:N,hasTreemap:L}}=i;if(N){const w=s.axis_rotated,X=i.getResettedPadding(1),W={x:w?X:0,y:w?0:m,subX:w?1:0,subY:w?0:P},H={x:w?m:v,y:w?v:X,subX:w?m:v,subY:w?S:1},k=e&&((n=f.x)==null?void 0:n.orgDomain()),K=e&&c.xDomain;f.x=i.getXScale(W.x,H.x,k,()=>o.x.tickOffset()),f.subX=i.getXScale(W.x,H.x,K,at=>{var ht;return at%1?0:((ht=o.subX)!=null?ht:o.x).tickOffset()}),l.xAxisTick=o.getXAxisTickFormat(),l.subXAxisTick=o.getXAxisTickFormat(!0),o.setAxis("x",f.x,s.axis_x_tick_outer,t),s.subchart_show&&o.setAxis("subX",f.subX,s.axis_x_tick_outer,t),f.y=i.getYScale("y",W.y,H.y,f.y?f.y.domain():s.axis_y_default),f.subY=i.getYScale("y",W.subY,H.subY,f.subY?f.subY.domain():s.axis_y_default),o.setAxis("y",f.y,s.axis_y_tick_outer,t),s.axis_y2_show&&(f.y2=i.getYScale("y2",W.y,H.y,f.y2?f.y2.domain():s.axis_y2_default),f.subY2=i.getYScale("y2",W.subY,H.subY,f.subY2?f.subY2.domain():s.axis_y2_default),o.setAxis("y2",f.y2,s.axis_y2_tick_outer,t))}else if(L){const w=i.getCurrentPadding();f.x=Di().rangeRound([w.left,g.width-w.right]),f.y=Di().rangeRound([w.top,g.height-w.bottom])}else(a=i.updateArc)==null||a.call(i)},xx(t){const e=this,{config:n,scale:{x:a,zoom:i}}=e,o=n.zoom_enabled&&i?i:a;return t?o(De(t.x)?t.x:t):null},xv(t){const e=this,{axis:n,config:a,scale:{x:i,zoom:o}}=e,s=a.zoom_enabled&&o?o:i;let l=e.getBaseValue(t);return n.isTimeSeries()?l=Yn.call(e,l):n.isCategorized()&&ze(l)&&(l=a.axis_x_categories.indexOf(l)),s(l)},yv(t){const e=this,{scale:{y:n,y2:a}}=e;return(t.axis&&t.axis==="y2"?a:n)(e.getBaseValue(t))},subxx(t){return t?this.scale.subX(t.x):null}},Up={setContainerSize(){const t=this,{state:e}=t;e.current.width=t.getCurrentWidth(),e.current.height=t.getCurrentHeight()},getCurrentWidth(){const t=this;return t.config.size_width||t.getParentWidth()},getCurrentHeight(){const t=this,{config:e}=t,n=e.size_height||t.getParentHeight();return n>0?n:320/(t.hasType("gauge")&&!e.gauge_fullCircle?2:1)},getParentRectValue(t){const e=`offset${Cn(t)}`;let n=this.$el.chart.node(),a=0;for(;a<30&&n&&n.tagName!=="BODY";){try{a=n.getBoundingClientRect()[t]}catch(o){e in n&&(a=n[e])}n=n.parentNode}const i=gn.body[e];return a>i&&(a=i),a},getParentWidth(){return this.getParentRectValue("width")},getParentHeight(){const t=this.$el.chart.style("height");let e=0;return t&&(e=/px$/.test(t)?parseInt(t,10):this.getParentRectValue("height")),e},getSvgLeft(t){const e=this,{config:n,state:{hasAxis:a},$el:i}=e,o=n.axis_rotated,s=o||!o&&!n.axis_y_inner,l=o?Tn.axisX:Tn.axisY,c=i.main.select(`.${l}`).node(),f=a&&n[`axis_${o?"x":"y"}_label`];let g=0;if(a&&(ze(f)||ze(f.text)||/^inner-/.test(f==null?void 0:f.position))){const N=i.main.select(`.${l}-label`);N.empty()||(g=N.node().getBoundingClientRect().left)}const v=c&&s?c.getBoundingClientRect():{right:0},m=i.chart.node().getBoundingClientRect().left+g,S=e.hasArcType(),P=v.right-m-(S?0:e.getCurrentPaddingByDirection("left",t));return P>0?P:0},updateDimension(t){var e;const n=this,{config:a,state:{hasAxis:i},$el:o}=n;i&&!t&&n.axis.x&&a.axis_rotated&&((e=n.axis.subX)==null||e.create(o.axis.subX)),n.updateScales(t),n.updateSvgSize(),n.transformAll(!1)},updateSvgSize(){const t=this,{config:e,state:{clip:n,current:a,hasAxis:i,width:o,height:s},$el:{svg:l}}=t;if(e.resize_auto==="viewBox"?l.attr("viewBox",`0 0 ${a.width} ${a.height}`):l.attr("width",a.width).attr("height",a.height),i){const c=l.select(`.${ks.brush} .overlay`),f={width:0,height:0};c.size()&&(f.width=+c.attr("width"),f.height=+c.attr("height")),l.selectAll([`#${n.id}`,`#${n.idGrid}`]).select("rect").attr("width",o).attr("height",s),l.select(`#${n.idXAxis}`).select("rect").call(t.setXAxisClipPath.bind(t)),l.select(`#${n.idYAxis}`).select("rect").call(t.setYAxisClipPath.bind(t)),n.idSubchart&&l.select(`#${n.idSubchart}`).select("rect").attr("width",o).attr("height",f.height)}},getCurrentPaddingByDirection(t,e=!1,n=!1){var a;const i=this,{config:o,$el:s,state:{hasAxis:l}}=i,c=o.axis_rotated,f=((a=o.padding)==null?void 0:a.mode)==="fit",g=he(o[`padding_${t}`])?o[`padding_${t}`]:void 0,v=l?{top:c?"y2":null,bottom:c?"y":"x",left:c?"x":"y",right:c?null:"y2"}[t]:null,m=/^(left|right)$/.test(t),S=v&&o[`axis_${v}_inner`],P=v&&o[`axis_${v}_show`],N=v?o[`axis_${v}_axes`].length:0;let L=v?m?i.getAxisWidthByAxisId(v,e):i.getHorizontalAxisHeight(v):0;const w=20;let X=0;!f&&m&&(L=Jg(L));let W=l&&m&&(S||ln(g)&&!P)?0:f?(P?L:0)+(g!=null?g:0):ln(g)?L:g;return m&&l?(v&&(f||S)&&o[`axis_${v}_label`].text&&(W+=i.axis.getAxisLabelPosition(v).isOuter?w:0),t==="right"?(W+=c?!f&&ln(g)?10:2:!P||S?f?2:1:0,W+=n?i.axis.getXAxisTickTextY2Overflow(w):0):t==="left"&&c&&ln(g)&&(W=o.axis_x_show?f?L:Math.max(L,40):1)):t==="top"?(s.title&&s.title.node()&&(W+=i.getTitlePadding()),X=c&&!S?N:0):t==="bottom"&&l&&c&&!P&&(W+=1),W+L*N-X},getCurrentPadding(t=!1){const e=this,[n,a,i,o]=["top","bottom","left","right"].map(s=>e.getCurrentPaddingByDirection(s,null,t));return{top:n,bottom:a,left:i,right:o}},getResettedPadding(t){const e=this,{config:n}=e,a=he(t);let i=a?0:{};return n.padding===!1?!a&&Object.keys(t).forEach(o=>{i[o]=!qn(n.data_labels)&&n.data_labels!==!1&&o==="top"?t[o]:0}):i=t,i},updateSizes(t){var e,n,a,i,o;const s=this,{config:l,state:c,$el:{legend:f}}=s,g=l.axis_rotated,v=s.hasArcType()||c.hasFunnel||c.hasTreemap,m=((e=l.padding)==null?void 0:e.mode)==="fit";!t&&s.setContainerSize();const S={width:f?s.getLegendWidth():0,height:f?s.getLegendHeight():0};!v&&l.axis_x_show&&l.axis_x_tick_autorotate&&s.updateXAxisTickClip();const P={right:l.legend_show&&c.isLegendRight?s.getLegendWidth()+(m?0:20):0,bottom:!l.legend_show||c.isLegendRight||c.isLegendInset?0:S.height},N=g||v?0:s.getHorizontalAxisHeight("x"),L=l.subchart_axis_x_show&&l.subchart_axis_x_tick_text_show?N:30,w=l.subchart_show&&!v?l.subchart_size_height+L:0,X=s.hasType("gauge")&&l.arc_needle_show&&!l.gauge_fullCircle&&!l.gauge_label_show?10:0,W=s.getCurrentPadding(!0);if(c.margin=!v&&g?{top:W.top,right:v?0:W.right+P.right,bottom:P.bottom+W.bottom,left:w+(v?0:W.left)}:{top:(m?0:4)+W.top,right:v?0:W.right+P.right,bottom:X+w+P.bottom+W.bottom,left:v?0:W.left},c.margin=s.getResettedPadding(c.margin),c.margin2=g?{top:c.margin.top,right:NaN,bottom:20+P.bottom,left:s.state.rotatedPadding.left}:{top:c.current.height-w-P.bottom,right:NaN,bottom:L+P.bottom,left:c.margin.left},c.margin3={top:0,right:NaN,bottom:0,left:0},(n=s.updateSizeForLegend)==null||n.call(s,S),c.width=c.current.width-c.margin.left-c.margin.right,c.height=c.current.height-c.margin.top-c.margin.bottom,c.width<0&&(c.width=0),c.height<0&&(c.height=0),c.width2=g?c.margin.left-c.rotatedPadding.left-c.rotatedPadding.right:c.width,c.height2=g?c.height:c.current.height-c.margin2.top-c.margin2.bottom,c.width2<0&&(c.width2=0),c.height2<0&&(c.height2=0),s.hasArcType()){const H=s.hasType("gauge"),k=l.legend_show&&c.isLegendRight,K=(a=c.hasRadar&&s.cache.get(Ln.radarTextWidth))!=null?a:0;c.arcWidth=c.width-(k?S.width+10:0)-K,c.arcHeight=c.height-(k&&!H?0:10),(i=l.arc_rangeText_values)!=null&&i.length&&(H?(c.arcWidth-=25,c.arcHeight-=10,c.margin.left+=10):(c.arcHeight-=20,c.margin.top+=10)),H&&!l.gauge_fullCircle&&(c.arcHeight+=c.height-s.getPaddingBottomForGauge()),(o=s.updateRadius)==null||o.call(s)}c.isLegendRight&&v&&(c.margin3.left=c.arcWidth/2+c.radiusExpanded*1.1)}},zp={setCssRule(t,e,n,a){const i=this,{config:o,state:{cssRule:s,style:l}}=i;return o.boost_useCssRule?c=>{c.each(f=>{const g=a&&(a==null?void 0:a.call(i,f)),v=`${t?`.${sn.shapes+i.getTargetSelectorSuffix(f.id)}`:""}${e}`;e in s&&l.sheet.deleteRule(s[v]),i.state.cssRule[v]=_g(l,v,n.filter(Boolean).map(m=>ze(g)&&m.indexOf(":")===-1?`${m}: ${g}`:m||""))})}:()=>{}},getStylePropValue(t){const{config:{boost_useCssRule:e}}=this;return e?null:ve(t)?t.bind(this):t}};function Uc(t){return typeof t=="string"?new Ie([document.querySelectorAll(t)],[document.documentElement]):new Ie([T(t)],_t)}function jp(t){let e="middle";return t>0&&t<=170?e="end":t>190&&t<=360&&(e="start"),e}function Vp(t,e,n,a,i){var o;const s=this,{value:l}=t,c=s.isCandlestickType(t),f=he(l)&&l<0||c&&!((o=s.getCandlestickData(t))!=null&&o._isUp);let{x:g,y:v}=e;const m=4,S=m*2;return a?n==="start"?(g+=f?0:S,v+=m):n==="middle"?(g+=S,v-=S):n==="end"&&(f&&(g-=S),v+=m):(n==="start"?(g+=m,f&&(v+=S*2)):n==="middle"?v-=S:n==="end"&&(g-=m,f&&(v+=S*2)),i&&(v+=f?-17:c?13:7)),{x:g,y:v}}function zc(t,e){var n;const a=this.config.data_labels_position,{id:i,index:o,value:s}=t;return(n=ve(a)?a.bind(this.api)(e,s,i,o,this.$el.text):(i in a?a[i]:a)[e])!=null?n:0}var Gp={opacityForText(t){const e=this;return e.isBarType(t)&&!e.meetsLabelThreshold(Math.abs(e.getRatio("bar",t)),"bar")?"0":e.hasDataLabel?null:"0"},initText(){const{$el:t}=this;t.main.select(`.${Se.chart}`).append("g").attr("class",On.chartTexts).style("pointer-events",t.funnel||t.treemap?"none":null)},updateTargetsForText(t){const e=this,n=e.getChartClass("Text"),a=e.getClass("texts","id"),i=e.classFocus.bind(e);e.$el.main.select(`.${On.chartTexts}`).selectAll(`.${On.chartText}`).data(t).attr("class",l=>`${n(l)}${i(l)}`.trim()).enter().append("g").style("opacity","0").attr("class",n).call(e.setCssRule(!0,` .${On.text}`,["fill","pointer-events:none"],e.updateTextColor)).append("g").attr("class",a)},updateText(){const t=this,{$el:e,$T:n,config:a,axis:i}=t,o=t.getClass("text","index"),s=a.data_labels.centered,l=e.main.selectAll(`.${On.texts}`).selectAll(`.${On.text}`).data(t.labelishData.bind(t));n(l.exit()).style("fill-opacity","0").remove(),e.text=l.enter().append("text").merge(l).attr("class",o).attr("text-anchor",c=>{let g=a[`axis_${i==null?void 0:i.getId(c.id)}_inverted`]?c.value>0:c.value<0;if(t.isCandlestickType(c)){const v=t.getCandlestickData(c);g=!(v!=null&&v._isUp)}else if(t.isTreemapType(c))return s?"middle":"start";return a.axis_rotated?g?"end":"start":"middle"}).style("fill",t.getStylePropValue(t.updateTextColor)).style("fill-opacity","0").each(function(c,f,g){const v=ot(this);let{value:m}=c;if(t.isBubbleZType(c))m=t.getBubbleZData(m,"z");else if(t.isCandlestickType(c)){const S=t.getCandlestickData(c);S&&(m=S.close)}m=t.isTreemapType(c)?t.treemapDataLabelFormat(c)(v):t.dataLabelFormat(c.id)(m,c.id,c.index,g),he(m)?this.textContent=m:wa(v,m)})},updateTextColor(t){const e=this,{config:n}=e,a=n.data_labels_colors,i=e.isArcType(t)&&!e.isRadarType(t)||e.isFunnelType(t)||e.isTreemapType(t)?null:e.color(t);let o;if(ze(a))o=a;else if(Be(a)){const{id:s}=t.data||t;o=a[s]}else ve(a)&&(o=a.bind(e.api)(i,t));if(e.isCandlestickType(t)&&!ve(a)){const s=e.getCandlestickData(t);if(!(s!=null&&s._isUp)){const l=n.candlestick_color_down;o=Be(l)?l[t.id]:l}}return o||i},updateTextBGColor(t,e){const n=this,{$el:a}=n;let i="";if(ze(e)||Be(e)){const o=ze(e)?"":n.getTargetSelectorSuffix("id"in t?t.id:t.data.id),s=a.defs.select(["filter[id*='labels-bg","']"].join(o));s.size()&&(i=`url(#${s.attr("id")})`)}return i||null},redrawText(t,e,n,a){const i=this,{$T:o,axis:s,config:l,state:{hasTreemap:c}}=i,f=gr(!0),g=l.axis_rotated,v=l.data_labels.rotate,m=jp(v),S=v?`rotate(${v})`:"";return i.$el.text.style("fill",i.getStylePropValue(i.updateTextColor)).attr("filter",P=>i.updateTextBGColor.bind(i)(P,l.data_labels_backgroundColors)).style("fill-opacity",n?0:i.opacityForText.bind(i)).each(function(P,N){const L=o(c&&this.childElementCount?this.parentNode:this,!!(a&&this.getAttribute("x")),f),w=l[`axis_${s==null?void 0:s.getId(P.id)}_inverted`];let X={x:t.bind(this)(P,N),y:e.bind(this)(P,N)};v&&(X=Vp.bind(i)(P,X,m,g,w),L.attr("text-anchor",m)),this.childElementCount||v?L.attr("transform",`translate(${X.x} ${X.y}) ${S}`):L.attr("x",X.x).attr("y",X.y)}),!0},getTextRect(t,e){const n=this;let a=t.node?t.node():t;/text/i.test(a.tagName)||(a=a.querySelector("text"));const i=a.textContent,o=`${Ln.textRect}-${i.replace(/\W/g,"_")}`;let s=n.cache.get(o);return s||(n.$el.svg.append("text").style("visibility","hidden").style("font",ot(a).style("font")).classed(e,!0).text(i).call(l=>{s=Ma(l.node())}).remove(),n.cache.add(o,s)),s},generateXYForText(t,e){const n=this,{state:{hasRadar:a,hasFunnel:i,hasTreemap:o}}=n,s=Object.keys(t),l={},c=e?n.getXForText:n.getYForText;return i&&s.push("funnel"),a&&s.push("radar"),o&&s.push("treemap"),s.forEach(f=>{l[f]=n[`generateGet${Cn(f)}Points`](t[f],!1)}),function(f,g){const v=n.isAreaType(f)&&"area"||n.isBarType(f)&&"bar"||n.isCandlestickType(f)&&"candlestick"||n.isFunnelType(f)&&"funnel"||n.isRadarType(f)&&"radar"||n.isTreemapType(f)&&"treemap"||"line";return c.call(n,l[v](f,g),f,this)}},getCenteredTextPos(t,e,n,a){const i=this,{config:o}=i,s=o.axis_rotated,l=i.isBarType(t),c=i.isTreemapType(t);if(o.data_labels.centered&&(l||c)){const f=Ma(n);if(l){const g=i.getRangedData(t,null,"bar")>=0;if(s){const v=(g?e[1][1]-e[0][1]:e[0][1]-e[1][1])/2+f.width/2;return g?-v-3:v+2}else{const v=(g?e[0][1]-e[1][1]:e[1][1]-e[0][1])/2+f.height/2;return g?v:-v-2}}else if(c)return a==="x"?(e[1][0]-e[0][0])/2:(e[1][1]-e[0][1])/2+f.height/2}return 0},getXForText(t,e,n){var a;const i=this,{config:o}=i,s=o.axis_rotated,l=i.isFunnelType(e),c=i.isTreemapType(e);let f=t?t[0][0]:0;if(i.isCandlestickType(e))s?f=(a=i.getCandlestickData(e))!=null&&a._isUp?t[2][2]+4:t[2][1]-4:f+=(t[1][0]-f)/2;else if(l)f+=i.state.current.width/2;else if(c)f+=o.data_labels.centered?0:5;else if(s){const g=o[`axis_${i.axis.getId(e.id)}_inverted`],v=i.isBarType(e)?4:6,m=e.value;f=t[2][1],g?f-=v*(m>0?1:-1):f+=v*(m<0?-1:1)}else f=i.hasType("bar")?(t[2][0]+t[0][0])/2:f;return(s||c)&&(f+=i.getCenteredTextPos(e,t,n,"x")),f+zc.call(this,e,"x")},getYForText(t,e,n){const a=this,{axis:i,config:o,state:s}=a,l=o.axis_rotated,c=o[`axis_${i==null?void 0:i.getId(e.id)}_inverted`],f=a.isBarType(e),g=a.isFunnelType(e),v=a.isTreemapType(e),m=o.point_r,S=Ma(n);let{value:P}=e,N=3,L;if(a.isCandlestickType(e))P=a.getCandlestickData(e),l?(L=t[0][0],L+=(t[1][0]-L)/2+N):(L=P&&P._isUp?t[2][2]-N:t[2][1]+N*4,c&&(L+=15*(P._isUp?1:-1)));else if(g)L=t?t[0][1]+(t[1][1]-t[0][1])/2+S.height/2-3:0;else if(v)L=t[0][1]+(o.data_labels.centered?0:S.height+5);else if(l)L=(t[0][0]+t[2][0]+S.height*.6)/2;else if(L=t[2][1],he(m)&&m>5&&(a.isLineType(e)||a.isScatterType(e))&&(N+=o.point_r/2.3),P<0||P===0&&!s.hasPositiveValue&&s.hasNegativeValue)L+=c?f?-3:-5:S.height+(f?-N:N);else{let w=-N*2;f?w=-N:a.isBubbleType(e)&&(w=N),c&&(w=f?10:15),L+=w}return(!l||v)&&(L+=a.getCenteredTextPos(e,t,n,"y")),L+zc.call(this,e,"y")},markOverlapped(t,e,n){const a=e.$el.arcs.selectAll(n),i=a.filter(c=>c.data.id!==t),o=a.filter(c=>c.data.id===t),s=Jl(o.node()),l=(c,f)=>Math.sqrt(Math.pow(c,2)+Math.pow(f,2));o.node()&&i.each(function(){const c=Jl(this),f=ot(this),g=l(s.e,s.f)>l(c.e,c.f)?o:f,v=Math.ceil(Math.abs(s.e-c.e))=i}};function jc(t="left",e){const n=he(e);let a;return t.indexOf("center")>-1?a=n?e/2:"middle":t.indexOf("right")>-1?a=n?e:"end":a=n?0:"start",a}var Xp={initTitle(){const t=this,{config:e,$el:n}=t;if(e.title_text){n.title=n.svg.append("g");const a=n.title.append("text").style("text-anchor",jc(e.title_position)).attr("class",On.title);wa(a,e.title_text,[.3,1.5])}},redrawTitle(){const t=this,{config:e,state:{current:n},$el:{title:a}}=t;if(a){const i=jc(e.title_position,n.width),o=(e.title_padding.top||0)+t.getTextRect(t.$el.title,On.title).height;a.attr("transform",`translate(${i}, ${o})`)}},getTitlePadding(){const t=this,{$el:{title:e},config:n}=t;return(n.title_padding.top||0)+(e?t.getTextRect(e,On.title).height:0)+(n.title_padding.bottom||0)}},Hp={initTooltip(){const t=this,{config:e,$el:n}=t;n.tooltip=ot(e.tooltip_contents.bindto),n.tooltip.empty()&&(n.tooltip=n.chart.append("div").attr("class",ei.tooltipContainer).style("position","absolute").style("pointer-events","none").style("display","none")),t.bindTooltipResizePos()},initShowTooltip(){var t;const e=this,{config:n,$el:a,state:{hasAxis:i,hasRadar:o}}=e;if(n.tooltip_init_show){const s=!(i||o);(t=e.axis)!=null&&t.isTimeSeries()&&ze(n.tooltip_init_x)&&(n.tooltip_init_x=Yn.call(e,n.tooltip_init_x)),e.api.tooltip.show({data:{[s?"index":"x"]:n.tooltip_init_x}});const l=n.tooltip_init_position;if(!n.tooltip_contents.bindto&&!qn(l)){const{top:c=0,left:f=50}=l;a.tooltip.style("top",ze(c)?c:`${c}px`).style("left",ze(f)?f:`${f}px`).style("display",null)}}},getTooltipHTML(...t){const e=this,{api:n,config:a}=e;return ve(a.tooltip_contents)?a.tooltip_contents.bind(n)(...t):e.getTooltipContent(...t)},getTooltipContent(t,e,n,a){var i;const o=this,{api:s,config:l,state:c,$el:f}=o,[g,v,m]=["title","name","value"].map(vt=>{const Q=l[`tooltip_format_${vt}`];return ve(Q)?Q.bind(s):Q}),S=(...vt)=>Po((g||e)(...vt)),P=(...vt)=>Po((v||(Q=>Q))(...vt)),N=(...vt)=>{const Q=m||(c.hasTreemap||o.isStackNormalized()?(St,ct)=>`${(ct*100).toFixed(2)}%`:n);return Po(Q(...vt))},L=l.tooltip_order,w=vt=>o.axis&&o.isBubbleZType(vt)?o.getBubbleZData(vt.value,"z"):o.getBaseValue(vt),X=o.levelColor?vt=>o.levelColor(vt.value):vt=>a(vt),W=l.tooltip_contents,H=W.template,k=o.mapToTargetIds();if(L===null&&l.data_groups.length){const vt=o.orderTargets(o.data.targets).map(Q=>Q.id).reverse();t.sort((Q,St)=>{let ct=Q?Q.value:null,At=St?St.value:null;return ct>0&&At>0&&(ct=Q.id?vt.indexOf(Q.id):null,At=St.id?vt.indexOf(St.id):null),ct-At})}else if(/^(asc|desc)$/.test(L)){const vt=L==="asc";t.sort((Q,St)=>{const ct=Q?w(Q):null,At=St?w(St):null;return vt?ct-At:At-ct})}else ve(L)&&t.sort(L.bind(s));const K=o.getTooltipContentTemplate(H),at=t.length;let ht,$t,dt,st,Vt;for(Vt=0;Vt${vt}`:""})}if(!$t.ratio&&f.arcs&&(dt=["arc",o.$el.arcs.select(`path.${Ve.arc}-${$t.id}`).data()[0]],$t.ratio=o.getRatio(...dt)),dt=[$t.ratio,$t.id,$t.index],o.isAreaRangeType($t)){const[vt,Q]=["high","low"].map(ct=>N(o.getRangedData($t,ct),...dt));st=`Mid: ${N(w($t),...dt)} High: ${vt} Low: ${Q}`}else if(o.isCandlestickType($t)){const[vt,Q,St,ct,At]=["open","high","low","close","volume"].map(Gt=>o.getRangedData($t,Gt,"candlestick")?N(o.getRangedData($t,Gt,"candlestick"),...dt):void 0);st=`Open: ${vt} High: ${Q} Low: ${St} Close: ${ct}${At?` Volume: ${At}`:""}`}else if(o.isBarRangeType($t)){const{value:vt,id:Q,index:St}=$t;st=`${N(vt,void 0,Q,St)}`}else st=N(w($t),...dt);if(st!==void 0){if($t.name===null)continue;const vt=P((i=$t.name)!=null?i:$t.id,...dt),Q=X($t),St={CLASS_TOOLTIP_NAME:ei.tooltipName+o.getTargetSelectorSuffix($t.id),COLOR:H||!o.patterns?Q:``,NAME:vt,VALUE:st};if(H&&Be(W.text)){const ct=k.indexOf($t.id);Object.keys(W.text).forEach(At=>{St[At]=W.text[At][ct]})}ht+=bi(K[1],St)}}return`${ht}`},getTooltipContentTemplate(t){return(t||` + {=TITLE} + {{ + + + }} +
${this.patterns?"{=COLOR}":''}{=NAME}{=VALUE}
`).replace(/(\r?\n|\t)/g,"").split(/{{(.*)}}/)},setTooltipPosition(t,e){var n,a;const i=this,{config:o,scale:s,state:l,$el:{eventRect:c,tooltip:f,svg:g}}=i,{bindto:v}=o.tooltip_contents,m=o.axis_rotated,S=f==null?void 0:f.datum();if(!v&&S){const P=t!=null?t:JSON.parse(S.current),[N,L]=Hn(l.event,e!=null?e:c==null?void 0:c.node()),w={x:N,y:L};if(l.hasAxis&&s.x&&S&&"x"in S){const k=(K=0,at,ht="y")=>{var $t;const dt=s[at?($t=i.axis)==null?void 0:$t.getId(at):ht];return dt?dt(K)+(m?l.margin.left:l.margin.top):0};w.xAxis=s.x(S.x)+(o.tooltip_position?m?l.margin.top:l.margin.left:0),P.length===1?w.yAxis=k(P[0].value,P[0].id):w.yAxis=k}const{width:X=0,height:W=0}=S,H=(a=(n=o.tooltip_position)==null?void 0:n.bind(i.api)(P,X,W,c==null?void 0:c.node(),w))!=null?a:Lo(g)?i.getTooltipPositionViewBox.bind(i)(X,W,w):i.getTooltipPosition.bind(i)(X,W,w);["top","left"].forEach(k=>{const K=H[k];f.style(k,`${K}px`),k==="left"&&!S.xPosInPercent&&(S.xPosInPercent=K/l.current.width*100)})}},getTooltipPositionViewBox(t,e,n){var a,i;const o=this,{$el:{eventRect:s,svg:l},config:c,state:f}=o,g=c.axis_rotated,v=o.hasArcType()||f.hasFunnel||f.hasTreemap,m=(i=(a=v?l:s)==null?void 0:a.node())!=null?i:f.event.target;let{x:S,y:P}=n;f.hasAxis&&(S=g?S:n.xAxis,P=g?n.xAxis:P);const N=Ai(m,S,P,!1),L=m.getBoundingClientRect(),w=Ai(m,20,0,!1).x;let X=N.y,W=N.x+t/2+w;return v&&(f.hasFunnel||f.hasTreemap||f.hasRadar?(W-=t/2+w,X+=e):(X+=L.height/2,W+=L.width/2-(t-w))),W+t>L.width&&(W=L.width-t-w),X+e>L.height&&(X-=e*2),{top:X,left:W}},getTooltipPosition(t,e,n){var a,i,o;const s=this,{config:l,scale:c,state:f}=s,{width:g,height:v,current:m,hasFunnel:S,hasRadar:P,hasTreemap:N,isLegendRight:L,inputType:w}=f,X=s.hasType("gauge")&&!l.gauge_fullCircle,W=l.axis_rotated,H=s.hasArcType(),k=s.getSvgLeft(!0);let K=k+m.width-s.getCurrentPaddingByDirection("right");const at=20;let{x:ht,y:$t}=n;if(P)ht+=ht>=g/2?15:-(t+15),$t+=15;else if(H){if(w!=="touch"){let Vt=(i=(a=s.getTitlePadding)==null?void 0:a.call(s))!=null?i:0;Vt&&X&&((o=l.arc_rangeText_values)!=null&&o.length)&&(Vt+=10),ht+=(g-(L?s.getLegendWidth():0))/2,$t+=(X?v:v/2+e)+Vt}}else if(S||N)$t+=e;else{const st={top:s.getCurrentPaddingByDirection("top",!0),left:s.getCurrentPaddingByDirection("left",!0)};W?(ht+=k+st.left+at,$t=st.top+n.xAxis+at,K-=k):(ht=k+st.left+at+(c.zoom?ht:n.xAxis),$t+=st.top-5)}if(ht+t+15>K&&(ht-=t+(S||N||H?0:W?at*2:38)),$t+e>m.height){const st=N?e+10:30;$t-=X?e*1.5:e+st}const dt={top:$t,left:ht};return Object.keys(dt).forEach(st=>{dt[st]<0&&(dt[st]=0)}),dt},showTooltip(t,e){const n=this,{config:a,$el:{tooltip:i}}=n,o=t.filter(c=>c&&De(n.getBaseValue(c)));if(!i||o.length===0||!a.tooltip_show)return;let s=i.datum();const l=JSON.stringify(t);if(!s||s.current!==l){const{index:c,x:f}=t.concat().sort()[0];_e(a.tooltip_onshow,n.api,t),i.html(n.getTooltipHTML(t,n.axis?n.axis.getXAxisTickFormat():n.categoryName.bind(n),n.getDefaultValueFormat(),n.color)).style("display",null).style("visibility",null).datum(s={index:c,x:f,current:l,width:i.property("offsetWidth"),height:i.property("offsetHeight")}),_e(a.tooltip_onshown,n.api,t),n._handleLinkedCharts(!0,c)}n.setTooltipPosition(o,e)},bindTooltipResizePos(){const t=this,{resizeFunction:e,state:n,$el:{tooltip:a}}=t;e.add(()=>{if(a.style("display")==="block"){const{current:i}=n,{width:o,xPosInPercent:s}=a.datum();let l=i.width/100*s;const c=i.width-(l+o);c<0&&(l+=c),a.style("left",`${l}px`)}})},hideTooltip(t){var e;const n=this,{api:a,config:i,$el:{tooltip:o}}=n;if(o&&o.style("display")!=="none"&&(!i.tooltip_doNotHide||t)){const s=JSON.parse((e=o.datum().current)!=null?e:{});_e(i.tooltip_onhide,a,s),o.style("display","none").style("visibility","hidden").datum(null),_e(i.tooltip_onhidden,a,s)}},_handleLinkedCharts(t,e){const n=this,{charts:a,config:i,state:{event:o}}=n;if(o!=null&&o.isTrusted&&i.tooltip_linked&&a.length>1){const s=i.tooltip_linked_name;a.filter(l=>l!==n.api).forEach(l=>{const{config:c,$el:f}=l.internal,g=c.tooltip_linked,v=c.tooltip_linked_name,m=gn.body.contains(f.chart.node());if(g&&s===v&&m){const S=f.tooltip.data()[0],P=e!==(S==null?void 0:S.index);try{l.tooltip[t&&P?"show":"hide"]({index:e})}catch(N){}}})}},updateTooltipOnRedraw(t,e){var n;const a=this,{config:i,$el:{eventRect:o,svg:s,tooltip:l},state:{event:c,hasAxis:f,hasRadar:g,hasTreemap:v}}=a;if((l==null?void 0:l.style("display"))==="block"&&c){const m=t!=null?t:(n=g?s:o)==null?void 0:n.node();if(f||g)if(a.isMultipleX())a.selectRectForMultipleXs(m,!1);else{const S=e!=null?e:a.getDataIndexFromEvent(c);e===-1?a.api.tooltip.hide():(a.selectRectForSingle(m,S),a.setExpand(S,null,!0))}else{const{clientX:S,clientY:P}=c;setTimeout(()=>{let N=[S,P].every(Number.isFinite)&&gn.elementFromPoint(S,P);const L=N&&ot(N).datum();if(L){const w=a.hasArcType()?a.convertToArcData(a.updateAngle(L)):L==null?void 0:L.data;v&&(N=s.node()),w&&a.showTooltip([w],N)}else a.api.tooltip.hide()},i.transition_duration)}}}},Yp={getTranslate(t,e=0){var n;const a=this,{config:i,state:o}=a,s=i.axis_rotated;let l=0,c,f;if(e&&/^(x|y2?)$/.test(t)&&(l=a.getAxisSize(t)*e),t==="main")c=$i(o.margin.left),f=$i(o.margin.top);else if(t==="context")c=$i(o.margin2.left),f=$i(o.margin2.top);else if(t==="legend")c=o.margin3.left,f=o.margin3.top;else if(t==="x")c=s?-l:0,f=s?0:o.height+l;else if(t==="y")c=s?0:-l,f=s?o.height+l:0;else if(t==="y2")c=s?0:o.width+l,f=s?-l-1:0;else if(t==="subX")c=0,f=s?0:o.height2;else if(t==="arc")c=o.arcWidth/2,f=o.arcHeight/2,(n=i.arc_rangeText_values)!=null&&n.length&&(f+=5+(a.hasType("gauge")&&i.title_text?10:0));else if(t==="polar")c=o.arcWidth/2,f=o.arcHeight/2;else if(t==="radar"){const[g,v]=a.getRadarSize();c=o.width/2-g,f=o.height/2-v}return`translate(${c}, ${f})`},transformMain(t,e){const n=this,{$el:{main:a},$T:i}=n,o=e!=null&&e.axisX?e.axisX:i(a.select(`.${Tn.axisX}`),t),s=e!=null&&e.axisY?e.axisY:i(a.select(`.${Tn.axisY}`),t),l=e!=null&&e.axisY2?e.axisY2:i(a.select(`.${Tn.axisY2}`),t);i(a,t).attr("transform",n.getTranslate("main")),o.attr("transform",n.getTranslate("x")),s.attr("transform",n.getTranslate("y")),l.attr("transform",n.getTranslate("y2")),a.select(`.${Ve.chartArcs}`).attr("transform",n.getTranslate("arc"))},transformAll(t,e){const n=this,{config:a,state:{hasAxis:i,hasFunnel:o,hasTreemap:s},$el:l}=n;!o&&!s&&n.transformMain(t,e),i&&a.subchart_show&&n.transformContext(t,e),l.legend&&n.transformLegend(t)}},Wp={isValidChartType(t){return!!(t&&Object.values(oe).indexOf(t)>-1)},setTargetType(t,e){const n=this,{config:a,state:{withoutFadeIn:i}}=n;n.mapToTargetIds(t).forEach(o=>{i[o]=e===a.data_types[o],a.data_types[o]=e}),t||(a.data_type=e)},updateTypesElements(){const t=this,{state:{current:e}}=t;Object.keys(oe).forEach(n=>{const a=oe[n],i=t.hasType(a,null,!0),o=e.types.indexOf(a);o===-1&&i?e.types.push(a):o>-1&&!i&&e.types.splice(o,1)}),t.setChartElements()},hasType(t,e,n=!1){var a;const i=this,{config:o,state:{current:s}}=i,l=o.data_types,c=e||i.data.targets;let f=!1;return!n&&((a=s.types)==null?void 0:a.indexOf(t))>-1?f=!0:c!=null&&c.length?c.forEach(g=>{const v=l[g.id];(v===t||!v&&t==="line")&&(f=!0)}):Object.keys(l).length?Object.keys(l).forEach(g=>{l[g]===t&&(f=!0)}):f=o.data_type===t,f},hasTypeOf(t,e,n=[]){return t in Sr?!Sr[t].filter(a=>n.indexOf(a)===-1).every(a=>!this.hasType(a,e)):!1},isTypeOf(t,e){var n;const a=ze(t)?t:t.id,i=this.config&&(((n=this.config.data_types)==null?void 0:n[a])||this.config.data_type);return je(e)?e.indexOf(i)>=0:i===e},hasPointType(){const t=this;return t.hasTypeOf("Line")||t.hasType("bubble")||t.hasType("scatter")},hasArcType(t,e){return this.hasTypeOf("Arc",t,e)},hasMultiArcGauge(){return this.hasType("gauge")&&this.config.gauge_type==="multi"},isLineType(t){const e=ze(t)?t:t.id;return!this.config.data_types[e]||this.isTypeOf(e,Sr.Line)},isStepType(t){return this.isTypeOf(t,Sr.Step)},isSplineType(t){return this.isTypeOf(t,Sr.Spline)},isAreaType(t){return this.isTypeOf(t,Sr.Area)},isAreaRangeType(t){return this.isTypeOf(t,Sr.AreaRange)},isBarType(t){return this.isTypeOf(t,"bar")},isBubbleType(t){return this.isTypeOf(t,"bubble")},isCandlestickType(t){return this.isTypeOf(t,"candlestick")},isScatterType(t){return this.isTypeOf(t,"scatter")},isTreemapType(t){return this.isTypeOf(t,"treemap")},isPieType(t){return this.isTypeOf(t,"pie")},isFunnelType(t){return this.isTypeOf(t,"funnel")},isGaugeType(t){return this.isTypeOf(t,"gauge")},isDonutType(t){return this.isTypeOf(t,"donut")},isPolarType(t){return this.isTypeOf(t,"polar")},isRadarType(t){return this.isTypeOf(t,"radar")},isArcType(t){return this.isPieType(t)||this.isDonutType(t)||this.isGaugeType(t)||this.isPolarType(t)||this.isRadarType(t)},isCirclePoint(t){const{config:e}=this,n=e.point_pattern;let a=!1;return(t==null?void 0:t.tagName)==="circle"?a=!0:a=e.point_type==="circle"&&(!n||je(n)&&n.length===0),a},lineData(t){return this.isLineType(t)?[t]:[]},arcData(t){return this.isArcType(t.data)?[t]:[]},labelishData(t){return this.isBarType(t)||this.isLineType(t)||this.isScatterType(t)||this.isBubbleType(t)||this.isCandlestickType(t)||this.isFunnelType(t)||this.isRadarType(t)||this.isTreemapType(t)?t.values.filter(e=>he(e.value)||!!e.value):[]},barLineBubbleData(t){return this.isBarType(t)||this.isLineType(t)||this.isBubbleType(t)?t.values:[]},isInterpolationType(t){return["basis","basis-closed","basis-open","bundle","cardinal","cardinal-closed","cardinal-open","catmull-rom","catmull-rom-closed","catmull-rom-open","linear","linear-closed","monotone-x","monotone-y","natural"].indexOf(t)>=0}};function Ni(t,e,n){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+e)/6,(t._y0+4*t._y1+n)/6)}function Fi(t){this._context=t}Fi.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Ni(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1);break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Ni(this,t,e);break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}};function Kp(t){return new Fi(t)}function Ar(){}function Vc(t){this._context=t}Vc.prototype={areaStart:Ar,areaEnd:Ar,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:{this._context.moveTo(this._x2,this._y2),this._context.closePath();break}case 2:{this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break}case 3:{this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4);break}}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x2=t,this._y2=e;break;case 1:this._point=2,this._x3=t,this._y3=e;break;case 2:this._point=3,this._x4=t,this._y4=e,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+e)/6);break;default:Ni(this,t,e);break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}};function Zp(t){return new Vc(t)}function Gc(t){this._context=t}Gc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var n=(this._x0+4*this._x1+t)/6,a=(this._y0+4*this._y1+e)/6;this._line?this._context.lineTo(n,a):this._context.moveTo(n,a);break;case 3:this._point=4;default:Ni(this,t,e);break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}};function Jp(t){return new Gc(t)}function Xc(t,e){this._basis=new Fi(t),this._beta=e}Xc.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,e=this._y,n=t.length-1;if(n>0)for(var a=t[0],i=e[0],o=t[n]-a,s=e[n]-i,l=-1,c;++l<=n;)c=l/n,this._basis.point(this._beta*t[l]+(1-this._beta)*(a+c*o),this._beta*e[l]+(1-this._beta)*(i+c*s));this._x=this._y=null,this._basis.lineEnd()},point:function(t,e){this._x.push(+t),this._y.push(+e)}};var Qp=function t(e){function n(a){return e===1?new Fi(a):new Xc(a,e)}return n.beta=function(a){return t(+a)},n}(.85);function Bi(t,e,n){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-e),t._y2+t._k*(t._y1-n),t._x2,t._y2)}function ls(t,e){this._context=t,this._k=(1-e)/6}ls.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:Bi(this,this._x1,this._y1);break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2,this._x1=t,this._y1=e;break;case 2:this._point=3;default:Bi(this,t,e);break}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var kp=function t(e){function n(a){return new ls(a,e)}return n.tension=function(a){return t(+a)},n}(0);function cs(t,e){this._context=t,this._k=(1-e)/6}cs.prototype={areaStart:Ar,areaEnd:Ar,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:{this._context.moveTo(this._x3,this._y3),this._context.closePath();break}case 2:{this._context.lineTo(this._x3,this._y3),this._context.closePath();break}case 3:{this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5);break}}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:Bi(this,t,e);break}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var qp=function t(e){function n(a){return new cs(a,e)}return n.tension=function(a){return t(+a)},n}(0);function us(t,e){this._context=t,this._k=(1-e)/6}us.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Bi(this,t,e);break}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var _p=function t(e){function n(a){return new us(a,e)}return n.tension=function(a){return t(+a)},n}(0);const Hc=Math.abs,En=Math.atan2,jr=Math.cos,tm=Math.max,fs=Math.min,rr=Math.sin,oa=Math.sqrt,bn=1e-12,Fa=Math.PI,Ui=Fa/2,zi=2*Fa;function em(t){return t>1?0:t<-1?Fa:Math.acos(t)}function Yc(t){return t>=1?Ui:t<=-1?-Ui:Math.asin(t)}function ds(t,e,n){var a=t._x1,i=t._y1,o=t._x2,s=t._y2;if(t._l01_a>bn){var l=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);a=(a*l-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*l-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>bn){var f=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,g=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*f+t._x1*t._l23_2a-e*t._l12_2a)/g,s=(s*f+t._y1*t._l23_2a-n*t._l12_2a)/g}t._context.bezierCurveTo(a,i,o,s,t._x2,t._y2)}function Wc(t,e){this._context=t,this._alpha=e}Wc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2);break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,a=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+a*a,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3;default:ds(this,t,e);break}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var nm=function t(e){function n(a){return e?new Wc(a,e):new ls(a,0)}return n.alpha=function(a){return t(+a)},n}(.5);function Kc(t,e){this._context=t,this._alpha=e}Kc.prototype={areaStart:Ar,areaEnd:Ar,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:{this._context.moveTo(this._x3,this._y3),this._context.closePath();break}case 2:{this._context.lineTo(this._x3,this._y3),this._context.closePath();break}case 3:{this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5);break}}},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,a=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+a*a,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:ds(this,t,e);break}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var rm=function t(e){function n(a){return e?new Kc(a,e):new cs(a,0)}return n.alpha=function(a){return t(+a)},n}(.5);function Zc(t,e){this._context=t,this._alpha=e}Zc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||this._line!==0&&this._point===3)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,a=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+a*a,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:ds(this,t,e);break}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};var am=function t(e){function n(a){return e?new Zc(a,e):new us(a,0)}return n.alpha=function(a){return t(+a)},n}(.5);function Jc(t){return t<0?-1:1}function Qc(t,e,n){var a=t._x1-t._x0,i=e-t._x1,o=(t._y1-t._y0)/(a||i<0&&-0),s=(n-t._y1)/(i||a<0&&-0),l=(o*i+s*a)/(a+i);return(Jc(o)+Jc(s))*Math.min(Math.abs(o),Math.abs(s),.5*Math.abs(l))||0}function kc(t,e){var n=t._x1-t._x0;return n?(3*(t._y1-t._y0)/n-e)/2:e}function hs(t,e,n){var a=t._x0,i=t._y0,o=t._x1,s=t._y1,l=(o-a)/3;t._context.bezierCurveTo(a+l,i+l*e,o-l,s-l*n,o,s)}function ji(t){this._context=t}ji.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:hs(this,this._t0,kc(this,this._t0));break}(this._line||this._line!==0&&this._point===1)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){var n=NaN;if(t=+t,e=+e,!(t===this._x1&&e===this._y1)){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,hs(this,kc(this,n=Qc(this,t,e)),n);break;default:hs(this,this._t0,n=Qc(this,t,e));break}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e,this._t0=n}}};function qc(t){this._context=new _c(t)}(qc.prototype=Object.create(ji.prototype)).point=function(t,e){ji.prototype.point.call(this,e,t)};function _c(t){this._context=t}_c.prototype={moveTo:function(t,e){this._context.moveTo(e,t)},closePath:function(){this._context.closePath()},lineTo:function(t,e){this._context.lineTo(e,t)},bezierCurveTo:function(t,e,n,a,i,o){this._context.bezierCurveTo(e,t,a,n,o,i)}};function im(t){return new ji(t)}function om(t){return new qc(t)}function tu(t){this._context=t}tu.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,e=this._y,n=t.length;if(n)if(this._line?this._context.lineTo(t[0],e[0]):this._context.moveTo(t[0],e[0]),n===2)this._context.lineTo(t[1],e[1]);else for(var a=eu(t),i=eu(e),o=0,s=1;s=0;--e)i[e]=(s[e]-i[e+1])/o[e];for(o[n-1]=(t[n]+i[n-1])/2,e=0;e=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:{if(this._t<=0)this._context.lineTo(this._x,e),this._context.lineTo(t,e);else{var n=this._x*(1-this._t)+t*this._t;this._context.lineTo(n,this._y),this._context.lineTo(n,e)}break}}this._x=t,this._y=e}};function cm(t){return new Vi(t,.5)}function um(t){return new Vi(t,0)}function fm(t){return new Vi(t,1)}function dm(t){const e=this;let n;return e.isLineType(t)?n=e.generateGetLinePoints(e.getShapeIndices(e.isLineType)):e.isBarType(t)&&(n=e.generateGetBarPoints(e.getShapeIndices(e.isBarType))),n}var hm={getDrawShape(){const t=this,e=t.config.axis_rotated,{hasRadar:n,hasTreemap:a}=t.state,i={type:{},indices:{},pos:{}};if(!a&&["bar","candlestick","line","area"].forEach(o=>{const s=Cn(/^(bubble|scatter)$/.test(o)?"line":o);if(t.hasType(o)||t.hasTypeOf(s)||o==="line"&&(t.hasType("bubble")||t.hasType("scatter"))){const l=t.getShapeIndices(t[`is${s}Type`]),c=t[`generateDraw${s}`];i.indices[o]=l,i.type[o]=c?c.bind(t)(l,!1):void 0}}),!t.hasArcType()||n||a){let o,s;a||(o=n?t.radarCircleX:e?t.circleY:t.circleX,s=n?t.radarCircleY:e?t.circleX:t.circleY),i.pos={xForText:t.generateXYForText(i.indices,!0),yForText:t.generateXYForText(i.indices,!1),cx:(o||function(){}).bind(t),cy:(s||function(){}).bind(t)}}return i},getShapeIndices(t){const e=this,{config:n}=e,a=n.data_xs,i=cn(a),o={};let s=i?{}:0;return i&&Mo(Object.keys(a).map(l=>a[l])).forEach(l=>{s[l]=0,o[l]={}}),e.filterTargetsToShow(e.data.targets.filter(t,e)).forEach(l=>{var c;const f=l.id in a?a[l.id]:"",g=f?o[f]:o;for(let v=0,m;m=n.data_groups[v];v++)if(!(m.indexOf(l.id)<0))for(let S=0,P;P=m[S];S++){if(P in g){g[l.id]=g[P];break}l.id!==P&&f&&(g[P]=(c=g[l.id])!=null?c:s[f])}ln(g[l.id])&&(g[l.id]=f?s[f]++:s++,g.__max__=(f?s[f]:s)-1)}),o},getIndices(t,e,n){const a=this,{data_xs:i,bar_indices_removeNull:o}=a.config,{id:s,index:l}=e;if(a.isBarType(s)&&o){const c={};return a.getAllValuesOnIndex(l,!0).forEach((f,g)=>{c[f.id]=g,c.__max__=g}),c}return cn(i)?t[i[s]]:t},getIndicesMax(t){return cn(this.config.data_xs)?Object.keys(t).map(e=>t[e].__max__||0).reduce((e,n)=>e+n):t.__max__},getShapeX(t,e,n){const a=this,{config:i,scale:o}=a,s=n?o.subX:o.zoom||o.x,l=i.bar_overlap,c=i.bar_padding,f=(v,m)=>v+m,g=nr(t)&&(t._$total.length?t._$total.reduce(f)/2:0);return v=>{const m=a.getIndices(e,v,"getShapeX"),S=v.id in m?m[v.id]:0,P=(m.__max__||0)+1;let N=0;if(cn(v.x)){const L=s(v.x,!0);if(g){const w=t[v.id]||t._$width;N=l?L-w/2:L-w+t._$total.slice(0,S+1).reduce(f)-g}else N=L-(he(t)?t:t._$width)*(P/2-(l?1:S))}return t&&N&&P>1&&c&&(S&&(N+=c*S),P>2?N-=(P-1)*c/2:P===2&&(N-=c/2)),N}},getShapeY(t){const e=this,n=e.isStackNormalized();return a=>{let{value:i}=a;return he(a)?i=a:e.isAreaRangeType(a)?i=e.getBaseValue(a,"mid"):n?i=e.getRatio("index",a,!0):e.isBubbleZType(a)?i=e.getBubbleZData(a.value,"y"):e.isBarRangeType(a)&&(i=i[1]),e.getYScaleById(a.id,t)(i)}},getShapeYMin(t){const e=this,n=e.axis.getId(t),a=e.scale[n],[i]=a.domain(),o=e.config[`axis_${n}_inverted`];return!e.isGrouped(t)&&!o&&i>0?i:0},getShapeOffsetData(t){const e=this,n=e.orderTargets(e.filterTargetsToShow(e.data.targets.filter(t,e))),a=e.isStackNormalized(),i=n.map(s=>{let l=s.values;const c={};e.isStepType(s)&&(l=e.convertValuesToStep(l));const f=l.reduce((g,v)=>{const m=Number(v.x);return g[m]=v,c[m]=a?e.getRatio("index",v,!0):v.value,g},{});return{id:s.id,rowValues:l,rowValueMapByXValue:f,values:c}});return{indexMapByTargetId:n.reduce((s,{id:l},c)=>(s[l]=c,s),{}),shapeOffsetTargets:i}},getShapeOffset(t,e,n){const a=this,{shapeOffsetTargets:i,indexMapByTargetId:o}=a.getShapeOffsetData(t),s=a.config.data_groupsZeroAs;return(l,c)=>{const{id:f,value:g,x:v}=l,m=a.getIndices(e,l),S=a.getYScaleById(f,n);if(a.isBarRangeType(l))return S(g[0]);const P=Number(v),N=S(s==="zero"?0:a.getShapeYMin(f));let L=N;return i.filter(w=>w.id!==f&&m[w.id]===m[f]).forEach(w=>{const{id:X,rowValueMapByXValue:W,rowValues:H,values:k}=w;if(o[X]=0&&he(K)&&(g!==0||s==="positive"&&K>0||s==="negative"&&K<0)&&(L+=S(K)-N)}}),L}},circleY(t,e){const n=this,a=t.id;let i;return n.isGrouped(a)&&(i=dm.bind(n)(t)),i?i(t,e)[0][1]:n.getYScaleById(a)(n.getBaseValue(t))},getBarW(t,e,n){var a,i,o,s,l;const c=this,{config:f,org:g,scale:v,state:m}=c,S=c.getMaxDataCount(),P=t==="bar"&&((a=f.data_groups)==null?void 0:a.length),N=`${t}_width`,{k:L}=(o=(i=c.getZoomTransform)==null?void 0:i.call(c))!=null?o:{k:1},w=[(s=f.axis_x_min)!=null?s:g.xDomain[0],(l=f.axis_x_max)!=null?l:g.xDomain[1]].map(c.axis.isTimeSeries()?Yn.bind(c):Number);let X=e.tickInterval(S);if(v.zoom&&!c.axis.isCategorized()&&L>1){const k=w.every((K,at)=>K===g.xDomain[at]);X=g.xDomain.map((K,at)=>{const ht=k?K:K-Math.abs(w[at]);return v.zoom(ht)}).reduce((K,at)=>Math.abs(K)+at)/S}const W=k=>{const K=k?f[N][k]:f[N],at=k?K.ratio:f[`${N}_ratio`],ht=k?K.max:f[`${N}_max`],$t=he(K)?K:ve(K)?K.call(c,m.width,n,S):n?X*at/n:0;return ht&&$t>ht?ht:$t};let H=W();return!P&&nr(f[N])&&(H={_$width:H,_$total:[]},c.filterTargetsToShow(c.data.targets).forEach(k=>{f[N][k.id]&&(H[k.id]=W(k.id),H._$total.push(H[k.id]||H._$width))})),H},getShapeByIndex(t,e,n){const a=this,{$el:i}=a,o=De(e)?`-${e}`:"";let s=i[t];return s&&!s.empty()?s=s.filter(l=>n?l.id===n:!0).filter(l=>De(e)?l.index===e:!0):s=(n?i.main.selectAll(`.${Ue[`${t}s`]}${a.getTargetSelectorSuffix(n)}`):i.main).selectAll(`.${Ue[t]}${o}`),s},isWithinShape(t,e){var n;const a=this,i=ot(t);let o;return a.isTargetToShow(e.id)?(n=a.hasValidPointType)!=null&&n.call(a,t.nodeName)?o=a.isStepType(e)?a.isWithinStep(t,a.getYScaleById(e.id)(a.getBaseValue(e))):a.isWithinCircle(t,a.isBubbleType(e)?a.pointSelectR(e)*1.5:0):t.nodeName==="path"&&(o=i.classed(Ue.bar)?a.isWithinBar(t):!0):o=!1,o},getInterpolate(t){const n=this.getInterpolateType(t);return{basis:Kp,"basis-closed":Zp,"basis-open":Jp,bundle:Qp,cardinal:kp,"cardinal-closed":qp,"cardinal-open":_p,"catmull-rom":nm,"catmull-rom-closed":rm,"catmull-rom-open":am,"monotone-x":im,"monotone-y":om,natural:sm,"linear-closed":lm,linear:gs,step:cm,"step-after":fm,"step-before":um}[n]},getInterpolateType(t){const e=this,{config:n}=e,a=n.spline_interpolation_type,i=e.isInterpolationType(a)?a:"cardinal";return e.isSplineType(t)?i:e.isStepType(t)?n.line_step_type:"linear"},isWithinBar(t){const e=Hn(this.state.event,t),n=Hl(t),[a,i]=n,o=Math.min(a.x,i.x),s=Math.min(a.y,i.y),l=this.config.bar_sensitivity,{width:c,height:f}=t.getBBox(),g=o-l,v=o+c+l,m=s+f+l,S=s-l;return ge in t?gm(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,Rn=(t,e,n)=>vm(t,typeof e!="symbol"?e+"":e,n);class Vr{constructor(e){Rn(this,"api"),Rn(this,"config"),Rn(this,"cache"),Rn(this,"$el"),Rn(this,"state"),Rn(this,"charts"),Rn(this,"data",{xs:{},targets:[]}),Rn(this,"axis"),Rn(this,"scale",{x:null,y:null,y2:null,subX:null,subY:null,subY2:null,zoom:null}),Rn(this,"org",{xScale:null,xDomain:null}),Rn(this,"color"),Rn(this,"patterns"),Rn(this,"levelColor"),Rn(this,"point"),Rn(this,"brush"),Rn(this,"format",{extraLineClasses:null,xAxisTick:null,dataTime:null,defaultAxisTime:null,axisTime:null});const n=this;n.api=e,n.config=new Nr,n.cache=new gv;const a=new uv;n.$el=a.getStore("element"),n.state=a.getStore("state"),n.$T=n.$T.bind(n)}$T(e,n,a){const{config:i,state:o}=this,s=i.transition_duration,l=i.subchart_show;let c=e;return c&&("tagName"in c&&(c=ot(c)),c=(n!==!1&&s||n)&&(!o.zooming||o.dragging)&&!o.resizing&&o.rendered&&!l?c.transition(a).duration(s):c),c}beforeInit(){const e=this;e.callPluginHook("$beforeInit"),_e(e.config.onbeforeinit,e.api)}afterInit(){const e=this;e.callPluginHook("$afterInit"),_e(e.config.onafterinit,e.api)}init(){const e=this,{config:n,state:a,$el:i}=e,o=n.boost_useCssRule;if(vv(e),a.hasRadar=!a.hasAxis&&e.hasType("radar"),a.hasFunnel=!a.hasAxis&&e.hasType("funnel"),a.hasTreemap=!a.hasAxis&&e.hasType("treemap"),a.hasAxis=!e.hasArcType()&&!a.hasFunnel&&!a.hasTreemap,a.datetimeId=`bb-${+new Date*gr()}`,o){const l=gn.createElement("style");l.type="text/css",gn.head.appendChild(l),a.style={rootSelctor:`.${a.datetimeId}`,sheet:l.sheet},i.style=l}const s={element:n.bindto,classname:"bb"};Be(n.bindto)&&(s.element=n.bindto.element||"#chart",s.classname=n.bindto.classname||s.classname),i.chart=ve(s.element.node)?n.bindto.element:ot(s.element||[]),i.chart.empty()&&(i.chart=ot(gn.body.appendChild(gn.createElement("div")))),i.chart.html("").classed(s.classname,!0).classed(a.datetimeId,o).style("position","relative"),e.initParams(),e.initToRender()}initToRender(e){const n=this,{config:a,state:i,$el:{chart:o}}=n,s=()=>nv(o,{display:"none",visibility:"hidden"}),l=a.render.lazy===!1?!1:a.render.lazy||s(),c=Ke.MutationObserver;l&&c&&a.render.observe!==!1&&!e&&new c((f,g)=>{s()||(g.disconnect(),!i.rendered&&n.initToRender(!0))}).observe(o.node(),{attributes:!0,attributeFilter:["class","style"]}),(!l||e)&&n.convertData(a,f=>{n.initWithData(f),n.afterInit()})}initParams(){var e;const n=this,{config:a,format:i,state:o}=n,s=a.axis_rotated;if(n.color=n.generateColor(),n.levelColor=n.generateLevelColor(),a.padding===!1&&(a.axis_x_show=!1,a.axis_y_show=!1,a.axis_y2_show=!1,a.subchart_show=!1),(n.hasPointType()||(e=n.hasLegendDefsPoint)!=null&&e.call(n))&&(n.point=n.generatePoint()),o.hasAxis){n.initClip(),i.extraLineClasses=n.generateExtraLineClass(),i.dataTime=a.data_xLocaltime?Ws:Ks,i.axisTime=a.axis_x_localtime?ao:io;const l=n.config.zoom_enabled&&n.config.zoom_type==="drag";i.defaultAxisTime=c=>{const{x:f,zoom:g}=n.scale,v=l?g:g&&f.orgDomain().toString()!==g.domain().toString(),m=c.getMilliseconds()&&".%L"||c.getSeconds()&&".:%S"||c.getMinutes()&&"%I:%M"||c.getHours()&&"%I %p"||c.getDate()!==1&&"%b %d"||v&&c.getDate()===1&&"%b'%y"||c.getMonth()&&"%-m/%-d"||"%Y";return i.axisTime(m)(c)}}o.isLegendRight=a.legend_position==="right",o.isLegendInset=a.legend_position==="inset",o.isLegendTop=a.legend_inset_anchor==="top-left"||a.legend_inset_anchor==="top-right",o.isLegendLeft=a.legend_inset_anchor==="top-left"||a.legend_inset_anchor==="bottom-left",o.rotatedPadding.top=n.getResettedPadding(o.rotatedPadding.top),o.rotatedPadding.right=s&&!a.axis_x_show?0:30,o.inputType=rv(a.interaction_inputType_mouse,a.interaction_inputType_touch)}initWithData(e){var n,a,i;const o=this,{config:s,scale:l,state:c,$el:f,org:g}=o,{hasAxis:v,hasFunnel:m,hasTreemap:S}=c,P=s.interaction_enabled,N=o.hasType("polar"),L=s.data_labels_backgroundColors;if(v&&(o.axis=o.getAxisInstance(),s.zoom_enabled&&o.initZoom()),o.data.xs={},o.data.targets=o.convertDataToTargets(e),s.data_filter&&(o.data.targets=o.data.targets.filter(s.data_filter.bind(o.api))),s.data_hide&&o.addHiddenTargetIds(s.data_hide===!0?o.mapToIds(o.data.targets):s.data_hide),s.legend_hide&&o.addHiddenLegendIds(s.legend_hide===!0?o.mapToIds(o.data.targets):s.legend_hide),o.updateSizes(),o.updateScales(!0),v){const{x:W,y:H,y2:k,subX:K,subY:at,subY2:ht}=l;W&&(W.domain(na(o.getXDomain(o.data.targets),!s.axis_x_inverted)),K.domain(W.domain()),g.xDomain=W.domain()),H&&(H.domain(o.getYDomain(o.data.targets,"y")),at.domain(H.domain())),k&&(k.domain(o.getYDomain(o.data.targets,"y2")),ht&&ht.domain(k.domain()))}if(f.svg=f.chart.append("svg").style("overflow","hidden").style("display","block"),P&&c.inputType){const W=c.inputType==="touch",{onclick:H,onover:k,onout:K}=s;f.svg.on("click",(H==null?void 0:H.bind(o.api))||null).on(W?"touchstart":"mouseenter",(k==null?void 0:k.bind(o.api))||null).on(W?"touchend":"mouseleave",(K==null?void 0:K.bind(o.api))||null)}s.svg_classname&&f.svg.attr("class",s.svg_classname);const w=ve(s.color_tiles)&&o.patterns;(v||w||N||S||L||(n=o.hasLegendDefsPoint)!=null&&n.call(o))&&(f.defs=f.svg.append("defs"),v&&["id","idXAxis","idYAxis","idGrid"].forEach(W=>{o.appendClip(f.defs,c.clip[W])}),o.generateTextBGColorFilter(L),w&&o.patterns.forEach(W=>f.defs.append(()=>W.node))),o.updateSvgSize(),o.bindResize();const X=f.svg.append("g").classed(Se.main,!0).attr("transform",m||S?null:o.getTranslate("main"));if(f.main=X,s.subchart_show&&o.initSubchart(),s.tooltip_show&&o.initTooltip(),s.title_text&&o.initTitle(),!S&&s.legend_show&&o.initLegend(),s.data_empty_label_text&&X.append("text").attr("class",`${On.text} ${Se.empty}`).attr("text-anchor","middle").attr("dominant-baseline","middle"),v&&(s.regions.length&&o.initRegion(),!s.clipPath&&o.axis.init()),X.append("g").classed(Se.chart,!0).attr("clip-path",v?c.clip.path:null),o.callPluginHook("$init"),o.initChartElements(),v&&(P&&((a=o.initEventRect)==null||a.call(o)),o.initGrid(),s.clipPath&&((i=o.axis)==null||i.init())),o.updateTargets(o.data.targets),o.updateDimension(),_e(s.oninit,o.api),o.setBackground(),o.redraw({withTransition:!1,withTransform:!0,withUpdateXDomain:!0,withUpdateOrgXDomain:!0,withTransitionForAxis:!1,initializing:!0}),s.data_onmin||s.data_onmax){const W=o.getMinMaxData();_e(s.data_onmin,o.api,W.min),_e(s.data_onmax,o.api,W.max)}s.tooltip_show&&o.initShowTooltip(),c.rendered=!0}initChartElements(){const e=this,{hasAxis:n,hasRadar:a,hasTreemap:i}=e.state,o=[];if(n){const s=["bar","bubble","candlestick","line"];e.config.bar_front&&s.push(s.shift()),s.forEach(l=>{const c=Cn(l);(l==="line"&&e.hasTypeOf(c)||e.hasType(l))&&o.push(c)})}else if(i)o.push("Treemap");else if(e.hasType("funnel"))o.push("Funnel");else{const s=e.hasType("polar");a||o.push("Arc","Pie"),e.hasType("gauge")?o.push("Gauge"):a?o.push("Radar"):s&&o.push("Polar")}o.forEach(s=>{e[`init${s}`]()}),cn(e.config.data_labels)&&!e.hasArcType(null,["radar"])&&e.initText()}setChartElements(){const e=this,{$el:{chart:n,svg:a,defs:i,main:o,tooltip:s,legend:l,title:c,grid:f,needle:g,arcs:v,circle:m,bar:S,candlestick:P,line:N,area:L,text:w}}=e;e.api.$={chart:n,svg:a,defs:i,main:o,tooltip:s,legend:l,title:c,grid:f,arc:v,circles:m,bar:{bars:S},candlestick:P,line:{lines:N,areas:L},needle:g,text:{texts:w}}}setBackground(){const e=this,{config:{background:n},state:a,$el:{svg:i}}=e;if(cn(n)){const o=i.select("g").insert(n.imgUrl?"image":"rect",":first-child");n.imgUrl?o.attr("href",n.imgUrl):n.color&&o.style("fill",n.color).attr("clip-path",a.clip.path),o.attr("class",n.class||null).attr("width","100%").attr("height","100%")}}updateTargets(e){var n;const a=this,{hasAxis:i,hasFunnel:o,hasRadar:s,hasTreemap:l}=a.state,c=g=>a[`updateTargetsFor${g}`](e.filter(a[`is${g}Type`].bind(a)));if(a.updateTargetsForText(e),i)["bar","candlestick","line"].forEach(g=>{const v=Cn(g);(g==="line"&&a.hasTypeOf(v)||a.hasType(g))&&c(v)}),a.updateTargetsForSubchart&&a.updateTargetsForSubchart(e);else if(a.hasArcType(e)){let g="Arc";s?g="Radar":a.hasType("polar")&&(g="Polar"),c(g)}else o?c("Funnel"):l&&c("Treemap");const f=a.hasType("bubble")||a.hasType("scatter");f&&((n=a.updateTargetForCircle)==null||n.call(a)),a.filterTargetsToShowAtInit(f)}filterTargetsToShowAtInit(e=!1){const n=this,{$el:{svg:a},$T:i}=n;let o=`.${Se.target}`;e&&(o+=`, .${$n.chartCircles} > .${$n.circles}`),i(a.selectAll(o).filter(s=>n.isTargetToShow(s.id))).style("opacity",null)}getWithOption(e){const n={Dimension:!0,EventRect:!0,Legend:!1,Subchart:!0,Transform:!1,Transition:!0,TrimXDomain:!0,UpdateXAxis:"UpdateXDomain",UpdateXDomain:!1,UpdateOrgXDomain:!1,TransitionForExit:"Transition",TransitionForAxis:"Transition",Y:!0};return Object.keys(n).forEach(a=>{let i=n[a];ze(i)&&(i=n[i]),n[a]=$r(e,`with${a}`,i)}),n}initialOpacity(e){const n=this,{withoutFadeIn:a}=n.state;return n.getBaseValue(e)!==null&&a[e.id]?null:"0"}bindResize(){const e=this,{$el:n,config:a,state:i}=e,o=xv(a.resize_timer),s=[];s.push(()=>_e(a.onresize,e.api)),/^(true|parent)$/.test(a.resize_auto)&&s.push(()=>{i.resizing=!0,a.legend_show&&(e.updateSizes(),e.updateLegend()),e.api.flush(!1)}),s.push(()=>{_e(a.onresized,e.api),i.resizing=!1}),s.forEach(l=>o.add(l)),e.resizeFunction=o,a.resize_auto==="parent"?(e.resizeFunction.resizeObserver=new ResizeObserver(e.resizeFunction.bind(e))).observe(n.chart.node().parentNode):Ke.addEventListener("resize",e.resizeFunction)}callPluginHook(e,...n){this.config.plugins.forEach(a=>{e==="$beforeInit"&&(a.$$=this,this.api.plugins.push(a)),a[e](...n)})}}yn(Vr.prototype,[Mv,Dv,Lv,jv,Vv,Yv,Wv,zv,Kv,Zv,Jv,Bp,hm,Up,zp,Gp,Xp,Hp,Yp,Wp]);function pm(t){const e=this.config;let n,a,i;const o=()=>{const s=a.shift();if(s&&n&&nr(n)&&s in n)return n=n[s],o();if(!s)return n};Object.keys(e).forEach(s=>{n=t,a=s.split("_"),i=o(),Qe(i)&&(e[s]=i)}),this.api&&(this.state.orgConfig=t)}var mm={resize(t){const e=this.internal,{config:n,state:a}=e;a.rendered&&(n.size_width=t?t.width:null,n.size_height=t?t.height:null,a.resizing=!0,this.flush(!1),e.resizeFunction())},flush(t){var e,n;const a=this.internal,{state:i,$el:{zoomResetBtn:o}}=a;i.rendered?(i.resizing?(e=a.brush)==null||e.updateResize():(n=a.axis)==null||n.setOrient(),o==null||o.style("display","none"),a.scale.zoom=null,t?a.redraw({withTransform:!0,withUpdateXDomain:!0,withUpdateOrgXDomain:!0,withLegend:!0}):a.updateAndRedraw({withLegend:!0,withTransition:!1,withTransitionForTransform:!1}),!i.resizing&&a.brush&&(a.brush.getSelection().call(a.brush.move),a.unselectRect())):a.initToRender(!0)},destroy(){var t;const e=this.internal,{$el:{chart:n,style:a,svg:i}}=e;if(cn(e)){e.callPluginHook("$willDestroy"),e.charts.splice(e.charts.indexOf(this),1),e.unbindAllEvents(),i.select("*").interrupt(),e.resizeFunction.clear(),(t=e.resizeFunction.resizeObserver)==null||t.disconnect(),Ke.removeEventListener("resize",e.resizeFunction),n.classed("bb",!1).style("position",null).selectChildren().remove(),a&&a.parentNode.removeChild(a),Object.keys(this).forEach(o=>{o==="internal"&&Object.keys(e).forEach(s=>{e[s]=null}),this[o]=null,delete this[o]});for(const o in this)this[o]=()=>{}}return null},config(t,e,n){const a=this.internal,{config:i,state:o}=a,s=t==null?void 0:t.replace(/\./g,"_");let l;return t&&s in i?Qe(e)?(i[s]=e,l=e,n&&this.flush()):l=i[s]:(arguments.length===0||qn(t))&&(l=o.orgConfig),l}},ym={color(t){return this.internal.color(t)}};const au=function(t){const{targets:e}=this.internal.data;if(!ln(t)){const n=je(t)?t:[t];return e.filter(a=>n.some(i=>i===a.id))}return e};yn(au,{shown:function(t){return this.internal.filterTargetsToShow(this.data(t))},values:function(t,e=!0){let n=null;if(t){const a=this.data(t);je(a)&&(n=[],a.forEach(i=>{const o=i.values.map(s=>s.value);e?n=n.concat(o):n.push(o)}))}return n},names:function(t){return this.internal.updateDataAttributes("names",t)},colors:function(t){return this.internal.updateDataAttributes("colors",t)},axes:function(t){return this.internal.updateDataAttributes("axes",t)},min:function(){return this.internal.getMinMaxData().min},max:function(){return this.internal.getMinMaxData().max}});var xm={data:au};const Tm=t=>{var e,n;return(n=(e=Ke).btoa)==null?void 0:n.call(e,encodeURIComponent(t).replace(/%([0-9A-F]{2})/g,(a,i)=>String.fromCharCode(+`0x${i}`)))};function $m(t,e,n){const{width:a,height:i}=e||n,o=new XMLSerializer,s=t.cloneNode(!0),l=tv(Lr(gn.styleSheets)).filter(m=>m.cssText).map(m=>m.cssText);s.setAttribute("xmlns",ae.xhtml),s.style.margin="0",s.style.padding="0",e.preserveFontStyle&&s.querySelectorAll("text").forEach(m=>{m.innerHTML=""});const c=o.serializeToString(s),f=gn.createElement("style");f.appendChild(gn.createTextNode(l.join(` +`)));const g=o.serializeToString(f),v=` + + ${g} + ${c.replace(/(url\()[^#]+/g,"$1")} + `;return`data:image/svg+xml;base64,${Tm(v)}`}function Sm(t,e){const{top:n,left:a}=e,{x:i,y:o}=t.getBBox(),{a:s,b:l,c,d:f,e:g,f:v}=t.getScreenCTM(),{width:m,height:S}=t.getBoundingClientRect();return{x:s*i+c*o+g-a,y:l*i+f*o+v-n+(S-Math.round(S/4)),width:m,height:S}}function Am(t){const{left:e,top:n}=t.getBoundingClientRect(),a=o=>o.textContent||o.childElementCount,i=[];return Lr(t.querySelectorAll("text")).filter(a).forEach(o=>{const s=l=>{const{fill:c,fontFamily:f,fontSize:g,textAnchor:v,transform:m}=Ke.getComputedStyle(l),{x:S,y:P,width:N,height:L}=Sm(l,{left:e,top:n});return{[l.textContent]:{x:S,y:P,width:N,height:L,fill:c,fontFamily:f,fontSize:g,textAnchor:v,transform:m}}};if(o.childElementCount>1){const l=[];return Lr(o.querySelectorAll("tspan")).filter(a).forEach(c=>{i.push(s(c))}),l}else i.push(s(o))}),i}function Em(t,e){e.forEach(n=>{Object.keys(n).forEach(a=>{const{x:i,y:o,width:s,height:l,fill:c,fontFamily:f,fontSize:g,transform:v}=n[a];if(t.save(),t.font=`${g} ${f}`,t.fillStyle=c,v==="none")t.fillText(a,i,o);else{const m=v.replace(/(matrix|\(|\))/g,"").split(",");m.splice(4).every(S=>+S==0)?(m.push(i+s-s/4),m.push(o-l+l/3)):(m.push(i),m.push(o)),t.transform(...m),t.fillText(a,0,0)}t.restore()})})}var bm={export(t,e){const n=this.internal,{state:a,$el:{chart:i,svg:o}}=n,{width:s,height:l}=a.current,c=ea(Object.create(null),{width:s,height:l,preserveAspectRatio:!0,preserveFontStyle:!1,mimeType:"image/png"},t),f=$m(i.node(),c,{width:s,height:l}),g=c.preserveFontStyle?Am(o.node()):[];if(e&&ve(e)){const v=new Image;v.crossOrigin="Anonymous",v.onload=()=>{const m=gn.createElement("canvas"),S=m.getContext("2d");m.width=c.width||s,m.height=c.height||l,S.drawImage(v,0,0),g.length&&(Em(S,g),g.length=0),e.bind(this)(m.toDataURL(c.mimeType))},v.src=f}return f}},Rm={focus(t){const e=this.internal,{state:n}=e,a=e.mapToTargetIds(t),i=e.$el.svg.selectAll(e.selectorTargets(a.filter(e.isTargetToShow,e)));this.revert(),this.defocus(),i.classed(qe.focused,!0).classed(qe.defocused,!1),e.hasArcType()&&!n.hasRadar&&(e.expandArc(a),e.hasType("gauge")&&e.markOverlapped(t,e,`.${Un.gaugeValue}`)),e.toggleFocusLegend(a,!0),n.focusedTargetIds=a,n.defocusedTargetIds=n.defocusedTargetIds.filter(o=>a.indexOf(o)<0)},defocus(t){const e=this.internal,{state:n}=e,a=e.mapToTargetIds(t);e.$el.svg.selectAll(e.selectorTargets(a.filter(e.isTargetToShow,e))).classed(qe.focused,!1).classed(qe.defocused,!0),e.hasArcType(null,["polar"])&&(e.unexpandArc(a),e.hasType("gauge")&&e.undoMarkOverlapped(e,`.${Un.gaugeValue}`)),e.toggleFocusLegend(a,!1),n.focusedTargetIds=n.focusedTargetIds.filter(o=>a.indexOf(o)<0),n.defocusedTargetIds=a},revert(t){const e=this.internal,{config:n,state:a,$el:i}=e,o=e.mapToTargetIds(t);i.svg.selectAll(e.selectorTargets(o)).classed(qe.focused,!1).classed(qe.defocused,!1),e.hasArcType(null,["polar"])&&e.unexpandArc(o),n.legend_show&&(e.showLegend(o.filter(e.isLegendToShow.bind(e))),i.legend.selectAll(e.selectorLegends(o)).filter(function(){return ot(this).classed(qe.legendItemFocused)}).classed(qe.legendItemFocused,!1)),a.focusedTargetIds=[],a.defocusedTargetIds=[]}},Im={legend:{show:function(t){const e=this.internal;e.showLegend(e.mapToTargetIds(t)),e.updateAndRedraw({withLegend:!0})},hide:function(t){const e=this.internal;e.hideLegend(e.mapToTargetIds(t)),e.updateAndRedraw({withLegend:!0})}}},Om={load(t){const e=this.internal,{config:n}=e;t.xs&&e.addXs(t.xs),"names"in t&&this.data.names(t.names),"classes"in t&&Object.keys(t.classes).forEach(a=>{n.data_classes[a]=t.classes[a]}),"categories"in t&&e.axis.isCategorized()&&(n.axis_x_categories=t.categories),"axes"in t&&Object.keys(t.axes).forEach(a=>{n.data_axes[a]=t.axes[a]}),"colors"in t&&Object.keys(t.colors).forEach(a=>{n.data_colors[a]=t.colors[a]}),"unload"in t&&t.unload!==!1?e.unload(e.mapToTargetIds(t.unload===!0?null:t.unload),()=>{jl(()=>e.loadFromArgs(t))}):e.loadFromArgs(t)},unload(t){const e=this.internal;let n=t||{};qn(n)&&this.tooltip.hide(),je(n)?n={ids:n}:ze(n)&&(n={ids:[n]});const a=e.mapToTargetIds(n.ids);e.unload(a,()=>{e.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0}),e.cache.remove(a),cc.call(e,n.done,n.resizeAfter)})}};function iu(t,e,n){const a=this.internal,i=a.mapToTargetIds(e),o=a.state.hiddenTargetIds.map(c=>i.indexOf(c)>-1&&c).filter(Boolean);a.state.toggling=!0,a[`${t?"remove":"add"}HiddenTargetIds`](i);const s=a.$el.svg.selectAll(a.selectorTargets(i)),l=t?null:"0";t&&o.length&&(s.style("display",null),_e(a.config.data_onshown,this,o)),a.$T(s).style("opacity",l,"important").call(Si,()=>{var c;!t&&o.length===0&&(s.style("display","none"),_e((c=a.config)==null?void 0:c.data_onhidden,this,i)),s.style("opacity",l)}),n.withLegend&&a[`${t?"show":"hide"}Legend`](i),a.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0,withLegend:!0}),a.state.toggling=!1}var Cm={show(t,e={}){iu.call(this,!0,t,e)},hide(t,e={}){iu.call(this,!1,t,e)},toggle(t,e={}){const n=this.internal,a={show:[],hide:[]};n.mapToTargetIds(t).forEach(i=>a[n.isTargetToShow(i)?"hide":"show"].push(i)),a.show.length&&this.show(a.show,e),a.hide.length&&setTimeout(()=>this.hide(a.hide,e),0)}},Pm={tooltip:{show:function(t){var e,n,a;const i=this.internal,{$el:o,config:s,state:{eventReceiver:l,hasFunnel:c,hasTreemap:f,inputType:g}}=i;let v,m;if(t.mouse&&(m=t.mouse),t.data){const{data:S}=t,P=(e=i.getYScaleById(S.id))==null?void 0:e(S.value);if((c||f)&&S.id){const N=i.selectorTarget(S.id,void 0,`.${sn.shape}`);l.rect=o.main.select(N)}else i.isMultipleX()?m=[i.xx(S),P]:(s.tooltip_grouped||(m=[0,P]),v=(a=S.index)!=null?a:i.hasArcType()&&S.id?(n=i.getArcElementByIdOrIndex(S.id))==null?void 0:n.datum().index:i.getIndexByX(S.x))}else Qe(t.x)?v=i.getIndexByX(t.x):Qe(t.index)&&(v=t.index);(g==="mouse"?["mouseover","mousemove"]:["touchstart"]).forEach(S=>{i.dispatchEvent(S,v,m)})},hide:function(){var t,e,n;const a=this.internal,{state:{inputType:i},$el:{tooltip:o}}=a,s=o==null?void 0:o.datum();if(s){const{index:l}=JSON.parse(s.current)[0];(i==="mouse"?["mouseout"]:["touchend"]).forEach(c=>{a.dispatchEvent(c,l)})}i==="touch"&&a.callOverOutForTouch(),a.hideTooltip(!0),(t=a.hideGridFocus)==null||t.call(a),(e=a.unexpandCircles)==null||e.call(a),(n=a.expandBarTypeShapes)==null||n.call(a,!1)}}},wm=Object.defineProperty,Mm=(t,e,n)=>e in t?wm(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,ou=(t,e,n)=>Mm(t,typeof e!="symbol"?e+"":e,n);class Er{constructor(e){ou(this,"plugins",[]),ou(this,"internal");const n=new Vr(this);this.internal=n,function a(i,o,s){Object.keys(i).forEach(l=>{const c=ve(i[l]),f=o!==s,g=cn(i[l]),v=g&&Object.keys(i[l]).length>0;c&&(!f&&v||f)?o[l]=i[l].bind(s):g&&!c?o[l]={}:o[l]=i[l],v&&a(i[l],o[l],s)})}(Er.prototype,this,this),pm.call(n,e),n.beforeInit(),n.init()}}yn(Er.prototype,[mm,ym,xm,bm,Rm,Im,Om,Cm,Pm]);function su(t=!1,e,n,a){const i=this,{config:o,$el:{main:s}}=i,l=o.data_selection_grouped,c=o.data_selection_isselectable.bind(i.api);o.data_selection_enabled&&s.selectAll(`.${sn.shapes}`).selectAll(`.${sn.shape}`).each(function(f){const g=ot(this),{id:v,index:m}=f.data?f.data:f,S=i.getToggle(this,f).bind(i),P=l||!e||e.indexOf(v)>=0,N=!n||n.indexOf(m)>=0,L=g.classed(tn.SELECTED);g.classed(ur.line)||g.classed(ti.area)||(t?P&&N&&c(f)&&!L?S(!0,g.classed(tn.SELECTED,!0),f,m):Qe(a)&&a&&L&&S(!1,g.classed(tn.SELECTED,!1),f,m):P&&N&&c(f)&&L&&S(!1,g.classed(tn.SELECTED,!1),f,m))})}var Dm={selected(t){const e=this.internal,n=[];return e.$el.main.selectAll(`.${sn.shapes+e.getTargetSelectorSuffix(t)}`).selectAll(`.${sn.shape}`).filter(function(){return ot(this).classed(tn.SELECTED)}).each(a=>n.push(a)),n},select(t,e,n){const a=this.internal;su.bind(a)(!0,t,e,n)},unselect(t,e){const n=this.internal;su.bind(n)(!1,t,e)}};const lu=function(t){var e;const n=this.internal,{axis:a,brush:i,config:o,scale:{x:s,subX:l},state:c}=n;let f;return o.subchart_show&&(f=t,Array.isArray(f)?(a.isTimeSeries()&&(f=f.map(v=>Yn.bind(n)(v))),n.withinRange(f,n.getZoomDomain("subX",!0),n.getZoomDomain("subX"))&&(c.domain=f,i.move(i.getSelection(),f.map(l)))):f=(e=c.domain)!=null?e:s.orgDomain()),f};yn(lu,{show(){var t,e;const n=this.internal,{$el:{subchart:a},config:i}=n,o=i.subchart_show;if(!o){n.unbindZoomEvent(),i.subchart_show=!o,!a.main&&n.initSubchart();let s=a.main.selectAll(`.${Se.target}`);n.data.targets.length!==s.size()&&(n.updateSizes(),n.updateTargetsForSubchart(n.data.targets),s=(t=a.main)==null?void 0:t.selectAll(`.${Se.target}`)),s==null||s.style("opacity",null),(e=a.main)==null||e.style("display",null),this.resize()}},hide(){const t=this.internal,{$el:{subchart:{main:e}},config:n}=t;n.subchart_show&&(e==null?void 0:e.style("display"))!=="none"&&(n.subchart_show=!1,e.style("display","none"),this.resize())},toggle(){const t=this.internal,{config:e}=t;this.subchart[e.subchart_show?"hide":"show"]()},reset(){const t=this.internal,{brush:e}=t;e.clear(e.getSelection())}});var Lm={subchart:lu},Nm=1e-12;function cu(t){return((t=Math.exp(t))+1/t)/2}function Fm(t){return((t=Math.exp(t))-1/t)/2}function Bm(t){return((t=Math.exp(2*t))-1)/(t+1)}var Um=function t(e,n,a){function i(o,s){var l=o[0],c=o[1],f=o[2],g=s[0],v=s[1],m=s[2],S=g-l,P=v-c,N=S*S+P*P,L,w;if(N()=>t;function zm(t,{sourceEvent:e,target:n,transform:a,dispatch:i}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:e,enumerable:!0,configurable:!0},target:{value:n,enumerable:!0,configurable:!0},transform:{value:a,enumerable:!0,configurable:!0},_:{value:i}})}function vr(t,e,n){this.k=t,this.x=e,this.y=n}vr.prototype={constructor:vr,scale:function(t){return t===1?this:new vr(this.k*t,this.x,this.y)},translate:function(t,e){return t===0&e===0?this:new vr(this.k,this.x+this.k*t,this.y+this.k*e)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var ar=new vr(1,0,0);vs.prototype=vr.prototype;function vs(t){for(;!t.__zoom;)if(!(t=t.parentNode))return ar;return t.__zoom}function ps(t){t.stopImmediatePropagation()}function Ba(t){t.preventDefault(),t.stopImmediatePropagation()}function jm(t){return(!t.ctrlKey||t.type==="wheel")&&!t.button}function Vm(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t,t.hasAttribute("viewBox")?(t=t.viewBox.baseVal,[[t.x,t.y],[t.x+t.width,t.y+t.height]]):[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]):[[0,0],[t.clientWidth,t.clientHeight]]}function uu(){return this.__zoom||ar}function Gm(t){return-t.deltaY*(t.deltaMode===1?.05:t.deltaMode?1:.002)*(t.ctrlKey?10:1)}function Xm(){return navigator.maxTouchPoints||"ontouchstart"in this}function Hm(t,e,n){var a=t.invertX(e[0][0])-n[0][0],i=t.invertX(e[1][0])-n[1][0],o=t.invertY(e[0][1])-n[0][1],s=t.invertY(e[1][1])-n[1][1];return t.translate(i>a?(a+i)/2:Math.min(0,a)||Math.max(0,i),s>o?(o+s)/2:Math.min(0,o)||Math.max(0,s))}function Ym(){var t=jm,e=Vm,n=Hm,a=Gm,i=Xm,o=[0,1/0],s=[[-1/0,-1/0],[1/0,1/0]],l=250,c=Um,f=ri("start","zoom","end"),g,v,m,S=500,P=150,N=0,L=10;function w(Q){Q.property("__zoom",uu).on("wheel.zoom",ht,{passive:!1}).on("mousedown.zoom",$t).on("dblclick.zoom",dt).filter(i).on("touchstart.zoom",st).on("touchmove.zoom",Vt).on("touchend.zoom touchcancel.zoom",vt).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}w.transform=function(Q,St,ct,At){var Gt=Q.selection?Q.selection():Q;Gt.property("__zoom",uu),Q!==Gt?k(Q,St,ct,At):Gt.interrupt().each(function(){K(this,arguments).event(At).start().zoom(null,typeof St=="function"?St.apply(this,arguments):St).end()})},w.scaleBy=function(Q,St,ct,At){w.scaleTo(Q,function(){var Gt=this.__zoom.k,Bt=typeof St=="function"?St.apply(this,arguments):St;return Gt*Bt},ct,At)},w.scaleTo=function(Q,St,ct,At){w.transform(Q,function(){var Gt=e.apply(this,arguments),Bt=this.__zoom,Kt=ct==null?H(Gt):typeof ct=="function"?ct.apply(this,arguments):ct,ne=Bt.invert(Kt),le=typeof St=="function"?St.apply(this,arguments):St;return n(W(X(Bt,le),Kt,ne),Gt,s)},ct,At)},w.translateBy=function(Q,St,ct,At){w.transform(Q,function(){return n(this.__zoom.translate(typeof St=="function"?St.apply(this,arguments):St,typeof ct=="function"?ct.apply(this,arguments):ct),e.apply(this,arguments),s)},null,At)},w.translateTo=function(Q,St,ct,At,Gt){w.transform(Q,function(){var Bt=e.apply(this,arguments),Kt=this.__zoom,ne=At==null?H(Bt):typeof At=="function"?At.apply(this,arguments):At;return n(ar.translate(ne[0],ne[1]).scale(Kt.k).translate(typeof St=="function"?-St.apply(this,arguments):-St,typeof ct=="function"?-ct.apply(this,arguments):-ct),Bt,s)},At,Gt)};function X(Q,St){return St=Math.max(o[0],Math.min(o[1],St)),St===Q.k?Q:new vr(St,Q.x,Q.y)}function W(Q,St,ct){var At=St[0]-ct[0]*Q.k,Gt=St[1]-ct[1]*Q.k;return At===Q.x&&Gt===Q.y?Q:new vr(Q.k,At,Gt)}function H(Q){return[(+Q[0][0]+ +Q[1][0])/2,(+Q[0][1]+ +Q[1][1])/2]}function k(Q,St,ct,At){Q.on("start.zoom",function(){K(this,arguments).event(At).start()}).on("interrupt.zoom end.zoom",function(){K(this,arguments).event(At).end()}).tween("zoom",function(){var Gt=this,Bt=arguments,Kt=K(Gt,Bt).event(At),ne=e.apply(Gt,Bt),le=ct==null?H(ne):typeof ct=="function"?ct.apply(Gt,Bt):ct,be=Math.max(ne[1][0]-ne[0][0],ne[1][1]-ne[0][1]),Oe=Gt.__zoom,Ce=typeof St=="function"?St.apply(Gt,Bt):St,He=c(Oe.invert(le).concat(be/Oe.k),Ce.invert(le).concat(be/Ce.k));return function(Fe){if(Fe===1)Fe=Ce;else{var dn=He(Fe),Jt=be/dn[2];Fe=new vr(Jt,le[0]-dn[0]*Jt,le[1]-dn[1]*Jt)}Kt.zoom(null,Fe)}})}function K(Q,St,ct){return!ct&&Q.__zooming||new at(Q,St)}function at(Q,St){this.that=Q,this.args=St,this.active=0,this.sourceEvent=null,this.extent=e.apply(Q,St),this.taps=0}at.prototype={event:function(Q){return Q&&(this.sourceEvent=Q),this},start:function(){return++this.active===1&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(Q,St){return this.mouse&&Q!=="mouse"&&(this.mouse[1]=St.invert(this.mouse[0])),this.touch0&&Q!=="touch"&&(this.touch0[1]=St.invert(this.touch0[0])),this.touch1&&Q!=="touch"&&(this.touch1[1]=St.invert(this.touch1[0])),this.that.__zoom=St,this.emit("zoom"),this},end:function(){return--this.active===0&&(delete this.that.__zooming,this.emit("end")),this},emit:function(Q){var St=ot(this.that).datum();f.call(Q,this.that,new zm(Q,{sourceEvent:this.sourceEvent,target:w,type:Q,transform:this.that.__zoom,dispatch:f}),St)}};function ht(Q,...St){if(!t.apply(this,arguments))return;var ct=K(this,St).event(Q),At=this.__zoom,Gt=Math.max(o[0],Math.min(o[1],At.k*Math.pow(2,a.apply(this,arguments)))),Bt=Xn(Q);if(ct.wheel)(ct.mouse[0][0]!==Bt[0]||ct.mouse[0][1]!==Bt[1])&&(ct.mouse[1]=At.invert(ct.mouse[0]=Bt)),clearTimeout(ct.wheel);else{if(At.k===Gt)return;ct.mouse=[Bt,At.invert(Bt)],qr(this),ct.start()}Ba(Q),ct.wheel=setTimeout(Kt,P),ct.zoom("mouse",n(W(X(At,Gt),ct.mouse[0],ct.mouse[1]),ct.extent,s));function Kt(){ct.wheel=null,ct.end()}}function $t(Q,...St){if(m||!t.apply(this,arguments))return;var ct=Q.currentTarget,At=K(this,St,!0).event(Q),Gt=ot(Q.view).on("mousemove.zoom",le,!0).on("mouseup.zoom",be,!0),Bt=Xn(Q,ct),Kt=Q.clientX,ne=Q.clientY;co(Q.view),ps(Q),At.mouse=[Bt,this.__zoom.invert(Bt)],qr(this),At.start();function le(Oe){if(Ba(Oe),!At.moved){var Ce=Oe.clientX-Kt,He=Oe.clientY-ne;At.moved=Ce*Ce+He*He>N}At.event(Oe).zoom("mouse",n(W(At.that.__zoom,At.mouse[0]=Xn(Oe,ct),At.mouse[1]),At.extent,s))}function be(Oe){Gt.on("mousemove.zoom mouseup.zoom",null),uo(Oe.view,At.moved),Ba(Oe),At.event(Oe).end()}}function dt(Q,...St){if(t.apply(this,arguments)){var ct=this.__zoom,At=Xn(Q.changedTouches?Q.changedTouches[0]:Q,this),Gt=ct.invert(At),Bt=ct.k*(Q.shiftKey?.5:2),Kt=n(W(X(ct,Bt),At,Gt),e.apply(this,St),s);Ba(Q),l>0?ot(this).transition().duration(l).call(k,Kt,At,Q):ot(this).call(w.transform,Kt,At,Q)}}function st(Q,...St){if(t.apply(this,arguments)){var ct=Q.touches,At=ct.length,Gt=K(this,St,Q.changedTouches.length===At).event(Q),Bt,Kt,ne,le;for(ps(Q),Kt=0;KtYn.bind(n)(v))),n.withinRange(f,n.getZoomDomain("zoom",!0),n.getZoomDomain("zoom"))){if(l.domain=f,f=n.getZoomDomainValue(f),n.api.tooltip.hide(),i.subchart_show){const v=s.zoom||s.x;n.brush.getSelection().call(n.brush.move,f.map(v))}else{const v=c?s.x.orgScale():o.xScale||s.x;n.updateCurrentZoomTransform(v,f)}n.setZoomResetButton()}}else f=n.zoom.getDomain();return(e=l.domain)!=null?e:f};yn(fu,{enable(t){const e=this.internal,{config:n}=e;/^(drag|wheel)$/.test(t)&&(n.zoom_type=t),n.zoom_enabled=!!t,e.zoom?t===!1&&e.bindZoomEvent(!1):(e.initZoom(),e.bindZoomEvent()),e.updateAndRedraw()},max(t){const e=this.internal,{config:n,org:{xDomain:a}}=e;return(t===0||t)&&(n.zoom_x_max=_n("max",[a[1],t])),n.zoom_x_max},min(t){const e=this.internal,{config:n,org:{xDomain:a}}=e;return(t===0||t)&&(n.zoom_x_min=_n("min",[a[0],t])),n.zoom_x_min},range(t){const e=this.zoom;if(Be(t)){const{min:n,max:a}=t;Qe(n)&&e.min(n),Qe(a)&&e.max(a)}return{min:e.min(),max:e.max()}}});var Wm={zoom:fu,unzoom(){const t=this.internal,{config:e,$el:{eventRect:n,zoomResetBtn:a},scale:{zoom:i},state:o}=t;i&&(e.subchart_show?t.brush.getSelection().call(t.brush.move,null):t.zoom.updateTransformScale(ar),t.updateZoom(!0),a==null||a.style("display","none"),vs(n.node())!==ar&&t.zoom.transform(n,ar),o.domain=void 0)}},Km={initBrush(){const t=this,{config:e,scale:n,$el:{subchart:a},state:i}=t,o=e.axis_rotated,s=e.subchart_size_height;let l,c,f;t.brush=(o?Gg():Vg()).handleSize(5),t.brush.on("start brush end",g=>{const{selection:v,sourceEvent:m,target:S,type:P}=g;P==="start"&&(t.state.inputType==="touch"&&t.hideTooltip(),c=m?v:null),/(start|brush)/.test(P)&&(P==="brush"&&m&&i.domain&&(c==null||c.forEach((N,L)=>{N!==v[L]&&(i.domain[L]=n.x.orgDomain()[L])})),t.redrawForBrush(P!=="start")),P==="end"&&(l=n.x.orgDomain()),S!=null&&S.handle&&(v===null?t.brush.handle.attr("display","none"):t.brush.handle.attr("display",null).attr("transform",(N,L)=>{const w=[v[L],s/2];return`translate(${o?w.reverse():w})`}))}),t.brush.updateResize=function(){f&&clearTimeout(f),f=setTimeout(()=>{const g=this.getSelection();l&&zl(g.node())&&this.move(g,l.map(n.subX.orgScale()))},0)},t.brush.update=function(){var g;return this.extent()()[1].filter(m=>isNaN(m)).length===0&&((g=a.main)==null||g.select(`.${Ue.brush}`).call(this)),this},t.brush.scale=function(g){const v=e.subchart_size_height;let m=t.axis.getExtent();!m&&g.range?m=[[0,0],[g.range()[1],v]]:je(m)&&(m=m.map((S,P)=>[S,P>0?v:P])),o&&m[1].reverse(),this.extent(m),this.update()},t.brush.getSelection=()=>a.main?a.main.select(`.${Ue.brush}`):ot([])},initSubchart(){const t=this,{config:e,state:{clip:n,hasAxis:a},$el:{defs:i,svg:o,subchart:s,axis:l}}=t;if(!a)return;const c=e.subchart_show?null:"hidden",f=`${n.id}-subchart`,g=t.getClipPath(f);n.idSubchart=f,t.appendClip(i,f),t.initBrush(),s.main=o.append("g").classed(Ue.subchart,!0).attr("transform",t.getTranslate("context"));const{main:v}=s;v.style("visibility",c),v.append("g").attr("clip-path",g).attr("class",Ue.chart),["bar","line","bubble","candlestick","scatter"].forEach(S=>{const P=Cn(/^(bubble|scatter)$/.test(S)?"circle":S);if(t.hasType(S)||t.hasTypeOf(P)){const N=v.select(`.${Ue.chart}`),L=Ue[`chart${P}s`];N.select(`.${L}`).empty()&&N.append("g").attr("class",L)}});const m=v.append("g").attr("clip-path",g).attr("class",Ue.brush).call(t.brush);e.subchart_showHandle&&t.addBrushHandle(m),l.subX=v.append("g").attr("class",Ue.axisX).attr("transform",t.getTranslate("subX")).attr("clip-path",e.axis_rotated?"":n.pathXAxis).style("visibility",e.subchart_axis_x_show?c:"hidden")},addBrushHandle(t){const e=this,{config:n}=e,a=n.axis_rotated,i=n.subchart_init_range,o="handle--custom",s=a?["M8.5 0 a6 6 0 0 0 -6 -6.5 H-2.5 a 6 6 0 0 0 -6 6.5 z m-5 -2 H-3.5 m7 -2 H-3.5z","M8.5 0 a6 -6 0 0 1 -6 6.5 H-2.5 a 6 -6 0 0 1 -6 -6.5z m-5 2 H-3.5 m7 2 H-3.5z"]:["M0 -8.5 A6 6 0 0 0 -6.5 -3.5 V2.5 A6 6 0 0 0 0 8.5 Z M-2 -3.5 V3.5 M-4 -3.5 V3.5z","M0 -8.5 A6 6 0 0 1 6.5 -3.5 V2.5 A6 6 0 0 1 0 8.5 Z M2 -3.5 V3.5 M4 -3.5 V3.5z"];e.brush.handle=t.selectAll(`.${o}`).data(a?[{type:"n"},{type:"s"}]:[{type:"w"},{type:"e"}]).enter().append("path").attr("class",o).attr("cursor",`${a?"ns":"ew"}-resize`).attr("d",l=>s[+/[se]/.test(l.type)]).attr("display",i?null:"none")},updateTargetsForSubchart(t){const e=this,{config:n,state:a,$el:{subchart:{main:i}}}=e;n.subchart_show&&(["bar","line","bubble","candlestick","scatter"].filter(o=>e.hasType(o)||e.hasTypeOf(Cn(o))).forEach(o=>{const s=/^(bubble|scatter)$/.test(o),l=Cn(s?"circle":o),c=e.getChartClass(l,!0),f=e.getClass(s?"circles":`${o}s`,!0),g=i.select(`.${Ue[`chart${`${l}s`}`]}`);if(s){const v=g.selectAll(`.${Ue.circles}`).data(t.filter(e[`is${Cn(o)}Type`].bind(e))).attr("class",f);v.exit().remove(),v.enter().append("g").attr("class",f)}else{const v=g.selectAll(`.${Ue[`chart${l}`]}`).attr("class",c).data(t.filter(e[`is${l}Type`].bind(e))),m=v.enter().append("g").style("opacity","0").attr("class",c).append("g").attr("class",f);v.exit().remove(),o==="line"&&e.hasTypeOf("Area")&&m.append("g").attr("class",e.getClass("areas",!0))}}),i.selectAll(`.${Ue.brush} rect`).attr(n.axis_rotated?"width":"height",n.axis_rotated?a.width2:a.height2))},redrawSubchart(t,e,n){var a;const i=this,{config:o,$el:{subchart:{main:s}},state:l}=i,c=!!e;if(s.style("visibility",o.subchart_show?null:"hidden"),o.subchart_show&&(((a=l.event)==null?void 0:a.type)==="zoom"&&i.brush.update(),t)){const f=o.subchart_init_range;if(!Kl(i)&&i.brush.update(),Object.keys(n.type).forEach(g=>{const v=Cn(g),m=i[`generateDraw${v}`](n.indices[g],!0);i[`update${v}`](c,!0),i[`redraw${v}`](m,c,!0)}),i.hasType("bubble")||i.hasType("scatter")){const{cx:g}=n.pos,v=i.updateCircleY(!0);i.updateCircle(!0),i.redrawCircle(g,v,c,void 0,!0)}!l.rendered&&f&&(l.domain=f,i.brush.move(i.brush.getSelection(),f.map(i.scale.x)))}},redrawForBrush(t=!0){var e;const n=this,{config:{subchart_onbrush:a,zoom_rescale:i},scale:o,state:s}=n;n.redraw({withTransition:!1,withY:i,withSubchart:!1,withUpdateXDomain:!0,withDimension:!1}),t&&s.rendered&&a.bind(n.api)((e=s.domain)!=null?e:o.x.orgDomain())},transformContext(t,e){const n=this,{$el:{subchart:a},$T:i}=n,o=e!=null&&e.axisSubX?e.axisSubX:i(a.main.select(`.${Ue.axisX}`),t);a.main.attr("transform",n.getTranslate("context")),o.attr("transform",n.getTranslate("subX"))}},Zm={initZoom(){const t=this;t.scale.zoom=null,t.generateZoom(),t.config.zoom_type==="drag"&&t.initZoomBehaviour()},bindZoomEvent(t=!0){const e=this,{config:n}=e;n.zoom_enabled&&t?!n.subchart_show&&e.bindZoomOnEventRect():t===!1&&(e.api.unzoom(),e.unbindZoomEvent())},generateZoom(){const t=this,{config:e,org:n,scale:a}=t,i=Ym().duration(0).on("start",t.onZoomStart.bind(t)).on("zoom",t.onZoom.bind(t)).on("end",t.onZoomEnd.bind(t));i.orgScaleExtent=()=>{const o=e.zoom_extent||[1,10];return[o[0],Math.max(t.getMaxDataCount()/o[1],o[1])]},i.updateScaleExtent=function(){const o=Dr(t.scale.x.orgDomain())/Dr(t.getZoomDomain()),s=this.orgScaleExtent();return this.scaleExtent([s[0]*o,s[1]*o]),this},i.updateTransformScale=(o,s)=>{var l;const c=e.axis_rotated;(l=n.xScale)==null||l.range(a.x.range());const f=o[c?"rescaleY":"rescaleX"](n.xScale||a.x);if(f.domain().some(m=>/(Invalid Date|NaN)/.test(m.toString())))return;const g=t.trimXDomain(f.domain()),v=e.zoom_rescale;if(f.domain(g,n.xDomain),s){const m=f(a.x.domain()[0]),S=c?o.x:m,P=c?m:o.y;t.$el.eventRect.property("__zoom",ar.translate(S,P).scale(o.k))}t.state.xTickOffset||(t.state.xTickOffset=t.axis.x.tickOffset()),a.zoom=t.getCustomizedXScale(f),t.axis.x.scale(a.zoom),v?(!n.xScale&&(n.xScale=a.x.copy()),a.x.domain(g)):n.xScale&&(a.x.domain(n.xScale.domain()),n.xScale=null)},i.getDomain=()=>{const o=a[a.zoom?"zoom":"subX"].domain();return t.axis.isCategorized()&&(o[1]-=2),o},t.zoom=i},onZoomStart(t){const e=this,{sourceEvent:n}=t;n&&(e.zoom.startEvent=n,e.state.zooming=!0,_e(e.config.zoom_onzoomstart,e.api,t))},onZoom(t){var e;const n=this,{config:a,scale:i,state:o,org:s}=n,{sourceEvent:l}=t,c=(t==null?void 0:t.transform)===ar;if(!a.zoom_enabled||n.filterTargetsToShow(n.data.targets).length===0||!i.zoom&&(l==null?void 0:l.type.indexOf("touch"))>-1&&(l==null?void 0:l.touches.length)===1)return;t.sourceEvent&&(o.zooming=!0,o.domain=void 0);const f=(l==null?void 0:l.type)==="mousemove",g=(l==null?void 0:l.wheelDelta)<0,{transform:v}=t;!f&&g&&i.x.domain().every((S,P)=>S!==s.xDomain[P])&&i.x.domain(s.xDomain),n.zoom.updateTransformScale(v,a.zoom_type==="wheel"&&l);const m=a.transition_duration>0&&!a.subchart_show&&(o.dragging||c||!t.sourceEvent);n.redraw({withTransition:m,withY:a.zoom_rescale,withSubchart:!1,withEventRect:!1,withDimension:!1}),n.state.cancelClick=f,!c&&_e(a.zoom_onzoom,n.api,(e=n.state.domain)!=null?e:n.zoom.getDomain())},onZoomEnd(t){var e,n;const a=this,{config:i,state:o}=a;let{startEvent:s}=a.zoom,l=t==null?void 0:t.sourceEvent;const c=(t==null?void 0:t.transform)===ar;(s==null?void 0:s.type.indexOf("touch"))>-1&&(s=s.changedTouches[0],l=(e=l==null?void 0:l.changedTouches)==null?void 0:e[0]),!(i.zoom_type==="drag"&&l&&s.clientX===l.clientX&&s.clientY===l.clientY)&&(o.zooming=!1,a.redrawEventRect(),a.updateZoom(),!c&&(l||o.dragging)&&_e(i.zoom_onzoomend,a.api,(n=a.state.domain)!=null?n:a.zoom.getDomain()))},updateZoom(t){const e=this,{subX:n,x:a,zoom:i}=e.scale;if(i){const o=i.domain(),s=n.domain(),l=.015,c=e.config.axis_x_inverted?(o[0]>=s[0]||o[0]+l>=s[0])&&(s[1]>=o[1]||s[1]>=o[1]+l):(o[0]<=s[0]||o[0]-l<=s[0])&&(s[1]<=o[1]||s[1]<=o[1]-l);(t||c)&&(e.axis.x.scale(n),a.domain(n.orgDomain()),e.scale.zoom=null)}},updateCurrentZoomTransform(t,e){const n=this,{$el:{eventRect:a},config:i}=n,o=i.axis_rotated,s=[-t(e[0]),0],l=ar.scale(t.range()[1]/(t(e[1])-t(e[0]))).translate(...o?s.reverse():s);a.call(n.zoom.transform,l)},bindZoomOnEventRect(){var t;const e=this,{config:n,$el:{eventRect:a,svg:i}}=e,o=n.zoom_type==="drag"?e.zoomBehaviour:e.zoom;Ke.GestureEvent&&/^((?!chrome|android|mobile).)*safari/i.test((t=Ke.navigator)==null?void 0:t.userAgent)&&i.on("wheel",()=>{}),a==null||a.call(o).on("dblclick.zoom",null)},initZoomBehaviour(){const t=this,{config:e,state:n}=t,a=e.axis_rotated;let i=0,o=0,s,l;const c={axis:a?"y":"x",attr:a?"height":"width",index:a?1:0};t.zoomBehaviour=uc().clickDistance(4).on("start",function(f){l=t.scale.zoom?null:t.axis.getExtent(),n.event=f,t.setDragStatus(!0),t.unselectRect(),s||(s=t.$el.main.append("rect").attr("clip-path",n.clip.path).attr("class",so.zoomBrush).attr("width",a?n.width:0).attr("height",a?0:n.height)),i=Hn(f,this)[c.index],l&&(il[1]&&(i=l[1])),o=i,s.attr(c.axis,i).attr(c.attr,0),t.onZoomStart(f)}).on("drag",function(f){o=Hn(f,this)[c.index],l&&(o>l[1]?o=l[1]:o{const g=t.scale.zoom||t.scale.x;n.event=f,s.attr(c.axis,0).attr(c.attr,0),i>o&&([i,o]=[o,i]),i<0&&(o+=Math.abs(i),i=0),i!==o&&t.api.zoom([i,o].map(v=>g.invert(v))),t.setDragStatus(!1)})},setZoomResetButton(){const t=this,{config:e,$el:n}=t,a=e.zoom_resetButton;a&&e.zoom_type==="drag"&&(n.zoomResetBtn?n.zoomResetBtn.style("display",null):n.zoomResetBtn=t.$el.chart.append("div").classed(Se.button,!0).append("span").on("click",function(){ve(a.onclick)&&a.onclick.bind(t.api)(this),t.api.unzoom()}).classed(so.buttonZoomReset,!0).text(a.text||"Reset Zoom"))},getZoomTransform(){const t=this,{$el:{eventRect:e}}=t;return e!=null&&e.node()?vs(e.node()):{k:1}}},Jm={drag(t){const e=this,{config:n,state:a,$el:{main:i}}=e,o=n.data_selection_grouped,s=n.interaction_enabled&&n.data_selection_isselectable;if(e.hasArcType()||!n.data_selection_enabled||n.zoom_enabled&&!e.zoom.altDomain||!n.data_selection_multiple)return;const[l,c]=a.dragStart||[0,0],[f,g]=t,v=Math.min(l,f),m=Math.max(l,f),S=o?a.margin.top:Math.min(c,g),P=o?a.height:Math.max(c,g);i.select(`.${Or.dragarea}`).attr("x",v).attr("y",S).attr("width",m-v).attr("height",P-S),i.selectAll(`.${sn.shapes}`).selectAll(`.${sn.shape}`).filter(N=>s==null?void 0:s.bind(e.api)(N)).each(function(N,L){const w=ot(this),X=w.classed(tn.SELECTED),W=w.classed(Or.INCLUDED);let H=!1,k;if(w.classed($n.circle)){const K=+w.attr("cx")*1,at=+w.attr("cy")*1;k=e.togglePoint,H=ve in t?Qm(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,ey=(t,e)=>{for(var n in e||(e={}))_m.call(e,n)&&hu(t,n,e[n]);if(du)for(var n of du(e))ty.call(e,n)&&hu(t,n,e[n]);return t},ny=(t,e)=>km(t,qm(e)),ry=ny(ey({},Jm),{selectPoint(t,e,n){const a=this,{config:i,$el:{main:o},$T:s}=a,l=i.axis_rotated,c=(l?a.circleY:a.circleX).bind(a),f=(l?a.circleX:a.circleY).bind(a),g=a.pointSelectR.bind(a);_e(i.data_onselected,a.api,e,t.node()),s(o.select(`.${tn.selectedCircles}${a.getTargetSelectorSuffix(e.id)}`).selectAll(`.${tn.selectedCircle}-${n}`).data([e]).enter().append("circle").attr("class",()=>a.generateClass(tn.selectedCircle,n)).attr("cx",c).attr("cy",f).attr("stroke",a.color).attr("r",v=>a.pointSelectR(v)*1.4)).attr("r",g)},unselectPoint(t,e,n){const a=this,{config:i,$el:{main:o},$T:s}=a;_e(i.data_onunselected,a.api,e,t==null?void 0:t.node()),s(o.select(`.${tn.selectedCircles}${a.getTargetSelectorSuffix(e.id)}`).selectAll(`.${tn.selectedCircle}-${n}`)).attr("r",0).remove()},togglePoint(t,e,n,a){this[`${t?"":"un"}selectPoint`](e,n,a)},selectPath(t,e){const n=this,{config:a}=n;_e(a.data_onselected,n.api,e,t.node()),a.interaction_brighten&&t.style("filter","brightness(1.25)")},unselectPath(t,e){const n=this,{config:a}=n;_e(a.data_onunselected,n.api,e,t.node()),a.interaction_brighten&&t.style("filter",null)},togglePath(t,e,n,a){this[`${t?"":"un"}selectPath`](e,n,a)},getToggle(t,e){const n=this;return t.nodeName==="path"?n.togglePath:n.isStepType(e)?()=>{}:n.togglePoint},toggleShape(t,e,n){var a;const i=this,{config:o,$el:{main:s}}=i;if(o.data_selection_enabled&&o.data_selection_isselectable.bind(i.api)(e)){const l=ot(t),c=l.classed(tn.SELECTED),f=i.getToggle(t,e).bind(i);let g;if(!o.data_selection_multiple){const v=(a=i.isPointFocusOnly)==null?void 0:a.call(i);let m=`.${v?tn.selectedCircles:sn.shapes}`;o.data_selection_grouped&&(m+=i.getTargetSelectorSuffix(e.id)),s.selectAll(m).selectAll(v?`.${tn.selectedCircle}`:`.${sn.shape}.${tn.SELECTED}`).classed(tn.SELECTED,!1).each(function(S){const P=ot(this);g=P,f(!1,P,S,S.index)})}(!g||g.node()!==l.node())&&(l.classed(tn.SELECTED,!c),f(!c,l,e,n))}}}),ay={data_selection_enabled:!1,data_selection_grouped:!1,data_selection_isselectable:()=>!0,data_selection_multiple:!0,data_selection_draggable:!1,data_onselected:()=>{},data_onunselected:()=>{}},iy={subchart_show:!1,subchart_showHandle:!1,subchart_size_height:60,subchart_axis_x_show:!0,subchart_axis_x_tick_show:!0,subchart_axis_x_tick_format:void 0,subchart_axis_x_tick_text_show:!0,subchart_init_range:void 0,subchart_onbrush:()=>{}},oy={zoom_enabled:!1,zoom_type:"wheel",zoom_extent:void 0,zoom_privileged:!1,zoom_rescale:!1,zoom_onzoom:void 0,zoom_onzoomstart:void 0,zoom_onzoomend:void 0,zoom_resetButton:!0,zoom_x_min:void 0,zoom_x_max:void 0};let gu=()=>(yn(Vr.prototype,ry),yn(Er.prototype,Dm),Nr.setOptions([ay]),(gu=()=>!0)()),vu=()=>(yn(Vr.prototype,Km),yn(Er.prototype,Lm),Nr.setOptions([iy]),(vu=()=>!0)()),pu=()=>(yn(Vr.prototype,Zm),yn(Er.prototype,Wm),Nr.setOptions([oy]),(pu=()=>!0)());function mu(t,e,n){const{config:a}=t,i=(o,s)=>{const l=he(s)?s:s===!1?void 0:null;l!==null&&(a[`axis_${o}_${e}`]=l)};Qe(n)&&(nr(n)?Object.keys(n).forEach(o=>{i(o,n[o])}):(he(n)||n===!1)&&["y","y2"].forEach(o=>{i(o,n)}),t.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0}))}function yu(t,e){const{config:n}=t;return{x:n[`axis_x_${e}`],y:n[`axis_y_${e}`],y2:n[`axis_y2_${e}`]}}var sy={axis:{labels:function(t){const e=this.internal;let n;return t&&(Object.keys(t).forEach(a=>{e.axis.setLabelText(a,t[a])}),e.axis.updateLabels()),["x","y","y2"].forEach(a=>{const i=e.axis.getLabelText(a);i&&(!n&&(n={}),n[a]=i)}),n},min:function(t){const e=this.internal;return De(t)||t===!1?mu(e,"min",t):yu(e,"min")},max:function(t){const e=this.internal;return De(t)||t===!1?mu(e,"max",t):yu(e,"max")},range:function(t){const{axis:e}=this;if(arguments.length){const{min:n,max:a}=t;Qe(a)&&e.max(a),Qe(n)&&e.min(n)}else return{max:e.max(),min:e.min()}}}},ly={category(t,e){const n=this.internal,{config:a}=n;return arguments.length>1&&(a.axis_x_categories[t]=e,n.redraw()),a.axis_x_categories[t]},categories(t){const e=this.internal,{config:n}=e;if(!t||!Array.isArray(t)){const a=n.axis_x_categories;return qn(a)?Object.values(e.data.xs)[0]:a}return n.axis_x_categories=t,e.redraw(),n.axis_x_categories}},cy={flow(t){const e=this.internal;let n;(t.json||t.rows||t.columns)&&e.convertData(t,i=>{n=i,a()});function a(){let i,o=0,s=0,l,c;if(e.state.redrawing||!n||!Da())return;const f=[],g=e.getMaxDataCount(),v=e.convertDataToTargets(n,!0),m=e.axis.isTimeSeries();e.data.targets.forEach(N=>{let L=!1;for(let w=0;w{for(let L=0;L{const L=[];for(let w=e.data.targets[0].values[0].index;w{w.index+=s,m||(w.x+=s)}),N.values=L.concat(N.values)}),e.data.targets=e.data.targets.concat(v);const S=e.data.targets[0],P=S.values[0];Qe(t.to)?(o=0,c=m?Yn.call(e,t.to):t.to,S.values.forEach(N=>{N.x1?S.values[S.values.length-1].x-P.x:P.x-e.getXDomain(e.data.targets)[0]:l=1,i=[P.x-l,P.x]),i&&e.updateXDomain(null,!0,!0,!1,i),e.updateTargets(e.data.targets),e.redraw({flow:{index:P.index,length:o,duration:De(t.duration)?t.duration:e.config.transition_duration,done:t.done,orgDataCount:g},withLegend:!0,withTransition:g>1,withTrimXDomain:!1,withUpdateXAxis:!0})}}};function ms(t,e){const n=this.internal,{config:a}=n,i=a.transition_duration&&Da(),o=`grid_${e}_lines`;return t&&(a[o]=t,n.updateGrid(),n.redrawGrid(i)),a[o]}function xu(t,e){const n=`grid_${e}_lines`;return ms.bind(this)(this.internal.config[n].concat(t||[]),e)}function Tu(t,e){this.internal.removeGridLines(t,e)}const $u=function(t){return ms.bind(this)(t,"x")};yn($u,{add(t){return xu.bind(this)(t,"x")},remove(t){return Tu.bind(this)(t,!0)}});const Su=function(t){return ms.bind(this)(t,"y")};yn(Su,{add(t){return xu.bind(this)(t,"y")},remove(t){return Tu.bind(this)(t,!1)}});var uy={xgrids:$u,ygrids:Su},fy={groups(t){const e=this.internal,{config:n}=e;return ln(t)||(n.data_groups=t,e.redraw()),n.data_groups}};function Au(t,e=!1){const n=this.internal,{config:a}=n,i=a.transition_duration&&Da();return t?(a.regions=e?a.regions.concat(t):t,n.updateRegion(),n.redrawRegion(i),e?a.regions:t):a.regions}const Eu=function(t){return Au.bind(this)(t)};yn(Eu,{add:function(t){return Au.bind(this)(t,!0)},remove:function(t){const e=this.internal,{config:n,$T:a}=e,i=t||{},o=$r(i,"classes",[$a.region]);let s=e.$el.main.select(`.${$a.regions}`).selectAll(o.map(l=>`.${l}`));return a(s).style("opacity","0").remove(),s=n.regions,Object.keys(i).length?(s=s.filter(l=>{let c=!1;return l.class?(l.class.split(" ").forEach(f=>{o.indexOf(f)>=0&&(c=!0)}),!c):!0}),n.regions=s):n.regions=[],s}});var dy={regions:Eu},hy={x(t){const e=this.internal,{axis:n,data:a}=e,i=n.isCustomX()&&n.isCategorized();return je(t)&&(i?this.categories(t):(e.updateTargetX(a.targets,t),e.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0}))),i?this.categories():a.xs},xs(t){const e=this.internal;return Be(t)&&(e.updateTargetXs(e.data.targets,t),e.redraw({withUpdateOrgXDomain:!0,withUpdateXDomain:!0})),e.data.xs}};function gy(t){return t}var Xi=1,Hi=2,ys=3,Ua=4,bu=1e-6;function vy(t){return"translate("+t+",0)"}function py(t){return"translate(0,"+t+")"}function my(t){return e=>+t(e)}function yy(t,e){return e=Math.max(0,t.bandwidth()-e*2)/2,t.round()&&(e=Math.round(e)),n=>+t(n)+e}function xy(){return!this.__axis}function Yi(t,e){var n=[],a=null,i=null,o=6,s=6,l=3,c=typeof window!="undefined"&&window.devicePixelRatio>1?0:.5,f=t===Xi||t===Ua?-1:1,g=t===Ua||t===Hi?"x":"y",v=t===Xi||t===ys?vy:py;function m(S){var P=a==null?e.ticks?e.ticks.apply(e,n):e.domain():a,N=i==null?e.tickFormat?e.tickFormat.apply(e,n):gy:i,L=Math.max(o,0)+l,w=e.range(),X=+w[0]+c,W=+w[w.length-1]+c,H=(e.bandwidth?yy:my)(e.copy(),c),k=S.selection?S.selection():S,K=k.selectAll(".domain").data([null]),at=k.selectAll(".tick").data(P,e).order(),ht=at.exit(),$t=at.enter().append("g").attr("class","tick"),dt=at.select("line"),st=at.select("text");K=K.merge(K.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),at=at.merge($t),dt=dt.merge($t.append("line").attr("stroke","currentColor").attr(g+"2",f*o)),st=st.merge($t.append("text").attr("fill","currentColor").attr(g,f*L).attr("dy",t===Xi?"0em":t===ys?"0.71em":"0.32em")),S!==k&&(K=K.transition(S),at=at.transition(S),dt=dt.transition(S),st=st.transition(S),ht=ht.transition(S).attr("opacity",bu).attr("transform",function(Vt){return isFinite(Vt=H(Vt))?v(Vt+c):this.getAttribute("transform")}),$t.attr("opacity",bu).attr("transform",function(Vt){var vt=this.parentNode.__axis;return v((vt&&isFinite(vt=vt(Vt))?vt:H(Vt))+c)})),ht.remove(),K.attr("d",t===Ua||t===Hi?s?"M"+f*s+","+X+"H"+c+"V"+W+"H"+f*s:"M"+c+","+X+"V"+W:s?"M"+X+","+f*s+"V"+c+"H"+W+"V"+f*s:"M"+X+","+c+"H"+W),at.attr("opacity",1).attr("transform",function(Vt){return v(H(Vt)+c)}),dt.attr(g+"2",f*o),st.attr(g,f*L).text(N),k.filter(xy).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===Hi?"start":t===Ua?"end":"middle"),k.each(function(){this.__axis=H})}return m.scale=function(S){return arguments.length?(e=S,m):e},m.ticks=function(){return n=Array.from(arguments),m},m.tickArguments=function(S){return arguments.length?(n=S==null?[]:Array.from(S),m):n.slice()},m.tickValues=function(S){return arguments.length?(a=S==null?null:Array.from(S),m):a&&a.slice()},m.tickFormat=function(S){return arguments.length?(i=S,m):i},m.tickSize=function(S){return arguments.length?(o=s=+S,m):o},m.tickSizeInner=function(S){return arguments.length?(o=+S,m):o},m.tickSizeOuter=function(S){return arguments.length?(s=+S,m):s},m.tickPadding=function(S){return arguments.length?(l=+S,m):l},m.offset=function(S){return arguments.length?(c=+S,m):c},m}function Ty(t){return Yi(Xi,t)}function $y(t){return Yi(Hi,t)}function Ru(t){return Yi(ys,t)}function Iu(t){return Yi(Ua,t)}var Sy=Object.defineProperty,Ay=(t,e,n)=>e in t?Sy(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,xs=(t,e,n)=>Ay(t,typeof e!="symbol"?e+"":e,n);class Ou{constructor(e){xs(this,"owner"),xs(this,"config"),xs(this,"scale");const n=zr(),{config:a,params:i}=e;this.owner=e,this.config=a,this.scale=n,(a.noTransition||!i.config.transition_duration)&&(a.withoutTransition=!0),a.range=this.scaleExtent((i.orgXScale||n).range())}static getSizeFor1Char(e,n=!0){const a={w:5.5,h:11.5};return!e.empty()&&e.text("0").call(i=>{try{const{width:o,height:s}=i.node().getBBox();o&&s&&(a.w=o,a.h=s)}finally{i.text("")}}),n&&(this.getSizeFor1Char=()=>a),a}getTickTransformSetter(e){const{config:n}=this,a=e==="x"?i=>`translate(${i+n.tickOffset},0)`:i=>`translate(0,${i})`;return(i,o)=>{i.attr("transform",s=>{const l=o(s);return De(s)?a(l):null})}}scaleExtent(e){const n=e[0],a=e[e.length-1];return n0?i:1,o]).range(e.range());s=c.ticks();for(let f=o.toFixed().length;s.length>15;f--)s=c.ticks(f);s.splice(0,1,i),s.splice(s.length-1,1,o)}else s=e.ticks(...this.config.tickArguments||[]);s=s.map(c=>ze(c)&&he(c)&&!isNaN(c)&&Math.round(c*10)/10||c)}return s}copyScale(){const e=this.scale.copy();return e.domain().length||e.domain(this.scale.domain()),e.type=this.scale.type,e}textFormatted(e){const n=this.config.tickFormat,a=/\d+\.\d+0{5,}\d$/.test(e)?+String(e).replace(/0+\d$/,""):e,i=n?n(a):a;return Qe(i)?i:""}transitionise(e){const{config:n}=this;let a=e;if(n.withoutTransition)a=e.interrupt();else if(n.transition||!this.owner.params.noTransition)try{a=e.transition(n.transition)}catch(i){}return a}}var Ey=Object.defineProperty,by=(t,e,n)=>e in t?Ey(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,za=(t,e,n)=>by(t,typeof e!="symbol"?e+"":e,n);class Ry{constructor(e={}){za(this,"helper"),za(this,"config"),za(this,"params"),za(this,"g"),za(this,"generatedTicks");const n={innerTickSize:6,outerTickSize:e.outerTick?6:0,orient:"bottom",range:[],tickArguments:null,tickCentered:null,tickCulling:!0,tickFormat:null,tickLength:9,tickOffset:0,tickPadding:3,tickValues:null,transition:null,noTransition:e.noTransition};n.tickLength=Math.max(n.innerTickSize,0)+n.tickPadding,this.config=n,this.params=e,this.helper=new Ou(this)}create(e){const n=this,{config:a,helper:i,params:o}=n,{scale:s}=i,{orient:l}=a,c=this.splitTickText.bind(n),f=/^(left|right)$/.test(l),g=/^(top|bottom)$/.test(l),v=i.getTickTransformSetter(g?"x":"y"),m=v===i.axisX?"y":"x",S=/^(top|left)$/.test(l)?-1:1,P=o.tickTextRotate;this.config.range=s.rangeExtent?s.rangeExtent():i.scaleExtent((o.orgXScale||s).range());const{innerTickSize:N,tickLength:L,range:w}=a,X=o.id,W=X&&/^(x|y|y2)$/.test(X)?o.config[`axis_${X}_tick_text_position`]:{x:0,y:0},H=X==="subX"?"subchart_axis_x":`axis_${X}`,k=o.config[`${H}_show`],K={tick:k?o.config[`${H}_tick_show`]:!1,text:k?o.config[`${H}_tick_text_show`]:!1},at=o.config.axis_evalTextSize;let ht;e.each(function(){const $t=ot(this);let dt=this.__chart__||s,st=i.copyScale();ht=$t,this.__chart__=st,a.tickOffset=o.isCategory?(st(1)-st(0))/2:0;const Vt=$t.selectAll(".domain").data([0]);if(Vt.enter().append("path").attr("class","domain").merge(Vt).attr("d",()=>{const vt=a.outerTickSize*S;return g?`M${w[0]},${vt}V0H${w[1]}V${vt}`:`M${vt},${w[0]}H0V${w[1]}H${vt}`}),K.tick||K.text){const vt=a.tickValues||i.generateTicks(st,f);n.generatedTicks=vt;let Q=$t.selectAll(".tick").data(vt,st);const St=Q.enter().insert("g",".domain").attr("class","tick"),ct=Q.exit().remove();Q=St.merge(Q),K.tick&&St.append("line"),K.text&&St.append("text");const At=Q.select("text"),Gt=ve(at)?at.bind(n.params.owner.api)(At.node()):Ou.getSizeFor1Char(At,at),Bt=[];let Kt=At.selectAll("tspan").data((be,Oe)=>{const Ce=o.tickMultiline?c(be,st,vt,f,Gt.w):je(i.textFormatted(be))?i.textFormatted(be).concat():[i.textFormatted(be)];return Bt[Oe]=Ce.length,Ce.map(He=>({index:Oe,splitted:He}))});Kt.exit().remove(),Kt=Kt.enter().append("tspan").merge(Kt).text(be=>be.splitted),Kt.attr("x",g?0:L*S).attr("dx",(()=>{let be=0;return/(top|bottom)/.test(l)&&P&&(be=8*Math.sin(Math.PI*(P/180))*(l==="top"?-1:1)),be+(W.x||0)})()).attr("dy",(be,Oe)=>{const Ce=".71em";let He=0;return l!=="top"&&(He=Gt.h,Oe===0&&(He=f?-((Bt[be.index]-1)*(Gt.h/2)-3):W.y===0?Ce:0)),he(He)&&W.y?He+W.y:He||Ce});const ne=Q.select("line"),le=Q.select("text");if(St.select("line").attr(`${m}2`,N*S),St.select("text").attr(m,L*S),n.setTickLineTextPosition(ne,le),o.tickTitle){const be=le.select("title");(be.empty()?le.append("title"):be).text(Oe=>o.tickTitle[Oe])}if(st.bandwidth){const be=st,Oe=be.bandwidth()/2;dt=Ce=>be(Ce)+Oe,st=dt}else dt.bandwidth?dt=st:v(ct,st);Q=o.owner.state.flowing?i.transitionise(Q):o.owner.$T(Q),v(St,dt),v(Q.style("opacity",null),st)}}),this.g=ht}getGeneratedTicks(e){var n;const a=((n=this.generatedTicks)==null?void 0:n.length)-1;let i=this.generatedTicks;if(a>e){const o=Math.round(a/e+.1);i=this.generatedTicks.map((s,l)=>l%o===0?s:null).filter(s=>s!==null).splice(0,e)}return i}getTickXY(){const{config:e}=this,n={x:0,y:0};return this.params.isCategory&&(n.x=e.tickCentered?0:e.tickOffset,n.y=e.tickCentered?e.tickOffset:0),n}getTickSize(e){const{scale:n}=this.helper,{config:a}=this,{innerTickSize:i,range:o}=a,s=n(e)+(a.tickCentered?0:a.tickOffset);return o[0]{const N=["start","end"];return o==="top"&&N.reverse(),P?N[P>0?0:1]:"middle"},g=P=>P?`rotate(${P})`:null,v=P=>{const N=P/(o==="bottom"?15:23);return P?11.5-2.5*N*(P>0?1:-1):s},{config:{axis_rotated:m,axis_x_tick_text_inner:S}}=this.params.owner;switch(o){case"bottom":e.attr("x1",a.x).attr("x2",a.x).attr("y2",this.getTickSize.bind(this)),n.attr("x",0).attr("y",v(c)).style("text-anchor",f(c)).style("text-anchor",(P,N,{length:L})=>!m&&N===0&&(S===!0||S.first)?"start":!m&&N===L-1&&(S===!0||S.last)?"end":f(c)).attr("transform",g(c));break;case"top":e.attr("x2",0).attr("y2",-i),n.attr("x",0).attr("y",-v(c)*2).style("text-anchor",f(c)).attr("transform",g(c));break;case"left":e.attr("x2",-i).attr("y1",a.y).attr("y2",a.y),n.attr("x",-s).attr("y",l).style("text-anchor","end");break;case"right":e.attr("x2",i).attr("y2",0),n.attr("x",s).attr("y",0).style("text-anchor","start")}}splitTickText(e,n,a,i,o){const{params:s}=this,l=this.helper.textFormatted(e),c=ze(l)&&l.indexOf(` +`)>-1?l.split(` +`):[];if(c.length)return c;if(je(l))return l;let f=s.tickWidth;(!f||f<=0)&&(f=i?95:s.isCategory?(s.isInverted?n(a[0])-n(a[1]):n(a[1])-n(a[0]))-12:110);function g(v,m){let S,P,N;for(let L=1;L{const S=v+1;return Se(this.helper.scale.domain());else{if(!arguments.length)return n.tickValues;n.tickValues=e}return this}setTransition(e){return this.config.transition=e,this}}var Iy=Object.defineProperty,Oy=(t,e,n)=>e in t?Iy(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,pr=(t,e,n)=>Oy(t,typeof e!="symbol"?e+"":e,n),Cy={getAxisInstance:function(){return this.axis||new Py(this)}};class Py{constructor(e){pr(this,"owner"),pr(this,"x"),pr(this,"subX"),pr(this,"y"),pr(this,"y2"),pr(this,"axesList",{}),pr(this,"tick",{x:null,y:null,y2:null}),pr(this,"xs",[]),pr(this,"orient",{x:"bottom",y:"left",y2:"right",subX:"bottom"}),this.owner=e,this.setOrient()}getAxisClassName(e){return`${Tn.axis} ${Tn[`axis${Cn(e)}`]}`}isHorizontal(e,n){const a=e.config.axis_rotated;return n?a:!a}isCategorized(){const{config:e,state:n}=this.owner;return e.axis_x_type.indexOf("category")>=0||n.hasRadar}isCustomX(){const{config:e}=this.owner;return!this.isTimeSeries()&&(e.data_x||cn(e.data_xs))}isTimeSeries(e="x"){return this.owner.config[`axis_${e}_type`]==="timeseries"}isLog(e="x"){return this.owner.config[`axis_${e}_type`]==="log"}isTimeSeriesY(){return this.isTimeSeries("y")}getAxisType(e="x"){let n="linear";return this.isTimeSeries(e)?n=this.owner.config.axis_x_localtime?"time":"utc":this.isLog(e)&&(n="log"),n}getExtent(){const e=this.owner,{config:n,scale:a}=e;let i=n.axis_x_extent;if(i){if(ve(i))i=i.bind(e.api)(e.getXDomain(e.data.targets),a.subX);else if(this.isTimeSeries()&&i.every(isNaN)){const o=Yn.bind(e);i=i.map(s=>a.subX(o(s)))}}return i}init(){const e=this.owner,{config:n,$el:{main:a,axis:i},state:{clip:o}}=e,s=["x","y"];n.axis_y2_show&&s.push("y2"),s.forEach(l=>{const c=this.getAxisClassName(l);i[l]=a.append("g").attr("class",c).attr("clip-path",()=>{let f=null;return l==="x"?f=o.pathXAxis:l==="y"&&(f=o.pathYAxis),f}).attr("transform",e.getTranslate(l)).style("visibility",n[`axis_${l}_show`]?null:"hidden"),this.generateAxes(l)})}setOrient(){const e=this.owner,{axis_rotated:n,axis_y_inner:a,axis_y2_inner:i}=e.config;this.orient={x:n?"left":"bottom",y:n?a?"top":"bottom":a?"right":"left",y2:n?i?"bottom":"top":i?"left":"right",subX:n?"left":"bottom"}}generateAxes(e){const n=this.owner,{config:a}=n,i=[],o=a[`axis_${e}_axes`],s=a.axis_rotated;let l;e==="x"?l=s?Iu:Ru:e==="y"?l=s?Ru:Iu:e==="y2"&&(l=s?Ty:$y),o.length&&o.forEach(c=>{const f=c.tick||{},g=n.scale[e].copy();c.domain&&g.domain(c.domain),i.push(l(g).ticks(f.count).tickFormat(ve(f.format)?f.format.bind(n.api):v=>v).tickValues(f.values).tickSizeOuter(f.outer===!1?0:6))}),this.axesList[e]=i}updateAxes(){const e=this.owner,{config:n,$el:{main:a},$T:i}=e;Object.keys(this.axesList).forEach(o=>{const s=n[`axis_${o}_axes`],l=e.scale[o].copy(),c=l.range();this.axesList[o].forEach((f,g)=>{const v=f.scale().range();c.every((P,N)=>P===v[N])||f.scale().range(c);const m=`${this.getAxisClassName(o)}-${g+1}`;let S=a.select(`.${m.replace(/\s/,".")}`);S.empty()?S=a.append("g").attr("class",m).style("visibility",n[`axis_${o}_show`]?null:"hidden").call(f):(s[g].domain&&l.domain(s[g].domain),i(S).call(f.scale(l))),S.attr("transform",e.getTranslate(o,g+1))})})}setAxis(e,n,a,i){const o=this.owner;e!=="subX"&&(this.tick[e]=this.getTickValues(e)),this[e]=this.getAxis(e,n,a,e==="x"&&(o.scale.zoom||o.config.subchart_show||o.state.resizing)?!0:i)}getAxis(e,n,a,i,o){const s=this.owner,{config:l}=s,c=/^(x|subX)$/.test(e),f=c?"x":e,g=c&&this.isCategorized(),v=this.orient[e],m=o?0:s.getAxisTickRotate(f);let S;if(c)S=e==="subX"?s.format.subXAxisTick:s.format.xAxisTick;else{const X=l[`axis_${e}_tick_format`];ve(X)&&(S=X.bind(s.api))}let P=this.tick[f];const N=ea({outerTick:a,noTransition:i,config:l,id:e,tickTextRotate:m,owner:s},c&&{isCategory:g,isInverted:l.axis_x_inverted,tickMultiline:l.axis_x_tick_multiline,tickWidth:l.axis_x_tick_width,tickTitle:g&&l.axis_x_tick_tooltip&&s.api.categories(),orgXScale:s.scale.x});c||(N.tickStepSize=l[`axis_${f}_tick_stepSize`]);const L=new Ry(N).scale(c&&s.scale.zoom||n).orient(v);if(c&&this.isTimeSeries()&&P&&!ve(P)){const X=Yn.bind(s);P=P.map(W=>X(W))}else!c&&this.isTimeSeriesY()&&(L.ticks(l.axis_y_tick_time_value),P=null);P&&L.tickValues(P),L.tickFormat(S||!c&&s.isStackNormalized()&&(X=>`${X}%`)),g&&(L.tickCentered(l.axis_x_tick_centered),qn(l.axis_x_tick_culling)&&(l.axis_x_tick_culling=!1));const w=l[`axis_${f}_tick_count`];return w&&L.ticks(w),L}updateXAxisTickValues(e,n){var a;const i=this.owner,{config:o}=i,s=o.axis_x_tick_fit;let l=o.axis_x_tick_count,c;return(s||l&&s)&&(c=i.mapTargetsToUniqueXs(e),this.isCategorized()&&l>c.length&&(l=c.length),c=this.generateTickValues(c,l,this.isTimeSeries())),n?n.tickValues(c):this.x&&(this.x.tickValues(c),(a=this.subX)==null||a.tickValues(c)),c}getId(e){const{config:n,scale:a}=this.owner;let i=n.data_axes[e];return(!i||!a[i])&&(i="y"),i}getXAxisTickFormat(e){const n=this.owner,{config:a,format:i}=n,o=e&&a.subchart_axis_x_tick_format||a.axis_x_tick_format,s=this.isTimeSeries(),l=this.isCategorized();let c;return o?ve(o)?c=o.bind(n.api):s&&(c=f=>f?i.axisTime(o)(f):""):c=s?i.defaultAxisTime:l?n.categoryName:f=>f<0?f.toFixed(0):f,ve(c)?f=>c.apply(n,l?[f,n.categoryName(f)]:[f]):c}getTickValues(e){const n=this.owner,a=n.config[`axis_${e}_tick_values`],i=n[`${e}Axis`];return(ve(a)?a.call(n.api):a)||(i?i.tickValues():void 0)}getLabelOptionByAxisId(e){return this.owner.config[`axis_${e}_label`]}getLabelText(e){const n=this.getLabelOptionByAxisId(e);return ze(n)?n:n?n.text:null}setLabelText(e,n){const a=this.owner,{config:i}=a,o=this.getLabelOptionByAxisId(e);ze(o)?i[`axis_${e}_label`]=n:o&&(o.text=n)}getLabelPosition(e,n){const a=this.owner.config.axis_rotated,i=this.getLabelOptionByAxisId(e),o=nr(i)&&i.position?i.position:n[+!a],s=l=>!!~o.indexOf(l);return{isInner:s("inner"),isOuter:s("outer"),isLeft:s("left"),isCenter:s("center"),isRight:s("right"),isTop:s("top"),isMiddle:s("middle"),isBottom:s("bottom")}}getAxisLabelPosition(e){return this.getLabelPosition(e,e==="x"?["inner-top","inner-right"]:["inner-right","inner-top"])}getLabelPositionById(e){return this.getAxisLabelPosition(e)}xForAxisLabel(e){const n=this.owner,{state:{width:a,height:i}}=n,o=this.getAxisLabelPosition(e);let s=o.isMiddle?-i/2:0;return this.isHorizontal(n,e!=="x")?s=o.isLeft?0:o.isCenter?a/2:a:o.isBottom&&(s=-i),s}textAnchorForAxisLabel(e){const n=this.owner,a=this.getAxisLabelPosition(e);let i=a.isMiddle?"middle":"end";return this.isHorizontal(n,e!=="x")?i=a.isLeft?"start":a.isCenter?"middle":"end":a.isBottom&&(i="start"),i}dxForAxisLabel(e){const n=this.owner,a=this.getAxisLabelPosition(e);let i=a.isBottom?"0.5em":"0";return this.isHorizontal(n,e!=="x")?i=a.isLeft?"0.5em":a.isRight?"-0.5em":"0":a.isTop&&(i="-0.5em"),i}dyForAxisLabel(e){const n=this.owner,{config:a}=n,i=a.axis_rotated,o=this.getAxisLabelPosition(e).isInner,s=a[`axis_${e}_tick_rotate`]?n.getHorizontalAxisHeight(e):0,{width:l}=this.getMaxTickSize(e);let c;if(e==="x"){const f=a.axis_x_height;i?c=o?"1.2em":-25-l:o?c="-0.5em":f?c=f-10:s?c=s-10:c="3em"}else c={y:["-0.5em",10,"3em","1.2em",10],y2:["1.2em",-20,"-2.2em","-0.5em",15]}[e],i?o?c=c[0]:s?c=s*(e==="y2"?-1:1)-c[1]:c=c[2]:c=o?c[3]:(c[4]+(a[`axis_${e}_inner`]?0:l+c[4]))*(e==="y"?-1:1);return c}getMaxTickSize(e,n){const a=this.owner,{config:i,state:{current:o},$el:{svg:s,chart:l}}=a,c=o.maxTickSize[e],f=`axis_${e}`,g={width:0,height:0};if(n||!i[`${f}_show`]||c.width>0&&a.filterTargetsToShow().length===0)return c;if(s){const v=/^y2?$/.test(e),m=a.filterTargetsToShow(a.data.targets),S=a.scale[e].copy().domain(a[`get${v?"Y":"X"}Domain`](m,e)),P=S.domain(),N=P[0]===P[1]&&P.every(K=>K>0),L=je(c.domain)&&c.domain[0]===c.domain[1]&&c.domain.every(K=>K>0);if(N||L)return c.size;c.domain=P,v||c.ticks.splice(0);const w=this.getAxis(e,S,!1,!1,!0),X=i[`${f}_tick_rotate`],W=i[`${f}_tick_count`];!i[`${f}_tick_values`]&&W&&w.tickValues(this.generateTickValues(P,W,v?this.isTimeSeriesY():this.isTimeSeries())),!v&&this.updateXAxisTickValues(m,w);const k=l.append("svg").style("visibility","hidden").style("position","fixed").style("top","0").style("left","0");w.create(k),k.selectAll("text").attr("transform",he(X)?`rotate(${X})`:null).each(function(K,at){const{width:ht,height:$t}=this.getBoundingClientRect();g.width=Math.max(g.width,ht),g.height=Math.max(g.height,$t),v||(c.ticks[at]=ht)}),k.remove()}return Object.keys(g).forEach(v=>{g[v]>0&&(c[v]=g[v])}),c}getXAxisTickTextY2Overflow(e){const n=this.owner,{axis:a,config:i,state:{current:o,isLegendRight:s,legendItemWidth:l}}=n,c=n.getAxisTickRotate("x"),f=c>0&&c<90;if((a.isCategorized()||a.isTimeSeries())&&i.axis_x_tick_fit&&(!i.axis_x_tick_culling||qn(i.axis_x_tick_culling))&&!i.axis_x_tick_multiline&&f){const g=i.axis_y2_show&&o.maxTickSize.y2.width||0,v=s&&l||0,m=o.width-n.getCurrentPaddingByDirection("left"),S=this.getXAxisTickMaxOverflow(c,m-e)-g-v,P=Math.max(0,S)+e;return Math.min(P,m/2)}return 0}getXAxisTickMaxOverflow(e,n){const a=this.owner,{axis:i,config:o,state:s}=a,l=i.isTimeSeries(),c=s.current.maxTickSize.x.ticks,f=c.length,{left:g,right:v}=s.axis.x.padding;let m=0;const S=f-(l&&o.axis_x_tick_fit?.5:0);for(let L=0;L{const c=this.getLabelText(l),f=`axis${Cn(l)}`,g=Tn[`${f}Label`];if(c){let v=i.select(`text.${g}`);v.empty()&&(v=i.select(`g.${Tn[f]}`).insert("text",":first-child").attr("class",g).attr("transform",["rotate(-90)",null][l==="x"?+!s:+s]).style("text-anchor",()=>this.textAnchorForAxisLabel(l))),o(v,e).attr("x",()=>this.xForAxisLabel(l)).attr("dx",()=>this.dxForAxisLabel(l)).attr("dy",()=>this.dyForAxisLabel(l)).text(c)}})}getPadding(e,n,a,i){const o=he(e)?e:e[n];return De(o)?this.owner.convertPixelToScale(/(bottom|top)/.test(n)?"y":"x",o,i):a}generateTickValues(e,n,a){let i=e;if(n){const o=ve(n)?n():n;if(o===1)i=[e[0]];else if(o===2)i=[e[0],e[e.length-1]];else if(o>2){const s=this.isCategorized(),l=o-2,c=e[0],f=e[e.length-1],g=(f-c)/(l+1);let v;i=[c];for(let m=0;mo-s)),i}generateTransitions(e){const n=this.owner,{$el:{axis:a},$T:i}=n,[o,s,l,c]=["x","y","y2","subX"].map(f=>i(a[f],e));return{axisX:o,axisY:s,axisY2:l,axisSubX:c}}redraw(e,n,a){const i=this.owner,{config:o,state:s,$el:l}=i,c=n?"0":null;["x","y","y2","subX"].forEach(f=>{const g=this[f],v=l.axis[f];g&&v&&(!a&&!o.transition_duration&&(g.config.withoutTransition=!0),v.style("opacity",c),g.create(e[`axis${Cn(f)}`]))}),this.updateAxes(),!s.rendered&&o.axis_tooltip&&this.setAxisTooltip()}redrawAxis(e,n,a,i,o){var s,l,c;const f=this.owner,{config:g,scale:v,$el:m}=f,S=!!v.zoom;let P;!S&&this.isCategorized()&&e.length===0&&v.x.domain([0,m.axis.x.selectAll(".tick").size()]),v.x&&e.length?(!S&&f.updateXDomain(e,n.UpdateXDomain,n.UpdateOrgXDomain,n.TrimXDomain),g.axis_x_tick_values||this.updateXAxisTickValues(e)):this.x&&(this.x.tickValues([]),(s=this.subX)==null||s.tickValues([])),g.zoom_rescale&&!i&&(P=v.x.orgDomain()),["y","y2"].forEach(N=>{const L=`axis_${N}_`,w=v[N];if(w){const X=g[`${L}tick_values`],W=g[`${L}tick_count`];if(w.domain(f.getYDomain(e,N,P)),!X&&W){const H=f.axis[N],k=w.domain();H.tickValues(this.generateTickValues(k,k.every(K=>K===0)?1:W,this.isTimeSeriesY()))}}}),this.redraw(a,f.hasArcType(),o),this.updateLabels(n.Transition),(n.UpdateXDomain||n.UpdateXAxis||n.Y)&&e.length&&this.setCulling(),n.Y&&((l=v.subY)==null||l.domain(f.getYDomain(e,"y")),(c=v.subY2)==null||c.domain(f.getYDomain(e,"y2")))}setCulling(){const e=this.owner,{config:n,state:{clip:a,current:i},$el:o}=e;["subX","x","y","y2"].forEach(s=>{const l=o.axis[s],f=`axis_${s==="subX"?"x":s}_tick_culling`,g=n[f];if(l&&g){const v=l.selectAll(".tick"),m=na(v.data()),S=m.length,P=n[`${f}_max`],N=n[`${f}_lines`];let L;if(S){for(let w=1;w{var f,g,v;if(ze(l)||l[c])if(s[c]=(f=o[c])==null?void 0:f.append("text").classed(Tn[`axis${c.toUpperCase()}Tooltip`],!0).attr("filter",n.updateTextBGColor({id:c},l)),a){const m=c==="x"?"x":"y",S=c==="y"?"1.15em":c==="x"?"-0.3em":"-0.4em";(g=s[c])==null||g.attr(m,S).attr(`d${c==="x"?"y":"x"}`,c==="x"?"0.4em":"-1.3em").style("text-anchor",c==="x"?"end":null)}else{const m=c==="x"?"y":"x",S=c==="x"?"1.15em":`${c==="y"?"-":""}0.4em`;(v=s[c])==null||v.attr(m,S).attr(`d${c==="x"?"x":"y"}`,c==="x"?"-1em":"0.3em").style("text-anchor",c==="y"?"end":null)}})}}var wy={initEventRect(){this.$el.main.select(`.${Se.chart}`).append("g").attr("class",Zn.eventRects).style("fill-opacity","0")},redrawEventRect(){var t;const e=this,{config:n,state:a,$el:i}=e,o=e.isMultipleX(),s=n.axis_x_inverted;if(i.eventRect)e.updateEventRect(i.eventRect,!0);else if(e.data.targets.length){const c=e.$el.main.select(`.${Zn.eventRects}`).style("cursor",n.zoom_enabled&&n.zoom_type!=="drag"?n.axis_rotated?"ns-resize":"ew-resize":null).classed(Zn.eventRectsMultiple,o).classed(Zn.eventRectsSingle,!o).selectAll(`.${Zn.eventRect}`).data([0]).enter().append("rect");e.updateEventRect(c),e.updateEventType(c),c.call(e.getDraggableSelection()),i.eventRect=c,e.state.inputType==="touch"&&!i.svg.on("touchstart.eventRect")&&!e.hasArcType()&&e.bindTouchOnEventRect(),a.rendered&&e.updateEventRect(i.eventRect,!0)}if(!o){const l=e.getMaxDataCountTarget();(!n.data_xSort||s)&&l.sort((c,f)=>s?f.x-c.x:c.x-f.x),e.updateDataIndexByX(l),e.updateXs(l),(t=e.updatePointClass)==null||t.call(e,!0),a.eventReceiver.data=l}e.updateEventRectData()},bindTouchOnEventRect(){const t=this,{config:e,state:n,$el:{eventRect:a,svg:i}}=t,o=m=>{if(t.isMultipleX())t.selectRectForMultipleXs(m);else{const S=t.getDataIndexFromEvent(n.event);t.callOverOutForTouch(S),S===-1?t.unselectRect():t.selectRectForSingle(m,S)}},s=()=>{t.unselectRect(),t.callOverOutForTouch()},l=e.interaction_inputType_touch.preventDefault,c=Co(l)&&l||!1,f=!isNaN(l)&&l||null;let g;const v=m=>{const S=m.type,N=m.changedTouches[0][`client${e.axis_rotated?"Y":"X"}`];S==="touchstart"?c?m.preventDefault():f!==null&&(g=N):S==="touchmove"&&(c||g===!0||f!==null&&Math.abs(g-N)>=f)&&(g=!0,m.preventDefault())};a.on("touchstart",m=>{n.event=m,t.updateEventRect()}).on("touchstart.eventRect touchmove.eventRect",m=>{if(n.event=m,!a.empty()&&a.classed(Zn.eventRect)){if(n.dragging||n.flowing||t.hasArcType()||m.touches.length>1)return;v(m),o(a.node())}else s()},!0).on("touchend.eventRect",m=>{n.event=m,!a.empty()&&a.classed(Zn.eventRect)&&(t.hasArcType()||!t.toggleShape||n.cancelClick)&&n.cancelClick&&(n.cancelClick=!1)},!0),i.on("touchstart",m=>{n.event=m;const{target:S}=m;S&&S!==a.node()&&s()})},updateEventRect(t,e=!1){const n=this,{state:a,$el:i}=n,{eventReceiver:o,width:s,height:l,rendered:c,resizing:f}=a,g=t||i.eventRect,v=()=>{if(o){const m=Zl(i.chart.node());o.rect=g.node().getBoundingClientRect().toJSON(),o.rect.top+=m.y,o.rect.left+=m.x}};(!c||f||e)&&(g.attr("x",0).attr("y",0).attr("width",s).attr("height",l),(!c||e)&&g.classed(Zn.eventRect,!0)),v()},updateEventType(t){const e=this,n=Co(t),a=n?e.$el.eventRect:t,i=n?t!==(a==null?void 0:a.datum().multipleX):!1;a&&(i&&(a==null||a.on("mouseover mousemove mouseout click",null)),e.isMultipleX()?e.generateEventRectsForMultipleXs(a):e.generateEventRectsForSingleX(a))},updateEventRectData(){const t=this,{config:e,scale:n,state:a}=t,i=n.zoom||n.x,o=e.axis_rotated,s=t.isMultipleX();let l,c,f,g;if(t.updateEventType(s),s)l=0,c=0,f=a.width,g=a.height;else{let S,P;if(t.axis.isCategorized())S=t.getEventRectWidth(),P=N=>i(N.x)-S/2;else{const N=({index:L})=>({prev:t.getPrevX(L),next:t.getNextX(L)});S=L=>{const w=N(L),X=i.domain();let W;return w.prev===null&&w.next===null?W=o?a.height:a.width:w.prev===null?W=(i(w.next)+i(L.x))/2:w.next===null?W=i(X[1])-(i(w.prev)+i(L.x))/2:(Object.keys(w).forEach((H,k)=>{var K;w[H]=(K=w[H])!=null?K:X[k]}),W=Math.max(0,(i(w.next)-i(w.prev))/2)),W},P=L=>{const w=N(L);let X;return w.prev===null&&w.next===null?X=0:w.prev===null?X=i(i.domain()[0]):X=(i(L.x)+i(w.prev))/2,X}}l=o?0:P,c=o?P:0,f=o?a.width:S,g=o?S:a.height}const{eventReceiver:v}=a,m=(S,P)=>ve(S)?S(P):S;v.coords.splice(v.data.length),v.data.forEach((S,P)=>{v.coords[P]={x:m(l,S),y:m(c,S),w:m(f,S),h:m(g,S)}})},selectRectForSingle(t,e){var n,a;const i=this,{config:o,$el:{main:s,circle:l}}=i,c=o.data_selection_enabled,f=o.data_selection_grouped,g=o.data_selection_isselectable,v=o.tooltip_grouped,m=i.getAllValuesOnIndex(e);if(v&&(i.showTooltip(m,t),(n=i.showGridFocus)==null||n.call(i,m),!c||f))return;!l&&s.selectAll(`.${Se.EXPANDED}:not(.${sn.shape}-${e})`).classed(Se.EXPANDED,!1);const S=s.selectAll(`.${sn.shape}-${e}`).classed(Se.EXPANDED,!0).style("cursor",g?"pointer":null).filter(function(P){return i.isWithinShape(this,P)});S.empty()&&!v&&o.interaction_onout&&((a=i.hideGridFocus)==null||a.call(i),i.hideTooltip(),!f&&i.setExpand(e)),S.call(P=>{var N,L;const w=P.data();c&&(f||g!=null&&g.bind(i.api)(w))&&(t.style.cursor="pointer"),v||(i.showTooltip(w,t),(N=i.showGridFocus)==null||N.call(i,w),(L=i.unexpandCircles)==null||L.call(i),P.each(X=>i.setExpand(e,X.id)))})},selectRectForMultipleXs(t,e=!0){const n=this,{config:a,state:i}=n,o=n.filterTargetsToShow(n.data.targets);if(i.dragging||n.hasArcType(o))return;const s=Hn(i.event,t),l=n.findClosestFromTargets(o,s);if(e&&i.mouseover&&(!l||l.id!==i.mouseover.id)&&(a.data_onout.call(n.api,i.mouseover),i.mouseover=void 0),!l){n.unselectRect();return}const f=(n.isBubbleType(l)||n.isScatterType(l)||!a.tooltip_grouped?[l]:n.filterByX(o,l.x)).map(v=>n.addName(v));n.showTooltip(f,t),n.setExpand(l.index,l.id,!0),n.showGridFocus(f);const g=n.dist(l,s);(n.isBarType(l.id)||g{const c=l?e.getDataIndexFromEvent(l):i.currentIdx;return c>-1?i.data[c]:null};o.on("mouseover",l=>{a.event=l,e.updateEventRect(),Object.values(e.$el.axisTooltip).forEach(c=>c==null?void 0:c.style("display",null))}).on("mousemove",function(l){const c=s(l);if(a.event=l,!c)return;let{index:f}=c;const g=n.line_step_type;if(n.line_step_tooltipMatch&&e.hasType("step")&&/^step\-(before|after)$/.test(g)){const m=e.scale.zoom||e.scale.x,S=e.axis.xs[f],P=m.invert(Hn(l,this)[0]);g==="step-after"&&PS&&(f+=1)}e.showAxisGridFocus();const v=n.tooltip_grouped&&f===i.currentIdx;if(a.dragging||a.flowing||e.hasArcType()||v){n.tooltip_show&&v&&e.setTooltipPosition();return}f!==i.currentIdx&&(e.setOverOut(!1,i.currentIdx),i.currentIdx=f),f===-1?e.unselectRect():e.selectRectForSingle(this,f),e.setOverOut(f!==-1,f)}).on("mouseout",l=>{a.event=l,!(!n||e.hasArcType()||i.currentIdx===-1||!n.interaction_onout)&&(e.hideAxisGridFocus(),e.unselectRect(),e.setOverOut(!1,i.currentIdx),i.currentIdx=-1)})}return o},clickHandlerForSingleX(t,e){const n=e,{config:a,state:i,$el:{main:o}}=n;if(!t||n.hasArcType()||i.cancelClick){i.cancelClick&&(i.cancelClick=!1);return}const{index:s}=t;o.selectAll(`.${sn.shape}-${s}`).each(function(l){var c;(a.data_selection_grouped||n.isWithinShape(this,l))&&((c=n.toggleShape)==null||c.call(n,this,l,s),a.data_onclick.bind(n.api)(l,this))})},generateEventRectsForMultipleXs(t){const e=this,{config:n,state:a}=e;t.on("click",function(i){a.event=i,e.clickHandlerForMultipleXS.bind(this)(e)}).datum({multipleX:!0}),a.inputType==="mouse"&&t.on("mouseover mousemove",function(i){a.event=i,e.selectRectForMultipleXs(this)}).on("mouseout",i=>{a.event=i,!(!e.config||e.hasArcType()||!n.interaction_onout)&&e.unselectRect()})},clickHandlerForMultipleXS(t){const e=t,{config:n,state:a}=e,i=e.filterTargetsToShow(e.data.targets);if(e.hasArcType(i))return;const o=Hn(a.event,this),s=e.findClosestFromTargets(i,o),l=e.getPointSensitivity(s);s&&(e.isBarType(s.id)||e.dist(s,o)+t;var Dy={generateFlow(t){const e=this,{data:n,state:a,$el:i}=e;return function(){const o=t.flow.length;a.flowing=!0,n.targets.forEach(l=>{l.values.splice(0,o)}),e.updateXGrid&&e.updateXGrid(!0);const s={};["axis.x","grid.x","gridLines.x","region.list","text","bar","line","area","circle"].forEach(l=>{const c=l.split(".");let f=i[c[0]];f&&c.length>1&&(f=f[c[1]]),f!=null&&f.size()&&(s[l]=f)}),e.hideGridFocus(),e.setFlowList(s,t)}},setFlowList(t,e){const n=this,{flow:a,targets:i}=e,{duration:o=e.duration,index:s,length:l,orgDataCount:c}=a,f=n.getFlowTransform(i,c,s,l),g=ec();let v;g.add(Object.keys(t).map(m=>(v=t[m].transition().ease(My).duration(o),m==="axis.x"?v=v.call(S=>{n.axis.x.setTransition(S).create(S)}):m==="region.list"?v=v.filter(n.isRegionOnX).attr("transform",f):v=v.attr("transform",f),v))),v.call(g,()=>{n.cleanUpFlow(t,e)})},cleanUpFlow(t,e){const n=this,{config:a,state:i,$el:{svg:o}}=n,s=a.axis_rotated,{flow:l,shape:c,xv:f}=e,{cx:g,cy:v,xForText:m,yForText:S}=c.pos,{done:P=()=>{},length:N}=l;N&&(["circle","text","shape","eventRect"].forEach(L=>{const w=[];for(let X=0;X{const w=t[L];if(L!=="axis.x"&&w.attr("transform",null),L==="grid.x")w.attr(i.xgridAttr);else if(L==="gridLines.x")w.attr("x1",s?0:f).attr("x2",s?i.width:f),w.select("text").attr("x",s?i.width:0).attr("y",f);else if(/^(area|bar|line)$/.test(L))w.attr("d",c.type[L]);else if(L==="text")w.attr("x",m).attr("y",S).style("fill-opacity",n.opacityForText.bind(n));else if(L==="circle")if(n.isCirclePoint())w.attr("cx",g).attr("cy",v);else{const X=H=>g(H)-a.point_r,W=H=>v(H)-a.point_r;w.attr("x",X).attr("y",W)}else L==="region.list"&&w.select("rect").filter(n.isRegionOnX).attr("x",n.regionX.bind(n)).attr("width",n.regionWidth.bind(n))}),a.interaction_enabled&&n.redrawEventRect(),P.call(n.api),i.flowing=!1},getFlowTransform(t,e,n,a){const i=this,{data:o,scale:{x:s}}=i,l=o.targets[0].values;let c=i.getValueOnIndex(l,n),f=i.getValueOnIndex(l,n+a),g;const v=s.domain(),m=i.updateXDomain(t,!0,!0);e?e===1||(c==null?void 0:c.x)===(f==null?void 0:f.x)?g=s(v[0])-s(m[0]):g=i.axis.isTimeSeries()?s(v[0])-s(m[0]):s((c==null?void 0:c.x)||0)-s(f.x):l.length!==1?g=s(v[0])-s(m[0]):i.axis.isTimeSeries()?(c=i.getValueOnIndex(l,0),f=i.getValueOnIndex(l,l.length-1),g=s(c.x)-s(f.x)):g=Dr(m)/2;const S=Dr(v)/Dr(m);return`translate(${g},0) scale(${S},1)`}},Ly={initClip(){const t=this,{clip:e,datetimeId:n}=t.state;e.id=`${n}-clip`,e.idXAxis=`${e.id}-xaxis`,e.idYAxis=`${e.id}-yaxis`,e.idGrid=`${e.id}-grid`,e.path=t.getClipPath(e.id),e.pathXAxis=t.getClipPath(e.idXAxis),e.pathYAxis=t.getClipPath(e.idYAxis),e.pathGrid=t.getClipPath(e.idGrid)},getClipPath(t){const e=this,{config:n}=e;return!n.clipPath&&/-clip$/.test(t)||!n.axis_x_clipPath&&/-clip-xaxis$/.test(t)||!n.axis_y_clipPath&&/-clip-yaxis$/.test(t)?null:`url(#${t})`},appendClip(t,e){e&&t.append("clipPath").attr("id",e).append("rect")},setXAxisClipPath(t){const e=this,{config:n,state:{margin:a,width:i,height:o}}=e,s=n.axis_rotated,l=Math.max(30,a.left)-(s?0:20),c=(s?a.top+o+10:a.bottom)+20,f=s?-(1+l):-(l-1),g=-15,v=s?a.left+20:i+10+l;t.attr("x",f).attr("y",g).attr("width",v).attr("height",c)},setYAxisClipPath(t){const e=this,{config:n,state:{margin:a,width:i,height:o}}=e,s=n.axis_rotated,l=Math.max(30,a.left)-(s?20:0),c=n.axis_y_inner,f=c&&!s?n.axis_y_label.text?-20:-1:s?-(1+l):-(l-1),g=-(s?20:a.top),v=(s?i+15+l:a.left+20)+(c?20:0),m=(s?a.bottom+10:a.top+o)+10;t.attr("x",f).attr("y",g).attr("width",v).attr("height",m)},updateXAxisTickClip(){const t=this,{config:e,state:{clip:n,xAxisHeight:a},$el:{defs:i}}=t,o=t.getHorizontalAxisHeight("x");if(i&&!n.idXAxisTickTexts){const s=`${n.id}-xaxisticktexts`;t.appendClip(i,s),n.pathXAxisTickTexts=t.getClipPath(n.idXAxisTickTexts),n.idXAxisTickTexts=s}!e.axis_x_tick_multiline&&t.getAxisTickRotate("x")&&o!==a&&(t.setXAxisTickClipWidth(),t.setXAxisTickTextClipPathWidth()),t.state.xAxisHeight=o},setXAxisTickClipWidth(){const t=this,{config:e,state:{current:{maxTickSize:n}}}=t,a=t.getAxisTickRotate("x");if(!e.axis_x_tick_multiline&&a){const i=Math.sin(Math.PI/180*Math.abs(a));n.x.clipPath=(t.getHorizontalAxisHeight("x")-20)/i}else n.x.clipPath=null},setXAxisTickTextClipPathWidth(){const t=this,{state:{clip:e,current:n},$el:{svg:a}}=t;a&&a.select(`#${e.idXAxisTickTexts} rect`).attr("width",n.maxTickSize.x.clipPath).attr("height",30)}};const Ny=t=>De(t.position)||"end",Fy=t=>t.position==="start"?4:t.position==="middle"?0:-4;function Cu(t,e,n){return a=>{let i=t?0:e;return a.position==="start"?i=t?-n:0:a.position==="middle"&&(i=(t?-n:e)/2),i}}function Pu(t,e){e==="grid"&&t.each(function(){const n=ot(this);["x1","x2","y1","y2"].forEach(a=>n.attr(a,+n.attr(a)))})}var By={hasGrid(){const{config:t}=this;return["x","y"].some(e=>t[`grid_${e}_show`]||t[`grid_${e}_lines`].length)},initGrid(){const t=this;t.hasGrid()&&t.initGridLines(),t.initFocusGrid()},initGridLines(){const t=this,{config:e,state:{clip:n},$el:a}=t;(e.grid_x_lines.length||e.grid_y_lines.length)&&(a.gridLines.main=a.main.insert("g",`.${Se.chart}${e.grid_lines_front?" + *":""}`).attr("clip-path",n.pathGrid).attr("class",`${on.grid} ${on.gridLines}`),a.gridLines.main.append("g").attr("class",on.xgridLines),a.gridLines.main.append("g").attr("class",on.ygridLines),a.gridLines.x=Uc([]))},updateXGrid(t){const e=this,{config:n,scale:a,state:i,$el:{main:o,grid:s}}=e,l=n.axis_rotated,c=e.generateGridData(n.grid_x_type,a.x),f=e.axis.isCategorized()?e.axis.x.tickOffset():0,g=v=>(a.zoom||a.x)(v)+f*(l?-1:1);i.xgridAttr=l?{x1:0,x2:i.width,y1:g,y2:g}:{x1:g,x2:g,y1:0,y2:i.height},s.x=o.select(`.${on.xgrids}`).selectAll(`.${on.xgrid}`).data(c),s.x.exit().remove(),s.x=s.x.enter().append("line").attr("class",on.xgrid).merge(s.x),t||s.x.each(function(){const v=ot(this);Object.keys(i.xgridAttr).forEach(m=>{v.attr(m,i.xgridAttr[m]).style("opacity",()=>v.attr(l?"y1":"x1")===(l?i.height:0)?"0":null)})})},updateYGrid(){const t=this,{axis:e,config:n,scale:a,state:i,$el:{grid:o,main:s}}=t,l=n.axis_rotated,c=g=>a.y(g),f=e.y.getGeneratedTicks(n.grid_y_ticks)||t.scale.y.ticks(n.grid_y_ticks);o.y=s.select(`.${on.ygrids}`).selectAll(`.${on.ygrid}`).data(f),o.y.exit().remove(),o.y=o.y.enter().append("line").attr("class",on.ygrid).merge(o.y),o.y.attr("x1",l?c:0).attr("x2",l?c:i.width).attr("y1",l?0:c).attr("y2",l?i.height:c),Pu(o.y,"grid")},updateGrid(){const t=this,{$el:{grid:e,gridLines:n}}=t;!n.main&&t.initGridLines(),e.main.style("visibility",t.hasArcType()?"hidden":null),t.hideGridFocus(),t.updateGridLines("x"),t.updateGridLines("y")},updateGridLines(t){const e=this,{config:n,$el:{gridLines:a,main:i},$T:o}=e,s=n.axis_rotated,l=t==="x";n[`grid_${t}_show`]&&e[`update${t.toUpperCase()}Grid`]();let c=i.select(`.${on[`${t}gridLines`]}`).selectAll(`.${on[`${t}gridLine`]}`).data(n[`grid_${t}_lines`]);o(c.exit()).style("opacity","0").remove();const f=c.enter().append("g");f.append("line").style("opacity","0"),c=f.merge(c),c.each(function(g){const v=ot(this);v.select("text").empty()&&g.text&&v.append("text").style("opacity","0")}),o(c.attr("class",g=>`${on[`${t}gridLine`]} ${g.class||""}`.trim()).select("text").attr("text-anchor",Ny).attr("transform",()=>l?s?null:"rotate(-90)":s?"rotate(-90)":null).attr("dx",Fy).attr("dy",-5)).text(function(g){var v;return(v=g.text)!=null?v:this.remove()}),a[t]=c},redrawGrid(t){const e=this,{config:{axis_rotated:n},state:{width:a,height:i},$el:{gridLines:o},$T:s}=e,l=e.xv.bind(e),c=e.yv.bind(e);let f=o.x.select("line"),g=o.x.select("text"),v=o.y.select("line"),m=o.y.select("text");return f=s(f,t).attr("x1",n?0:l).attr("x2",n?a:l).attr("y1",n?l:0).attr("y2",n?l:i),g=s(g,t).attr("x",Cu(!n,a,i)).attr("y",l),v=s(v,t).attr("x1",n?c:0).attr("x2",n?c:a).attr("y1",n?0:c).attr("y2",n?i:c),m=s(m,t).attr("x",Cu(n,a,i)).attr("y",c),[f.style("opacity",null),g.style("opacity",null),v.style("opacity",null),m.style("opacity",null)]},initFocusGrid(){const t=this,{config:e,state:{clip:n},$el:a}=t,i=e.grid_front,o=`.${i&&a.gridLines.main?on.gridLines:Se.chart}${i?" + *":""}`,s=a.main.insert("g",o).attr("clip-path",n.pathGrid).attr("class",on.grid);if(a.grid.main=s,e.grid_x_show&&s.append("g").attr("class",on.xgrids),e.grid_y_show&&s.append("g").attr("class",on.ygrids),e.axis_tooltip){const l=s.append("g").attr("class","bb-axis-tooltip");l.append("line").attr("class","bb-axis-tooltip-x"),l.append("line").attr("class","bb-axis-tooltip-y")}e.interaction_enabled&&e.grid_focus_show&&!e.axis_tooltip&&(s.append("g").attr("class",qe.xgridFocus).append("line").attr("class",qe.xgridFocus),e.grid_focus_y&&!e.tooltip_grouped&&s.append("g").attr("class",qe.ygridFocus).append("line").attr("class",qe.ygridFocus))},showAxisGridFocus(){var t,e;const n=this,{config:a,format:i,state:{event:o,width:s,height:l}}=n,c=a.axis_rotated,[f,g]=Hn(o,(t=n.$el.eventRect)==null?void 0:t.node()),v={x:f,y:g};for(const[m,S]of Object.entries(n.$el.axisTooltip)){const P=m==="x"&&!c||m!=="x"&&c?"x":"y",N=v[P];let L=(e=n.scale[m])==null?void 0:e.invert(N);L&&(L=m==="x"&&n.axis.isTimeSeries()?i.xAxisTick(L):L==null?void 0:L.toFixed(2),S==null||S.attr(P,N).text(L))}n.$el.main.selectAll("line.bb-axis-tooltip-x, line.bb-axis-tooltip-y").style("visibility",null).each(function(m,S){const P=ot(this);S===0?P.attr("x1",f).attr("x2",f).attr("y1",S?0:l).attr("y2",S?l:0):P.attr("x1",S?0:s).attr("x2",S?s:0).attr("y1",g).attr("y2",g)})},hideAxisGridFocus(){const t=this;t.$el.main.selectAll("line.bb-axis-tooltip-x, line.bb-axis-tooltip-y").style("visibility","hidden"),Object.values(t.$el.axisTooltip).forEach(e=>e==null?void 0:e.style("display","none"))},showGridFocus(t){var e;const n=this,{config:a,state:{width:i,height:o}}=n,s=a.axis_rotated,l=n.$el.main.selectAll(`line.${qe.xgridFocus}, line.${qe.ygridFocus}`),c=(t||[l.datum()]).filter(v=>v&&De(n.getBaseValue(v)));if(!a.tooltip_show||c.length===0||!a.axis_x_forceAsSingle&&n.hasType("bubble")||n.hasArcType())return;const f=a.grid_focus_edge&&!a.tooltip_grouped,g=n.xx.bind(n);l.style("visibility",null).data(c.concat(c)).each(function(v){const m=ot(this),S={x:g(v),y:n.getYScaleById(v.id)(v.value)};let P;if(m.classed(qe.xgridFocus))P=s?[null,S.x,f?S.y:i,S.x]:[S.x,f?S.y:null,S.x,o];else{const N=n.axis.getId(v.id)==="y2";P=s?[S.y,f&&!N?S.x:null,S.y,f&&N?S.x:o]:[f&&N?S.x:null,S.y,f&&!N?S.x:i,S.y]}["x1","y1","x2","y2"].forEach((N,L)=>m.attr(N,P[L]))}),Pu(l,"grid"),(e=n.showCircleFocus)==null||e.call(n,t)},hideGridFocus(){var t;const e=this,{state:{inputType:n,resizing:a},$el:{main:i}}=e;(n==="mouse"||!a)&&(i.selectAll(`line.${qe.xgridFocus}, line.${qe.ygridFocus}`).style("visibility","hidden"),(t=e.hideCircleFocus)==null||t.call(e))},updateGridFocus(){var t;const e=this,{state:{inputType:n,width:a,height:i,resizing:o},$el:{grid:s}}=e,l=s.main.select(`line.${qe.xgridFocus}`);if(n==="touch")l.empty()?o&&((t=e.showCircleFocus)==null||t.call(e)):e.showGridFocus();else{const c=e.config.axis_rotated;l.attr("x1",c?0:-10).attr("x2",c?a:-10).attr("y1",c?-10:0).attr("y2",c?-10:i)}return!0},generateGridData(t,e){const n=this,a=n.$el.main.select(`.${Tn.axisX}`).selectAll(".tick").size();let i=[];if(t==="year"){const o=n.getXDomain(),[s,l]=o.map(c=>c.getFullYear());for(let c=s;c<=l;c++)i.push(new Date(`${c}-01-01 00:00:00`))}else i=e.ticks(10),i.length>a&&(i=i.filter(o=>String(o).indexOf(".")<0));return i},getGridFilterToRemove(t){return t?e=>{let n=!1;return(je(t)?t.concat():[t]).forEach(a=>{("value"in a&&e.value===a.value||"class"in a&&e.class===a.class)&&(n=!0)}),n}:()=>!0},removeGridLines(t,e){const n=this,{config:a,$T:i}=n,o=n.getGridFilterToRemove(t),s=g=>!o(g),l=e?on.xgridLines:on.ygridLines,c=e?on.xgridLine:on.ygridLine;i(n.$el.main.select(`.${l}`).selectAll(`.${c}`).filter(o)).style("opacity","0").remove();const f=`grid_${e?"x":"y"}_lines`;a[f]=a[f].filter(s)}},Uy={initRegion(){const t=this,{$el:e}=t;e.region.main=e.main.insert("g",":first-child").attr("clip-path",t.state.clip.path).attr("class",$a.regions)},updateRegion(){const t=this,{config:e,$el:{region:n},$T:a}=t;n.main||t.initRegion(),n.main.style("visibility",t.hasArcType()?"hidden":null);const i=n.main.selectAll(`.${$a.region}`).data(e.regions);a(i.exit()).style("opacity","0").remove();const o=i.enter().append("g");o.append("rect").style("fill-opacity","0"),n.list=o.merge(i).attr("class",t.classRegion.bind(t)),n.list.each(function(s){var l;ot(this).select("text").empty()&&((l=s.label)!=null&&l.text)&&ot(this).append("text").style("opacity","0")})},redrawRegion(t){const e=this,{$el:{region:n},$T:a}=e,i=e.regionX.bind(e),o=e.regionY.bind(e),s=["width","height"];let l=n.list.select("rect"),c=n.list.selectAll("text");return l=a(l,t).attr("x",i).attr("y",o).attr("width",e.regionWidth.bind(e)).attr("height",e.regionHeight.bind(e)),c=a(c,t).text(f=>{var g;return(g=f.label)==null?void 0:g.text}).attr("transform",({label:f})=>f.rotated?" rotate(-90)":null).attr("transform",function(f){var g;const{x:v=0,y:m=0,center:S=!1,rotated:P=!1}=(g=f.label)!=null?g:{},N=this.previousElementSibling,L={x:0,y:0};return ze(S)&&["x","y"].forEach((w,X)=>{S.indexOf(w)>-1&&(L[w]=(+N.getAttribute(s[X])-Ma(this)[s[X]])/2)}),`translate(${i(f)+L.x+v}, ${o(f)+L.y+m})${P?" rotate(-90)":""}`}).attr("text-anchor",({label:f})=>f!=null&&f.rotated?"end":null).attr("dy","1em").style("fill",({label:f})=>{var g;return(g=f==null?void 0:f.color)!=null?g:null}),[l.style("fill-opacity",f=>De(f.opacity)?f.opacity:null).on("end",function(){ot(this.parentNode).selectAll("rect:not([x])").remove()}),c.style("opacity",null)]},regionX(t){return this.getRegionSize("x",t)},regionY(t){return this.getRegionSize("y",t)},regionWidth(t){return this.getRegionSize("width",t)},regionHeight(t){return this.getRegionSize("height",t)},getRegionSize(t,e){const n=this,{config:a,scale:i,state:o}=n,s=a.axis_rotated,l=/(x|y|y2)/.test(t),c=l?t==="x":t==="width",f=!l&&n[c?"regionX":"regionY"](e);let g=l?"start":"end",v=l?0:o[t],m;if(e.axis==="y"||e.axis==="y2"?(!l&&!c?g="start":l&&!c&&(g="end"),(c?s:!s)&&g in e&&(m=i[e.axis])):(c?!s:s)&&g in e&&(m=i.zoom||i.x),m){let S=0;v=e[g],n.axis.isTimeSeries(e.axis)?v=Yn.call(n,v):/(x|width)/.test(t)&&n.axis.isCategorized()&&isNaN(v)&&(v=a.axis_x_categories.indexOf(v),S=n.axis.x.tickOffset()*(g==="start"?-1:1)),v=m(v)+S}return l?v:v0&&(!i.axis_x_tick_autorotate||a.needToRotateXAxisTickTexts());return(i.axis_x_tick_multiline||L)&&N.height>S&&(P+=N.height-S),P+(a.axis.getLabelPositionById(t).isInner?0:10)+(t==="y2"&&!f?-10:0)},getEventRectWidth(){const t=this,{config:e,axis:n}=t,a=e.axis_x_inverted,i=n.x.tickInterval();return Math.max(0,a?Math.abs(i):i)},getAxisTickRotate(t){const e=this,{axis:n,config:a,state:i,$el:o}=e;let s=a[`axis_${t}_tick_rotate`];if(t==="x"){const l=n.isCategorized()||n.isTimeSeries();if(a.axis_x_tick_fit&&l){const c=a.axis_x_tick_count,f=i.current.maxTickSize.x.ticks.length;let g=0;if(c?g=c>f?f:c:f&&(g=f),g!==i.axis.x.tickCount){const{targets:v}=e.data;i.axis.x.padding=e.getXDomainPadding([e.getXDomainMinMax(v,"min"),e.getXDomainMinMax(v,"max")],g)}i.axis.x.tickCount=g}o.svg&&a.axis_x_tick_autorotate&&a.axis_x_tick_fit&&!a.axis_x_tick_multiline&&!a.axis_x_tick_culling&&l&&(s=e.needToRotateXAxisTickTexts()?a.axis_x_tick_rotate:0)}return s},needToRotateXAxisTickTexts(){const t=this,{state:{axis:e,current:n,isLegendRight:a,legendItemWidth:i}}=t,o=a&&i,s=n.width-o-t.getCurrentPaddingByDirection("left")-t.getCurrentPaddingByDirection("right"),l=e.x.tickCount+e.x.padding.left+e.x.padding.right,{width:c}=t.axis.getMaxTickSize("x"),f=l?s/l:0;return c>f}},jy={axis_x_clipPath:!0,axis_x_show:!0,axis_x_forceAsSingle:!1,axis_x_type:"indexed",axis_x_localtime:!0,axis_x_categories:[],axis_x_tick_centered:!1,axis_x_tick_format:void 0,axis_x_tick_culling:{},axis_x_tick_culling_max:10,axis_x_tick_culling_lines:!0,axis_x_tick_count:void 0,axis_x_tick_show:!0,axis_x_tick_text_show:!0,axis_x_tick_text_inner:!1,axis_x_tick_text_position:{x:0,y:0},axis_x_tick_fit:!0,axis_x_tick_values:null,axis_x_tick_autorotate:!1,axis_x_tick_rotate:0,axis_x_tick_outer:!0,axis_x_tick_multiline:!0,axis_x_tick_width:null,axis_x_tick_tooltip:!1,axis_x_max:void 0,axis_x_min:void 0,axis_x_inverted:!1,axis_x_padding:{},axis_x_height:void 0,axis_x_extent:void 0,axis_x_label:{},axis_x_axes:[]},Vy={axis_y_clipPath:!0,axis_y_show:!0,axis_y_type:"indexed",axis_y_max:void 0,axis_y_min:void 0,axis_y_inverted:!1,axis_y_center:void 0,axis_y_inner:!1,axis_y_label:{},axis_y_tick_format:void 0,axis_y_tick_culling:!1,axis_y_tick_culling_max:5,axis_y_tick_culling_lines:!0,axis_y_tick_outer:!0,axis_y_tick_values:null,axis_y_tick_rotate:0,axis_y_tick_count:void 0,axis_y_tick_show:!0,axis_y_tick_stepSize:null,axis_y_tick_text_show:!0,axis_y_tick_text_position:{x:0,y:0},axis_y_tick_time_value:void 0,axis_y_padding:{},axis_y_default:void 0,axis_y_axes:[]},Gy={axis_y2_show:!1,axis_y2_type:"indexed",axis_y2_max:void 0,axis_y2_min:void 0,axis_y2_inverted:!1,axis_y2_center:void 0,axis_y2_inner:!1,axis_y2_label:{},axis_y2_tick_format:void 0,axis_y2_tick_culling:!1,axis_y2_tick_culling_max:5,axis_y2_tick_culling_lines:!0,axis_y2_tick_outer:!0,axis_y2_tick_values:null,axis_y2_tick_rotate:0,axis_y2_tick_count:void 0,axis_y2_tick_show:!0,axis_y2_tick_stepSize:null,axis_y2_tick_text_show:!0,axis_y2_tick_text_position:{x:0,y:0},axis_y2_padding:{},axis_y2_default:void 0,axis_y2_axes:[]},Xy=Object.defineProperty,wu=Object.getOwnPropertySymbols,Hy=Object.prototype.hasOwnProperty,Yy=Object.prototype.propertyIsEnumerable,Mu=(t,e,n)=>e in t?Xy(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,Ts=(t,e)=>{for(var n in e||(e={}))Hy.call(e,n)&&Mu(t,n,e[n]);if(wu)for(var n of wu(e))Yy.call(e,n)&&Mu(t,n,e[n]);return t},Wy=Ts(Ts(Ts({axis_evalTextSize:!0,axis_rotated:!1,axis_tooltip:!1},jy),Vy),Gy),Ky={grid_x_show:!1,grid_x_type:"tick",grid_x_lines:[],grid_y_show:!1,grid_y_lines:[],grid_y_ticks:void 0,grid_focus_edge:!1,grid_focus_show:!0,grid_focus_y:!1,grid_front:!1,grid_lines_front:!0},Zy={data_xs:{},data_xFormat:"%Y-%m-%d",data_xLocaltime:!0,data_xSort:!0,data_axes:{},data_regions:{},data_stack_normalize:!1};const Jy=[sy,ly,cy,uy,fy,dy,hy],Du={axis:Cy,clip:Ly,eventrect:wy,flow:Dy,grid:By,region:Uy,sizeAxis:zy},Lu={optDataAxis:Zy,optAxis:Wy,optGrid:Ky};var I1=Array.prototype.slice;function $s(t){return typeof t=="object"&&"length"in t?t:Array.from(t)}function Le(t){return function(){return t}}function Qy(t,e){return et?1:e>=t?0:NaN}function ky(t){return t}function qy(){var t=ky,e=Qy,n=null,a=Le(0),i=Le(zi),o=Le(0);function s(l){var c,f=(l=$s(l)).length,g,v,m=0,S=new Array(f),P=new Array(f),N=+a.apply(this,arguments),L=Math.min(zi,Math.max(-zi,i.apply(this,arguments)-N)),w,X=Math.min(Math.abs(L)/f,o.apply(this,arguments)),W=X*(L<0?-1:1),H;for(c=0;c0&&(m+=H);for(e!=null?S.sort(function(k,K){return e(P[k],P[K])}):n!=null&&S.sort(function(k,K){return n(l[k],l[K])}),c=0,v=m?(L-f*W)/m:0;c0?H*v:0)+W,P[g]={data:l[g],index:c,value:H,startAngle:N,endAngle:w,padAngle:X};return P}return s.value=function(l){return arguments.length?(t=typeof l=="function"?l:Le(+l),s):t},s.sortValues=function(l){return arguments.length?(e=l,n=null,s):e},s.sort=function(l){return arguments.length?(n=l,e=null,s):n},s.startAngle=function(l){return arguments.length?(a=typeof l=="function"?l:Le(+l),s):a},s.endAngle=function(l){return arguments.length?(i=typeof l=="function"?l:Le(+l),s):i},s.padAngle=function(l){return arguments.length?(o=typeof l=="function"?l:Le(+l),s):o},s}var _y=Math.pow;const Ss=Math.PI,As=2*Ss,Gr=1e-6,tx=As-Gr;function Nu(t){this._+=t[0];for(let e=1,n=t.length;e=0))throw new Error(`invalid digits: ${t}`);if(e>15)return Nu;const n=_y(10,e);return function(a){this._+=a[0];for(let i=1,o=a.length;iGr)if(!(Math.abs(v*c-f*g)>Gr)||!o)this._append`L${this._x1=e},${this._y1=n}`;else{let S=a-s,P=i-l,N=c*c+f*f,L=S*S+P*P,w=Math.sqrt(N),X=Math.sqrt(m),W=o*Math.tan((Ss-Math.acos((N+m-L)/(2*w*X)))/2),H=W/X,k=W/w;Math.abs(H-1)>Gr&&this._append`L${e+H*g},${n+H*v}`,this._append`A${o},${o},0,0,${+(v*S>g*P)},${this._x1=e+k*c},${this._y1=n+k*f}`}}arc(e,n,a,i,o,s){if(e=+e,n=+n,a=+a,s=!!s,a<0)throw new Error(`negative radius: ${a}`);let l=a*Math.cos(i),c=a*Math.sin(i),f=e+l,g=n+c,v=1^s,m=s?i-o:o-i;this._x1===null?this._append`M${f},${g}`:(Math.abs(this._x1-f)>Gr||Math.abs(this._y1-g)>Gr)&&this._append`L${f},${g}`,a&&(m<0&&(m=m%As+As),m>tx?this._append`A${a},${a},0,1,${v},${e-l},${n-c}A${a},${a},0,1,${v},${this._x1=f},${this._y1=g}`:m>Gr&&this._append`A${a},${a},0,${+(m>=Ss)},${v},${this._x1=e+a*Math.cos(o)},${this._y1=n+a*Math.sin(o)}`)}rect(e,n,a,i){this._append`M${this._x0=this._x1=+e},${this._y0=this._y1=+n}h${a=+a}v${+i}h${-a}Z`}toString(){return this._}}function nx(){return new Wi}nx.prototype=Wi.prototype;function O1(t=3){return new Wi(+t)}function Es(t){let e=3;return t.digits=function(n){if(!arguments.length)return e;if(n==null)e=null;else{const a=Math.floor(n);if(!(a>=0))throw new RangeError(`invalid digits: ${n}`);e=a}return t},()=>new Wi(e)}function rx(t){return t.innerRadius}function ax(t){return t.outerRadius}function ix(t){return t.startAngle}function ox(t){return t.endAngle}function sx(t){return t&&t.padAngle}function lx(t,e,n,a,i,o,s,l){var c=n-t,f=a-e,g=s-i,v=l-o,m=v*c-g*f;if(!(m*mQ*Q+St*St&&(ht=dt,$t=st),{cx:ht,cy:$t,x01:-g,y01:-v,x11:ht*(i/k-1),y11:$t*(i/k-1)}}function Fu(){var t=rx,e=ax,n=Le(0),a=null,i=ix,o=ox,s=sx,l=null,c=Es(f);function f(){var g,v,m=+t.apply(this,arguments),S=+e.apply(this,arguments),P=i.apply(this,arguments)-Ui,N=o.apply(this,arguments)-Ui,L=Hc(N-P),w=N>P;if(l||(l=g=c()),Sbn))l.moveTo(0,0);else if(L>zi-bn)l.moveTo(S*jr(P),S*rr(P)),l.arc(0,0,S,P,N,!w),m>bn&&(l.moveTo(m*jr(N),m*rr(N)),l.arc(0,0,m,N,P,w));else{var X=P,W=N,H=P,k=N,K=L,at=L,ht=s.apply(this,arguments)/2,$t=ht>bn&&(a?+a.apply(this,arguments):oa(m*m+S*S)),dt=fs(Hc(S-m)/2,+n.apply(this,arguments)),st=dt,Vt=dt,vt,Q;if($t>bn){var St=Yc($t/m*rr(ht)),ct=Yc($t/S*rr(ht));(K-=St*2)>bn?(St*=w?1:-1,H+=St,k-=St):(K=0,H=k=(P+N)/2),(at-=ct*2)>bn?(ct*=w?1:-1,X+=ct,W-=ct):(at=0,X=W=(P+N)/2)}var At=S*jr(X),Gt=S*rr(X),Bt=m*jr(k),Kt=m*rr(k);if(dt>bn){var ne=S*jr(W),le=S*rr(W),be=m*jr(H),Oe=m*rr(H),Ce;if(Lbn?Vt>bn?(vt=Ki(be,Oe,At,Gt,S,Vt,w),Q=Ki(ne,le,Bt,Kt,S,Vt,w),l.moveTo(vt.cx+vt.x01,vt.cy+vt.y01),Vtbn)||!(K>bn)?l.lineTo(Bt,Kt):st>bn?(vt=Ki(Bt,Kt,ne,le,m,-st,w),Q=Ki(At,Gt,be,Oe,m,-st,w),l.lineTo(vt.cx+vt.x01,vt.cy+vt.y01),ste in t?cx(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,gx=(t,e)=>{for(var n in e||(e={}))dx.call(e,n)&&Uu(t,n,e[n]);if(Bu)for(var n of Bu(e))hx.call(e,n)&&Uu(t,n,e[n]);return t},vx=(t,e)=>ux(t,fx(e));function zu(t=0){const e=this,{config:n,state:a}=e,i=e.hasMultiArcGauge(),o=a.gaugeArcWidth/e.filterTargetsToShow(e.data.targets).length,s=t?Math.min(a.radiusExpanded*t-a.radius,o*.8-(1-t)*100):0;return{inner(l){const{innerRadius:c}=e.getRadius(l);return i?a.radius-o*(l.index+1):he(c)?c:0},outer(l){const{outerRadius:c}=e.getRadius(l);let f;if(i)f=a.radius-o*l.index+s;else if(e.hasType("polar")&&!t)f=e.getPolarOuterRadius(l,c);else if(f=c,t){let{radiusExpanded:g}=a;a.radius!==c&&(g-=Math.abs(a.radius-c)),f=g*t}return f},corner(l,c){const{arc_cornerRadius_ratio:f=0,arc_cornerRadius:g=0}=n,{data:{id:v},value:m}=l;let S=0;return f?S=f*c:S=he(g)?g:g.call(e.api,v,m,c),S}}}function bs(t){return function(e){const n=({startAngle:i=0,endAngle:o=0,padAngle:s=0})=>({startAngle:i,endAngle:o,padAngle:s}),a=Qr(n(this._current),n(e));return this._current=e,function(i){const o=a(i),{data:s,index:l,value:c}=e;return t(vx(gx({},o),{data:s,index:l,value:c}))}}}var px={initPie(){const t=this,{config:e}=t,n=e.data_type,a=e[`${n}_padding`],i=e[`${n}_startingAngle`]||0,o=(a?a*.01:e[`${n}_padAngle`])||0;t.pie=qy().startAngle(i).endAngle(i+2*Math.PI).padAngle(o).value(s=>{var l,c;return(c=(l=s.values)==null?void 0:l.reduce((f,g)=>f+g.value,0))!=null?c:s}).sort(t.getSortCompareFn.bind(t)(!0))},updateRadius(){const t=this,{config:e,state:n}=t,a=e.data_type,i=e[`${a}_padding`],o=e.gauge_width||e.donut_width,s=t.filterTargetsToShow(t.data.targets).length*e.gauge_arcs_minWidth;n.radiusExpanded=Math.min(n.arcWidth,n.arcHeight)/2*(t.hasMultiArcGauge()&&e.gauge_label_show?.85:1),n.radius=n.radiusExpanded*.95,n.innerRadiusRatio=o?(n.radius-o)/n.radius:.6,n.gaugeArcWidth=o||(s<=n.radius-n.innerRadius?n.radius-n.innerRadius:s<=n.radius?s:n.radius);const l=e.pie_innerRadius||(i?i*(n.innerRadiusRatio+.1):0);n.outerRadius=e.pie_outerRadius,n.innerRadius=t.hasType("donut")||t.hasType("gauge")?n.radius*n.innerRadiusRatio:l},getRadius(t){const e=this,n=t==null?void 0:t.data;let{innerRadius:a,outerRadius:i}=e.state;return!he(a)&&n&&(a=a[n.id]||0),Be(i)&&n&&n.id in i?i=i[n.id]:he(i)||(i=e.state.radius),{innerRadius:a,outerRadius:i}},updateArc(){const t=this;t.updateRadius(),t.svgArc=t.getSvgArc(),t.svgArcExpanded=t.getSvgArcExpanded()},getArcLength(){const t=this,{config:e}=t,n=e.gauge_arcLength*3.6;let a=2*(n/360);return n<-360?a=-2:n>360&&(a=2),a*Math.PI},getStartingAngle(){const t=this,{config:e}=t,n=e.data_type,a=t.hasType("gauge")?e.gauge_fullCircle:!1,i=-1*Math.PI/2,o=Math.PI/2;let s=e[`${n}_startingAngle`]||0;return!a&&s<=i?s=i:!a&&s>=o?s=o:(s>Math.PI||s<-1*Math.PI)&&(s=Math.PI),s},updateAngle(t,e=!1){var n;const a=this,{config:i,state:o}=a,s=e&&a.hasType("gauge");let{pie:l}=a,c=t,f=!1;if(!i)return null;const g=a.getStartingAngle(),v=i.gauge_fullCircle||e&&!s?a.getArcLength():g*-2;if(c.data&&a.isGaugeType(c.data)&&!a.hasMultiArcGauge()){const{gauge_min:m,gauge_max:S}=i,P=a.getTotalDataSum(o.rendered),N=v*((P-m)/(S-m));l=l.startAngle(g).endAngle(N+g)}if(e===!1&&l(a.filterTargetsToShow()).forEach((m,S)=>{var P;!f&&m.data.id===((P=c.data)==null?void 0:P.id)&&(f=!0,c=m,c.index=S)}),isNaN(c.startAngle)&&(c.startAngle=0),isNaN(c.endAngle)&&(c.endAngle=c.startAngle),e||c.data&&(i.gauge_enforceMinMax||a.hasMultiArcGauge())){const{gauge_min:m,gauge_max:S}=i,P=e&&!s?a.getTotalDataSum(o.rendered):S,N=v/(P-m),L=(n=c.value)!=null?n:0,w=L{const l=e.updateAngle(s),c=a(l);let f=0;return l&&(f=i(l,c)),l?o.cornerRadius(f)(l):"M 0 0"}},getArc(t,e,n){return n||this.isArcType(t.data)?this.svgArc(t,e):"M 0 0"},redrawArcRangeText(){const t=this,{config:e,$el:{arcs:n},state:a,$T:i}=t,o=e.arc_rangeText_format,s=t.hasType("gauge")&&e.arc_rangeText_fixed;let l=e.arc_rangeText_values;if(l!=null&&l.length){const c=e.arc_rangeText_unit==="%",f=t.getTotalDataSum(a.rendered);c&&(l=l.map(m=>f/100*m));const g=t.pie(l).map((m,S)=>(m.index=S,m));let v=n.selectAll(`.${Ve.arcRange}`).data(l);v.exit(),v=i(v.enter().append("text").attr("class",Ve.arcRange).style("text-anchor","middle").style("pointer-events","none").style("opacity","0").text(m=>{const S=c?m/f*100:m;return ve(o)?o(S):`${S}${c?"%":""}`}).merge(v)),(!a.rendered||a.rendered&&!s)&&f>0&&v.attr("transform",(m,S)=>t.transformForArcLabel(g[S],!0)),v.style("opacity",m=>!s&&(m>f||f===0)?"0":null)}},transformForArcLabel(t,e=!1){var n,a,i;const o=this,{config:s,state:{radiusExpanded:l}}=o,c=o.updateAngle(t,e);let f="";if(c){if(e||o.hasMultiArcGauge()){const g=Math.sin(c.endAngle-Math.PI/2),v=s.arc_rangeText_position;let m=Math.cos(c.endAngle-Math.PI/2)*(l+(e?5:25)),S=g*(l+15-Math.abs(g*10))+3;if(e&&v){const P=s.arc_rangeText_values,N=ve(v)?v(P[t.index]):v;m+=(n=N==null?void 0:N.x)!=null?n:0,S+=(a=N==null?void 0:N.y)!=null?a:0}f=`translate(${m},${S})`}else if(!o.hasType("gauge")||o.data.targets.length>1){let{outerRadius:g}=o.getRadius(t);o.hasType("polar")&&(g=o.getPolarOuterRadius(t,g));const v=this.svgArc.centroid(c),[m,S]=v.map(L=>isNaN(L)?0:L),P=Math.sqrt(m*m+S*S);let N=(i=["donut","gauge","pie","polar"].filter(o.hasType.bind(o)).map(L=>s[`${L}_label_ratio`]))==null?void 0:i[0];N?N=ve(N)?N.bind(o.api)(t,g,P):N:N=g&&(P?(36/g>.375?1.175-36/g:.8)*g/P:0),f=`translate(${m*N},${S*N})`}}return f},convertToArcData(t){return this.addName({id:"data"in t?t.data.id:t.id,value:t.value,ratio:this.getRatio("arc",t),index:t.index})},textForArcLabel(t){const e=this,n=e.hasType("gauge");e.shouldShowArcLabel()&&t.style("fill",e.updateTextColor.bind(e)).attr("filter",a=>e.updateTextBGColor.bind(e)(a,e.config.data_labels_backgroundColors)).each(function(a){var i;const o=ot(this),s=e.updateAngle(a),l=e.getRatio("arc",s);if(e.meetsLabelThreshold(l,(i=["donut","gauge","pie","polar"].filter(e.hasType.bind(e)))==null?void 0:i[0])){const{value:f}=s||a,g=(e.getArcLabelFormat()||e.defaultArcValueFormat)(f,l,a.data.id).toString();wa(o,g,[-1,1],n)}else o.text("")})},expandArc(t){const e=this,{state:{transiting:n},$el:a}=e;if(n){const o=setInterval(()=>{n||(clearInterval(o),a.legend.selectAll(`.${qe.legendItemFocused}`).size()>0&&e.expandArc(t))},10);return}const i=e.mapToTargetIds(t);a.svg.selectAll(e.selectorTargets(i,`.${Ve.chartArc}`)).each(function(o){if(!e.shouldExpand(o.data.id))return;const s=e.getExpandConfig(o.data.id,"duration"),l=e.getSvgArcExpanded(e.getExpandConfig(o.data.id,"rate"));ot(this).selectAll("path").transition().duration(s).attrTween("d",bs(e.svgArcExpanded.bind(e))).transition().duration(s*2).attrTween("d",bs(l.bind(e)))})},unexpandArc(t){const e=this,{state:{transiting:n},$el:{svg:a}}=e;if(n)return;const i=e.mapToTargetIds(t);a.selectAll(e.selectorTargets(i,`.${Ve.chartArc}`)).selectAll("path").transition().duration(o=>e.getExpandConfig(o.data.id,"duration")).attrTween("d",bs(e.svgArc.bind(e))),a.selectAll(`${Ve.arc}`).style("opacity",null)},getExpandConfig(t,e){const n=this,{config:a}=n,i={duration:50,rate:.98};let o;return n.isDonutType(t)?o="donut":n.isGaugeType(t)?o="gauge":n.isPieType(t)&&(o="pie"),o?a[`${o}_expand_${e}`]:i[e]},shouldExpand(t){const e=this,{config:n}=e;return e.isDonutType(t)&&n.donut_expand||e.isGaugeType(t)&&n.gauge_expand||e.isPieType(t)&&n.pie_expand},shouldShowArcLabel(){const t=this,{config:e}=t;return["donut","gauge","pie","polar"].some(n=>t.hasType(n)&&e[`${n}_label_show`])},getArcLabelFormat(){const t=this,{config:e}=t;let n=a=>a;return["donut","gauge","pie","polar"].filter(t.hasType.bind(t)).forEach(a=>{n=e[`${a}_label_format`]}),ve(n)?n.bind(t.api):n},updateTargetsForArc(t){const e=this,{$el:n}=e,a=e.hasType("gauge"),i=e.getChartClass("Arc"),o=e.getClass("arcs",!0),s=e.classFocus.bind(e),l=n.main.select(`.${Ve.chartArcs}`),c=l.selectAll(`.${Ve.chartArc}`).data(e.pie(t)).attr("class",g=>i(g)+s(g.data)),f=c.enter().append("g").attr("class",i).call(this.setCssRule(!1,`.${Ve.chartArcs} text`,["pointer-events:none","text-anchor:middle"]));f.append("g").attr("class",o).merge(c),f.append("text").attr("dy",a&&!e.hasMultiTargets()?"-.1em":".35em").style("opacity","0").style("text-anchor",e.getStylePropValue("middle")).style("pointer-events",e.getStylePropValue("none")),n.text=l.selectAll(`.${Se.target} text`)},initArc(){const t=this,{$el:e}=t;e.arcs=e.main.select(`.${Se.chart}`).append("g").attr("class",Ve.chartArcs).attr("transform",t.getTranslate("arc")),t.setArcTitle()},setArcTitle(t){const e=this,n=t||e.getArcTitle(),a=e.hasType("gauge");if(n){const i=a?Un.chartArcsGaugeTitle:Ve.chartArcsTitle;let o=e.$el.arcs.select(`.${i}`);o.empty()&&(o=e.$el.arcs.append("text").attr("class",i).style("text-anchor","middle")),a&&o.attr("dy","-0.3em"),wa(o,n,a?void 0:[-.6,1.35],!0)}},getArcTitle(){const t=this,e=t.hasType("donut")&&"donut"||t.hasType("gauge")&&"gauge";return e?t.config[`${e}_title`]:""},getArcTitleWithNeedleValue(){const t=this,{config:e,state:n}=t,a=t.getArcTitle();if(a&&t.config.arc_needle_show&&/{=[A-Z_]+}/.test(a)){let i=n.current.needle;return he(i)||(i=e.arc_needle_value),bi(a,{NEEDLE_VALUE:he(i)?i:0})}return!1},redrawArc(t,e,n){const a=this,{config:i,state:o,$el:{main:s}}=a,l=i.interaction_enabled,c=l&&i.data_selection_isselectable;let f=s.selectAll(`.${Ve.arcs}`).selectAll(`.${Ve.arc}`).data(a.arcData.bind(a));f.exit().transition().duration(e).style("opacity","0").remove(),f=f.enter().append("path").attr("class",a.getClass("arc",!0)).style("fill",g=>a.color(g.data)).style("cursor",g=>{var v;return(v=c==null?void 0:c.bind)!=null&&v.call(c,a.api)(g)?"pointer":null}).style("opacity","0").each(function(g){a.isGaugeType(g.data)&&(g.startAngle=i.gauge_startingAngle,g.endAngle=i.gauge_startingAngle),this._current=g}).merge(f),a.hasType("gauge")&&(a.updateGaugeMax(),a.hasMultiArcGauge()&&a.redrawArcGaugeLine()),f.attr("transform",g=>!a.isGaugeType(g.data)&&n?"scale(0)":"").style("opacity",function(g){return g===this._current?"0":null}).each(()=>{o.transiting=!0}).transition().duration(t).attrTween("d",function(g){const v=a.updateAngle(g);if(!v)return()=>"M 0 0";isNaN(this._current.startAngle)&&(this._current.startAngle=0),isNaN(this._current.endAngle)&&(this._current.endAngle=this._current.startAngle);const m=Qr(this._current,v);return this._current=m(0),function(S){const P=m(S);return P.data=g.data,a.getArc(P,!0)}}).attr("transform",n?"scale(1)":"").style("fill",g=>{let v;return a.levelColor?(v=a.levelColor(g.data.values[0].value),i.data_colors[g.data.id]=v):v=a.color(g.data),v}).style("opacity",null).call(Si,function(){if(a.levelColor){const g=ot(this),v=g.datum(this._current);a.updateLegendItemColor(v.data.id,g.style("fill"))}o.transiting=!1,_e(i.onrendered,a.api)}),l&&a.bindArcEvent(f),a.hasType("polar")&&a.redrawPolar(),a.hasType("gauge")&&a.redrawBackgroundArcs(),i.arc_needle_show&&a.redrawNeedle(),a.redrawArcText(t),a.redrawArcRangeText()},redrawNeedle(){const t=this,{$el:e,config:n,state:{hiddenTargetIds:a,radius:i}}=t,o=(i-1)/100*n.arc_needle_length,s=a.length!==t.data.targets.length;let l=t.$el.arcs.select(`.${Ve.needle}`);const c=n.arc_needle_path,f=n.arc_needle_bottom_width/2,g=n.arc_needle_top_width/2,v=n.arc_needle_top_rx,m=n.arc_needle_top_ry,S=n.arc_needle_bottom_len,P=n.arc_needle_bottom_rx,N=n.arc_needle_bottom_ry,L=t.getNeedleAngle(),w=()=>{const X=t.getArcTitleWithNeedleValue();X&&t.setArcTitle(X)};if(w(),l.empty()&&(l=e.arcs.append("path").classed(Ve.needle,!0),e.needle=l,e.needle.updateHelper=(X,W=!1)=>{e.needle.style("display")!=="none"&&t.$T(e.needle).style("transform",`rotate(${t.getNeedleAngle(X)}deg)`).call(Si,()=>{W&&(n.arc_needle_value=X),w()})}),s){const X=ve(c)?c.call(t,o):`M-${f} ${S} A${P} ${N} 0 0 0 ${f} ${S} L${g} -${o} A${v} ${m} 0 0 0 -${g} -${o} L-${f} ${S} Z`;t.$T(l).attr("d",X).style("fill",n.arc_needle_color).style("display",null).style("transform",`rotate(${L}deg)`)}else l.style("display","none")},getNeedleAngle(t){const e=this,{config:n,state:a}=e,i=e.getArcLength(),o=e.hasType("gauge"),s=e.getTotalDataSum(!0);let l=Qe(t)?t:n.arc_needle_value,c=n[`${n.data_type}_startingAngle`]||0,f=0;if(he(l)||(l=o&&e.data.targets.length===1?s:0),a.current.needle=l,o){c=e.getStartingAngle();const g=n.gauge_fullCircle?i:c*-2,{gauge_min:v,gauge_max:m}=n;f=g*((l-v)/(m-v))}else f=i*(l/s);return(c+f)*(180/Math.PI)},redrawBackgroundArcs(){const t=this,{config:e,state:n}=t,a=t.hasMultiArcGauge(),i=e.gauge_fullCircle,o=t.filterTargetsToShow(t.data.targets).length===0&&!!e.data_empty_label_text,s=t.getStartingAngle(),l=i?s+t.getArcLength():s*-1;let c=t.$el.arcs.select(`${a?"g":""}.${Ve.chartArcsBackground}`);if(a){let f=0;c=c.selectAll(`path.${Ve.chartArcsBackground}`).data(t.data.targets),c.enter().append("path").attr("class",(g,v)=>`${Ve.chartArcsBackground} ${Ve.chartArcsBackground}-${v}`).merge(c).style("fill",e.gauge_background||null).attr("d",({id:g})=>{if(o||n.hiddenTargetIds.indexOf(g)>=0)return"M 0 0";const v={data:[{value:e.gauge_max}],startAngle:s,endAngle:l,index:f++};return t.getArc(v,!0,!0)}),c.exit().remove()}else c.attr("d",o?"M 0 0":()=>{const f={data:[{value:e.gauge_max}],startAngle:s,endAngle:l};return t.getArc(f,!0,!0)})},bindArcEvent(t){const e=this,{config:n,state:a}=e,i=a.inputType==="touch",o=a.inputType==="mouse";function s(c,f,g){e.expandArc(g),e.api.focus(g),e.toggleFocusLegend(g,!0),e.showTooltip([f],c)}function l(c){const f=(c==null?void 0:c.id)||void 0;e.unexpandArc(f),e.api.revert(),e.revertLegend(),e.hideTooltip()}if(t.on("click",function(c,f,g){var v;const m=e.updateAngle(f);let S;m&&(S=e.convertToArcData(m),(v=e.toggleShape)==null||v.call(e,this,S,g),n.data_onclick.bind(e.api)(S,this))}),o&&t.on("mouseover",function(c,f){if(a.transiting)return;a.event=c;const g=e.updateAngle(f),v=g?e.convertToArcData(g):null,m=(v==null?void 0:v.id)||void 0;s(this,v,m),e.setOverOut(!0,v)}).on("mouseout",(c,f)=>{if(a.transiting||!n.interaction_onout)return;a.event=c;const g=e.updateAngle(f),v=g?e.convertToArcData(g):null;l(),e.setOverOut(!1,v)}).on("mousemove",function(c,f){const g=e.updateAngle(f),v=g?e.convertToArcData(g):null;a.event=c,e.showTooltip([v],this)}),i&&e.hasArcType()&&!e.radars){const c=f=>{var g,v;const{clientX:m,clientY:S}=(v=(g=f.changedTouches)==null?void 0:g[0])!=null?v:{clientX:0,clientY:0};return ot(gn.elementFromPoint(m,S))};e.$el.svg.on("touchstart touchmove",function(f){if(a.transiting)return;a.event=f;const v=c(f).datum(),m=v!=null&&v.data&&v.data.id?e.updateAngle(v):null,S=m?e.convertToArcData(m):null,P=(S==null?void 0:S.id)||void 0;e.callOverOutForTouch(S),ln(P)?l():s(this,S,P)})}},redrawArcText(t){const e=this,{config:n,state:a,$el:{main:i,arcs:o}}=e,s=e.hasType("gauge"),l=e.hasMultiArcGauge();let c;if(s&&e.data.targets.length===1&&n.gauge_title||(c=i.selectAll(`.${Ve.chartArc}`).select("text").style("opacity","0").attr("class",f=>e.isGaugeType(f.data)?Un.gaugeValue:null).call(e.textForArcLabel.bind(e)).attr("transform",f=>e.transformForArcLabel.bind(e)(f)).style("font-size",f=>e.isGaugeType(f.data)&&e.data.targets.length===1&&!l?`${Math.round(a.radius/5)}px`:null).transition().duration(t).style("opacity",f=>e.isTargetToShow(f.data.id)&&e.isArcType(f.data)?null:"0"),l&&c.attr("dy","-.1em")),i.select(`.${Ve.chartArcsTitle}`).style("opacity",e.hasType("donut")||s?null:"0"),s){const f=n.gauge_fullCircle;f&&(c==null||c.attr("dy",`${l?0:Math.round(a.radius/14)}`)),n.gauge_label_show&&(o.select(`.${Un.chartArcsGaugeUnit}`).attr("dy",`${f?1.5:.75}em`).text(n.gauge_units),o.select(`.${Un.chartArcsGaugeMin}`).attr("dx",`${-1*(a.innerRadius+(a.radius-a.innerRadius)/(f?1:2))}px`).attr("dy","1.2em").text(e.textForGaugeMinMax(n.gauge_min,!1)),!f&&o.select(`.${Un.chartArcsGaugeMax}`).attr("dx",`${a.innerRadius+(a.radius-a.innerRadius)/2}px`).attr("dy","1.2em").text(e.textForGaugeMinMax(n.gauge_max,!0)))}},getArcElementByIdOrIndex(t){const e=this,{$el:{arcs:n}}=e,a=he(t)?i=>i.index===t:i=>i.data.id===t;return n==null?void 0:n.selectAll(`.${Se.target} path`).filter(a)}};function ju(t){return t[0]}function Vu(t){return t[1]}function Gu(t,e){var n=Le(!0),a=null,i=gs,o=null,s=Es(l);t=typeof t=="function"?t:t===void 0?ju:Le(t),e=typeof e=="function"?e:e===void 0?Vu:Le(e);function l(c){var f,g=(c=$s(c)).length,v,m=!1,S;for(a==null&&(o=i(S=s())),f=0;f<=g;++f)!(f=S;--P)l.point(W[P],H[P]);l.lineEnd(),l.areaEnd()}w&&(W[m]=+t(L,m,v),H[m]=+e(L,m,v),l.point(a?+a(L,m,v):W[m],n?+n(L,m,v):H[m]))}if(X)return l=null,X+""||null}function g(){return Gu().defined(i).curve(s).context(o)}return f.x=function(v){return arguments.length?(t=typeof v=="function"?v:Le(+v),a=null,f):t},f.x0=function(v){return arguments.length?(t=typeof v=="function"?v:Le(+v),f):t},f.x1=function(v){return arguments.length?(a=v==null?null:typeof v=="function"?v:Le(+v),f):a},f.y=function(v){return arguments.length?(e=typeof v=="function"?v:Le(+v),n=null,f):e},f.y0=function(v){return arguments.length?(e=typeof v=="function"?v:Le(+v),f):e},f.y1=function(v){return arguments.length?(n=v==null?null:typeof v=="function"?v:Le(+v),f):n},f.lineX0=f.lineY0=function(){return g().x(t).y(e)},f.lineY1=function(){return g().x(t).y(n)},f.lineX1=function(){return g().x(a).y(e)},f.defined=function(v){return arguments.length?(i=typeof v=="function"?v:Le(!!v),f):i},f.curve=function(v){return arguments.length?(s=v,o!=null&&(l=s(o)),f):s},f.context=function(v){return arguments.length?(v==null?o=l=null:l=s(o=v),f):o},f}var sa={initArea(t){const e=this,{config:n}=e;t.insert("g",`.${n.area_front?$n.circles:ur.lines}`).attr("class",e.getClass("areas",!0))},updateAreaColor(t){const e=this;return e.config.area_linearGradient?e.getGradienColortUrl(t.id):e.color(t)},updateArea(t,e=!1){const n=this,{config:a,state:i,$el:o,$T:s}=n,l=e?o.subchart:o;a.area_linearGradient&&n.updateLinearGradient();const c=l.main.selectAll(`.${ti.areas}`).selectAll(`.${ti.area}`).data(n.lineData.bind(n));s(c.exit(),t).style("opacity","0").remove(),l.area=c.enter().append("path").attr("class",n.getClass("area",!0)).style("fill",n.updateAreaColor.bind(n)).style("opacity",function(){return i.orgAreaOpacity=ot(this).style("opacity"),"0"}).merge(c),c.style("opacity",i.orgAreaOpacity),n.setRatioForGroupedData(l.area.data())},redrawArea(t,e,n=!1){const a=this,{area:i}=n?this.$el.subchart:this.$el,{orgAreaOpacity:o}=a.state;return[a.$T(i,e,gr()).attr("d",t).style("fill",a.updateAreaColor.bind(a)).style("opacity",s=>String(a.isAreaRangeType(s)?o/1.75:o))]},generateDrawArea(t,e){const n=this,{config:a}=n,i=a.line_connectNull,o=a.axis_rotated,s=n.generateGetAreaPoints(t,e),l=n.getYScaleById.bind(n),c=v=>(e?n.subxx:n.xx).call(n,v),f=(v,m)=>n.isGrouped(v.id)?s(v,m)[0][1]:l(v.id,e)(n.isAreaRangeType(v)?n.getRangedData(v,"high"):n.getShapeYMin(v.id)),g=(v,m)=>n.isGrouped(v.id)?s(v,m)[1][1]:l(v.id,e)(n.isAreaRangeType(v)?n.getRangedData(v,"low"):v.value);return v=>{let m=i?n.filterRemoveNull(v.values):v.values,S=0,P=0,N;if(n.isAreaType(v)){let L=mx();L=o?L.y(c).x0(f).x1(g):L.x(c).y0(a.area_above?0:a.area_below?n.state.height:f).y1(g),i||(L=L.defined(w=>n.getBaseValue(w)!==null)),n.isStepType(v)&&(m=n.convertValuesToStep(m)),N=L.curve(n.getCurve(v))(m)}else m[0]&&(S=n.scale.x(m[0].x),P=n.getYScaleById(v.id)(m[0].value)),N=o?`M ${P} ${S}`:`M ${S} ${P}`;return N||"M 0 0"}},generateGetAreaPoints(t,e){const n=this,{config:a}=n,i=n.getShapeX(0,t,e),o=n.getShapeY(!!e),s=n.getShapeOffset(n.isAreaType,t,e),l=n.getYScaleById.bind(n);return function(c,f){const g=l.call(n,c.id,e)(n.getShapeYMin(c.id)),v=s(c,f)||g,m=i(c),S=c.value;let P=o(c);return a.axis_rotated&&(S>0&&Pg.values.some(v=>he(v.value)||e.isBarRangeType(v)))).attr("class",g=>i(g)+s(g)).enter().append("g").attr("class",i).style("opacity","0").style("pointer-events",e.getStylePropValue("none")).append("g").attr("class",o).style("cursor",g=>{var v;return(v=l==null?void 0:l.bind)!=null&&v.call(l,e.api)(g)?"pointer":null}).call(e.setCssRule(!0,` .${Kn.bar}`,["fill"],e.color))},updateBar(t,e=!1){const n=this,{config:a,$el:i,$T:o}=n,s=e?i.subchart:i,l=n.getClass("bar",!0),c=n.initialOpacity.bind(n);a.bar_linearGradient&&n.updateLinearGradient();const f=s.main.selectAll(`.${Kn.bars}`).selectAll(`.${Kn.bar}`).data(n.labelishData.bind(n));o(f.exit(),t).style("opacity","0").remove(),s.bar=f.enter().append("path").attr("class",l).style("fill",n.updateBarColor.bind(n)).merge(f).style("opacity",c),n.setRatioForGroupedData(s.bar.data())},updateBarColor(t){const e=this,n=e.getStylePropValue(e.color);return e.config.bar_linearGradient?e.getGradienColortUrl(t.id):n?n(t):null},redrawBar(t,e,n=!1){const a=this,{bar:i}=n?a.$el.subchart:a.$el;return[a.$T(i,e,gr()).attr("d",o=>(he(o.value)||a.isBarRangeType(o))&&t(o)).style("fill",a.updateBarColor.bind(a)).style("clip-path",o=>o.clipPath).style("opacity",null)]},generateDrawBar(t,e){const n=this,{config:a}=n,i=n.generateGetBarPoints(t,e),o=a.axis_rotated,s=a.bar_radius,l=a.bar_radius_ratio,c=he(s)&&s>0?()=>s:he(l)?f=>f*l:null;return(f,g)=>{const v=i(f,g),m=+o,S=+!m,P=f.value<0,N=a[`axis_${n.axis.getId(f.id)}_inverted`],L=!N&&P||N&&!P,w=["",""],X=n.isGrouped(f.id),W=c&&X?n.isStackingRadiusData(f):!1,H=[v[0][m],v[0][S]];let k=0;if(f.clipPath=null,c){const ht=o?S:m,$t=v[2][ht]-v[0][ht];k=!X||W?c($t):0;const dt=`a${k} ${k} ${L?"1 0 0":"0 0 1"} `;w[+!o]=`${dt}${k},${k}`,w[+o]=`${dt}${[-k,k][o?"sort":"reverse"]()}`,L&&w.reverse()}const K=o?v[1][m]+(L?k:-k):v[1][S]+(L?-k:k);if(k){let ht="";o?L&&H[0]K&&(ht=`0 0 0 ${H[0]-K}px`):L&&H[1]>K?ht=`${H[1]-K}px 0 0 0`:!L&&H[1]-1){const m=n.bar.filter(S=>S.id===s&&S.value===c);return!m.empty()&&/a\d+/i.test(m.attr("d"))}const f=a.data_groups.find(m=>m.indexOf(s)>-1),v=e.orderTargets(e.filterTargetsToShow(i.targets.filter(e.isBarType,e))).filter(m=>f.indexOf(m.id)>-1).map(m=>m.values.filter(S=>S.index===l&&(he(c)&&c>0?S.value>0:S.value<0))[0]).filter(Boolean).map(m=>m.id);return c!==0&&v.indexOf(s)===v.length-1},generateGetBarPoints(t,e){const n=this,{config:a}=n,i=e?n.axis.subX:n.axis.x,o=n.getIndicesMax(t)+1,s=n.getBarW("bar",i,o),l=n.getShapeX(s,t,!!e),c=n.getShapeY(!!e),f=n.getShapeOffset(n.isBarType,t,!!e),g=n.getYScaleById.bind(n);return(v,m)=>{const{id:S}=v,P=g.call(n,S,e)(n.getShapeYMin(S)),N=f(v,m)||P,L=he(s)?s:s[v.id]||s._$width,w=a[`axis_${n.axis.getId(S)}_inverted`],X=v.value,W=l(v);let H=c(v);a.axis_rotated&&!w&&(X>0&&He.isBubbleZType(s)?e.getBubbleZData(s.value,"y"):Be(s.value)?s.value.mid:s.value)),i=n*n*Math.PI,o=(e.isBubbleZType(t)?e.getBubbleZData(t.value,"z"):t.value)*(i/a);return Math.sqrt(o/Math.PI)},getBubbleZData(t,e){return Be(t)?t[e]:t[e==="y"?0:1]}},Tx=Object.defineProperty,Xu=Object.getOwnPropertySymbols,$x=Object.prototype.hasOwnProperty,Sx=Object.prototype.propertyIsEnumerable,Hu=(t,e,n)=>e in t?Tx(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,Ax=(t,e)=>{for(var n in e||(e={}))$x.call(e,n)&&Hu(t,n,e[n]);if(Xu)for(var n of Xu(e))Sx.call(e,n)&&Hu(t,n,e[n]);return t},Ex={initCandlestick(){const{$el:t}=this;t.candlestick=t.main.select(`.${Se.chart}`).append("g").attr("class",cr.chartCandlesticks)},updateTargetsForCandlestick(t){const e=this,{$el:n}=e,a=e.getChartClass("Candlestick");n.candlestick||e.initCandlestick(),e.$el.main.select(`.${cr.chartCandlesticks}`).selectAll(`.${cr.chartCandlestick}`).data(t).enter().append("g").attr("class",a).style("pointer-events","none")},updateCandlestick(t,e=!1){const n=this,{$el:a,$T:i}=n,o=e?a.subchart:a,s=n.getClass("candlestick",!0),l=n.initialOpacity.bind(n),c=o.main.selectAll(`.${cr.chartCandlestick}`).selectAll(`.${cr.candlestick}`).data(n.labelishData.bind(n));i(c.exit(),t).style("opacity","0").remove();const f=c.enter().filter(g=>g.value).append("g").attr("class",s);f.append("line"),f.append("path"),o.candlestick=c.merge(f).style("opacity",l)},generateDrawCandlestick(t,e){const n=this,{config:a}=n,i=n.generateGetCandlestickPoints(t,e),o=a.axis_rotated,s=a.candlestick_color_down;return(l,c,f)=>{const g=i(l,c),v=n.getCandlestickData(l),m=v==null?void 0:v._isUp,S=+o,P=+!S;f.classed&&f.classed(cr[m?"valueUp":"valueDown"],!0);const N=o?`H${g[1][1]} V${g[1][0]} H${g[0][1]}`:`V${g[1][1]} H${g[1][0]} V${g[0][1]}`;f.select("path").attr("d",`M${g[0][S]},${g[0][P]}${N}z`).style("fill",X=>(m?n.color(X):Be(s)?s[X.id]:s)||n.color(X));const L=f.select("line"),w=o?{x1:g[2][1],x2:g[2][2],y1:g[2][0],y2:g[2][0]}:{x1:g[2][0],x2:g[2][0],y1:g[2][1],y2:g[2][2]};for(const X in w)L.attr(X,w[X])}},generateGetCandlestickPoints(t,e=!1){const n=this,a=e?n.axis.subX:n.axis.x,i=n.getIndicesMax(t)+1,o=n.getBarW("candlestick",a,i),s=n.getShapeX(o,t,!!e),l=n.getShapeY(!!e),c=n.getShapeOffset(n.isBarType,t,!!e),f=n.getYScaleById.bind(n);return(g,v)=>{const m=f.call(n,g.id,e)(n.getShapeYMin(g.id)),S=c(g,v)||m,P=he(o)?o:o[g.id]||o._$width,N=n.getCandlestickData(g);let L;if(N&&he(N.open)&&he(N.close)){const w={start:s(g),end:0};w.end=w.start+P;const X={start:l(N.open),end:l(N.close)},W={x:w.start+P/2,high:l(N.high),low:l(N.low)};X.start-=m-S,L=[[w.start,X.start],[w.end,X.end],[W.x,W.low,W.high]]}else L=[[0,0],[0,0],[0,0,0]];return L}},redrawCandlestick(t,e,n=!1){const a=this,{$el:i,$T:o}=a,{candlestick:s}=n?i.subchart:i,l=gr(!0);return[s.each(function(c,f){const g=o(ot(this),e,l);t(c,f,g)}).style("opacity",null)]},getCandlestickData({value:t}){let e;if(je(t)){const[n,a,i,o,s=!1]=t;e={open:n,high:a,low:i,close:o},s!==!1&&(e.volume=s)}else Be(t)&&(e=Ax({},t));return e&&(e._isUp=e.close>=e.open),e||null}},bx=Object.defineProperty,Yu=Object.getOwnPropertySymbols,Rx=Object.prototype.hasOwnProperty,Ix=Object.prototype.propertyIsEnumerable,Wu=(t,e,n)=>e in t?bx(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,Ox=(t,e)=>{for(var n in e||(e={}))Rx.call(e,n)&&Wu(t,n,e[n]);if(Yu)for(var n of Yu(e))Ix.call(e,n)&&Wu(t,n,e[n]);return t};function Zi(t=!1){const e=this,{config:n,state:{current:{width:a,height:i}}}=e,o=e.getCurrentPadding(),s=Ox({width:a-(o.left+o.right),height:i-(n.legend_show?e.getLegendHeight()+10:0)-(o.top+o.bottom)},o);if(t){const{width:l,height:c}=Ku.call(e,{width:s.width,height:s.height});s.width{let l=o;return Be(o)&&(l=t[s?"height":"width"]*o.ratio),l}),{width:a,height:i}}function Cx(t){const e=this,{top:n,left:a,width:i}=Zi.call(e,!0),o=[];return t.forEach((s,l)=>{const{ratio:c}=s,f=l>0?o[l-1][2][1]:n;o.push(s.coords=[[a,f],[a+i,f],[a+i,l>0?c+f:c+n],[a,l>0?c+f:c+n],[a,f]])}),o}function Zu(t=!1){const e=this,{width:n,height:a,top:i,left:o}=Zi.call(e,!0),s=Ku.call(e,{width:n,height:a}),l=(n-s.width)/2,c=(n+s.width)/2,f=a-s.height,g=[[0,0],[n,0],[c,f],[c,a],[l,a],[l,f],[0,0]];return t&&g.forEach(v=>{v[0]+=o,v[1]+=i}),`M${g.join("L")}z`}function Px(t){const e=this,{config:n}=e,a=t.map(i=>({id:i.id,value:i.values.reduce((o,s)=>o+s.value,0)}));return n.data_order&&a.sort(e.getSortCompareFn.bind(e)(!0)),Ju.call(e,a)}function Ju(t){const e=this,{height:n}=Zi.call(e),a=e.getTotalDataSum(!0);return t.forEach(i=>{i.ratio=i.value/a*n}),t}var wx={initFunnel(){const t=this,{$el:e}=t;e.funnel=e.main.select(`.${Se.chart}`).append("g").classed(Ta.chartFunnels,!0),e.funnel.background=e.funnel.append("path").classed(Ta.funnelBackground,!0),t.bindFunnelEvent()},bindFunnelEvent(){const t=this,{$el:{funnel:e},config:n,state:a}=t,i=o=>{var s;const l=o.isTrusted?o.target:(s=a.eventReceiver.rect)==null?void 0:s.node();let c;return/^path$/i.test(l.tagName)&&(a.event=o,c=ot(l).datum()),c};if(n.interaction_enabled){const o=a.inputType==="touch";e.on(o?"touchstart":"mouseover mousemove",s=>{const l=i(s);l&&(t.showTooltip([l],s.target),/^(touchstart|mouseover)$/.test(s.type)&&t.setOverOut(!0,l))}).on(o?"touchend":"mouseout",s=>{const l=i(s);n.interaction_onout&&(t.hideTooltip(),t.setOverOut(!1,l))})}},updateTargetsForFunnel(t){const e=this,{$el:{funnel:n}}=e,a=e.getChartClass("Funnel"),i=e.getClass("funnel",!0);n||e.initFunnel();const o=Px.call(e,t.filter(e.isFunnelType.bind(e))),s=n.selectAll(`.${Ta.chartFunnel}`).data(o);s.exit().remove();const l=s.enter().insert("g",`.${Ta.funnelBackground}`);l.append("path"),n.path=l.merge(s).attr("class",c=>a(c)).select("path").attr("class",i).style("opacity","0").style("fill",e.color)},updateFunnel(t){const e=this,{$el:{funnel:n}}=e,a=t.map(({id:i})=>i);n.path=n.path.filter(i=>a.indexOf(i.id)>=0)},generateGetFunnelPoints(){const t=this,{$el:{funnel:e}}=t,n=t.filterTargetsToShow(e.path),{top:a,left:i,right:o}=Zi.call(t),s=(i-o)/2,l={};let c=a!=null?a:0;return n.each((f,g)=>{var v;l[f.id]=[[s,c],[s,c+=((v=n==null?void 0:n[g])!=null?v:f).ratio]]}),f=>l[f.id]},redrawFunnel(){const t=this,{$T:e,$el:{funnel:n}}=t,a=t.filterTargetsToShow(n.path),i=Cx.call(t,Ju.call(t,a.data()));n.attr("clip-path",`path('${Zu.bind(t)()}')`),n.background.attr("d",Zu.call(t,!0)),e(a).attr("d",(o,s)=>`M${i[s].join("L")}z`).style("opacity","1"),n.selectAll("g").style("opacity",null)}},Mx={initGauge(){const t=this,{config:e,$el:{arcs:n}}=t,a=(i=null,o="")=>{n.append("text").attr("class",i).style("text-anchor","middle").style("pointer-events","none").text(o)};if(t.hasType("gauge")){const i=t.hasMultiArcGauge();n.append(i?"g":"path").attr("class",Ve.chartArcsBackground).style("fill",!i&&e.gauge_background||null),e.gauge_units&&a(Un.chartArcsGaugeUnit),e.gauge_label_show&&(a(Un.chartArcsGaugeMin),!e.gauge_fullCircle&&a(Un.chartArcsGaugeMax))}},updateGaugeMax(){const t=this,{config:e,state:n}=t,i=t.hasMultiArcGauge()?t.getMinMaxData().max[0].value:t.getTotalDataSum(n.rendered);!e.gauge_enforceMinMax&&i+e.gauge_min*(e.gauge_min>0?-1:1)>e.gauge_max&&(e.gauge_max=i-e.gauge_min)},redrawArcGaugeLine(){const t=this,{config:e,state:n,$el:a}=t,{hiddenTargetIds:i}=t.state,o=a.main.selectAll(`.${Ve.arcs}`).selectAll(`.${Ve.arcLabelLine}`).data(t.arcData.bind(t));o.enter().append("rect").attr("class",l=>`${Ve.arcLabelLine} ${Se.target} ${Se.target}-${l.data.id}`).merge(o).style("fill",l=>t.levelColor?t.levelColor(l.data.values[0].value):t.color(l.data)).style("display",e.gauge_label_show?null:"none").each(function(l){let c=0;const f=2;let g=0,v=0,m="";if(i.indexOf(l.data.id)<0){const S=t.updateAngle(l),P=n.gaugeArcWidth/t.filterTargetsToShow(t.data.targets).length*(S.index+1),N=S.endAngle-Math.PI/2,L=n.radius-P,w=N-(L===0?0:1/L);c=n.radiusExpanded-n.radius+P,g=Math.cos(w)*L,v=Math.sin(w)*L,m=`rotate(${N*180/Math.PI}, ${g}, ${v})`}ot(this).attr("x",g).attr("y",v).attr("width",c).attr("height",f).attr("transform",m).style("stroke-dasharray",`0, ${c+f}, 0`)})},textForGaugeMinMax(t,e){const n=this,{config:a}=n,i=a.gauge_label_extents;return ve(i)?i.bind(n.api)(t,e):t},getGaugeLabelHeight(){const{config:t}=this;return this.config.gauge_label_show&&!t.gauge_fullCircle?20:0},getPaddingBottomForGauge(){const t=this;return t.getGaugeLabelHeight()*(t.config.gauge_label_show?2:2.5)}};function Dx(t,e,n,a=!1){const i=t?[t,0]:n;for(let o=t||n.reduce((s,l)=>s+l);o<=e;)n.forEach(s=>{o+s<=e&&i.push(s),o+=s});return i.length%2!==0&&i.push(a?n[1]:0),{dash:i.join(" "),length:i.reduce((o,s)=>o+s,0)}}function Lx(t,e,n){const a=this,i=[],o="2 2";if(Qe(e)){const s=(l,c)=>ln(l)?c:n?Yn.call(a,l):l;for(let l=0,c;c=e[l];l++){const f=s(c.start,t[0].x),g=s(c.end,t[t.length-1].x),v=c.style||{dasharray:o};i[l]={start:f,end:g,style:v}}}return i}var Nx={initLine(){const{$el:t}=this;t.line=t.main.select(`.${Se.chart}`).append("g").attr("class",ur.chartLines).call(this.setCssRule(!1,`.${ur.chartLines}`,["pointer-events:none"]))},updateTargetsForLine(t){const e=this,{$el:{area:n,line:a,main:i}}=e,o=e.getChartClass("Line"),s=e.getClass("lines",!0),l=e.classFocus.bind(e);a||e.initLine();const c=t.filter(v=>!(e.isScatterType(v)||e.isBubbleType(v))),f=i.select(`.${ur.chartLines}`).selectAll(`.${ur.chartLine}`).data(c).attr("class",v=>o(v)+l(v)),g=f.enter().append("g").attr("class",o).style("opacity","0").style("pointer-events",e.getStylePropValue("none"));if(g.append("g").attr("class",s),e.hasTypeOf("Area")){const v=(!n&&g.empty()?f:g).filter(e.isAreaType.bind(e));e.initArea(v)}e.updateTargetForCircle(c,g)},updateLine(t,e=!1){const n=this,{format:{extraLineClasses:a},$el:i,$T:o}=n,s=e?i.subchart:i,l=s.main.selectAll(`.${ur.lines}`).selectAll(`.${ur.line}`).data(n.lineData.bind(n));o(l.exit(),t).style("opacity","0").remove(),s.line=l.enter().append("path").attr("class",c=>`${n.getClass("line",!0)(c)} ${a(c)||""}`).style("stroke",n.color).merge(l).style("opacity",n.initialOpacity.bind(n)).attr("transform",null)},redrawLine(t,e,n=!1){const a=this,{$el:i,$T:o}=a,{line:s}=n?i.subchart:i;return[o(s,e,gr()).attr("d",t).style("stroke",this.color).style("opacity",null)]},getCurve(t){const e=this;return e.config.axis_rotated&&e.isStepType(t)?a=>{const i=e.getInterpolate(t)(a);return i.orgPoint=i.point,i.pointRotated=function(o,s){this._point===1&&(this._point=2);const l=this._y*(1-this._t)+s*this._t;this._context.lineTo(this._x,l),this._context.lineTo(o,l),this._x=o,this._y=s},i.point=function(o,s){this._point===0?this.orgPoint(o,s):this.pointRotated(o,s)},i}:e.getInterpolate(t)},generateDrawLine(t,e){const n=this,{config:a,scale:i}=n,o=a.line_connectNull,s=a.axis_rotated,l=n.generateGetLinePoints(t,e),c=n.getYScaleById.bind(n),f=S=>(e?n.subxx:n.xx).call(n,S),g=(S,P)=>n.isGrouped(S.id)?l(S,P)[0][1]:c(S.id,e)(n.getBaseValue(S));let v=Gu();v=s?v.x(g).y(f):v.x(f).y(g),o||(v=v.defined(S=>n.getBaseValue(S)!==null));const m=e?i.subX:i.x;return S=>{const P=c(S.id,e);let N=o?n.filterRemoveNull(S.values):S.values,L=0,w=0,X;if(n.isLineType(S)){const W=a.data_regions[S.id];W?X=n.lineWithRegions(N,i.zoom||m,P,W):(n.isStepType(S)&&(N=n.convertValuesToStep(N)),X=v.curve(n.getCurve(S))(N))}else N[0]&&(L=m(N[0].x),w=P(N[0].value)),X=s?`M ${w} ${L}`:`M ${L} ${w}`;return X||"M 0 0"}},lineWithRegions(t,e,n,a){const i=this,{config:o}=i,s=o.axis_rotated,l=i.axis.isTimeSeries(),c="2 2",f=Lx.bind(i)(t,a,l),g=i.hasNullDataValue(t);let v,m,S,P;const N=s?dt=>n(dt.value):dt=>e(dt.x),L=s?dt=>e(dt.x):dt=>n(dt.value),w=dt=>`M${dt[0][0]},${dt[0][1]}L${dt[1][0]},${dt[1][1]}`,X=l?(dt,st,Vt,vt)=>{const Q=dt.x.getTime(),St=st.x-dt.x,ct=new Date(Q+St*Vt),At=new Date(Q+St*(Vt+vt)),Gt=s?[[n(m(Vt)),e(ct)],[n(m(Vt+S)),e(At)]]:[[e(ct),n(m(Vt))],[e(At),n(m(Vt+S))]];return w(Gt)}:(dt,st,Vt,vt)=>{const Q=e(st.x,!s),St=n(st.value,s),ct=Vt+vt,At=e(v(Vt),!s),Gt=n(m(Vt),s);let Bt=e(v(ct),!s),Kt=n(m(ct),s);Bt>Q&&(Bt=Q),dt.value>st.value&&(s?KtSt)&&(Kt=St);const ne=[[At,Gt],[Bt,Kt]];return s&&ne.forEach(le=>le.reverse()),w(ne)},W={x:i.axis.getAxisType("x"),y:i.axis.getAxisType("y")};let H="";const k=i.$el.line.filter(({id:dt})=>dt===t[0].id),K=k.clone().style("display","none"),at=(dt,st)=>dt.attr("d",st).node().getTotalLength(),ht={dash:[],lastLength:0};let $t=!1;for(let dt=0,st;st=t[dt];dt++){const Vt=t[dt-1],vt=Vt&&De(Vt.value);let Q=i.isWithinRegions(st.x,f);if(De(st.value)){if(ln(f)||!Q||!vt)H+=`${dt&&vt?"L":"M"}${N(st)},${L(st)}`;else if(vt)if(Q=((Q==null?void 0:Q.dasharray)||c).split(" ").map(Number),v=zr(W.x,Vt.x,st.x),m=zr(W.y,Vt.value,st.value),g){const St=e(st.x)-e(Vt.x),ct=n(st.value)-n(Vt.value),At=Math.sqrt(Math.pow(St,2)+Math.pow(ct,2));S=Q[0]/At,P=S*Q[1];for(let Gt=S;Gt<=1;Gt+=P)H+=X(Vt,st,Gt,S),Gt+P>=1&&(H+=X(Vt,st,1,0))}else{let St=[];if($t=st.x===t[t.length-1].x,l){const Bt=+Vt.x,Kt=new Date(Bt),ne=new Date(Bt+(+st.x-Bt));St=[[e(Kt),n(m(0))],[e(ne),n(m(1))]]}else St=[[e(v(0)),n(m(0))],[e(v(1)),n(m(1))]];s&&St.forEach(Bt=>Bt.reverse());const ct=at(K,H),At=at(K,H+=`L${St[1].join(",")}`),Gt=Dx(ct-ht.lastLength,At-ht.lastLength,Q,$t);ht.lastLength+=Gt.length,ht.dash.push(Gt.dash)}}}return ht.dash.length&&(!$t&&ht.dash.push(at(K,H)),K.remove(),k.attr("stroke-dasharray",ht.dash.join(" "))),H},isWithinRegions(t,e){for(let n=0,a;a=e[n];n++)if(a.startgr();var Ji={initialOpacityForCircle(t){const{config:e,state:{withoutFadeIn:n}}=this;let a=e.point_opacity;return ln(a)&&(a=this.getBaseValue(t)!==null&&n[t.id]?this.opacityForCircle(t):"0"),a},opacityForCircle(t){var e;const{config:n}=this;let a=n.point_opacity;return ln(a)&&(a=n.point_show&&!((e=this.isPointFocusOnly)!=null&&e.call(this))?null:"0",a=De(this.getBaseValue(t))?this.isBubbleType(t)||this.isScatterType(t)?"0.5":a:"0"),a},initCircle(){const t=this,{$el:{main:e}}=t;!t.point&&(t.point=t.generatePoint()),(t.hasType("bubble")||t.hasType("scatter"))&&e.select(`.${Se.chart} > .${$n.chartCircles}`).empty()&&e.select(`.${Se.chart}`).append("g").attr("class",$n.chartCircles)},updateTargetForCircle(t,e){const n=this,{config:a,data:i,$el:o}=n,s=a.interaction_enabled&&a.data_selection_enabled,l=s&&a.data_selection_isselectable,c=n.getClass("circles",!0);if(!a.point_show)return;n.initCircle();let f=t,g=e;if(!f){f=i.targets.filter(m=>this.isScatterType(m)||this.isBubbleType(m));const v=o.main.select(`.${$n.chartCircles}`).style("pointer-events","none").selectAll(`.${$n.circles}`).data(f);v.exit().remove(),g=v.enter()}s&&g.append("g").attr("class",v=>n.generateClass(tn.selectedCircles,v.id)),g.append("g").attr("class",c).call(v=>{n.setCssRule(!0,`.${$n.circles}`,["cursor:pointer"],l)(v),n.setCssRule(!0,` .${$n.circle}`,["fill","stroke"],n.color)(v)}).style("opacity",function(){return ot(this.parentNode).attr("class").indexOf($n.chartCircles)>-1?"0":null}),s&&f.forEach(v=>{o.main.selectAll(`.${tn.selectedCircles}${n.getTargetSelectorSuffix(v.id)}`).selectAll(`${tn.selectedCircle}`).each(m=>{m.value=v.values[m.index].value})})},updateCircle(t=!1){const e=this,{config:n,state:a,$el:i}=e,o=e.isPointFocusOnly(),s=t?i.subchart:i;if(n.point_show&&!a.toggling){n.point_radialGradient&&e.updateLinearGradient();const l=s.main.selectAll(`.${$n.circles}`).selectAll(`.${$n.circle}`).data(c=>e.isLineType(c)&&e.shouldDrawPointsForLine(c)||e.isBubbleType(c)||e.isRadarType(c)||e.isScatterType(c)?o?[c.values[0]]:c.values:[]);l.exit().remove(),l.enter().filter(Boolean).append(e.point("create",this,e.pointR.bind(e),e.updateCircleColor.bind(e))),s.circle=s.main.selectAll(`.${$n.circles} .${$n.circle}`).style("stroke",e.getStylePropValue(e.color)).style("opacity",e.initialOpacityForCircle.bind(e))}},updateCircleColor(t){const e=this,n=e.getStylePropValue(e.color);return e.config.point_radialGradient?e.getGradienColortUrl(t.id):n?n(t):null},redrawCircle(t,e,n,a,i=!1){const o=this,{state:{rendered:s},$el:l,$T:c}=o,f=i?l.subchart:l,g=f.main.selectAll(`.${tn.selectedCircle}`);if(!o.config.point_show)return[];const v=o.point("update",o,t,e,o.updateCircleColor.bind(o),n,a,g),m=o.isCirclePoint()?"c":"",S=gr(),P=o.opacityForCircle.bind(o),N=[];return f.circle.each(function(L){let w=v.bind(this)(L);w=c(w,n||!s,S).style("opacity",P),N.push(w)}),[N,c(g,n).attr(`${m}x`,t).attr(`${m}y`,e)]},showCircleFocus(t){const e=this,{state:{hasRadar:n,resizing:a,toggling:i,transiting:o},$el:s}=e;let{circle:l}=s;if(o===!1&&l&&e.isPointFocusOnly()){const c=(n?e.radarCircleX:e.circleX).bind(e),f=(n?e.radarCircleY:e.circleY).bind(e),g=i||ln(t),v=e.point("update",e,c,f,e.getStylePropValue(e.color),a?!1:g);t&&(l=l.filter(function(m){var S;const P=(S=t.filter)==null?void 0:S.call(t,N=>N.id===m.id);return P.length?ot(this).datum(P[0]):!1})),l.attr("class",this.updatePointClass.bind(this)).style("opacity",null).each(function(m){const{id:S,index:P,value:N}=m;let L="hidden";De(N)&&(v.bind(this)(m),e.expandCircles(P,S),L=""),this.style.visibility=L})}},hideCircleFocus(){const t=this,{$el:{circle:e}}=t;t.isPointFocusOnly()&&e&&(t.unexpandCircles(),e.style("visibility","hidden"))},circleX(t){return this.xx(t)},updateCircleY(t=!1){const e=this,n=e.generateGetLinePoints(e.getShapeIndices(e.isLineType),t);return(a,i)=>{const o=a.id;return e.isGrouped(o)?n(a,i)[0][1]:e.getYScaleById(o,t)(e.getBaseValue(a))}},expandCircles(t,e,n){const a=this,i=a.pointExpandedR.bind(a);n&&a.unexpandCircles();const o=a.getShapeByIndex("circle",t,e).classed(Se.EXPANDED,!0),s=i(o)/a.config.point_r,l=1-s;a.isCirclePoint()?o.attr("r",i):o.each(function(){const c=ot(this);if(this.tagName==="circle")c.attr("r",i);else{const{width:f,height:g}=this.getBBox(),v=l*(+c.attr("x")+f/2),m=l*(+c.attr("y")+g/2);c.attr("transform",`translate(${v} ${m}) scale(${s})`)}})},unexpandCircles(t){const e=this,n=e.pointR.bind(e),a=e.getShapeByIndex("circle",t).filter(function(){return ot(this).classed(Se.EXPANDED)}).classed(Se.EXPANDED,!1);if(a.attr("r",n),!e.isCirclePoint()){const i=n(a)/e.config.point_r;a.attr("transform",i!==1?`scale(${i})`:null)}},pointR(t){const e=this,{config:n}=e,a=n.point_r;let i=a;return e.isBubbleType(t)?i=e.getBubbleR(t):ve(a)&&(i=a.bind(e.api)(t)),t.r=i,i},pointExpandedR(t){const e=this,{config:n}=e,a=e.isBubbleType(t)?1.15:1.75;return n.point_focus_expand_enabled?n.point_focus_expand_r||e.pointR(t)*a:e.pointR(t)},pointSelectR(t){const e=this,n=e.config.point_select_r;return ve(n)?n(t):n||e.pointR(t)*4},isPointFocusOnly(){const t=this;return t.config.point_focus_only&&!t.hasType("bubble")&&!t.hasType("scatter")&&!t.hasArcType(null,["radar"])},isWithinCircle(t,e){const{state:n}=this,a=Hn(n.event,t),i=ot(t),o=this.isCirclePoint(t)?"c":"",s=this.getPointSensitivity(i==null?void 0:i.datum());let l=+i.attr(`${o}x`),c=+i.attr(`${o}y`);if(!(l||c)&&t.nodeType===1){const{x:f,y:g}=Ma(t);l=f,c=g}return Math.sqrt(Math.pow(l-a[0],2)+Math.pow(c-a[1],2))<(e||s)},getPointSensitivity(t){const e=this;let n=e.config.point_sensitivity;if(t)ve(n)?n=n.call(e.api,t):n==="radius"&&(n=t.r);else return n;return n},updatePointClass(t){const e=this,{circle:n}=e.$el;let a=!1;return(Be(t)||n)&&(a=t===!0?n.each(function(i){let o=e.getClass("circle",!0)(i);this.getAttribute("class").indexOf(Se.EXPANDED)>-1&&(o+=` ${Se.EXPANDED}`),this.setAttribute("class",o)}):e.getClass("circle",!0)(t)),a},generateGetLinePoints(t,e){const n=this,{config:a}=n,i=n.getShapeX(0,t,e),o=n.getShapeY(e),s=n.getShapeOffset(n.isLineType,t,e),l=n.getYScaleById.bind(n);return(c,f)=>{const g=l.call(n,c.id,e)(n.getShapeYMin(c.id)),v=s(c,f)||g,m=i(c);let S=o(c);a.axis_rotated&&(c.value>0&&SDe(S.value)?e(S)-c/2:0,v=S=>De(S.value)?n(S)-f/2:0;let m=t;return i&&(o&&m.attr("x",g),m=l.$T(m,i,la()),s&&l.$T(s,i,la())),m.attr("x",g).attr("y",v).style("fill",a)}},circle:{create(t,e,n){return t.append("circle").attr("class",this.updatePointClass.bind(this)).attr("r",e).style("fill",n).node()},update(t,e,n,a,i,o,s){const l=this;let c=t;return l.hasType("bubble")&&c.attr("r",l.pointR.bind(l)),i&&(o&&c.attr("cx",e),c.attr("cx")&&(c=l.$T(c,i,la())),s&&l.$T(c,i,la())),c.attr("cx",e).attr("cy",n).style("fill",a)}},rectangle:{create(t,e,n){const a=i=>e(i)*2;return t.append("rect").attr("class",this.updatePointClass.bind(this)).attr("width",a).attr("height",a).style("fill",n).node()},update(t,e,n,a,i,o,s){const l=this,c=l.config.point_r,f=m=>e(m)-c,g=m=>n(m)-c;let v=t;return i&&(o&&v.attr("x",f),v=l.$T(v,i,la()),s&&l.$T(s,i,la())),v.attr("x",f).attr("y",g).style("fill",a)}}};function Fx(t){return nr(t)&&ve(t.create)&&ve(t.update)}function Bx(t,e){var n;const a=this,i=(c,f)=>{const g=c.attributes;for(let v=0,m;m=g[v];v++)m=m.name,f.setAttribute(m,c.getAttribute(m))},s=new DOMParser().parseFromString(t,"image/svg+xml").documentElement,l=gn.createElementNS(ae.svg,s.nodeName.toLowerCase());if(l.id=e,l.style.fill="inherit",l.style.stroke="inherit",i(s,l),(n=s.childNodes)!=null&&n.length){const c=ot(l);"innerHTML"in l?c.html(s.innerHTML):Lr(s.childNodes).forEach(f=>{i(f,c.append(f.tagName).node())})}a.$el.defs.node().appendChild(l)}var ca={hasValidPointType(t){return/^(circle|rect(angle)?|polygon|ellipse|use)$/i.test(t||this.config.point_type)},hasLegendDefsPoint(){var t;const{config:e}=this;return e.legend_show&&((t=e.point_pattern)==null?void 0:t.length)&&e.legend_usePoint},getDefsPointId(t){const{state:{datetimeId:e}}=this;return`${e}-point${t}`},generatePoint(){const t=this,{$el:e,config:n}=t,a=[],i=cn(n.point_pattern)?n.point_pattern:[n.point_type];return function(o,s,...l){return function(c){var f,g,v,m;const S=t.getTargetSelectorSuffix(c.id||((f=c.data)==null?void 0:f.id)||c),P=ot(this);a.indexOf(S)<0&&a.push(S);let N=i[a.indexOf(S)%i.length];if(t.hasValidPointType(N))N=t[N];else if(!Fx(N||n.point_type)){const L=t.getDefsPointId(S);if(e.defs.select(`#${L}`).size()<1&&Bx.bind(t)(N,L),o==="create")return(g=t.custom)==null?void 0:g.create.bind(s)(P,L,...l);if(o==="update")return(v=t.custom)==null?void 0:v.update.bind(s)(P,...l)}return(m=N[o])==null?void 0:m.bind(s)(P,...l)}}}};function Qu(t){const e=t.config.polar_level_max;let n=t.getMinMaxData().max[0].value;return e&&e>n&&(n=e),n}var Ux={initPolar(){const t=this,{$el:{arcs:e},config:n}=t,a=n.polar_level_text_show,i=n.polar_level_text_backgroundColor;e.levels=e.append("g").attr("class",Tr.levels),a&&i&&t.generateTextBGColorFilter(i)},getPolarOuterRadius(t,e){var n;const a=Qu(this);return((n=t==null?void 0:t.data.values[0].value)!=null?n:0)/a*e},updateTargetsForPolar(t){this.updateTargetsForArc(t)},redrawPolar(){const t=this,{config:e}=t;e.polar_level_show&&t.updatePolarLevel()},updatePolarLevel(){const t=this,{config:e,state:n,$el:{arcs:{levels:a}}}=t,i=e.polar_level_depth,o=Qu(t),s=Ei(0,i),l=n.radius,c=s.map(m=>l*((m+1)/i)),f=(e.polar_level_text_format||function(){}).bind(t.api),g=a.selectAll(`.${Tr.level}`).data(s);g.exit().remove();const v=g.enter().append("g").attr("class",(m,S)=>`${Tr.level} ${Tr.level}-${S}`);if(v.append("circle"),v.merge(g).selectAll("circle").style("visibility",e.polar_level_show?null:"hidden").attr("cx",0).attr("cy",0).attr("r",m=>c[m]),e.polar_level_text_show){const m=e.polar_level_text_backgroundColor,S=`#${n.datetimeId}-labels-bg${t.getTargetSelectorSuffix(m)}`;v.append("text").style("text-anchor","middle"),v.merge(g).selectAll("text").attr("dy",P=>-c[P]+5).attr("filter",m?`url(${S})`:null).text(P=>f(o/s.length*(P+1)))}}};function zx(t,e,n,a,i,o){const s=t&&a>0?n-a:a,l=2*Math.PI;return i*(1-o*(e==="x"?Math.sin:Math.cos)(s*l/n))}const ua=Ln.radarPoints,ku=Ln.radarTextWidth;var jx={initRadar(){const t=this,{config:e,state:{current:n},$el:a}=t;t.hasType("radar")&&(a.radar=a.main.select(`.${Se.chart}`).append("g").attr("class",Qs.chartRadars),a.radar.levels=a.radar.append("g").attr("class",Tr.levels),a.radar.axes=a.radar.append("g").attr("class",Tn.axis),a.radar.shapes=a.radar.append("g").attr("class",sn.shapes),n.dataMax=e.radar_axis_max||t.getMinMaxData().max[0].value,e.radar_axis_text_show&&(e.interaction_enabled&&t.bindRadarEvent(),t.updateRadarLevel(),t.updateRadarAxes()))},getRadarSize(){const t=this,{config:e,state:{arcWidth:n,arcHeight:a}}=t,i=e.axis_x_categories.length<4?-20:10,o=(Math.min(n,a)-i)/2;return[o,o]},updateTargetsForRadar(t){const e=this,{config:n}=e;qn(n.axis_x_categories)&&(n.axis_x_categories=Ei(0,_n("max",t.map(a=>a.values.length)))),e.generateRadarPoints()},getRadarPosition(t,e,n,a){const i=this,{config:o}=i,[s,l]=i.getRadarSize(),c=o.axis_x_categories.length,f=o.radar_direction_clockwise,g=Lr(t).map(v=>zx(f,v,c,e,Qe(n)?n:t==="x"?s:l,he(a)?a:o.radar_size_ratio));return g.length===1?g[0]:g},generateRadarPoints(){const t=this,e=t.data.targets,[n,a]=t.getRadarSize(),i=t.cache.get(ua)||{},o=i._size;(!o||o.width!==n&&o.height!==a)&&(e.forEach(s=>{i[s.id]=s.values.map((l,c)=>t.getRadarPosition(["x","y"],c,void 0,t.getRatio("radar",l)))}),i._size={width:n,height:a},t.cache.add(ua,i))},redrawRadar(){const t=this,{radar:e,main:n}=t.$el,a=t.getTranslate("radar");a&&(e.attr("transform",a),n.select(`.${On.chartTexts}`).attr("transform",a),t.generateRadarPoints(),t.updateRadarLevel(),t.updateRadarAxes(),t.updateRadarShape())},generateGetRadarPoints(){const t=this.cache.get(ua);return(e,n)=>{const a=t[e.id][n];return[a,a,a,a]}},updateRadarLevel(){const t=this,{config:e,state:n,$el:{radar:a}}=t,[i,o]=t.getRadarSize(),s=e.radar_level_depth,l=e.axis_x_categories.length,c=e.radar_level_text_show,f=a.levels,g=Ei(0,s),v=e.radar_size_ratio*Math.min(i,o),m=g.map(w=>v*((w+1)/s)),S=(e.radar_level_text_format||function(){}).bind(t.api),P=g.map(w=>{const X=m[w];return Ei(0,l).map(H=>t.getRadarPosition(["x","y"],H,X,1).join(",")).join(" ")}),N=f.selectAll(`.${Tr.level}`).data(g);N.exit().remove();const L=N.enter().append("g").attr("class",(w,X)=>`${Tr.level} ${Tr.level}-${X}`);L.append("polygon").style("visibility",e.radar_level_show?null:"hidden"),c&&(f.select("text").empty()&&f.append("text").attr("dx","-.5em").attr("dy","-.7em").style("text-anchor","end").text(()=>S(0)),L.append("text").attr("dx","-.5em").style("text-anchor","end").text(w=>S(n.current.dataMax/g.length*(w+1)))),L.merge(N).attr("transform",w=>`translate(${i-m[w]}, ${o-m[w]})`).selectAll("polygon").attr("points",w=>P[w]),c&&f.selectAll("text").attr("x",w=>ln(w)?i:P[w].split(",")[0]).attr("y",w=>ln(w)?o:0)},updateRadarAxes(){const t=this,{config:e,$el:{radar:n}}=t,[a,i]=t.getRadarSize(),o=e.axis_x_categories;let s=n.axes.selectAll("g").data(o);s.exit().remove();const l=s.enter().append("g").attr("class",(c,f)=>`${Tn.axis}-${f}`);if(e.radar_axis_line_show&&l.append("line"),e.radar_axis_text_show&&l.append("text"),s=l.merge(s),e.radar_axis_line_show&&s.select("line").attr("x1",a).attr("y1",i).attr("x2",(c,f)=>t.getRadarPosition("x",f)).attr("y2",(c,f)=>t.getRadarPosition("y",f)),e.radar_axis_text_show){const{x:c=0,y:f=0}=e.radar_axis_text_position,g=t.cache.get(ku)||0;if(s.select("text").style("text-anchor","middle").attr("dy",".5em").call(v=>{v.each(function(m){wa(ot(this),String(m),[-.6,1.2])})}).datum((v,m)=>({index:m})).attr("transform",function(v){ln(this.width)&&(this.width=this.getBoundingClientRect().width/2);let m=t.getRadarPosition("x",v.index,void 0,1),S=Math.round(t.getRadarPosition("y",v.index,void 0,1));return m>a?m+=this.width+c:Math.round(m)i?(S/2===i&&this.firstChild.tagName==="tspan"&&this.firstChild.setAttribute("dy","0em"),S+=f):SYl(m.node()).width);v.every(m=>m>0)&&t.cache.add(ku,v[0]-v[1])}}},bindRadarEvent(){const t=this,{config:e,state:n,$el:{radar:a,svg:i}}=t,o=t.isPointFocusOnly(),{inputType:s,transiting:l}=n,c=s==="mouse",f=g=>{if(n.event=g,!e.interaction_onout)return;const v=t.getDataIndexFromEvent(g),m=ln(v);(c||m)&&(t.hideTooltip(),o?t.hideCircleFocus():t.unexpandCircles(),c?t.setOverOut(!1,v):m&&t.callOverOutForTouch())};a.axes.on(c?"mouseover ":"touchstart",g=>{if(l)return;n.event=g;const v=t.getDataIndexFromEvent(g);t.selectRectForSingle(i.node(),v),c?t.setOverOut(!0,v):t.callOverOutForTouch(v)}).on("mouseout",c?f:null),c||i.on("touchstart",f)},updateRadarShape(){const t=this,e=t.data.targets.filter(o=>t.isRadarType(o)),n=t.cache.get(ua),a=t.$el.radar.shapes.selectAll("polygon").data(e),i=a.enter().append("g").attr("class",t.getChartClass("Radar"));t.$T(a.exit()).remove(),i.append("polygon").merge(a).style("fill",t.color).style("stroke",t.color).attr("points",o=>n[o.id].join(" ")),t.updateTargetForCircle(e,i)},radarCircleX(t){return this.cache.get(ua)[t.id][t.index][0]},radarCircleY(t){return this.cache.get(ua)[t.id][t.index][1]}};function Vx(t){var e=0,n=t.children,a=n&&n.length;if(!a)e=1;else for(;--a>=0;)e+=n[a].value;t.value=e}function Gx(){return this.eachAfter(Vx)}function Xx(t,e){let n=-1;for(const a of this)t.call(e,a,++n,this);return this}function Hx(t,e){for(var n=this,a=[n],i,o,s=-1;n=a.pop();)if(t.call(e,n,++s,this),i=n.children)for(o=i.length-1;o>=0;--o)a.push(i[o]);return this}function Yx(t,e){for(var n=this,a=[n],i=[],o,s,l,c=-1;n=a.pop();)if(i.push(n),o=n.children)for(s=0,l=o.length;s=0;)n+=a[i].value;e.value=n})}function Zx(t){return this.eachBefore(function(e){e.children&&e.children.sort(t)})}function Jx(t){for(var e=this,n=Qx(e,t),a=[e];e!==n;)e=e.parent,a.push(e);for(var i=a.length;t!==n;)a.splice(i,0,t),t=t.parent;return a}function Qx(t,e){if(t===e)return t;var n=t.ancestors(),a=e.ancestors(),i=null;for(t=n.pop(),e=a.pop();t===e;)i=t,t=n.pop(),e=a.pop();return i}function kx(){for(var t=this,e=[t];t=t.parent;)e.push(t);return e}function qx(){return Array.from(this)}function _x(){var t=[];return this.eachBefore(function(e){e.children||t.push(e)}),t}function t0(){var t=this,e=[];return t.each(function(n){n!==t&&e.push({source:n.parent,target:n})}),e}function*e0(){var t=this,e,n=[t],a,i,o;do for(e=n.reverse(),n=[];t=e.pop();)if(yield t,a=t.children)for(i=0,o=a.length;i=0;--l)i.push(o=s[l]=new Qi(s[l])),o.parent=a,o.depth=a.depth+1;return n.eachBefore(o0)}function n0(){return Rs(this).eachBefore(i0)}function r0(t){return t.children}function a0(t){return Array.isArray(t)?t[1]:null}function i0(t){t.data.value!==void 0&&(t.value=t.data.value),t.data=t.data.data}function o0(t){var e=0;do t.height=e;while((t=t.parent)&&t.height<++e)}function Qi(t){this.data=t,this.depth=this.height=0,this.parent=null}Qi.prototype=Rs.prototype={constructor:Qi,count:Gx,each:Xx,eachAfter:Yx,eachBefore:Hx,find:Wx,sum:Kx,sort:Zx,path:Jx,ancestors:kx,descendants:qx,leaves:_x,links:t0,copy:n0,[Symbol.iterator]:e0};function s0(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function ki(t,e,n,a,i){for(var o=t.children,s,l=-1,c=o.length,f=t.value&&(a-e)/t.value;++lX&&(X=f),K=L*L*k,W=Math.max(X/K,K/w),W>H){L-=f;break}H=W}s.push(c={value:L,dice:S1?a:1)},n}(qu);function C1(t){return t==null?null:ef(t)}function ef(t){if(typeof t!="function")throw new Error;return t}function ja(){return 0}function Va(t){return function(){return t}}function l0(){var t=tf,e=!1,n=1,a=1,i=[0],o=ja,s=ja,l=ja,c=ja,f=ja;function g(m){return m.x0=m.y0=0,m.x1=n,m.y1=a,m.eachBefore(v),i=[0],e&&m.eachBefore(s0),m}function v(m){var S=i[m.depth],P=m.x0+S,N=m.y0+S,L=m.x1-S,w=m.y1-S;L=m-1){var X=o[v];X.x0=P,X.y0=N,X.x1=L,X.y1=w;return}for(var W=f[v],H=S/2+W,k=v+1,K=m-1;k>>1;f[at]w-N){var dt=S?(P*$t+L*ht)/S:L;g(v,k,ht,P,N,dt,w),g(k,m,$t,dt,N,L,w)}else{var st=S?(N*$t+w*ht)/S:w;g(v,k,ht,P,N,L,st),g(k,m,$t,P,st,L,w)}}}function c0(t,e,n,a,i){(t.depth&1?qi:ki)(t,e,n,a,i)}var u0=function t(e){function n(a,i,o,s,l){if((c=a._squarify)&&c.ratio===e)for(var c,f,g,v,m=-1,S,P=c.length,N=a.value;++m1?a:1)},n}(qu);function f0(t,e){const n=this,{scale:{x:a,y:i},state:{width:o}}=n;t.selectAll("g").attr("transform",s=>`translate(${s===e?"0,0":`${a(s.x0)},${i(s.y0)}`})`).select("rect").attr("width",s=>s===e?o:a(s.x1)-a(s.x0)).attr("height",s=>s===e?0:i(s.y1)-i(s.y0))}function d0(t){const e=this;return t.map(n=>{const{id:a,values:i}=n,{value:o}=i[0];return{name:a,id:a,value:o,ratio:e.getRatio("treemap",i[0])}})}function h0(t){const e=this,n=Rs(t).sum(i=>i.value),a=e.getSortCompareFn(!0);return[e.treemap(a?n.sort(a):n)]}var g0={initTreemap(){const t=this,{$el:e,state:{current:{width:n,height:a},clip:i,datetimeId:o}}=t;i.id=`${o}-clip`,t.treemap=l0().tile(t.getTreemapTile()),e.defs.append("clipPath").attr("id",i.id).append("rect").attr("width",n).attr("height",a),e.treemap=e.main.select(`.${Se.chart}`).attr("clip-path",`url(#${i.id})`).append("g").classed(qs.chartTreemaps,!0),t.bindTreemapEvent()},bindTreemapEvent(){const t=this,{$el:e,config:n,state:a}=t,i=o=>{var s;const l=o.isTrusted?o.target:(s=a.eventReceiver.rect)==null?void 0:s.node();let c;return/^rect$/i.test(l.tagName)&&(a.event=o,c=ot(l).datum()),c==null?void 0:c.data};if(n.interaction_enabled){const o=a.inputType==="touch";e.treemap.on(o?"touchstart":"mouseover mousemove",s=>{const l=i(s);l&&(t.showTooltip([l],s.currentTarget),/^(touchstart|mouseover)$/.test(s.type)&&t.setOverOut(!0,l))}).on(o?"touchend":"mouseout",s=>{const l=i(s);n.interaction_onout&&(t.hideTooltip(),t.setOverOut(!1,l))})}},getTreemapTile(){var t,e;const n=this,{config:a,state:{current:{width:i,height:o}}}=n,s=(e={binary:nf,dice:ki,slice:qi,sliceDice:c0,squarify:tf,resquarify:u0}[(t=a.treemap_tile)!=null?t:"binary"])!=null?e:nf;return(l,c,f,g,v)=>{s(l,0,0,i,o);for(const m of l.children)m.x0=c+m.x0/i*(g-c),m.x1=c+m.x1/i*(g-c),m.y0=f+m.y0/o*(v-f),m.y1=f+m.y1/o*(v-f)}},getTreemapData(t){const e=this;return{name:"root",children:d0.bind(e)(e.filterTargetsToShow(t.filter(e.isTreemapType,e)))}},updateTargetsForTreemap(t){const e=this,{$el:{treemap:n}}=e,a=h0.call(e,e.getTreemapData(t!=null?t:e.data.targets));n.data(a)},updateTreemap(t){const e=this,{$el:n,$T:a}=e,i=n.treemap.datum(),o=e.getChartClass("Treemap"),s=e.getClass("treemap",!0),l=n.treemap.selectAll("g").data(i.children);a(l.exit(),t).style("opacity","0").remove(),l.enter().append("g").append("rect"),n.treemap.selectAll("g").attr("class",o).select("rect").attr("class",s).attr("fill",c=>e.color(c.data.name))},generateGetTreemapPoints(){const t=this,{$el:e,scale:{x:n,y:a}}=t,i={};return e.treemap.selectAll("g").each(o=>{i[o.data.name]=[[n(o.x0),a(o.y0)],[n(o.x1),a(o.y1)]]}),o=>i[o.id]},redrawTreemap(t){const e=this,{$el:n,state:{current:{width:a,height:i}}}=e;return n.defs.select("rect").attr("width",a).attr("height",i),[e.$T(n.treemap,t,gr()).call(f0.bind(e),n.treemap.datum())]},treemapDataLabelFormat(t){const e=this,{config:n}=e,{id:a,value:i}=t,o=n.treemap_label_format,s=e.getRatio("treemap",t),l=(s*100).toFixed(2),c=n.treemap_label_show&&e.meetsLabelThreshold(s,"treemap")?null:"0";return function(f){return f.style("opacity",c),ve(o)?o.bind(e.api)(i,s,a):`${a} +${l}%`}}},Xr={point_show:!0,point_r:2.5,point_radialGradient:!1,point_sensitivity:10,point_focus_expand_enabled:!0,point_focus_expand_r:void 0,point_focus_only:!1,point_opacity:void 0,point_pattern:[],point_select_r:void 0,point_type:"circle"},fa={area_above:!1,area_below:!1,area_front:!0,area_linearGradient:!1,area_zerobased:!0},v0={bar_front:!1,bar_indices_removeNull:!1,bar_label_threshold:0,bar_linearGradient:!1,bar_overlap:!1,bar_padding:0,bar_radius:void 0,bar_radius_ratio:void 0,bar_sensitivity:2,bar_width:void 0,bar_width_ratio:.6,bar_width_max:void 0,bar_zerobased:!0},p0={bubble_maxR:35,bubble_zerobased:!1},m0={candlestick_width:void 0,candlestick_width_ratio:.6,candlestick_width_max:void 0,candlestick_color_down:"red"},y0={line_connectNull:!1,line_step_type:"step",line_step_tooltipMatch:!1,line_zerobased:!1,line_classes:void 0,line_point:!0},x0={scatter_zerobased:!1},Is={spline_interpolation_type:"cardinal"},_i={arc_cornerRadius:0,arc_cornerRadius_ratio:0,arc_needle_show:!1,arc_needle_color:void 0,arc_needle_value:void 0,arc_needle_path:void 0,arc_needle_length:100,arc_needle_top_rx:0,arc_needle_top_ry:0,arc_needle_top_width:0,arc_needle_bottom_rx:1,arc_needle_bottom_ry:1,arc_needle_bottom_width:15,arc_needle_bottom_len:0,arc_rangeText_values:void 0,arc_rangeText_unit:"absolute",arc_rangeText_fixed:!1,arc_rangeText_format:void 0,arc_rangeText_position:void 0},T0={donut_label_show:!0,donut_label_format:void 0,donut_label_threshold:.05,donut_label_ratio:void 0,donut_width:void 0,donut_title:"",donut_expand:{},donut_expand_rate:.98,donut_expand_duration:50,donut_padAngle:0,donut_startingAngle:0},$0={funnel_neck_width:0,funnel_neck_height:0},S0={gauge_background:"",gauge_fullCircle:!1,gauge_label_show:!0,gauge_label_extents:void 0,gauge_label_format:void 0,gauge_label_ratio:void 0,gauge_label_threshold:0,gauge_enforceMinMax:!1,gauge_min:0,gauge_max:100,gauge_type:"single",gauge_startingAngle:-1*Math.PI/2,gauge_arcLength:100,gauge_title:"",gauge_units:void 0,gauge_width:void 0,gauge_arcs_minWidth:5,gauge_expand:{},gauge_expand_rate:.98,gauge_expand_duration:50},A0={pie_label_show:!0,pie_label_format:void 0,pie_label_ratio:void 0,pie_label_threshold:.05,pie_expand:{},pie_expand_rate:.98,pie_expand_duration:50,pie_innerRadius:0,pie_outerRadius:void 0,pie_padAngle:0,pie_padding:0,pie_startingAngle:0},E0={polar_label_show:!0,polar_label_format:void 0,polar_label_threshold:.05,polar_label_ratio:void 0,polar_level_depth:3,polar_level_max:void 0,polar_level_show:!0,polar_level_text_backgroundColor:"#fff",polar_level_text_format:t=>t%1===0?t:t.toFixed(2),polar_level_text_show:!0,polar_padAngle:0,polar_padding:0,polar_startingAngle:0},b0={radar_axis_max:void 0,radar_axis_line_show:!0,radar_axis_text_show:!0,radar_axis_text_position:{},radar_level_depth:3,radar_level_show:!0,radar_level_text_format:t=>t%1===0?t:t.toFixed(2),radar_level_text_show:!0,radar_size_ratio:.87,radar_direction_clockwise:!1},R0={treemap_tile:"binary",treemap_label_format:void 0,treemap_label_threshold:.05,treemap_label_show:!0};function da(t,e){yn(Vr.prototype,Object.values(Du).concat(t)),yn(Er.prototype,Jy),Nr.setOptions(Object.values(Lu).concat(e||[]))}function mr(t,e){da([ca,Ji,Nx].concat(t||[])),Nr.setOptions([Xr,y0].concat(e||[]))}function ha(t,e){yn(Vr.prototype,[px,ca].concat(t||[])),Nr.setOptions([Xr].concat(e||[]))}let rf=()=>(mr(sa,[fa]),(rf=()=>oe.AREA)()),af=()=>(mr(sa,[fa]),(af=()=>oe.AREA_LINE_RANGE)()),of=()=>(mr(sa,[fa]),(of=()=>oe.AREA_STEP_RANGE)()),sf=()=>(mr(sa,[fa,Is]),(sf=()=>oe.AREA_SPLINE)()),lf=()=>(mr(sa,[fa,Is]),(lf=()=>oe.AREA_SPLINE_RANGE)()),cf=()=>(mr(sa,[fa]),(cf=()=>oe.AREA_STEP)()),uf=()=>(mr(),(uf=()=>oe.LINE)()),ff=()=>(mr(void 0,[Is]),(ff=()=>oe.SPLINE)()),df=()=>(mr(),(df=()=>oe.STEP)()),hf=()=>(ha(void 0,[_i,T0]),(hf=()=>oe.DONUT)()),gf=()=>(ha([Mx],[_i,S0]),(gf=()=>oe.GAUGE)()),vf=()=>(ha(void 0,[_i,A0]),(vf=()=>oe.PIE)()),pf=()=>(ha([Ux],[_i,E0]),(pf=()=>oe.POLAR)()),mf=()=>(ha([Du.eventrect,Ji,jx],[Xr,b0,{axis_x_categories:Lu.optAxis.axis_x_categories}]),(mf=()=>oe.RADAR)()),yf=()=>(da([yx,ca],[v0,Xr]),(yf=()=>oe.BAR)()),xf=()=>(da([ca,Ji,xx],[p0,Xr]),(xf=()=>oe.BUBBLE)()),Tf=()=>(da([Ex,ca],[m0,Xr]),(Tf=()=>oe.CANDLESTICK)()),$f=()=>(da([ca,Ji],[Xr,x0]),($f=()=>oe.SCATTER)()),Sf=()=>(ha([wx],[$0]),(Sf=()=>oe.FUNNEL)()),Af=()=>(da([g0],[R0]),(Af=()=>oe.TREEMAP)()),Os=Object.create(null);const Ef={version:"3.15.1",generate(t){const e=ea(Object.create(null),Os,t),n=new Er(e);return n.internal.charts=this.instance,this.instance.push(n),n},defaults(t){return Be(t)&&(Os=t),Os},instance:[],plugin:{}};Object.keys(d).forEach(t=>d[t]()),Object.keys(u).forEach(t=>u[t]())}],Xa={};function zn(x){var b=Xa[x];if(b!==void 0)return b.exports;var r=Xa[x]={exports:{}};return Cs[x].call(r.exports,r,r.exports,zn),r.exports}(function(){zn.d=function(x,b){for(var r in b)zn.o(b,r)&&!zn.o(x,r)&&Object.defineProperty(x,r,{enumerable:!0,get:b[r]})}})(),function(){zn.o=function(x,b){return Object.prototype.hasOwnProperty.call(x,b)}}(),function(){zn.r=function(x){typeof Symbol!="undefined"&&Symbol.toStringTag&&Object.defineProperty(x,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(x,"__esModule",{value:!0})}}(),zn(0);var Ha=zn(584);return Ha}()}); diff --git a/packages/image/build/report/_js/bootstrap.bundle.min.js b/packages/image/build/report/_js/bootstrap.bundle.min.js new file mode 100644 index 000000000..8739c91c5 --- /dev/null +++ b/packages/image/build/report/_js/bootstrap.bundle.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.3.6 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t.call(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function j(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function M(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${M(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${M(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1),e[i]=j(t.dataset[n])}return e},getDataAttribute:(t,e)=>j(t.getAttribute(`data-bs-${M(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.6"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map((t=>n(t))).join(","):null},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="ArrowLeft",lt="ArrowRight",ct="next",ht="prev",dt="left",ut="right",ft=`slide${ot}`,pt=`slid${ot}`,mt=`keydown${ot}`,gt=`mouseenter${ot}`,_t=`mouseleave${ot}`,bt=`dragstart${ot}`,vt=`load${ot}${rt}`,yt=`click${ot}${rt}`,wt="carousel",At="active",Et=".active",Tt=".carousel-item",Ct=Et+Tt,Ot={[at]:ut,[lt]:dt},xt={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},kt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class Lt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===wt&&this.cycle()}static get Default(){return xt}static get DefaultType(){return kt}static get NAME(){return"carousel"}next(){this._slide(ct)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(ht)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,pt,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,pt,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?ct:ht;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,mt,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,gt,(()=>this.pause())),N.on(this._element,_t,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,bt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(dt)),rightCallback:()=>this._slide(this._directionToOrder(ut)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Ot[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(Et,this._indicatorsElement);e.classList.remove(At),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(At),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===ct,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(ft).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(At),i.classList.remove(At,c,l),this._isSliding=!1,r(pt)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Ct,this._element)}_getItems(){return z.find(Tt,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===dt?ht:ct:t===dt?ct:ht}_orderToDirection(t){return p()?t===ht?dt:ut:t===ht?ut:dt}static jQueryInterface(t){return this.each((function(){const e=Lt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,yt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(wt))return;t.preventDefault();const i=Lt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,vt,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)Lt.getOrCreateInstance(e)})),m(Lt);const St=".bs.collapse",Dt=`show${St}`,$t=`shown${St}`,It=`hide${St}`,Nt=`hidden${St}`,Pt=`click${St}.data-api`,jt="show",Mt="collapse",Ft="collapsing",Ht=`:scope .${Mt} .${Mt}`,Wt='[data-bs-toggle="collapse"]',Bt={parent:null,toggle:!0},zt={parent:"(null|element)",toggle:"boolean"};class Rt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Wt);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Bt}static get DefaultType(){return zt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Rt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Dt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Mt),this._element.classList.add(Ft),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Ft),this._element.classList.add(Mt,jt),this._element.style[e]="",N.trigger(this._element,$t)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,It).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(Ft),this._element.classList.remove(Mt,jt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Ft),this._element.classList.add(Mt),N.trigger(this._element,Nt)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(jt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Wt);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(Ht,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Rt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,Pt,Wt,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Rt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Rt);var qt="top",Vt="bottom",Kt="right",Qt="left",Xt="auto",Yt=[qt,Vt,Kt,Qt],Ut="start",Gt="end",Jt="clippingParents",Zt="viewport",te="popper",ee="reference",ie=Yt.reduce((function(t,e){return t.concat([e+"-"+Ut,e+"-"+Gt])}),[]),ne=[].concat(Yt,[Xt]).reduce((function(t,e){return t.concat([e,e+"-"+Ut,e+"-"+Gt])}),[]),se="beforeRead",oe="read",re="afterRead",ae="beforeMain",le="main",ce="afterMain",he="beforeWrite",de="write",ue="afterWrite",fe=[se,oe,re,ae,le,ce,he,de,ue];function pe(t){return t?(t.nodeName||"").toLowerCase():null}function me(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function ge(t){return t instanceof me(t).Element||t instanceof Element}function _e(t){return t instanceof me(t).HTMLElement||t instanceof HTMLElement}function be(t){return"undefined"!=typeof ShadowRoot&&(t instanceof me(t).ShadowRoot||t instanceof ShadowRoot)}const ve={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];_e(s)&&pe(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});_e(n)&&pe(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function ye(t){return t.split("-")[0]}var we=Math.max,Ae=Math.min,Ee=Math.round;function Te(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ce(){return!/^((?!chrome|android).)*safari/i.test(Te())}function Oe(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&_e(t)&&(s=t.offsetWidth>0&&Ee(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&Ee(n.height)/t.offsetHeight||1);var r=(ge(t)?me(t):window).visualViewport,a=!Ce()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function xe(t){var e=Oe(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function ke(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&be(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Le(t){return me(t).getComputedStyle(t)}function Se(t){return["table","td","th"].indexOf(pe(t))>=0}function De(t){return((ge(t)?t.ownerDocument:t.document)||window.document).documentElement}function $e(t){return"html"===pe(t)?t:t.assignedSlot||t.parentNode||(be(t)?t.host:null)||De(t)}function Ie(t){return _e(t)&&"fixed"!==Le(t).position?t.offsetParent:null}function Ne(t){for(var e=me(t),i=Ie(t);i&&Se(i)&&"static"===Le(i).position;)i=Ie(i);return i&&("html"===pe(i)||"body"===pe(i)&&"static"===Le(i).position)?e:i||function(t){var e=/firefox/i.test(Te());if(/Trident/i.test(Te())&&_e(t)&&"fixed"===Le(t).position)return null;var i=$e(t);for(be(i)&&(i=i.host);_e(i)&&["html","body"].indexOf(pe(i))<0;){var n=Le(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Pe(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function je(t,e,i){return we(t,Ae(e,i))}function Me(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Fe(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const He={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=ye(i.placement),l=Pe(a),c=[Qt,Kt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Me("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Fe(t,Yt))}(s.padding,i),d=xe(o),u="y"===l?qt:Qt,f="y"===l?Vt:Kt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=Ne(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=je(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&ke(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function We(t){return t.split("-")[1]}var Be={top:"auto",right:"auto",bottom:"auto",left:"auto"};function ze(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Qt,y=qt,w=window;if(c){var A=Ne(i),E="clientHeight",T="clientWidth";A===me(i)&&"static"!==Le(A=De(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===qt||(s===Qt||s===Kt)&&o===Gt)&&(y=Vt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Qt&&(s!==qt&&s!==Vt||o!==Gt)||(v=Kt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&Be),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:Ee(i*s)/s||0,y:Ee(n*s)/s||0}}({x:f,y:m},me(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Re={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:ye(e.placement),variation:We(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,ze(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,ze(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var qe={passive:!0};const Ve={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=me(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,qe)})),a&&l.addEventListener("resize",i.update,qe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,qe)})),a&&l.removeEventListener("resize",i.update,qe)}},data:{}};var Ke={left:"right",right:"left",bottom:"top",top:"bottom"};function Qe(t){return t.replace(/left|right|bottom|top/g,(function(t){return Ke[t]}))}var Xe={start:"end",end:"start"};function Ye(t){return t.replace(/start|end/g,(function(t){return Xe[t]}))}function Ue(t){var e=me(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ge(t){return Oe(De(t)).left+Ue(t).scrollLeft}function Je(t){var e=Le(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ze(t){return["html","body","#document"].indexOf(pe(t))>=0?t.ownerDocument.body:_e(t)&&Je(t)?t:Ze($e(t))}function ti(t,e){var i;void 0===e&&(e=[]);var n=Ze(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=me(n),r=s?[o].concat(o.visualViewport||[],Je(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(ti($e(r)))}function ei(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ii(t,e,i){return e===Zt?ei(function(t,e){var i=me(t),n=De(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ce();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ge(t),y:l}}(t,i)):ge(e)?function(t,e){var i=Oe(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):ei(function(t){var e,i=De(t),n=Ue(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=we(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=we(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ge(t),l=-n.scrollTop;return"rtl"===Le(s||i).direction&&(a+=we(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(De(t)))}function ni(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?ye(s):null,r=s?We(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case qt:e={x:a,y:i.y-n.height};break;case Vt:e={x:a,y:i.y+i.height};break;case Kt:e={x:i.x+i.width,y:l};break;case Qt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Pe(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Ut:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Gt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function si(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Jt:a,c=i.rootBoundary,h=void 0===c?Zt:c,d=i.elementContext,u=void 0===d?te:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Me("number"!=typeof g?g:Fe(g,Yt)),b=u===te?ee:te,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=ti($e(t)),i=["absolute","fixed"].indexOf(Le(t).position)>=0&&_e(t)?Ne(t):t;return ge(i)?e.filter((function(t){return ge(t)&&ke(t,i)&&"body"!==pe(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ii(t,i,n);return e.top=we(s.top,e.top),e.right=Ae(s.right,e.right),e.bottom=Ae(s.bottom,e.bottom),e.left=we(s.left,e.left),e}),ii(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(ge(y)?y:y.contextElement||De(t.elements.popper),l,h,r),A=Oe(t.elements.reference),E=ni({reference:A,element:v,placement:s}),T=ei(Object.assign({},v,E)),C=u===te?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===te&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[Kt,Vt].indexOf(t)>=0?1:-1,i=[qt,Vt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function oi(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ne:l,h=We(n),d=h?a?ie:ie.filter((function(t){return We(t)===h})):Yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=si(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[ye(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const ri={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=ye(g),b=l||(_!==g&&p?function(t){if(ye(t)===Xt)return[];var e=Qe(t);return[Ye(t),e,Ye(e)]}(g):[Qe(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(ye(i)===Xt?oi(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=si(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?Kt:Qt:k?Vt:qt;y[S]>w[S]&&($=Qe($));var I=Qe($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},j=p?3:1;j>0&&"break"!==P(j);j--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function ai(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function li(t){return[qt,Kt,Vt,Qt].some((function(e){return t[e]>=0}))}const ci={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=si(e,{elementContext:"reference"}),a=si(e,{altBoundary:!0}),l=ai(r,n),c=ai(a,s,o),h=li(l),d=li(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},hi={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ne.reduce((function(t,i){return t[i]=function(t,e,i){var n=ye(t),s=[Qt,qt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Qt,Kt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},di={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ni({reference:e.rects.reference,element:e.rects.popper,placement:e.placement})},data:{}},ui={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=si(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=ye(e.placement),b=We(e.placement),v=!b,y=Pe(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?qt:Qt,D="y"===y?Vt:Kt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],j=f?-T[$]/2:0,M=b===Ut?E[$]:T[$],F=b===Ut?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?xe(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=je(0,E[$],W[$]),V=v?E[$]/2-j-q-z-O.mainAxis:M-q-z-O.mainAxis,K=v?-E[$]/2+j+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&Ne(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=je(f?Ae(N,I+V-Y-X):N,I,f?we(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?qt:Qt,tt="x"===y?Vt:Kt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[qt,Qt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=je(t,e,i);return n>i?i:n}(at,et,lt):je(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function fi(t,e,i){void 0===i&&(i=!1);var n,s,o=_e(e),r=_e(e)&&function(t){var e=t.getBoundingClientRect(),i=Ee(e.width)/t.offsetWidth||1,n=Ee(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=De(e),l=Oe(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==pe(e)||Je(a))&&(c=(n=e)!==me(n)&&_e(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Ue(n)),_e(e)?((h=Oe(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ge(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function pi(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var mi={placement:"bottom",modifiers:[],strategy:"absolute"};function gi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[void 0,t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Oi,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=Ki.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(ji);for(const i of e){const e=Ki.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ci,Oi].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Pi)?this:z.prev(this,Pi)[0]||z.next(this,Pi)[0]||z.findOne(Pi,t.delegateTarget.parentNode),o=Ki.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,$i,Pi,Ki.dataApiKeydownHandler),N.on(document,$i,Mi,Ki.dataApiKeydownHandler),N.on(document,Di,Ki.clearMenus),N.on(document,Ii,Ki.clearMenus),N.on(document,Di,Pi,(function(t){t.preventDefault(),Ki.getOrCreateInstance(this).toggle()})),m(Ki);const Qi="backdrop",Xi="show",Yi=`mousedown.bs.${Qi}`,Ui={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Gi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ji extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Ui}static get DefaultType(){return Gi}static get NAME(){return Qi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Xi),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Xi),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Yi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Yi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Zi=".bs.focustrap",tn=`focusin${Zi}`,en=`keydown.tab${Zi}`,nn="backward",sn={autofocus:!0,trapElement:null},on={autofocus:"boolean",trapElement:"element"};class rn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return sn}static get DefaultType(){return on}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Zi),N.on(document,tn,(t=>this._handleFocusin(t))),N.on(document,en,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Zi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===nn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?nn:"forward")}}const an=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",ln=".sticky-top",cn="padding-right",hn="margin-right";class dn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,cn,(e=>e+t)),this._setElementAttributes(an,cn,(e=>e+t)),this._setElementAttributes(ln,hn,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,cn),this._resetElementAttributes(an,cn),this._resetElementAttributes(ln,hn)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const un=".bs.modal",fn=`hide${un}`,pn=`hidePrevented${un}`,mn=`hidden${un}`,gn=`show${un}`,_n=`shown${un}`,bn=`resize${un}`,vn=`click.dismiss${un}`,yn=`mousedown.dismiss${un}`,wn=`keydown.dismiss${un}`,An=`click${un}.data-api`,En="modal-open",Tn="show",Cn="modal-static",On={backdrop:!0,focus:!0,keyboard:!0},xn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class kn extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new dn,this._addEventListeners()}static get Default(){return On}static get DefaultType(){return xn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,gn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(En),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,fn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Tn),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,un),N.off(this._dialog,un),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ji({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new rn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(Tn),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,_n,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,wn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,bn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,yn,(t=>{N.one(this._element,vn,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(En),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,mn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,pn).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(Cn)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(Cn),this._queueCallback((()=>{this._element.classList.remove(Cn),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=kn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,An,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,gn,(t=>{t.defaultPrevented||N.one(e,mn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&kn.getInstance(i).hide(),kn.getOrCreateInstance(e).toggle(this)})),R(kn),m(kn);const Ln=".bs.offcanvas",Sn=".data-api",Dn=`load${Ln}${Sn}`,$n="show",In="showing",Nn="hiding",Pn=".offcanvas.show",jn=`show${Ln}`,Mn=`shown${Ln}`,Fn=`hide${Ln}`,Hn=`hidePrevented${Ln}`,Wn=`hidden${Ln}`,Bn=`resize${Ln}`,zn=`click${Ln}${Sn}`,Rn=`keydown.dismiss${Ln}`,qn={backdrop:!0,keyboard:!0,scroll:!1},Vn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class Kn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return qn}static get DefaultType(){return Vn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,jn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new dn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(In),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add($n),this._element.classList.remove(In),N.trigger(this._element,Mn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,Fn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(Nn),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove($n,Nn),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new dn).reset(),N.trigger(this._element,Wn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ji({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,Hn)}:null})}_initializeFocusTrap(){return new rn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Rn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,Hn))}))}static jQueryInterface(t){return this.each((function(){const e=Kn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,zn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Wn,(()=>{a(this)&&this.focus()}));const i=z.findOne(Pn);i&&i!==e&&Kn.getInstance(i).hide(),Kn.getOrCreateInstance(e).toggle(this)})),N.on(window,Dn,(()=>{for(const t of z.find(Pn))Kn.getOrCreateInstance(t).show()})),N.on(window,Bn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&Kn.getOrCreateInstance(t).hide()})),R(Kn),m(Kn);const Qn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Xn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Yn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Un=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Xn.has(i)||Boolean(Yn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Gn={allowList:Qn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Jn={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Zn={entry:"(string|element|function|null)",selector:"(string|element)"};class ts extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Gn}static get DefaultType(){return Jn}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Zn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Un(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[void 0,this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const es=new Set(["sanitize","allowList","sanitizeFn"]),is="fade",ns="show",ss=".tooltip-inner",os=".modal",rs="hide.bs.modal",as="hover",ls="focus",cs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},hs={allowList:Qn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ds={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class us extends W{constructor(t,e){if(void 0===wi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org/docs/v2/)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(os),rs,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(ns),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(ns),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[ls]=!1,this._activeTrigger[as]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(is,ns),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(is),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new ts({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{[ss]:this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(is)}_isShown(){return this.tip&&this.tip.classList.contains(ns)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=cs[e.toUpperCase()];return yi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element,this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[void 0,e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===as?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===as?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?ls:as]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?ls:as]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(os),rs,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))es.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".popover-header",ps=".popover-body",ms={...us.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},gs={...us.DefaultType,content:"(null|string|element|function)"};class _s extends us{static get Default(){return ms}static get DefaultType(){return gs}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{[fs]:this._getTitle(),[ps]:this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=_s.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(_s);const bs=".bs.scrollspy",vs=`activate${bs}`,ys=`click${bs}`,ws=`load${bs}.data-api`,As="active",Es="[href]",Ts=".nav-link",Cs=`${Ts}, .nav-item > ${Ts}, .list-group-item`,Os={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},xs={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class ks extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return Os}static get DefaultType(){return xs}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ys),N.on(this._config.target,ys,Es,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(Es,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(As),this._activateParents(t),N.trigger(this._element,vs,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(As);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,Cs))t.classList.add(As)}_clearActiveClass(t){t.classList.remove(As);const e=z.find(`${Es}.${As}`,t);for(const t of e)t.classList.remove(As)}static jQueryInterface(t){return this.each((function(){const e=ks.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,ws,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))ks.getOrCreateInstance(t)})),m(ks);const Ls=".bs.tab",Ss=`hide${Ls}`,Ds=`hidden${Ls}`,$s=`show${Ls}`,Is=`shown${Ls}`,Ns=`click${Ls}`,Ps=`keydown${Ls}`,js=`load${Ls}`,Ms="ArrowLeft",Fs="ArrowRight",Hs="ArrowUp",Ws="ArrowDown",Bs="Home",zs="End",Rs="active",qs="fade",Vs="show",Ks=".dropdown-toggle",Qs=`:not(${Ks})`,Xs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Ys=`.nav-link${Qs}, .list-group-item${Qs}, [role="tab"]${Qs}, ${Xs}`,Us=`.${Rs}[data-bs-toggle="tab"], .${Rs}[data-bs-toggle="pill"], .${Rs}[data-bs-toggle="list"]`;class Gs extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ps,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Ss,{relatedTarget:t}):null;N.trigger(t,$s,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Rs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,Is,{relatedTarget:e})):t.classList.add(Vs)}),t,t.classList.contains(qs)))}_deactivate(t,e){t&&(t.classList.remove(Rs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Ds,{relatedTarget:e})):t.classList.remove(Vs)}),t,t.classList.contains(qs)))}_keydown(t){if(![Ms,Fs,Hs,Ws,Bs,zs].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([Bs,zs].includes(t.key))i=e[t.key===Bs?0:e.length-1];else{const n=[Fs,Ws].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Gs.getOrCreateInstance(i).show())}_getChildren(){return z.find(Ys,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(Ks,Rs),n(".dropdown-menu",Vs),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Rs)}_getInnerElement(t){return t.matches(Ys)?t:z.findOne(Ys,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Gs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ns,Xs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Gs.getOrCreateInstance(this).show()})),N.on(window,js,(()=>{for(const t of z.find(Us))Gs.getOrCreateInstance(t)})),m(Gs);const Js=".bs.toast",Zs=`mouseover${Js}`,to=`mouseout${Js}`,eo=`focusin${Js}`,io=`focusout${Js}`,no=`hide${Js}`,so=`hidden${Js}`,oo=`show${Js}`,ro=`shown${Js}`,ao="hide",lo="show",co="showing",ho={animation:"boolean",autohide:"boolean",delay:"number"},uo={animation:!0,autohide:!0,delay:5e3};class fo extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return uo}static get DefaultType(){return ho}static get NAME(){return"toast"}show(){N.trigger(this._element,oo).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(ao),d(this._element),this._element.classList.add(lo,co),this._queueCallback((()=>{this._element.classList.remove(co),N.trigger(this._element,ro),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,no).defaultPrevented||(this._element.classList.add(co),this._queueCallback((()=>{this._element.classList.add(ao),this._element.classList.remove(co,lo),N.trigger(this._element,so)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(lo),super.dispose()}isShown(){return this._element.classList.contains(lo)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Zs,(t=>this._onInteraction(t,!0))),N.on(this._element,to,(t=>this._onInteraction(t,!1))),N.on(this._element,eo,(t=>this._onInteraction(t,!0))),N.on(this._element,io,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=fo.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(fo),m(fo),{Alert:Q,Button:Y,Carousel:Lt,Collapse:Rt,Dropdown:Ki,Modal:kn,Offcanvas:Kn,Popover:_s,ScrollSpy:ks,Tab:Gs,Toast:fo,Tooltip:us}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/packages/image/build/report/_js/file.js b/packages/image/build/report/_js/file.js new file mode 100644 index 000000000..124a8a18f --- /dev/null +++ b/packages/image/build/report/_js/file.js @@ -0,0 +1,53 @@ +$(function () { + var $window = $(window) + , $top_link = $('#toplink') + , $body = $('body, html') + , offset = $('#code').offset().top; + + $top_link.hide().click(function (event) { + event.preventDefault(); + $body.animate({scrollTop: 0}, 800); + }); + + $window.scroll(function () { + if ($window.scrollTop() > offset) { + $top_link.fadeIn(); + } else { + $top_link.fadeOut(); + } + }); + + var $popovers = $('.popin > :first-child'); + $('.popin').on({ + 'click.popover': function (event) { + event.stopPropagation(); + + var $container = $(this).children().first(); + + //Close all other popovers: + $popovers.each(function () { + var $current = $(this); + if (!$current.is($container)) { + $current.popover('hide'); + } + }); + + // Toggle this popover: + $container.popover('toggle'); + }, + }); + + //Hide all popovers on outside click: + $(document).click(function (event) { + if ($(event.target).closest($('.popover')).length === 0) { + $popovers.popover('hide'); + } + }); + + //Hide all popovers on escape: + $(document).keyup(function (event) { + if (event.key === 'Escape') { + $popovers.popover('hide'); + } + }); +}); diff --git a/packages/image/build/report/_js/jquery.min.js b/packages/image/build/report/_js/jquery.min.js new file mode 100644 index 000000000..798cc8bf7 --- /dev/null +++ b/packages/image/build/report/_js/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="
",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0 - -> + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/image/src/Charcoal/Image/AbstractEffect.php b/packages/image/src/Charcoal/Image/AbstractEffect.php index 23a0bf7f8..3865ef17e 100644 --- a/packages/image/src/Charcoal/Image/AbstractEffect.php +++ b/packages/image/src/Charcoal/Image/AbstractEffect.php @@ -12,10 +12,7 @@ */ abstract class AbstractEffect implements EffectInterface { - /** - * @var ImageInterface $image - */ - private $image; + private ?\Charcoal\Image\ImageInterface $image = null; /** * @param ImageInterface $image The parent image. @@ -33,7 +30,7 @@ public function setImage(ImageInterface $image) */ public function image() { - if ($this->image === null) { + if (!$this->image instanceof \Charcoal\Image\ImageInterface) { throw new Exception( 'Can not get effect\'s image: Trying to access an unset image' ); @@ -60,7 +57,7 @@ public function setData(array $data) * @param array $data Optional effect data. If null, use the currently set properties. * @return AbstractEffect Chainable */ - abstract public function process(array $data = null); + abstract public function process(?array $data = null); /** * Allow an object to define how the key setter are called. @@ -68,7 +65,7 @@ abstract public function process(array $data = null); * @param string $key The key to get the setter from. * @return string The setter method name, for a given key. */ - protected function setter($key) + protected function setter(string $key) { $setter = 'set_' . $key; return $this->camelize($setter); @@ -82,6 +79,6 @@ protected function setter($key) */ protected function camelize($str) { - return lcfirst(implode('', array_map('ucfirst', explode('_', $str)))); + return lcfirst(implode('', array_map(ucfirst(...), explode('_', $str)))); } } diff --git a/packages/image/src/Charcoal/Image/AbstractImage.php b/packages/image/src/Charcoal/Image/AbstractImage.php index 3e61ce276..56c62367b 100644 --- a/packages/image/src/Charcoal/Image/AbstractImage.php +++ b/packages/image/src/Charcoal/Image/AbstractImage.php @@ -28,10 +28,7 @@ abstract class AbstractImage implements ImageInterface */ protected $effects = []; - /** - * @var EffectFactory $effectFactory - */ - private $effectFactory; + private ?\Charcoal\Image\EffectFactory $effectFactory = null; /** @@ -43,7 +40,7 @@ abstract class AbstractImage implements ImageInterface * @param array $data The effect options. * @return ImageInterface Chainable */ - public function __call($fxType, array $data) + public function __call(string $fxType, array $data) { $data['type'] = $fxType; @@ -61,7 +58,7 @@ public function __call($fxType, array $data) */ protected function effectFactory() { - if ($this->effectFactory === null) { + if (!$this->effectFactory instanceof \Charcoal\Image\EffectFactory) { $this->effectFactory = new EffectFactory(); } return $this->effectFactory; @@ -175,7 +172,7 @@ public function addEffect($effect) * @param array $effects Optional. The effects to process. If null, use in-memory's. * @return ImageInterface Chainable */ - public function process(array $effects = null) + public function process(?array $effects = null) { if ($effects !== null) { $this->setEffects($effects); @@ -255,9 +252,7 @@ public function ratio() 'Ratio can not be calculated. Invalid image dimensions' ); } - - $ratio = ($width / $height); - return $ratio; + return ($width / $height); } /** @@ -320,7 +315,7 @@ protected function createEffect($effect) ); } $fxType = $effect['type']; - if (strstr($fxType, '/') === false) { + if (!str_contains((string)$fxType, '/')) { // Core effects do not need to be namespaced $driver = $this->driverType(); $fxType = 'charcoal/image/' . $driver . '/effect/' . $driver . '-' . $fxType . '-effect'; diff --git a/packages/image/src/Charcoal/Image/Effect/AbstractAutoorientationEffect.php b/packages/image/src/Charcoal/Image/Effect/AbstractAutoorientationEffect.php index 0b1e716e7..cde5801c4 100644 --- a/packages/image/src/Charcoal/Image/Effect/AbstractAutoorientationEffect.php +++ b/packages/image/src/Charcoal/Image/Effect/AbstractAutoorientationEffect.php @@ -1,5 +1,7 @@ setData($data); } $mode = $this->mode(); - switch ($mode) { - case 'adaptive': - return $this->processAdaptive(); - - case 'gaussian': - return $this->processGaussian(); - - case 'motion': - return $this->processMotion(); - - case 'radial': - return $this->processRadial(); - - case 'soft': - return $this->processSoft(); - - case 'standard': - default: - return $this->processStandard(); - } + return match ($mode) { + 'adaptive' => $this->processAdaptive(), + 'gaussian' => $this->processGaussian(), + 'motion' => $this->processMotion(), + 'radial' => $this->processRadial(), + 'soft' => $this->processSoft(), + default => $this->processStandard(), + }; } /** diff --git a/packages/image/src/Charcoal/Image/Effect/AbstractCompressionEffect.php b/packages/image/src/Charcoal/Image/Effect/AbstractCompressionEffect.php index b9cf71f5d..bc7070cc0 100644 --- a/packages/image/src/Charcoal/Image/Effect/AbstractCompressionEffect.php +++ b/packages/image/src/Charcoal/Image/Effect/AbstractCompressionEffect.php @@ -1,5 +1,7 @@ repage = !!$repage; + $this->repage = (bool)$repage; return $this; } @@ -220,7 +202,7 @@ public function repage() * @param array $data The effect data. * @return AbstractCropEffect */ - public function process(array $data = null) + public function process(?array $data = null) { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Effect/AbstractDitherEffect.php b/packages/image/src/Charcoal/Image/Effect/AbstractDitherEffect.php index 3ef49b447..e38bdffde 100644 --- a/packages/image/src/Charcoal/Image/Effect/AbstractDitherEffect.php +++ b/packages/image/src/Charcoal/Image/Effect/AbstractDitherEffect.php @@ -1,5 +1,7 @@ height = (int)$height; + $this->height = $height; return $this; } @@ -329,7 +299,7 @@ public function backgroundColor() */ public function setAdaptive($adaptive) { - $this->adaptive = !!$adaptive; + $this->adaptive = (bool)$adaptive; return $this; } @@ -355,12 +325,10 @@ public function autoMode() return 'width'; } elseif ($height > 0) { return 'height'; + } elseif ($this->minWidth() || $this->minHeight() || $this->maxWidth() || $this->maxHeight()) { + return 'constraints'; } else { - if ($this->minWidth() || $this->minHeight() || $this->maxWidth() || $this->maxHeight()) { - return 'constraints'; - } else { - return 'none'; - } + return 'none'; } } @@ -369,7 +337,7 @@ public function autoMode() * @throws Exception If the effect data is invalid for its resize mode. * @return self */ - public function process(array $data = null) + public function process(?array $data = null) { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Effect/AbstractRotateEffect.php b/packages/image/src/Charcoal/Image/Effect/AbstractRotateEffect.php index 708eccda2..64cf29822 100644 --- a/packages/image/src/Charcoal/Image/Effect/AbstractRotateEffect.php +++ b/packages/image/src/Charcoal/Image/Effect/AbstractRotateEffect.php @@ -1,5 +1,7 @@ setData($data); } $mode = $this->mode(); - switch ($mode) { - case 'adaptive': - return $this->processAdaptive(); - - case 'unsharp': - return $this->processUnsharp(); - - case 'standard': - default: - return $this->processStandard(); - } + return match ($mode) { + 'adaptive' => $this->processAdaptive(), + 'unsharp' => $this->processUnsharp(), + default => $this->processStandard(), + }; } /** diff --git a/packages/image/src/Charcoal/Image/Effect/AbstractThresholdEffect.php b/packages/image/src/Charcoal/Image/Effect/AbstractThresholdEffect.php index 586ccbd88..177d26a0f 100644 --- a/packages/image/src/Charcoal/Image/Effect/AbstractThresholdEffect.php +++ b/packages/image/src/Charcoal/Image/Effect/AbstractThresholdEffect.php @@ -1,5 +1,7 @@ midtone = !!$midtone; + $this->midtone = (bool)$midtone; return $this; } diff --git a/packages/image/src/Charcoal/Image/Effect/AbstractWatermarkEffect.php b/packages/image/src/Charcoal/Image/Effect/AbstractWatermarkEffect.php index 30828bc77..69cc2f862 100644 --- a/packages/image/src/Charcoal/Image/Effect/AbstractWatermarkEffect.php +++ b/packages/image/src/Charcoal/Image/Effect/AbstractWatermarkEffect.php @@ -1,5 +1,7 @@ defaultMap(), $data['map']); - } else { - $data['map'] = $this->defaultMap(); - } + $data['map'] = isset($data['map']) ? array_merge($this->defaultMap(), $data['map']) : $this->defaultMap(); parent::__construct($data); } - /** - * @return array - */ - protected function defaultMap() + protected function defaultMap(): array { return [ - 'imagick' => '\Charcoal\Image\Imagick\ImagickImage', - 'imagemagick' => '\Charcoal\Image\Imagemagick\ImagemagickImage' + 'imagick' => \Charcoal\Image\Imagick\ImagickImage::class, + 'imagemagick' => \Charcoal\Image\Imagemagick\ImagemagickImage::class ]; } } diff --git a/packages/image/src/Charcoal/Image/ImageInterface.php b/packages/image/src/Charcoal/Image/ImageInterface.php index dc080978d..79dfd0dc7 100644 --- a/packages/image/src/Charcoal/Image/ImageInterface.php +++ b/packages/image/src/Charcoal/Image/ImageInterface.php @@ -1,5 +1,7 @@ setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickBlurEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickBlurEffect.php index b3b6af59d..5b3ab5e21 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickBlurEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickBlurEffect.php @@ -9,10 +9,7 @@ */ class ImagemagickBlurEffect extends AbstractBlurEffect { - /** - * @return self - */ - public function processAdaptive() + public function processAdaptive(): static { $channel = $this->image()->convertChannel($this->channel()); $cmd = '-channel ' . $channel . ' -adaptive-blur ' . $this->radius() . 'x' . $this->sigma(); @@ -20,10 +17,7 @@ public function processAdaptive() return $this; } - /** - * @return self - */ - public function processGaussian() + public function processGaussian(): static { $channel = $this->image()->convertChannel($this->channel()); $cmd = '-channel ' . $channel . ' -gaussian-blur ' . $this->radius() . 'x' . $this->sigma(); @@ -31,10 +25,7 @@ public function processGaussian() return $this; } - /** - * @return self - */ - public function processMotion() + public function processMotion(): static { $channel = $this->image()->convertChannel($this->channel()); $cmd = '-channel ' . $channel . ' -motion-blur ' . $this->radius() . 'x' . $this->sigma() . '+' . $this->angle(); @@ -42,10 +33,7 @@ public function processMotion() return $this; } - /** - * @return self - */ - public function processRadial() + public function processRadial(): static { $channel = $this->image()->convertChannel($this->channel()); $cmd = '-channel ' . $channel . ' -rotational-blur ' . $this->angle(); @@ -53,20 +41,14 @@ public function processRadial() return $this; } - /** - * @return self - */ - public function processSoft() + public function processSoft(): static { $cmd = '-define convolve:scale=60,40% -morphology Convolve \'Gaussian:' . $this->radius() . 'x' . $this->sigma() . '\''; $this->image()->applyCmd($cmd); return $this; } - /** - * @return self - */ - public function processStandard() + public function processStandard(): static { $channel = $this->image()->convertChannel($this->channel()); $cmd = '-channel ' . $channel . ' -blur ' . $this->radius() . 'x' . $this->sigma(); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickCompressionEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickCompressionEffect.php index d439f3221..f53d9efe6 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickCompressionEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickCompressionEffect.php @@ -11,9 +11,8 @@ class ImagemagickCompressionEffect extends AbstractCompressionEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickDitherEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickDitherEffect.php index 22875805b..639097ff5 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickDitherEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickDitherEffect.php @@ -1,5 +1,7 @@ setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickFormatEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickFormatEffect.php index 06bdc75c1..dc6daf5c4 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickFormatEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickFormatEffect.php @@ -1,5 +1,7 @@ setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickGrayscaleEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickGrayscaleEffect.php index 06b8e7725..bb610be0b 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickGrayscaleEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickGrayscaleEffect.php @@ -13,7 +13,7 @@ class ImagemagickGrayscaleEffect extends AbstractGrayscaleEffect * @param array $data The effect data, if available. * @return self */ - public function process(array $data = null) + public function process(?array $data = null) { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickMaskEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickMaskEffect.php index fba4e6138..70e965306 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickMaskEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickMaskEffect.php @@ -1,5 +1,7 @@ setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickMirrorEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickMirrorEffect.php index c56aa1b51..11799efb0 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickMirrorEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickMirrorEffect.php @@ -11,20 +11,15 @@ class ImagemagickMirrorEffect extends AbstractMirrorEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); } $axis = $this->axis(); - if ($axis == 'x') { - $cmd = '-flip'; - } else { - $cmd = '-flop'; - } + $cmd = $axis == 'x' ? '-flip' : '-flop'; $this->image()->applyCmd($cmd); return $this; } diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickModulateEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickModulateEffect.php index 43c3f7318..7068da2b8 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickModulateEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickModulateEffect.php @@ -11,9 +11,8 @@ class ImagemagickModulateEffect extends AbstractModulateEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickResizeEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickResizeEffect.php index f4e325329..ed12b3cae 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickResizeEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickResizeEffect.php @@ -20,11 +20,7 @@ class ImagemagickResizeEffect extends AbstractResizeEffect */ protected function doResize($width, $height, $bestFit = false) { - if ($this->adaptive()) { - $option = '-adaptive-resize'; - } else { - $option = '-resize'; - } + $option = $this->adaptive() ? '-adaptive-resize' : '-resize'; $size = $this->size(); if ($size) { diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickRevertEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickRevertEffect.php index 9109f6aca..7e5a2891c 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickRevertEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickRevertEffect.php @@ -11,9 +11,8 @@ class ImagemagickRevertEffect extends AbstractRevertEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickRotateEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickRotateEffect.php index 39f20f4d4..2fc48e7db 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickRotateEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickRotateEffect.php @@ -11,9 +11,8 @@ class ImagemagickRotateEffect extends AbstractRotateEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickSepiaEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickSepiaEffect.php index 5f5f699b7..41aeab7be 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickSepiaEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickSepiaEffect.php @@ -11,9 +11,8 @@ class ImagemagickSepiaEffect extends AbstractSepiaEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickSharpenEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickSharpenEffect.php index 336b29610..45d6e8b66 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickSharpenEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickSharpenEffect.php @@ -9,10 +9,7 @@ */ class ImagemagickSharpenEffect extends AbstractSharpenEffect { - /** - * @return self - */ - public function processAdaptive() + public function processAdaptive(): static { $radius = $this->radius(); $sigma = $this->sigma(); @@ -22,10 +19,7 @@ public function processAdaptive() return $this; } - /** - * @return self - */ - public function processUnsharp() + public function processUnsharp(): static { $radius = $this->radius(); $sigma = $this->sigma(); @@ -38,10 +32,7 @@ public function processUnsharp() return $this; } - /** - * @return self - */ - public function processStandard() + public function processStandard(): static { $radius = $this->radius(); $sigma = $this->sigma(); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickThresholdEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickThresholdEffect.php index d9e78e534..1a4b57aa0 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickThresholdEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickThresholdEffect.php @@ -11,9 +11,8 @@ class ImagemagickThresholdEffect extends AbstractThresholdEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickTintEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickTintEffect.php index 94c59c73f..a6b7e2ca2 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickTintEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickTintEffect.php @@ -11,19 +11,14 @@ class ImagemagickTintEffect extends AbstractTintEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); } - if ($this->midtone() === true) { - $tintCmd = '-tint'; - } else { - $tintCmd = '-colorize'; - } + $tintCmd = $this->midtone() === true ? '-tint' : '-colorize'; $color = $this->color(); $value = ($this->opacity() * 100) . '%'; $cmd = '-fill "' . $color . '" ' . $tintCmd . ' ' . $value; diff --git a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickWatermarkEffect.php b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickWatermarkEffect.php index f4f3caffa..f06888e2e 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickWatermarkEffect.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/Effect/ImagemagickWatermarkEffect.php @@ -12,9 +12,8 @@ class ImagemagickWatermarkEffect extends AbstractWatermarkEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); @@ -28,7 +27,7 @@ public function process(array $data = null) $watermark = $out; } else { $watermark = $this->watermark(); - $c = get_class($this->image()); + $c = $this->image()::class; $w = new $c(); $w->open($watermark); $width = $w->width(); diff --git a/packages/image/src/Charcoal/Image/Imagemagick/ImagemagickImage.php b/packages/image/src/Charcoal/Image/Imagemagick/ImagemagickImage.php index f4e6ca967..777254ac4 100644 --- a/packages/image/src/Charcoal/Image/Imagemagick/ImagemagickImage.php +++ b/packages/image/src/Charcoal/Image/Imagemagick/ImagemagickImage.php @@ -17,9 +17,8 @@ class ImagemagickImage extends AbstractImage { /** * The temporary file location - * @var string|null $tmpFile */ - private $tmpFile; + private ?string $tmpFile = null; /** * @var string $mogrifyCmd @@ -59,10 +58,7 @@ public function __destruct() $this->resetTmp(); } - /** - * @return string - */ - public function driverType() + public function driverType(): string { return 'imagemagick'; } @@ -74,9 +70,8 @@ public function driverType() * @param integer $height Image height, in pixels. * @param string $color Default to transparent. * @throws InvalidArgumentException If the size arguments are not valid. - * @return self */ - public function create($width, $height, $color = 'rgb(100%, 100%, 100%, 0)') + public function create($width, $height, $color = 'rgb(100%, 100%, 100%, 0)'): static { if (!is_numeric($width) || $width < 1) { throw new InvalidArgumentException( @@ -101,9 +96,8 @@ public function create($width, $height, $color = 'rgb(100%, 100%, 100%, 0)') * @param string $source The source path / filename. * @throws Exception If the source file does not exist. * @throws InvalidArgumentException If the source argument is not a string. - * @return self */ - public function open($source = null) + public function open($source = null): static { if ($source !== null && !is_string($source)) { throw new InvalidArgumentException( @@ -111,14 +105,12 @@ public function open($source = null) ); } - $source = ($source) ? $source : $this->source(); + $source = $source ?: $this->source(); $this->resetTmp(); - if (!file_exists($source)) { - if (null === parse_url($source, PHP_URL_HOST)) { - throw new Exception( - sprintf('File "%s" does not exist', $source) - ); - } + if (!file_exists($source) && null === parse_url($source, PHP_URL_HOST)) { + throw new Exception( + sprintf('File "%s" does not exist', $source) + ); } copy($source, $this->tmp()); @@ -133,9 +125,8 @@ public function open($source = null) * @param string $target The target path / filename. * @throws Exception If the target file does not exist or is not writeable. * @throws InvalidArgumentException If the target argument is not a string. - * @return self */ - public function save($target = null) + public function save($target = null): static { if ($target !== null && !is_string($target)) { throw new InvalidArgumentException( @@ -143,7 +134,7 @@ public function save($target = null) ); } - $target = ($target) ? $target : $this->target(); + $target = $target ?: $this->target(); if (!is_writable(dirname($target))) { throw new Exception( sprintf('Target "%s" is not writable', $target) @@ -157,10 +148,8 @@ public function save($target = null) /** * Get the image's width, in pixels - * - * @return integer */ - public function width() + public function width(): int { if (!file_exists($this->tmp())) { return 0; @@ -171,10 +160,8 @@ public function width() /** * Get the image's height, in pixels - * - * @return integer */ - public function height() + public function height(): int { if (!file_exists($this->tmp())) { return 0; @@ -185,9 +172,8 @@ public function height() /** * @param string $channel The channel name to convert. - * @return string */ - public function convertChannel($channel) + public function convertChannel($channel): string { return ucfirst($channel); } @@ -211,13 +197,13 @@ protected function findCmd($cmdName) if (!is_string($cmdName)) { throw new InvalidArgumentException(sprintf( 'Target image must be a string, received %s', - (is_object($cmdName) ? get_class($cmdName) : gettype($cmdName)) + (get_debug_type($cmdName)) )); } if (!in_array($cmdName, $this->availableCommands())) { if (!is_string($cmdName)) { - $cmdName = (is_object($cmdName) ? get_class($cmdName) : gettype($cmdName)); + $cmdName = (get_debug_type($cmdName)); } throw new OutOfBoundsException(sprintf( 'Unsupported command "%s" provided', @@ -228,7 +214,7 @@ protected function findCmd($cmdName) $cmd = exec('type -p ' . $cmdName); $cmd = str_replace($cmdName . ' is ', '', $cmd); - if (!$cmd) { + if ($cmd === '' || $cmd === '0') { $cmd = exec('where ' . $cmdName); } @@ -248,10 +234,8 @@ protected function findCmd($cmdName) /** * Retrieve the list of available commands. - * - * @return array */ - public function availableCommands() + public function availableCommands(): array { return [ 'mogrify', 'convert', 'composite', 'identify' ]; } @@ -269,7 +253,7 @@ public function cmd($name) if (!is_string($name)) { throw new InvalidArgumentException(sprintf( 'Command name must be a string, received %s', - (is_object($name) ? get_class($name) : gettype($name)) + (get_debug_type($name)) )); } @@ -288,7 +272,7 @@ public function cmd($name) default: if (!is_string($name)) { - $name = (is_object($name) ? get_class($name) : gettype($name)); + $name = (get_debug_type($name)); } throw new OutOfBoundsException(sprintf( 'Unsupported command "%s" provided', @@ -347,10 +331,8 @@ public function identifyCmd() /** * Generate a temporary file, to apply effects on. - * - * @return string */ - public function tmp() + public function tmp(): string { if ($this->tmpFile !== null) { return $this->tmpFile; @@ -363,7 +345,7 @@ public function tmp() /** * @return ImagemagickImage Chainable */ - public function resetTmp() + public function resetTmp(): static { if (file_exists($this->tmpFile)) { unlink($this->tmpFile); @@ -383,7 +365,7 @@ public function resetTmp() * @throws Exception If the command fails. * @return string */ - public function exec($cmd) + public function exec(string $cmd): string|false|null { if (function_exists('proc_open')) { $proc = proc_open( @@ -408,9 +390,7 @@ public function exec($cmd) return $out; } else { - $ret = shell_exec($cmd); - - return $ret; + return shell_exec($cmd); } } @@ -420,13 +400,9 @@ public function exec($cmd) * @throws Exception If the tmp file was not properly set. * @return ImagemagickImage Chainable */ - public function applyCmd($params, $cmd = null) + public function applyCmd(string $params, $cmd = null): static { - if ($cmd === null) { - $cmd = $this->mogrifyCmd(); - } else { - $cmd = $this->cmd($cmd); - } + $cmd = $cmd === null ? $this->mogrifyCmd() : $this->cmd($cmd); if (!file_exists($this->tmp())) { throw new Exception( @@ -444,9 +420,8 @@ public function applyCmd($params, $cmd = null) * * @param string $gravity The standard gravity name. * @throws InvalidArgumentException If the gravity argument is not a valid gravity. - * @return integer */ - public function imagemagickGravity($gravity) + public function imagemagickGravity($gravity): string { $gravityMap = [ 'center' => 'center', diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickAutoorientationEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickAutoorientationEffect.php index 630f0bd23..3f4517b41 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickAutoorientationEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickAutoorientationEffect.php @@ -14,7 +14,7 @@ class ImagickAutoorientationEffect extends AbstractAutoorientationEffect * @param array $data The effect data, if available. * @return ImagickAutoorientationEffect Chainable */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickBlurEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickBlurEffect.php index 2431759e1..0541a2ac0 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickBlurEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickBlurEffect.php @@ -13,7 +13,7 @@ class ImagickBlurEffect extends AbstractBlurEffect /** * @return ImagickBlurEffect Chainable */ - public function processAdaptive() + public function processAdaptive(): static { $channel = $this->image()->imagickChannel($this->channel()); $this->image()->imagick()->adaptiveBlurImage($this->radius(), $this->sigma(), $channel); @@ -23,7 +23,7 @@ public function processAdaptive() /** * @return ImagickBlurEffect Chainable */ - public function processGaussian() + public function processGaussian(): static { $channel = $this->image()->imagickChannel($this->channel()); $this->image()->imagick()->gaussianBlurImage($this->radius(), $this->sigma(), $channel); @@ -33,7 +33,7 @@ public function processGaussian() /** * @return ImagickBlurEffect Chainable */ - public function processMotion() + public function processMotion(): static { $channel = $this->image()->imagickChannel($this->channel()); $this->image()->imagick()->motionBlurImage($this->radius(), $this->sigma(), $this->angle(), $channel); @@ -43,7 +43,7 @@ public function processMotion() /** * @return ImagickBlurEffect Chainable */ - public function processRadial() + public function processRadial(): static { $angle = $this->angle(); $channel = $this->image()->imagickChannel($this->channel()); @@ -53,9 +53,8 @@ public function processRadial() /** * @throws Exception This method is not yet supported on Imagick. - * @return void */ - public function processSoft() + public function processSoft(): never { throw new Exception( 'Soft blur is not (yet) supported with imagick driver.' @@ -65,7 +64,7 @@ public function processSoft() /** * @return ImagickBlurEffect Chainable */ - public function processStandard() + public function processStandard(): static { $channel = $this->image()->imagickChannel($this->channel()); $this->image()->imagick()->blurImage($this->radius(), $this->sigma(), $channel); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickCompressionEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickCompressionEffect.php index cf31ad4bc..754a1db9a 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickCompressionEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickCompressionEffect.php @@ -11,16 +11,15 @@ class ImagickCompressionEffect extends AbstractCompressionEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); } - $target = $this->image()->target(); - $extension = strtolower($this->image()->imagick()->getImageFormat()); + $this->image()->target(); + $extension = strtolower((string)$this->image()->imagick()->getImageFormat()); $invalidExtensions = [ 'gif', 'bmp' ]; diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickDitherEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickDitherEffect.php index 8c054afe7..f7bbacff1 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickDitherEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickDitherEffect.php @@ -14,7 +14,7 @@ class ImagickDitherEffect extends AbstractDitherEffect * @param array $data The effect data, if available. * @return ImagickDitherEffect Chainable */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickFormatEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickFormatEffect.php index bd7cc6c02..d41d4d8d9 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickFormatEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickFormatEffect.php @@ -14,7 +14,7 @@ class ImagickFormatEffect extends AbstractFormatEffect * @param array $data The effect data, if available. * @return ImageFormatEffect Chainable */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($this->format()) { $this->image()->imagick()->setimageFormat($this->format()); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickGrayscaleEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickGrayscaleEffect.php index f9637ae29..b5b4fc593 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickGrayscaleEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickGrayscaleEffect.php @@ -14,7 +14,7 @@ class ImagickGrayscaleEffect extends AbstractGrayscaleEffect * @param array $data The effect data, if available. * @return ImagickGrayscaleEffect Chainable */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickMaskEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickMaskEffect.php index d52307a33..1673d50c9 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickMaskEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickMaskEffect.php @@ -1,5 +1,7 @@ setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickMirrorEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickMirrorEffect.php index 8e2a7d022..169754920 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickMirrorEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickMirrorEffect.php @@ -11,9 +11,8 @@ class ImagickMirrorEffect extends AbstractMirrorEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickModulateEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickModulateEffect.php index 626d60609..d65acbe74 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickModulateEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickModulateEffect.php @@ -13,7 +13,7 @@ class ImagickModulateEffect extends AbstractModulateEffect * @param array $data The effect data, if available. * @return AbstractModulateEffect Chainable */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickRevertEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickRevertEffect.php index 0892a1b88..f2767ad85 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickRevertEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickRevertEffect.php @@ -13,7 +13,7 @@ class ImagickRevertEffect extends AbstractRevertEffect * @param array $data The effect data, if available. * @return ImagickRevertEffect Chainable */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickRotateEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickRotateEffect.php index 46ac9b131..cf4cc4a00 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickRotateEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickRotateEffect.php @@ -13,7 +13,7 @@ class ImagickRotateEffect extends AbstractRotateEffect * @param array $data The effect data, if available. * @return ImagickRotateEffect Chainable */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickSepiaEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickSepiaEffect.php index 7171b3660..671cf0505 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickSepiaEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickSepiaEffect.php @@ -13,7 +13,7 @@ class ImagickSepiaEffect extends AbstractSepiaEffect * @param array $data The effect data, if available. * @return ImagickSepiaEffect Chainable */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickSharpenEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickSharpenEffect.php index 1af3ab40a..d9f05b759 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickSharpenEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickSharpenEffect.php @@ -12,7 +12,7 @@ class ImagickSharpenEffect extends AbstractSharpenEffect /** * @return ImagickSharpenEffect Chainable */ - public function processAdaptive() + public function processAdaptive(): static { $channel = $this->image()->imagickChannel($this->channel()); $this->image()->imagick()->adaptiveAbstractSharpenEffectImage($this->radius(), $this->sigma(), $channel); @@ -22,7 +22,7 @@ public function processAdaptive() /** * @return ImagickSharpenEffect Chainable */ - public function processUnsharp() + public function processUnsharp(): static { $radius = $this->radius(); $sigma = $this->sigma(); @@ -38,7 +38,7 @@ public function processUnsharp() /** * @return ImagickSharpenEffect Chainable */ - public function processStandard() + public function processStandard(): static { $channel = $this->image()->imagickChannel($this->channel()); $this->image()->imagick()->sharpenImage($this->radius(), $this->sigma(), $channel); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickThresholdEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickThresholdEffect.php index cf9630af7..915b55e5a 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickThresholdEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickThresholdEffect.php @@ -11,9 +11,8 @@ class ImagickThresholdEffect extends AbstractThresholdEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickTintEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickTintEffect.php index ce45437c8..666a84475 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickTintEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickTintEffect.php @@ -12,9 +12,8 @@ class ImagickTintEffect extends AbstractTintEffect { /** * @param array $data The effect data, if available. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); diff --git a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickWatermarkEffect.php b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickWatermarkEffect.php index ff9661a36..7db0fd884 100644 --- a/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickWatermarkEffect.php +++ b/packages/image/src/Charcoal/Image/Imagick/Effect/ImagickWatermarkEffect.php @@ -15,9 +15,8 @@ class ImagickWatermarkEffect extends AbstractWatermarkEffect /** * @param array $data The effect data, if available. * @throws Exception If the image data is invalid. - * @return self */ - public function process(array $data = null) + public function process(?array $data = null): static { if ($data !== null) { $this->setData($data); @@ -30,7 +29,7 @@ public function process(array $data = null) if ($this->watermark() instanceof ImageInterface) { $watermark = $this->watermark(); } else { - $imgClass = get_class($img); + $imgClass = $img::class; $watermark = new $imgClass(); $watermark->open($this->watermark()); } diff --git a/packages/image/src/Charcoal/Image/Imagick/ImagickImage.php b/packages/image/src/Charcoal/Image/Imagick/ImagickImage.php index 1c8480275..73256b5a2 100644 --- a/packages/image/src/Charcoal/Image/Imagick/ImagickImage.php +++ b/packages/image/src/Charcoal/Image/Imagick/ImagickImage.php @@ -12,10 +12,7 @@ */ class ImagickImage extends AbstractImage { - /** - * @var Imagick $imagick - */ - private $imagick; + private readonly \Imagick $imagick; /** * @throws Exception If imagick driver can not be loaded. @@ -30,18 +27,12 @@ public function __construct() $this->imagick = new Imagick(); } - /** - * @return string - */ - public function driverType() + public function driverType(): string { return 'imagick'; } - /** - * @return Imagick - */ - public function imagick() + public function imagick(): \Imagick { return $this->imagick; } @@ -53,9 +44,8 @@ public function imagick() * @param integer $height Image height, in pixels. * @param string $color Default to transparent. * @throws InvalidArgumentException If the size arguments are not valid, positive integers. - * @return self */ - public function create($width, $height, $color = 'rgb(100%, 100%, 100%, 0)') + public function create($width, $height, $color = 'rgb(100%, 100%, 100%, 0)'): static { if (!is_numeric($width) || $width < 1) { throw new InvalidArgumentException( @@ -76,9 +66,8 @@ public function create($width, $height, $color = 'rgb(100%, 100%, 100%, 0)') * * @param string $source The source path / filename. * @throws InvalidArgumentException If the source argument is not a string. - * @return self */ - public function open($source = null) + public function open($source = null): static { if ($source !== null && !is_string($source)) { throw new InvalidArgumentException( @@ -86,7 +75,7 @@ public function open($source = null) ); } - $source = ($source) ? $source : $this->source(); + $source = $source ?: $this->source(); if (parse_url($source, PHP_URL_HOST)) { $handle = fopen($source, 'rb'); $this->imagick()->readImageFile($handle); @@ -103,9 +92,8 @@ public function open($source = null) * * @param string $target The target path / filename. * @throws InvalidArgumentException If the target argument is not a string. - * @return self */ - public function save($target = null) + public function save($target = null): static { if ($target !== null && !is_string($target)) { throw new InvalidArgumentException( @@ -113,7 +101,7 @@ public function save($target = null) ); } - $target = ($target) ? $target : $this->target(); + $target = $target ?: $this->target(); $fileExt = pathinfo($target, PATHINFO_EXTENSION); $this->imagick()->setImageFormat($fileExt); @@ -124,20 +112,16 @@ public function save($target = null) /** * Get the image's width, in pixels - * - * @return integer */ - public function width() + public function width(): int { return $this->imagick()->getImageWidth(); } /** * Get the image's height, in pixels - * - * @return integer */ - public function height() + public function height(): int { return $this->imagick()->getImageHeight(); } @@ -147,9 +131,8 @@ public function height() * * @param string $channel The standard "channel" string. * @throws InvalidArgumentException If the channel argument is not a valid channel. - * @return integer */ - public function imagickChannel($channel) + public function imagickChannel($channel): int { $channelMap = [ // RGB @@ -180,9 +163,8 @@ public function imagickChannel($channel) * * @param string $gravity The standard gravity name. * @throws InvalidArgumentException If the gravity argument is not a valid gravity type. - * @return integer */ - public function imagickGravity($gravity) + public function imagickGravity($gravity): int { $gravityMap = [ 'center' => Imagick::GRAVITY_CENTER, diff --git a/packages/image/tests/Charcoal/Image/AbstractImageTest.php b/packages/image/tests/Charcoal/Image/AbstractImageTest.php index 7c0efee28..b1ccbafc7 100644 --- a/packages/image/tests/Charcoal/Image/AbstractImageTest.php +++ b/packages/image/tests/Charcoal/Image/AbstractImageTest.php @@ -1,15 +1,15 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); + $obj = new ImageMock(); $ret = $obj->setData( [ 'source'=>__DIR__.'/test.png', @@ -25,9 +25,9 @@ public function testSetData() $this->assertEquals('/tmp/phpunit.png', $obj->target()); } - public function testSetSource() + public function testSetSource(): void { - $obj = $this->getMockForAbstractClass('\Charcoal\Image\AbstractImage'); + $obj = new ImageMock(); $ret = $obj->setSource('test.png'); $this->assertSame($ret, $obj); $this->assertEquals('test.png', $obj->source()); @@ -36,9 +36,9 @@ public function testSetSource() $obj->setSource(false); } - public function testSetTarget() + public function testSetTarget(): void { - $obj = $this->getMockForAbstractClass('\Charcoal\Image\AbstractImage'); + $obj = new ImageMock(); $ret = $obj->setTarget('test.png'); $this->assertSame($ret, $obj); $this->assertEquals('test.png', $obj->target()); diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractBlurEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractBlurEffectTest.php index 9ae2e4a6c..4fd7bcc8c 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractBlurEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractBlurEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $img->method('driverType')->willReturn('imagick'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractBlurEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractBlurEffect { + public function process(?array $data = null) {} + public function processAdaptive() {} + public function processGaussian() {} + public function processMotion() {} + public function processRadial() {} + public function processSoft() {} + public function processStandard() {} + }; + $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; @@ -25,7 +36,7 @@ public function testDefaults() $this->assertEquals(0, $obj->angle()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -46,7 +57,7 @@ public function testSetData() $this->assertEquals(40, $obj->angle()); } - public function testSetRadius() + public function testSetRadius(): void { $obj = $this->obj; @@ -58,14 +69,14 @@ public function testSetRadius() $obj->setRadius(false); } - public function testSetRadiusNegativeThrowsException() + public function testSetRadiusNegativeThrowsException(): void { $this->expectException('\InvalidArgumentException'); $obj = $this->obj; $obj->setRadius(-1); } - public function testSetSigma() + public function testSetSigma(): void { $obj = $this->obj; @@ -77,14 +88,14 @@ public function testSetSigma() $obj->setSigma(false); } - public function testSetSigmaNegativeThrowsException() + public function testSetSigmaNegativeThrowsException(): void { $this->expectException('\InvalidArgumentException'); $obj = $this->obj; $obj->setSigma(-1); } - public function testSetMode() + public function testSetMode(): void { $obj = $this->obj; $ret = $obj->setMode('radial'); @@ -95,7 +106,7 @@ public function testSetMode() $obj->setMode('foobar'); } - public function testSetChannel() + public function testSetChannel(): void { $obj = $this->obj; $ret = $obj->setChannel('alpha'); @@ -106,7 +117,7 @@ public function testSetChannel() $obj->setChannel('foobar'); } - public function testSetAngle() + public function testSetAngle(): void { $obj = $this->obj; $ret = $obj->setAngle(45); diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractDitherEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractDitherEffectTest.php index 938fc672d..4d4e6abef 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractDitherEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractDitherEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $img->method('driverType')->willReturn('imagick'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractDitherEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractDitherEffect { + public function process(?array $data = null) {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; @@ -22,7 +26,7 @@ public function testDefaults() $this->assertEquals('', $obj->mode()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -37,7 +41,7 @@ public function testSetData() $this->assertEquals('h6x6a', $obj->mode()); } - public function testSetColors() + public function testSetColors(): void { $obj = $this->obj; $ret = $obj->setColors(6); @@ -48,7 +52,7 @@ public function testSetColors() $obj->setColors(false); } - public function testSetMode() + public function testSetMode(): void { $obj = $this->obj; $ret = $obj->setMode('checks'); diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractGrayscaleEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractGrayscaleEffectTest.php index b63d76372..ee169ee32 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractGrayscaleEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractGrayscaleEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $img->method('driverType')->willReturn('imagick'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractGrayscaleEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractGrayscaleEffect { + public function process(?array $data = null) {} + }; $this->obj->setImage($img); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([]); diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractMaskEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractMaskEffectTest.php index 4134b759f..5b843ea09 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractMaskEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractMaskEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $img->method('driverType')->willReturn('imagick'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractMaskEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractMaskEffect { + public function process(?array $data = null) {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; @@ -24,7 +28,7 @@ public function testDefaults() $this->assertEquals(0, $obj->y()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -45,7 +49,7 @@ public function testSetData() $this->assertEquals(20, $obj->y()); } - public function testSetMask() + public function testSetMask(): void { $obj = $this->obj; $ret = $obj->setMask('bar/baz.png'); @@ -56,7 +60,7 @@ public function testSetMask() $obj->setMask(false); } - public function testSetOpacity() + public function testSetOpacity(): void { $obj = $this->obj; $ret = $obj->setOpacity(0.42); @@ -67,7 +71,7 @@ public function testSetOpacity() $obj->setOpacity(false); } - public function testSetGravity() + public function testSetGravity(): void { $obj = $this->obj; $ret = $obj->setGravity('se'); @@ -78,7 +82,7 @@ public function testSetGravity() $obj->setGravity('foobar'); } - public function testSetX() + public function testSetX(): void { $obj = $this->obj; $ret = $obj->setX(15); @@ -89,7 +93,7 @@ public function testSetX() $obj->setX(false); } - public function testSetY() + public function testSetY(): void { $obj = $this->obj; $ret = $obj->setY(15); diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractMirrorEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractMirrorEffectTest.php index ad319ced4..d00a99ff9 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractMirrorEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractMirrorEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $img->method('driverType')->willReturn('imagick'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractMirrorEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractMirrorEffect { + public function process(?array $data = null) {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; @@ -24,7 +28,7 @@ public function testDefaults() ); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -37,7 +41,7 @@ public function testSetData() $this->assertEquals('x', $obj->axis()); } - public function testSetAxis() + public function testSetAxis(): void { $obj = $this->obj; diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractModulateEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractModulateEffectTest.php index 4c5893fef..a60a2319c 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractModulateEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractModulateEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $img->method('driverType')->willReturn('imagick'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractModulateEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractModulateEffect { + public function process(?array $data = null) {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; @@ -23,7 +27,7 @@ public function testDefaults() $this->assertEquals(0, $obj->luminance()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -40,7 +44,7 @@ public function testSetData() $this->assertEquals(-75, $obj->luminance()); } - public function testSetHue() + public function testSetHue(): void { $obj = $this->obj; @@ -52,7 +56,7 @@ public function testSetHue() $obj->setHue(false); } - public function testSetHueMaxExeption() + public function testSetHueMaxExeption(): void { $this->expectException('\InvalidArgumentException'); @@ -60,7 +64,7 @@ public function testSetHueMaxExeption() $obj->setHue(101); } - public function testSetHueMinExeption() + public function testSetHueMinExeption(): void { $this->expectException('\InvalidArgumentException'); @@ -68,7 +72,7 @@ public function testSetHueMinExeption() $obj->setHue(-101); } - public function testSetSaturation() + public function testSetSaturation(): void { $obj = $this->obj; @@ -80,7 +84,7 @@ public function testSetSaturation() $obj->setSaturation(false); } - public function testSetSaturationMaxExeption() + public function testSetSaturationMaxExeption(): void { $this->expectException('\InvalidArgumentException'); @@ -88,7 +92,7 @@ public function testSetSaturationMaxExeption() $obj->setSaturation(101); } - public function testSetSaturationMinExeption() + public function testSetSaturationMinExeption(): void { $this->expectException('\InvalidArgumentException'); @@ -96,7 +100,7 @@ public function testSetSaturationMinExeption() $obj->setSaturation(-101); } - public function testSetLuminance() + public function testSetLuminance(): void { $obj = $this->obj; @@ -108,7 +112,7 @@ public function testSetLuminance() $obj->setLuminance(false); } - public function testSetLuminanceMaxExeption() + public function testSetLuminanceMaxExeption(): void { $this->expectException('\InvalidArgumentException'); @@ -116,7 +120,7 @@ public function testSetLuminanceMaxExeption() $obj->setLuminance(101); } - public function testSetLuminanceMinExeption() + public function testSetLuminanceMinExeption(): void { $this->expectException('\InvalidArgumentException'); diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractResizeEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractResizeEffectTest.php index f0a4f9f12..429661901 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractResizeEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractResizeEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $img->method('driverType')->willReturn('imagick'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractResizeEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractResizeEffect { + protected function doResize($width, $height, $bestFit = false) {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; @@ -27,7 +31,7 @@ public function testDefaults() $this->assertFalse($obj->adaptive()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ @@ -50,7 +54,7 @@ public function testSetData() $this->assertTrue($obj->adaptive()); } - public function testSetMode() + public function testSetMode(): void { $obj = $this->obj; $ret = $obj->setMode('width'); @@ -61,7 +65,7 @@ public function testSetMode() $obj->setMode('foobar'); } - public function testSetSize() + public function testSetSize(): void { $obj = $this->obj; @@ -70,14 +74,14 @@ public function testSetSize() $this->assertEquals('50%', $obj->size()); - $ret = $obj->setSize(400); + $obj->setSize(400); $this->assertEquals(400, $obj->size()); - $ret = $obj->setSize(null); + $obj->setSize(null); $this->assertEquals(null, $obj->size()); } - public function testSetSizeException() + public function testSetSizeException(): void { $obj = $this->obj; @@ -88,7 +92,7 @@ public function testSetSizeException() $obj->setSize([ 'foo', 'bar' ]); } - public function testSetWidth() + public function testSetWidth(): void { $obj = $this->obj; $ret = $obj->setWidth(400); @@ -96,14 +100,14 @@ public function testSetWidth() $this->assertEquals(400, $obj->width()); } - public function testSetWidthNegativeException() + public function testSetWidthNegativeException(): void { $obj = $this->obj; $this->expectException('\InvalidArgumentException'); $obj->setWidth(-1); } - public function testSetHeight() + public function testSetHeight(): void { $obj = $this->obj; $ret = $obj->setHeight(400); @@ -111,14 +115,14 @@ public function testSetHeight() $this->assertEquals(400, $obj->height()); } - public function testSetHeightNegativeException() + public function testSetHeightNegativeException(): void { $obj = $this->obj; $this->expectException('\InvalidArgumentException'); $obj->setHeight(-1); } - public function testSetGravity() + public function testSetGravity(): void { $obj = $this->obj; $ret = $obj->setGravity('nw'); @@ -129,7 +133,7 @@ public function testSetGravity() $obj->setGravity('foobar'); } - public function testSetBackgroundColor() + public function testSetBackgroundColor(): void { $obj = $this->obj; $ret = $obj->setBackgroundColor('red'); @@ -140,7 +144,7 @@ public function testSetBackgroundColor() $obj->setBackgroundColor(false); } - public function testSetAdaptive() + public function testSetAdaptive(): void { $obj = $this->obj; $ret = $obj->setAdaptive(true); @@ -148,7 +152,7 @@ public function testSetAdaptive() $this->assertTrue($obj->adaptive()); } - public function testAutoMode() + public function testAutoMode(): void { $obj = $this->obj; $obj->setMode('auto'); @@ -170,7 +174,7 @@ public function testAutoMode() $this->assertEquals('none', $obj->autoMode()); } - public function testProcessExactParametersException() + public function testProcessExactParametersException(): void { $obj = $this->obj; $obj->setMode('exact'); @@ -178,7 +182,7 @@ public function testProcessExactParametersException() $obj->process(); } - public function testProcessWidthParameterException() + public function testProcessWidthParameterException(): void { $obj = $this->obj; $obj->setMode('width'); @@ -186,7 +190,7 @@ public function testProcessWidthParameterException() $obj->process(); } - public function testProcessHeightParameterException() + public function testProcessHeightParameterException(): void { $obj = $this->obj; $obj->setMode('height'); @@ -194,7 +198,7 @@ public function testProcessHeightParameterException() $obj->process(); } - public function testProcessBestFitParameterException() + public function testProcessBestFitParameterException(): void { $obj = $this->obj; $obj->setMode('best_fit'); @@ -202,7 +206,7 @@ public function testProcessBestFitParameterException() $obj->process(); } - public function testProcessCropException() + public function testProcessCropException(): void { $obj = $this->obj; $obj->setMode('crop'); @@ -210,7 +214,7 @@ public function testProcessCropException() $obj->process(); } - public function testProcessFillException() + public function testProcessFillException(): void { $obj = $this->obj; $obj->setMode('fill'); diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractRevertEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractRevertEffectTest.php index 97d790e69..7ffaf0a0e 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractRevertEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractRevertEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractRevertEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractRevertEffect { + public function process(?array $data = null) {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; $this->assertEquals('all', $obj->channel()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -33,7 +38,7 @@ public function testSetData() $this->assertEquals('green', $obj->channel()); } - public function testSetChannel() + public function testSetChannel(): void { $obj = $this->obj; $ret = $obj->setChannel('gray'); diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractRotateEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractRotateEffectTest.php index 5bd045324..57dde115d 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractRotateEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractRotateEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractRotateEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractRotateEffect { + public function process(?array $data = null) {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; @@ -21,7 +26,7 @@ public function testDefaults() $this->assertEquals('rgb(100%, 100%, 100%, 0)', $obj->backgroundColor()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -36,7 +41,7 @@ public function testSetData() $this->assertEquals('blue', $obj->backgroundColor()); } - public function testSetAngle() + public function testSetAngle(): void { $obj = $this->obj; $ret = $obj->setAngle(135); @@ -47,7 +52,7 @@ public function testSetAngle() $obj->setAngle('foobar'); } - public function testSetBackgroundColor() + public function testSetBackgroundColor(): void { $obj = $this->obj; $ret = $obj->setBackgroundColor('red'); diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractSepiaEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractSepiaEffectTest.php index e282359da..744aafd25 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractSepiaEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractSepiaEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractSepiaEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractSepiaEffect { + public function process(?array $data = null) {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; $this->assertEquals(75, $obj->threshold()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -33,7 +38,7 @@ public function testSetData() $this->assertEquals(100, $obj->threshold()); } - public function testSetThreshold() + public function testSetThreshold(): void { $obj = $this->obj; @@ -45,13 +50,13 @@ public function testSetThreshold() $obj->setThreshold('foobar'); } - public function testSetThresholdMinException() + public function testSetThresholdMinException(): void { $this->expectException('\InvalidArgumentException'); $obj = $this->obj; $obj->setThreshold(-1); } - public function testSetThresholdMaxException() + public function testSetThresholdMaxException(): void { $this->expectException('\InvalidArgumentException'); $obj = $this->obj; diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractSharpenEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractSharpenEffectTest.php index 67e2547a0..26c6ffdf0 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractSharpenEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractSharpenEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractSharpenEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractSharpenEffect { + public function process(?array $data = null) {} + public function processAdaptive() {} + public function processUnsharp() {} + public function processStandard() {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; @@ -25,7 +33,7 @@ public function testDefaults() $this->assertEquals('all', $obj->channel()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -48,7 +56,7 @@ public function testSetData() $this->assertEquals('blue', $obj->channel()); } - public function testSetRadius() + public function testSetRadius(): void { $obj = $this->obj; @@ -60,14 +68,14 @@ public function testSetRadius() $obj->setRadius(false); } - public function testSetRadiusNegativeThrowsException() + public function testSetRadiusNegativeThrowsException(): void { $this->expectException('\InvalidArgumentException'); $obj = $this->obj; $obj->setRadius(-1); } - public function testSetSigma() + public function testSetSigma(): void { $obj = $this->obj; @@ -79,14 +87,14 @@ public function testSetSigma() $obj->setSigma(false); } - public function testSetSigmaNegativeThrowsException() + public function testSetSigmaNegativeThrowsException(): void { $this->expectException('\InvalidArgumentException'); $obj = $this->obj; $obj->setSigma(-1); } - public function testSetAmount() + public function testSetAmount(): void { $obj = $this->obj; @@ -98,14 +106,14 @@ public function testSetAmount() $obj->setAmount('foobar'); } - public function testSetAmountNegativeThrowsException() + public function testSetAmountNegativeThrowsException(): void { $this->expectException('\InvalidArgumentException'); $obj = $this->obj; $obj->setAmount(-1); } - public function testSetThreshold() + public function testSetThreshold(): void { $obj = $this->obj; @@ -117,7 +125,7 @@ public function testSetThreshold() $obj->setThreshold('foobar'); } - public function testSetMode() + public function testSetMode(): void { $obj = $this->obj; $ret = $obj->setMode('unsharp'); @@ -128,7 +136,7 @@ public function testSetMode() $obj->setMode('foobar'); } - public function testSetChannel() + public function testSetChannel(): void { $obj = $this->obj; $ret = $obj->setChannel('alpha'); diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractThresholdEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractThresholdEffectTest.php index bc6e4bc6f..15ac7e369 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractThresholdEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractThresholdEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractThresholdEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractThresholdEffect { + public function process(?array $data = null) {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; $this->assertEquals(0.5, $obj->threshold()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -33,7 +38,7 @@ public function testSetData() $this->assertEquals(0.1, $obj->threshold()); } - public function testSetThreshold() + public function testSetThreshold(): void { $obj = $this->obj; @@ -45,14 +50,14 @@ public function testSetThreshold() $obj->setThreshold('foobar'); } - public function testSetThresholdMinException() + public function testSetThresholdMinException(): void { $this->expectException('\InvalidArgumentException'); $obj = $this->obj; $obj->setThreshold(-1); } - public function testSetThresholdMaxException() + public function testSetThresholdMaxException(): void { $this->expectException('\InvalidArgumentException'); $obj = $this->obj; diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractTintEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractTintEffectTest.php index e544cb4d2..281a363ef 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractTintEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractTintEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractTintEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractTintEffect { + public function process(?array $data = null) {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; @@ -22,7 +27,7 @@ public function testDefaults() $this->assertTrue($obj->midtone()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -39,7 +44,7 @@ public function testSetData() $this->assertFalse($obj->midtone()); } - public function testSetColor() + public function testSetColor(): void { $obj = $this->obj; $ret = $obj->setColor('#ff00ff'); @@ -50,7 +55,7 @@ public function testSetColor() $obj->setColor(false); } - public function testSetOpacity() + public function testSetOpacity(): void { $obj = $this->obj; $ret = $obj->setOpacity(0.42); @@ -61,7 +66,7 @@ public function testSetOpacity() $obj->setOpacity(false); } - public function testSetMidtone() + public function testSetMidtone(): void { $obj = $this->obj; $ret = $obj->setMidtone(false); diff --git a/packages/image/tests/Charcoal/Image/Effect/AbstractWatermarkEffectTest.php b/packages/image/tests/Charcoal/Image/Effect/AbstractWatermarkEffectTest.php index 1f259e200..5a710df36 100644 --- a/packages/image/tests/Charcoal/Image/Effect/AbstractWatermarkEffectTest.php +++ b/packages/image/tests/Charcoal/Image/Effect/AbstractWatermarkEffectTest.php @@ -1,6 +1,9 @@ getMockForAbstractClass('\Charcoal\Image\AbstractImage'); - $this->obj = $this->getMockForAbstractClass('\Charcoal\Image\Effect\AbstractWatermarkEffect'); + $img = new ImageMock(); + $this->obj = new class () extends AbstractWatermarkEffect { + public function process(?array $data = null) {} + }; $this->obj->setImage($img); } - public function testDefaults() + public function testDefaults(): void { $obj = $this->obj; @@ -23,7 +28,7 @@ public function testDefaults() $this->assertEquals(0, $obj->y()); } - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData( @@ -44,7 +49,7 @@ public function testSetData() $this->assertEquals(20, $obj->y()); } - public function testSetWatermark() + public function testSetWatermark(): void { $obj = $this->obj; $ret = $obj->setWatermark('bar/baz.png'); @@ -55,7 +60,7 @@ public function testSetWatermark() $obj->setWatermark(false); } - public function testSetOpacity() + public function testSetOpacity(): void { $obj = $this->obj; $ret = $obj->setOpacity(0.42); @@ -66,7 +71,7 @@ public function testSetOpacity() $obj->setOpacity(false); } - public function testSetGravity() + public function testSetGravity(): void { $obj = $this->obj; $ret = $obj->setGravity('se'); @@ -77,7 +82,7 @@ public function testSetGravity() $obj->setGravity('foobar'); } - public function testSetX() + public function testSetX(): void { $obj = $this->obj; $ret = $obj->setX(15); @@ -88,7 +93,7 @@ public function testSetX() $obj->setX(false); } - public function testSetY() + public function testSetY(): void { $obj = $this->obj; $ret = $obj->setY(15); diff --git a/packages/image/tests/Charcoal/Image/Imagemagick/ImagemagickImageTest.php b/packages/image/tests/Charcoal/Image/Imagemagick/ImagemagickImageTest.php index 8cde190fa..2446f6b3d 100644 --- a/packages/image/tests/Charcoal/Image/Imagemagick/ImagemagickImageTest.php +++ b/packages/image/tests/Charcoal/Image/Imagemagick/ImagemagickImageTest.php @@ -1,6 +1,6 @@ factory === null) { + if (!$this->factory instanceof \Charcoal\Image\ImageFactory) { $this->factory = new ImageFactory(); } @@ -25,7 +25,7 @@ public function createImage() return $this->imageFactory()->create('imagemagick'); } - public function testFromFactory() + public function testFromFactory(): void { $obj = $this->createImage(); $this->assertInstanceOf(Image::class, $obj); @@ -41,21 +41,21 @@ public function testFromFactory() // $obj->create('foo', 'bar'); // } - public function testCreateMinWidth() + public function testCreateMinWidth(): void { $obj = $this->createImage(); $this->expectException(InvalidArgumentException::class); $obj->create(400, 0); } - public function testCreateMinHeigth() + public function testCreateMinHeigth(): void { $obj = $this->createImage(); $this->expectException(InvalidArgumentException::class); $obj->create(0, 400); } - public function testOpen() + public function testOpen(): void { $obj = $this->createImage(); $ret = $obj->open(EXAMPLES_DIR.'/test01.jpg'); @@ -65,7 +65,7 @@ public function testOpen() $obj->open(false); } - public function testOpenInvalidFile() + public function testOpenInvalidFile(): void { $obj = $this->createImage(); $this->expectException('\Exception'); @@ -88,7 +88,7 @@ public function testOpenInvalidFile() // //$this->assertEquals($id1, $id2); // } - public function testWidth() + public function testWidth(): void { $obj = $this->createImage(); $obj->open(EXAMPLES_DIR.'/test01.jpg'); @@ -97,7 +97,7 @@ public function testWidth() $this->assertEquals(3456, $width); } - public function testHeight() + public function testHeight(): void { $obj = $this->createImage(); $obj->open(EXAMPLES_DIR.'/test01.jpg'); @@ -106,10 +106,8 @@ public function testHeight() $this->assertEquals(2304, $height); } - /** - * @dataProvider effectProvider - */ - public function testEffects($effect, $filename) + #[\PHPUnit\Framework\Attributes\DataProvider('effectProvider')] + public function testEffects(array $effect, string $filename): void { $obj = $this->createImage(); $obj->open(EXAMPLES_DIR.'/test02.png'); @@ -120,10 +118,8 @@ public function testEffects($effect, $filename) $this->assertTrue(file_exists(OUTPUT_DIR.'/'.$filename)); } - /** - * @dataProvider invalidEffectProvider - */ - public function testInvalidEffext($effect) + #[\PHPUnit\Framework\Attributes\DataProvider('invalidEffectProvider')] + public function testInvalidEffext(array $effect): void { $obj = $this->createImage(); $obj->open(EXAMPLES_DIR.'/test02.png'); @@ -132,7 +128,7 @@ public function testInvalidEffext($effect) $obj->processsEffect($effect); } - public function effectProvider() + public static function effectProvider(): array { return [ # Blur @@ -186,7 +182,7 @@ public function effectProvider() ]; } - public function invalidEffectProvider() + public static function invalidEffectProvider(): array { return [ # Dither diff --git a/packages/image/tests/Charcoal/Image/Imagick/ImagickImageTest.php b/packages/image/tests/Charcoal/Image/Imagick/ImagickImageTest.php index 0bb7fc05f..41b291f52 100644 --- a/packages/image/tests/Charcoal/Image/Imagick/ImagickImageTest.php +++ b/packages/image/tests/Charcoal/Image/Imagick/ImagickImageTest.php @@ -1,6 +1,6 @@ factory === null) { + if (!$this->factory instanceof \Charcoal\Image\ImageFactory) { $this->factory = new ImageFactory(); } @@ -27,13 +27,13 @@ public function createImage() return $this->imageFactory()->create('imagick'); } - public function testFromFactory() + public function testFromFactory(): void { $obj = $this->createImage(); $this->assertInstanceOf(Image::class, $obj); } - public function testCreate() + public function testCreate(): void { $obj = $this->createImage(); $ret = $obj->create(1, 1); @@ -43,21 +43,21 @@ public function testCreate() $obj->create('foo', 'bar'); } - public function testCreateMinWidth() + public function testCreateMinWidth(): void { $obj = $this->createImage(); $this->expectException('\InvalidArgumentException'); $obj->create(400, 0); } - public function testCreateMinHeigth() + public function testCreateMinHeigth(): void { $obj = $this->createImage(); $this->expectException('\InvalidArgumentException'); $obj->create(0, 400); } - public function testOpen() + public function testOpen(): void { $obj = $this->createImage(); $ret = $obj->open(EXAMPLES_DIR.'/test01.jpg'); @@ -67,14 +67,14 @@ public function testOpen() $obj->open(false); } - public function testOpenInvalidFile() + public function testOpenInvalidFile(): void { $obj = $this->createImage(); $this->expectException('\Exception'); $obj->open('foo/bar/baz.png'); } - public function testOpenWithoutParamUseSource() + public function testOpenWithoutParamUseSource(): void { $obj1 = $this->createImage(); $obj1->open(EXAMPLES_DIR.'/test01.jpg'); @@ -90,25 +90,25 @@ public function testOpenWithoutParamUseSource() $this->assertEquals($id1, $id2); } - public function testWidth() + public function testWidth(): void { $obj = $this->createImage(); - $ret = $obj->open(EXAMPLES_DIR.'/test01.jpg'); + $obj->open(EXAMPLES_DIR.'/test01.jpg'); $width = $obj->width(); $this->assertEquals(3456, $width); } - public function testHeight() + public function testHeight(): void { $obj = $this->createImage(); - $ret = $obj->open(EXAMPLES_DIR.'/test01.jpg'); + $obj->open(EXAMPLES_DIR.'/test01.jpg'); $height = $obj->height(); $this->assertEquals(2304, $height); } - public function testImagickChannel() + public function testImagickChannel(): void { $obj = $this->createImage(); $ret = $obj->imagickChannel('red'); @@ -118,7 +118,7 @@ public function testImagickChannel() $obj->imagickChannel('foobar'); } - public function testImagickGravity() + public function testImagickGravity(): void { $obj = $this->createImage(); $ret = $obj->imagickGravity('ne'); @@ -128,10 +128,8 @@ public function testImagickGravity() $obj->imagickGravity('foobar'); } - /** - * @dataProvider effectProvider - */ - public function testEffects($effect, $filename) + #[\PHPUnit\Framework\Attributes\DataProvider('effectProvider')] + public function testEffects(array $effect, string $filename): void { $obj = $this->createImage(); $obj->open(EXAMPLES_DIR.'/test02.png'); @@ -142,10 +140,8 @@ public function testEffects($effect, $filename) $this->assertTrue(file_exists(OUTPUT_DIR.'/'.$filename)); } - /** - * @dataProvider invalidEffectProvider - */ - public function testInvalidEffect($effect) + #[\PHPUnit\Framework\Attributes\DataProvider('invalidEffectProvider')] + public function testInvalidEffect(array $effect): void { $obj = $this->createImage(); $obj->open(EXAMPLES_DIR.'/test02.png'); @@ -154,7 +150,7 @@ public function testInvalidEffect($effect) $obj->processsEffect($effect); } - public function effectProvider() + public static function effectProvider(): array { return [ # Blur @@ -220,7 +216,7 @@ public function effectProvider() ]; } - public function invalidEffectProvider() + public static function invalidEffectProvider(): array { return [ # Blur diff --git a/packages/image/tests/Charcoal/Mock/ImageMock.php b/packages/image/tests/Charcoal/Mock/ImageMock.php new file mode 100644 index 000000000..8e7671e00 --- /dev/null +++ b/packages/image/tests/Charcoal/Mock/ImageMock.php @@ -0,0 +1,57 @@ + + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal diff --git a/packages/object/src/Charcoal/Object/ArchivableInterface.php b/packages/object/src/Charcoal/Object/ArchivableInterface.php index 1ce701cb3..7b346c396 100644 --- a/packages/object/src/Charcoal/Object/ArchivableInterface.php +++ b/packages/object/src/Charcoal/Object/ArchivableInterface.php @@ -1,5 +1,7 @@ numCategoryItems === null) { $items = $this->getCategoryItems(); - if (is_array($items) || ($items instanceof \Countable)) { - $count = count($items); - } else { - $count = 0; - } + $count = is_countable($items) ? count($items) : 0; $this->numCategoryItems = $count; } @@ -98,10 +94,8 @@ public function numCategoryItems() /** * Gets wether the category has any items, directly within it. - * - * @return boolean */ - public function hasCategoryItems() + public function hasCategoryItems(): bool { $numItems = $this->getNumCategoryItems(); return ($numItems > 0); diff --git a/packages/object/src/Charcoal/Object/Content.php b/packages/object/src/Charcoal/Object/Content.php index 32cf80941..800ece6c7 100644 --- a/packages/object/src/Charcoal/Object/Content.php +++ b/packages/object/src/Charcoal/Object/Content.php @@ -36,32 +36,28 @@ class Content extends AbstractModel implements /** * Objects are active by default - * @var boolean */ - private $active = true; + private bool $active = true; /** * The position is used for ordering lists - * @var integer */ - private $position = 0; + private ?int $position = 0; - /** - * @var FactoryInterface - */ - private $modelFactory; + private ?\Charcoal\Factory\FactoryInterface $modelFactory = null; /** * @var string[] */ - private $requiredAclPermissions = []; + private array $requiredAclPermissions = []; /** * Dependencies * @param Container $container DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -74,7 +70,7 @@ protected function setDependencies(Container $container) * @param FactoryInterface $factory The factory used to create models. * @return Content Chainable */ - protected function setModelFactory(FactoryInterface $factory) + protected function setModelFactory(FactoryInterface $factory): static { $this->modelFactory = $factory; return $this; @@ -83,7 +79,7 @@ protected function setModelFactory(FactoryInterface $factory) /** * @return FactoryInterface The model factory. */ - protected function modelFactory() + protected function modelFactory(): ?\Charcoal\Factory\FactoryInterface { return $this->modelFactory; } @@ -92,16 +88,13 @@ protected function modelFactory() * @param boolean $active The active flag. * @return Content Chainable */ - public function setActive($active) + public function setActive($active): static { - $this->active = !!$active; + $this->active = (bool)$active; return $this; } - /** - * @return boolean - */ - public function getActive() + public function getActive(): bool { return $this->active; } @@ -111,7 +104,7 @@ public function getActive() * @throws InvalidArgumentException If the position is not an integer (or numeric integer string). * @return Content Chainable */ - public function setPosition($position) + public function setPosition($position): static { if ($position === null) { $this->position = null; @@ -121,7 +114,7 @@ public function setPosition($position) if (!is_numeric($position)) { throw new InvalidArgumentException(sprintf( 'Position must be an integer, received %s', - is_object($position) ? get_class($position) : gettype($position) + get_debug_type($position) )); } @@ -132,7 +125,7 @@ public function setPosition($position) /** * @return integer */ - public function getPosition() + public function getPosition(): ?int { return $this->position; } @@ -143,7 +136,7 @@ public function getPosition() * @param string|string[] $permissions The required ACL permissions. * @return Content Chainable */ - public function setRequiredAclPermissions($permissions) + public function setRequiredAclPermissions($permissions): static { if ($permissions === null || !$permissions) { $this->requiredAclPermissions = []; @@ -151,7 +144,7 @@ public function setRequiredAclPermissions($permissions) } if (is_string($permissions)) { $permissions = explode(',', $permissions); - $permissions = array_map('trim', $permissions); + $permissions = array_map(trim(...), $permissions); } if (!is_array($permissions)) { throw new InvalidArgumentException( @@ -165,7 +158,7 @@ public function setRequiredAclPermissions($permissions) /** * @return string[] */ - public function getRequiredAclPermissions() + public function getRequiredAclPermissions(): array { return $this->requiredAclPermissions; } @@ -173,9 +166,9 @@ public function getRequiredAclPermissions() /** * StorableTrait > preSave(): Called automatically before saving the object to source. * For content object, set the `created` and `lastModified` properties automatically - * @return boolean */ - protected function preSave() + #[\Override] + protected function preSave(): bool { parent::preSave(); @@ -191,9 +184,9 @@ protected function preSave() * For content object, set the `lastModified` property automatically. * * @param array $properties The properties (ident) set for update. - * @return boolean */ - protected function preUpdate(array $properties = null) + #[\Override] + protected function preUpdate(?array $properties = null): bool { parent::preUpdate($properties); diff --git a/packages/object/src/Charcoal/Object/ContentInterface.php b/packages/object/src/Charcoal/Object/ContentInterface.php index ad6380702..86bd50bcc 100644 --- a/packages/object/src/Charcoal/Object/ContentInterface.php +++ b/packages/object/src/Charcoal/Object/ContentInterface.php @@ -1,5 +1,7 @@ $children) { + if ($rootObjects === [] && $childObjects !== []) { + foreach ($childObjects as $children) { $parentObj = $children[0]->getMasterObject(); $parentObj->auxiliary = true; @@ -111,14 +108,12 @@ public function sortTree() } // Display orphaned descendants. - if ($childObjects) { - foreach ($childObjects as $orphans) { - foreach ($orphans as $descendants) { - $descendants->level = 0; - $sortedObjects[$descendants->id()] = $descendants; + foreach ($childObjects as $orphans) { + foreach ($orphans as $descendants) { + $descendants->level = 0; + $sortedObjects[$descendants->id()] = $descendants; - $count++; - } + $count++; } } } else { @@ -184,15 +179,14 @@ public function sortTree() * @param integer $level The level directly below the $parentObj. * @param HierarchicalInterface[] $sortedObjects The list of objects to be displayed. * Passed by reference. - * @return void */ private function sortDescendantObjects( HierarchicalInterface $parentObj, array &$childObjects, - &$count, - $level, + int|float &$count, + int|float $level, array &$sortedObjects - ) { + ): void { $pageNum = $this->getPage(); $perPage = $this->getNumPerPage(); @@ -293,7 +287,7 @@ private function sortDescendantObjects( * @throws InvalidArgumentException If the parameter is not numeric or < 0. * @return Pagination (Chainable) */ - public function setPage($page) + public function setPage($page): static { if (!is_numeric($page)) { throw new InvalidArgumentException( @@ -326,7 +320,7 @@ public function getPage() * @throws InvalidArgumentException If the parameter is not numeric or < 0. * @return Pagination (Chainable) */ - public function setNumPerPage($num) + public function setNumPerPage($num): static { if (!is_numeric($num)) { throw new InvalidArgumentException( @@ -359,9 +353,9 @@ public function getNumPerPage() * Determine if the given value is acceptable for the collection. * * @param mixed $value The value being vetted. - * @return boolean */ - public function isAcceptable($value) + #[\Override] + public function isAcceptable($value): bool { return ($value instanceof HierarchicalInterface); } diff --git a/packages/object/src/Charcoal/Object/HierarchicalInterface.php b/packages/object/src/Charcoal/Object/HierarchicalInterface.php index c83a65cea..9a20080c4 100644 --- a/packages/object/src/Charcoal/Object/HierarchicalInterface.php +++ b/packages/object/src/Charcoal/Object/HierarchicalInterface.php @@ -1,5 +1,7 @@ masterObject && $this->hasMaster()) { $master = $this->objFromIdent($this->getMaster()); - if ($master instanceof ModelInterface) { - if ($master->id() === $this->id()) { - throw new UnexpectedValueException(sprintf( - 'Can not be ones own parent: %s', - $master->id() - )); - } + if ($master instanceof ModelInterface && $master->id() === $this->id()) { + throw new UnexpectedValueException(sprintf( + 'Can not be ones own parent: %s', + $master->id() + )); } $this->masterObject = $master; @@ -129,20 +127,16 @@ public function getMasterObject() /** * Determine if this object's immediate parent exists. - * - * @return boolean */ - public function hasMasterObject() + public function hasMasterObject(): bool { return (bool)$this->getMasterObject(); } /** * Determine if this object has a direct parent. - * - * @return boolean */ - public function hasMaster() + public function hasMaster(): bool { return (bool)$this->getMaster(); } @@ -151,10 +145,8 @@ public function hasMaster() * Determine if this object is the head (top-level) of its hierarchy. * * Top-level objects do not have a parent (master). - * - * @return boolean */ - public function isTopLevel() + public function isTopLevel(): bool { return !$this->getMaster(); } @@ -163,10 +155,8 @@ public function isTopLevel() * Determine if this object is the tail (last-level) of its hierarchy. * * Last-level objects do not have a children. - * - * @return boolean */ - public function isLastLevel() + public function isLastLevel(): bool { return !$this->hasChildren(); } @@ -177,15 +167,12 @@ public function isLastLevel() * Starts at "1" (top-level). * * The level is calculated by loading all ancestors with {@see self::hierarchy()}. - * - * @return integer */ - public function hierarchyLevel() + public function hierarchyLevel(): int { $hierarchy = $this->hierarchy(); - $level = (count($hierarchy) + 1); - return $level; + return (count($hierarchy) + 1); } /** @@ -205,10 +192,8 @@ public function toplevelMaster() /** * Determine if this object has any ancestors. - * - * @return boolean */ - public function hasParents() + public function hasParents(): bool { return count($this->hierarchy()) > 0; } @@ -232,7 +217,7 @@ public function hierarchy() * * @return HierarchicalInterface[] */ - public function loadHierarchy() + public function loadHierarchy(): array { $hierarchy = []; $master = $this->getMasterObject(); @@ -249,7 +234,7 @@ public function loadHierarchy() * * @return HierarchicalInterface[] */ - public function invertedHierarchy() + public function invertedHierarchy(): array { $hierarchy = $this->hierarchy(); @@ -260,9 +245,8 @@ public function invertedHierarchy() * Determine if the object is the parent of the given object. * * @param mixed $child The child (or ID) to match against. - * @return boolean */ - public function isMasterOf($child) + public function isMasterOf($child): bool { $child = $this->objFromIdent($child); @@ -273,21 +257,19 @@ public function isMasterOf($child) * Determine if the object is a parent/ancestor of the given object. * * @param mixed $child The child (or ID) to match against. - * @return boolean * @todo Implementation needed. */ - public function recursiveIsMasterOf($child) + public function recursiveIsMasterOf($child): bool { - $child = $this->objFromIdent($child); + $this->objFromIdent($child); return false; } /** * Get wether the object has any children at all - * @return boolean */ - public function hasChildren() + public function hasChildren(): bool { $numChildren = $this->numChildren(); @@ -296,9 +278,8 @@ public function hasChildren() /** * Get the number of children directly under this object. - * @return integer */ - public function numChildren() + public function numChildren(): int { $children = $this->children(); @@ -308,10 +289,9 @@ public function numChildren() /** * Get the total number of children in the entire hierarchy. * This method counts all children and sub-children, unlike `numChildren()` which only count 1 level. - * @return integer * @todo Implementation needed. */ - public function recursiveNumChildren() + public function recursiveNumChildren(): int { return 0; } @@ -339,13 +319,11 @@ public function addChild($child) { $child = $this->objFromIdent($child); - if ($child instanceof ModelInterface) { - if ($child->id() === $this->id()) { - throw new UnexpectedValueException(sprintf( - 'Can not be ones own child: %s', - $child->id() - )); - } + if ($child instanceof ModelInterface && $child->id() === $this->id()) { + throw new UnexpectedValueException(sprintf( + 'Can not be ones own child: %s', + $child->id() + )); } $this->children[] = $child; @@ -375,9 +353,8 @@ abstract public function loadChildren(); /** * @param mixed $master The master object (or ident) to check against. - * @return boolean */ - public function isChildOf($master) + public function isChildOf($master): bool { $master = $this->objFromIdent($master); @@ -401,20 +378,14 @@ public function recursiveIsChildOf($master) return false; } - /** - * @return boolean - */ - public function hasSiblings() + public function hasSiblings(): bool { $numSiblings = $this->numSiblings(); return ($numSiblings > 1); } - /** - * @return integer - */ - public function numSiblings() + public function numSiblings(): int { $siblings = $this->siblings(); @@ -453,9 +424,8 @@ public function loadSiblings() /** * @param mixed $sibling The sibling to check. - * @return boolean */ - public function isSiblingOf($sibling) + public function isSiblingOf($sibling): bool { $sibling = $this->objFromIdent($sibling); @@ -473,9 +443,9 @@ private function objFromIdent($ident) return null; } - $class = get_called_class(); + $class = static::class; - if (is_object($ident) && ($ident instanceof $class)) { + if ($ident instanceof $class) { return $ident; } @@ -530,11 +500,8 @@ private function loadObjectFromSource($id) private function loadObjectFromCache($id) { $objType = $this->objType(); - if (isset(static::$objectCache[$objType][$id])) { - return static::$objectCache[$objType][$id]; - } - return null; + return (static::$objectCache[$objType][$id] ?? null); } /** diff --git a/packages/object/src/Charcoal/Object/ObjectRevision.php b/packages/object/src/Charcoal/Object/ObjectRevision.php index 4f847c572..1c4e195ec 100644 --- a/packages/object/src/Charcoal/Object/ObjectRevision.php +++ b/packages/object/src/Charcoal/Object/ObjectRevision.php @@ -33,9 +33,8 @@ class ObjectRevision extends AbstractModel implements ObjectRevisionInterface /** * Object type of this revision (required) - * @var string $targetType */ - private $targetType; + private ?string $targetType = null; /** * Object ID of this revision (required) @@ -45,21 +44,18 @@ class ObjectRevision extends AbstractModel implements ObjectRevisionInterface /** * Revision number. Sequential integer for each object's ID. (required) - * @var integer $revNum */ - private $revNum; + private ?int $revNum = null; /** * Timestamp; when this revision was created - * @var DateTimeInterface|null $revTs */ - private $revTs; + private ?\DateTimeInterface $revTs = null; /** * The (admin) user that was - * @var string|null $revUser */ - private $revUser; + private ?string $revUser = null; /** * @var array $dataPrev @@ -80,6 +76,7 @@ class ObjectRevision extends AbstractModel implements ObjectRevisionInterface * @param Container $container DI Container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -92,7 +89,7 @@ protected function setDependencies(Container $container) * @throws InvalidArgumentException If the obj type parameter is not a string. * @return ObjectRevision Chainable */ - public function setTargetType($targetType) + public function setTargetType($targetType): static { if (!is_string($targetType)) { throw new InvalidArgumentException( @@ -106,7 +103,7 @@ public function setTargetType($targetType) /** * @return string */ - public function getTargetType() + public function getTargetType(): ?string { return $this->targetType; } @@ -115,7 +112,7 @@ public function getTargetType() * @param mixed $targetId The object ID. * @return ObjectRevision Chainable */ - public function setTargetId($targetId) + public function setTargetId($targetId): static { $this->targetId = $targetId; return $this; @@ -134,7 +131,7 @@ public function getTargetId() * @throws InvalidArgumentException If the revision number argument is not numerical. * @return ObjectRevision Chainable */ - public function setRevNum($revNum) + public function setRevNum($revNum): static { if (!is_numeric($revNum)) { throw new InvalidArgumentException( @@ -148,7 +145,7 @@ public function setRevNum($revNum) /** * @return integer */ - public function getRevNum() + public function getRevNum(): ?int { return $this->revNum; } @@ -158,7 +155,7 @@ public function getRevNum() * @throws InvalidArgumentException If the timestamp is invalid. * @return ObjectRevision Chainable */ - public function setRevTs($revTs) + public function setRevTs($revTs): static { if ($revTs === null) { $this->revTs = null; @@ -176,10 +173,7 @@ public function setRevTs($revTs) return $this; } - /** - * @return DateTimeInterface|null - */ - public function getRevTs() + public function getRevTs(): ?\DateTimeInterface { return $this->revTs; } @@ -189,7 +183,7 @@ public function getRevTs() * @throws InvalidArgumentException If the revision user parameter is not a string. * @return ObjectRevision Chainable */ - public function setRevUser($revUser) + public function setRevUser($revUser): static { if ($revUser === null) { $this->revUser = null; @@ -207,7 +201,7 @@ public function setRevUser($revUser) /** * @return string */ - public function getRevUser() + public function getRevUser(): ?string { return $this->revUser; } @@ -216,10 +210,10 @@ public function getRevUser() * @param string|array|null $data The previous revision data. * @return ObjectRevision Chainable */ - public function setDataPrev($data) + public function setDataPrev($data): static { if (!is_array($data)) { - $data = json_decode($data, true); + $data = json_decode((string)$data, true); } if ($data === null) { $data = []; @@ -240,10 +234,10 @@ public function getDataPrev() * @param array|string|null $data The current revision (object) data. * @return ObjectRevision Chainable */ - public function setDataObj($data) + public function setDataObj($data): static { if (!is_array($data)) { - $data = json_decode($data, true); + $data = json_decode((string)$data, true); } if ($data === null) { $data = []; @@ -262,9 +256,8 @@ public function getDataObj() /** * @param array|string $data The data diff. - * @return ObjectRevision */ - public function setDataDiff($data) + public function setDataDiff($data): static { if (!is_array($data)) { $data = json_decode($data, true); @@ -294,7 +287,7 @@ public function getDataDiff() * @param RevisionableInterface $obj The object to create the revision from. * @return ObjectRevision Chainable */ - public function createFromObject(RevisionableInterface $obj) + public function createFromObject(RevisionableInterface $obj): static { $prevRev = $this->lastObjectRevision($obj); @@ -321,7 +314,7 @@ public function createFromObject(RevisionableInterface $obj) * @param array $dataObj Optional. Current revision (object) data. * @return array The diff data */ - public function createDiff(array $dataPrev = null, array $dataObj = null) + public function createDiff(?array $dataPrev = null, ?array $dataObj = null): array { if ($dataPrev === null) { $dataPrev = $this->getDataPrev(); @@ -329,8 +322,7 @@ public function createDiff(array $dataPrev = null, array $dataObj = null) if ($dataObj === null) { $dataObj = $this->getDataObj(); } - $dataDiff = $this->recursiveDiff($dataPrev, $dataObj); - return $dataDiff; + return $this->recursiveDiff($dataPrev, $dataObj); } /** @@ -340,7 +332,7 @@ public function createDiff(array $dataPrev = null, array $dataObj = null) * @param array $array2 Second Array. * @return array The array diff. */ - public function recursiveDiff(array $array1, array $array2) + public function recursiveDiff(array $array1, array $array2): array { $diff = []; @@ -354,13 +346,11 @@ public function recursiveDiff(array $array1, array $array2) $diff[1][$key] = $array2[$key]; } else { $new = $this->recursiveDiff($value, $array2[$key]); - if ($new !== false) { - if (isset($new[0])) { - $diff[0][$key] = $new[0]; - } - if (isset($new[1])) { - $diff[1][$key] = $new[1]; - } + if (isset($new[0])) { + $diff[0][$key] = $new[0]; + } + if (isset($new[1])) { + $diff[1][$key] = $new[1]; } } } elseif ($array2[$key] !== $value) { diff --git a/packages/object/src/Charcoal/Object/ObjectRevisionInterface.php b/packages/object/src/Charcoal/Object/ObjectRevisionInterface.php index 9206ee66c..3f1649607 100644 --- a/packages/object/src/Charcoal/Object/ObjectRevisionInterface.php +++ b/packages/object/src/Charcoal/Object/ObjectRevisionInterface.php @@ -1,5 +1,7 @@ generateUniqueSlug(); @@ -159,7 +159,8 @@ protected function preSave() * @param array $properties Optional. The list of properties to update. * @return boolean */ - protected function preUpdate(array $properties = null) + #[\Override] + protected function preUpdate(?array $properties = null) { $this->setCreationDate('now'); $this->setLastModificationDate('now'); @@ -169,10 +170,8 @@ protected function preUpdate(array $properties = null) /** * Determine if the current slug is unique. - * - * @return boolean */ - public function isSlugUnique() + public function isSlugUnique(): bool { $proto = $this->modelFactory()->get(static::class); $loader = $this->collectionLoader(); @@ -235,9 +234,8 @@ public function generateUniqueSlug() * * @param string|null $slug The route. * @throws InvalidArgumentException If the slug argument is not a string. - * @return self */ - public function setSlug($slug) + public function setSlug($slug): static { if ($slug === null) { $this->slug = null; @@ -258,9 +256,8 @@ public function setSlug($slug) * Set the locale of the object route. * * @param string $lang The route's locale. - * @return self */ - public function setLang($lang) + public function setLang($lang): static { $this->lang = $lang; @@ -272,9 +269,8 @@ public function setLang($lang) * * @param string|DateTimeInterface|null $time The date/time value. * @throws InvalidArgumentException If the date/time value is invalid. - * @return self */ - public function setCreationDate($time) + public function setCreationDate($time): static { if (empty($time) && !is_numeric($time)) { $this->creationDate = null; @@ -309,9 +305,8 @@ public function setCreationDate($time) * * @param string|DateTimeInterface|null $time The date/time value. * @throws InvalidArgumentException If the date/time value is invalid. - * @return self */ - public function setLastModificationDate($time) + public function setLastModificationDate($time): static { if (empty($time) && !is_numeric($time)) { $this->lastModificationDate = null; @@ -345,9 +340,8 @@ public function setLastModificationDate($time) * Set the foreign object type related to this route. * * @param string $type The object type. - * @return self */ - public function setRouteObjType($type) + public function setRouteObjType($type): static { $this->routeObjType = $type; @@ -358,9 +352,8 @@ public function setRouteObjType($type) * Set the foreign object ID related to this route. * * @param string $id The object ID. - * @return self */ - public function setRouteObjId($id) + public function setRouteObjId($id): static { $this->routeObjId = $id; @@ -371,9 +364,8 @@ public function setRouteObjId($id) * Set the foreign object's template identifier. * * @param string $template The template identifier. - * @return self */ - public function setRouteTemplate($template) + public function setRouteTemplate($template): static { $this->routeTemplate = $template; @@ -384,9 +376,8 @@ public function setRouteTemplate($template) * Customize the template's options. * * @param mixed $options Template options. - * @return self */ - public function setRouteOptions($options) + public function setRouteOptions($options): static { if (is_string($options)) { $options = json_decode($options, true); @@ -399,9 +390,8 @@ public function setRouteOptions($options) /** * @param string $routeOptionsIdent Template options ident. - * @return self */ - public function setRouteOptionsIdent($routeOptionsIdent) + public function setRouteOptionsIdent($routeOptionsIdent): static { $this->routeOptionsIdent = $routeOptionsIdent; @@ -498,9 +488,8 @@ public function getRouteOptionsIdent() /** * Alias of {@see self::slug()}. - * - * @return string */ + #[\Override] public function __toString(): string { return (string)$this->getSlug(); diff --git a/packages/object/src/Charcoal/Object/ObjectRouteInterface.php b/packages/object/src/Charcoal/Object/ObjectRouteInterface.php index 97b1263ab..3aba191b8 100644 --- a/packages/object/src/Charcoal/Object/ObjectRouteInterface.php +++ b/packages/object/src/Charcoal/Object/ObjectRouteInterface.php @@ -1,5 +1,7 @@ modelFactory = $factory; @@ -92,14 +82,13 @@ public function setModelFactory(FactoryInterface $factory) * Retrieve the object model factory. * * @throws RuntimeException If the model factory was not previously set. - * @return FactoryInterface */ - protected function modelFactory() + protected function modelFactory(): \Charcoal\Factory\FactoryInterface { - if (!isset($this->modelFactory)) { + if (!$this->modelFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException(sprintf( 'Model Factory is not defined for "%s"', - get_class($this) + static::class )); } @@ -113,7 +102,7 @@ protected function modelFactory() * @throws InvalidArgumentException If the object type parameter is not a string. * @return ObjectScheduleInterface Chainable */ - public function setTargetType($targetType) + public function setTargetType($targetType): static { if (!is_string($targetType)) { throw new InvalidArgumentException( @@ -131,7 +120,7 @@ public function setTargetType($targetType) * * @return string */ - public function getTargetType() + public function getTargetType(): ?string { return $this->targetType; } @@ -142,7 +131,7 @@ public function getTargetType() * @param mixed $targetId The object ID. * @return ObjectScheduleInterface Chainable */ - public function setTargetId($targetId) + public function setTargetId($targetId): static { $this->targetId = $targetId; @@ -163,7 +152,7 @@ public function getTargetId() * @param array|string $data The data diff. * @return ObjectRevision */ - public function setDataDiff($data) + public function setDataDiff($data): static { if (!is_array($data)) { $data = json_decode($data, true); @@ -189,19 +178,17 @@ public function getDataDiff() * @param boolean $processed Whether the schedule has been processed. * @return ObjectScheduleInterface Chainable */ - public function setProcessed($processed) + public function setProcessed($processed): static { - $this->processed = !!$processed; + $this->processed = (bool)$processed; return $this; } /** * Determine if the schedule has been processed. - * - * @return boolean */ - public function getProcessed() + public function getProcessed(): bool { return $this->processed; } @@ -213,7 +200,7 @@ public function getProcessed() * @throws InvalidArgumentException If the date/time is invalid. * @return ObjectScheduleInterface Chainable */ - public function setScheduledDate($ts) + public function setScheduledDate($ts): static { if ($ts === null) { $this->scheduledDate = null; @@ -245,10 +232,8 @@ public function setScheduledDate($ts) /** * Retrieve the date/time the item should be processed at. - * - * @return null|DateTimeInterface */ - public function getScheduledDate() + public function getScheduledDate(): ?\DateTimeInterface { return $this->scheduledDate; } @@ -260,7 +245,7 @@ public function getScheduledDate() * @throws InvalidArgumentException If the date/time is invalid. * @return ObjectScheduleInterface Chainable */ - public function setProcessedDate($ts) + public function setProcessedDate($ts): static { if ($ts === null) { $this->processedDate = null; @@ -292,10 +277,8 @@ public function setProcessedDate($ts) /** * Retrieve the date/time the item was processed at. - * - * @return null|DateTimeInterface */ - public function getProcessedDate() + public function getProcessedDate(): ?\DateTimeInterface { return $this->processedDate; } @@ -304,10 +287,9 @@ public function getProcessedDate() * Hook called before saving the item. * * Presets the item as _to-be_ processed and queued now. - * - * @return boolean */ - protected function preSave() + #[\Override] + protected function preSave(): bool { parent::preSave(); @@ -325,12 +307,12 @@ protected function preSave() * @return boolean|null Success / Failure, or null in case of a skipped item. */ public function process( - callable $callback = null, - callable $successCallback = null, - callable $failureCallback = null + ?callable $callback = null, + ?callable $successCallback = null, + ?callable $failureCallback = null ) { - if ($this->getProcessed() === true) { + if ($this->getProcessed()) { // Do not process twice, ever. return null; } @@ -369,14 +351,11 @@ public function process( $this->setProcessed(true); $this->setProcessedDate('now'); $this->update([ 'processed', 'processed_date' ]); - if ($successCallback !== null) { $successCallback($this); } - } else { - if ($failureCallback !== null) { - $failureCallback($this); - } + } elseif ($failureCallback !== null) { + $failureCallback($this); } if ($callback !== null) { diff --git a/packages/object/src/Charcoal/Object/ObjectScheduleInterface.php b/packages/object/src/Charcoal/Object/ObjectScheduleInterface.php index 6ae5ae05a..bd271a1bc 100644 --- a/packages/object/src/Charcoal/Object/ObjectScheduleInterface.php +++ b/packages/object/src/Charcoal/Object/ObjectScheduleInterface.php @@ -1,5 +1,7 @@ publishDateStatus() === static::STATUS_PUBLISHED); } diff --git a/packages/object/src/Charcoal/Object/RevisionableInterface.php b/packages/object/src/Charcoal/Object/RevisionableInterface.php index 6b60497ed..b8be26ec7 100644 --- a/packages/object/src/Charcoal/Object/RevisionableInterface.php +++ b/packages/object/src/Charcoal/Object/RevisionableInterface.php @@ -1,5 +1,7 @@ revisionEnabled = !!$enabled; + $this->revisionEnabled = (bool)$enabled; return $this; } @@ -49,18 +49,14 @@ public function getRevisionEnabled() /** * Create a revision collection loader. - * - * @return CollectionLoader */ - public function createRevisionObjectCollectionLoader() + public function createRevisionObjectCollectionLoader(): \Charcoal\Loader\CollectionLoader { - $loader = new CollectionLoader([ + return new CollectionLoader([ 'logger' => $this->logger, 'factory' => $this->modelFactory(), 'model' => $this->getRevisionObjectPrototype(), ]); - - return $loader; } /** @@ -70,9 +66,7 @@ public function createRevisionObjectCollectionLoader() */ public function createRevisionObject() { - $rev = $this->modelFactory()->create($this->getObjectRevisionClass()); - - return $rev; + return $this->modelFactory()->create($this->getObjectRevisionClass()); } /** @@ -82,9 +76,7 @@ public function createRevisionObject() */ public function getRevisionObjectPrototype() { - $proto = $this->modelFactory()->get($this->getObjectRevisionClass()); - - return $proto; + return $this->modelFactory()->get($this->getObjectRevisionClass()); } /** @@ -149,9 +141,8 @@ public function generateRevision() public function latestRevision() { $rev = $this->createRevisionObject(); - $rev = $rev->lastObjectRevision($this); - return $rev; + return $rev->lastObjectRevision($this); } /** @@ -165,9 +156,8 @@ public function latestRevision() public function revisionNum($revNum) { $rev = $this->createRevisionObject(); - $rev = $rev->objectRevisionNum($this, intval($revNum)); - return $rev; + return $rev->objectRevisionNum($this, intval($revNum)); } /** @@ -176,7 +166,7 @@ public function revisionNum($revNum) * @param callable $callback Optional object callback. * @return array */ - public function allRevisions(callable $callback = null) + public function allRevisions(?callable $callback = null) { $loader = $this->createRevisionObjectCollectionLoader(); $loader @@ -197,7 +187,7 @@ public function allRevisions(callable $callback = null) } $revisions = $loader->load(); - return $revisions->objects(); + return $revisions->values(); } /** @@ -205,7 +195,7 @@ public function allRevisions(callable $callback = null) * @throws InvalidArgumentException If revision number is invalid. * @return boolean Success / Failure. */ - public function revertToRevision($revNum) + public function revertToRevision($revNum): bool { if (!$revNum) { throw new InvalidArgumentException( diff --git a/packages/object/src/Charcoal/Object/RoutableInterface.php b/packages/object/src/Charcoal/Object/RoutableInterface.php index 96dfbccc5..c4296c560 100644 --- a/packages/object/src/Charcoal/Object/RoutableInterface.php +++ b/packages/object/src/Charcoal/Object/RoutableInterface.php @@ -1,5 +1,7 @@ isSlugEditable === null) { $metadata = $this->metadata(); - if (isset($metadata['routable']['editable'])) { - $this->isSlugEditable = !!$metadata['routable']['editable']; - } else { - $this->isSlugEditable = false; - } + $this->isSlugEditable = isset($metadata['routable']['editable']) && (bool)$metadata['routable']['editable']; } return $this->isSlugEditable; @@ -191,18 +187,15 @@ public function setSlug($slug) $slug = $this->translator()->translation($slug); if ($slug !== null) { $this->slug = $slug; - $values = $this->slug->data(); foreach ($values as $lang => $val) { $this->slug[$lang] = $this->slugify($val); } - } else { + } elseif (isset($_POST['slug'])) { /** @todo Hack used for regenerating route */ - if (isset($_POST['slug'])) { - $this->slug = []; - } else { - $this->slug = null; - } + $this->slug = []; + } else { + $this->slug = null; } return $this; @@ -240,7 +233,7 @@ public function generateSlug() $newSlug[$lang] = $curSlug[$lang]; } else { $newSlug[$lang] = $this->generateRoutePattern($pattern); - if (!strlen($newSlug[$lang])) { + if ((string)$newSlug[$lang] === '') { throw new UnexpectedValueException(sprintf( 'The slug is empty. The pattern is "%s"', $pattern @@ -274,9 +267,9 @@ public function generateSlug() * @param string $pattern The slug pattern. * @return string Returns the generated route. */ - protected function generateRoutePattern($pattern) + protected function generateRoutePattern(string $pattern) { - if ($this instanceof ViewableInterface && $this->view() !== null) { + if ($this instanceof ViewableInterface && $this->view() instanceof \Charcoal\View\ViewInterface) { $route = $this->view()->renderTemplate($pattern, $this->viewController()); } else { $route = preg_replace_callback('~\{\{\s*(.*?)\s*\}\}~i', [ $this, 'parseRouteToken' ], $pattern); @@ -294,14 +287,14 @@ protected function generateRoutePattern($pattern) * @throws InvalidArgumentException If a route token is not a string. * @return string */ - protected function parseRouteToken($token) + protected function parseRouteToken($token): string|float|int { // Processes matches from a regular expression operation if (is_array($token) && isset($token[1])) { $token = $token[1]; } - $token = trim($token); + $token = trim((string)$token); $method = [ $this, $token ]; if (is_callable($method)) { @@ -318,8 +311,8 @@ protected function parseRouteToken($token) throw new InvalidArgumentException(sprintf( 'Route token "%1$s" must be a string with %2$s; received %3$s', $token, - get_called_class(), - (is_object($value) ? get_class($value) : gettype($value)) + static::class, + (get_debug_type($value)) )); } @@ -374,9 +367,9 @@ protected function generateObjectRoute($slug = null, array $data = []) } else { throw new InvalidArgumentException(sprintf( '[%s] slug parameter must be an instance of %s, received %s', - get_called_class() . '::' . __FUNCTION__, + static::class . '::' . __FUNCTION__, Translation::class, - is_object($slug) ? get_class($slug) : gettype($slug) + get_debug_type($slug) )); } @@ -453,7 +446,7 @@ protected function getLatestObjectRoute($lang = null) } elseif (!in_array($lang, $this->translator()->availableLocales())) { throw new InvalidArgumentException(sprintf( 'Invalid language, received %s', - (is_object($lang) ? get_class($lang) : gettype($lang)) + (get_debug_type($lang)) )); } @@ -491,7 +484,7 @@ protected function getLatestObjectRoute($lang = null) $collection = $loader->load()->objects(); - if (!count($collection)) { + if (count($collection) === 0) { return $this->createRouteObject(); } @@ -515,9 +508,7 @@ public function url($lang = null) if ($slug) { return $slug; } - - $url = (string)$this->getLatestObjectRoute($lang)->getSlug(); - return $url; + return (string)$this->getLatestObjectRoute($lang)->getSlug(); } /** @@ -535,7 +526,7 @@ public function slugify($str) } $metadata = $this->metadata(); - $separator = isset($metadata['routable']['separator']) ? $metadata['routable']['separator'] : '-'; + $separator = ($metadata['routable']['separator'] ?? '-'); $delimiters = '-_|'; $pregDelim = preg_quote($delimiters); $directories = '\\/'; @@ -545,41 +536,41 @@ public function slugify($str) $slug = preg_replace('![^(\p{L}|\p{N})(\s|\/)]!u', $separator, $str); if (!isset($metadata['routable']['lowercase']) || $metadata['routable']['lowercase'] === false) { - $slug = mb_strtolower($slug, 'UTF-8'); + $slug = mb_strtolower((string)$slug, 'UTF-8'); } // Strip HTML - $slug = strip_tags($slug); + $slug = strip_tags((string)$slug); // Remove diacritics $slug = htmlentities($slug, ENT_COMPAT, 'UTF-8'); $slug = preg_replace('!&([a-zA-Z])(uml|acute|grave|circ|tilde|cedil|ring);!', '$1', $slug); // Simplify ligatures - $slug = preg_replace('!&([a-zA-Z]{2})(lig);!', '$1', $slug); + $slug = preg_replace('!&([a-zA-Z]{2})(lig);!', '$1', (string)$slug); // Remove unescaped HTML characters $unescaped = '!&(raquo|laquo|rsaquo|lsaquo|rdquo|ldquo|rsquo|lsquo|hellip|amp|nbsp|quot|ordf|ordm);!'; - $slug = preg_replace($unescaped, '', $slug); + $slug = preg_replace($unescaped, '', (string)$slug); // Unify all dashes/underscores as one separator character $flip = ($separator === '-') ? '_' : '-'; - $slug = preg_replace('![' . preg_quote($flip) . ']+!u', $separator, $slug); + $slug = preg_replace('![' . preg_quote($flip) . ']+!u', $separator, (string)$slug); // Remove all whitespace and normalize delimiters - $slug = preg_replace('![_\|\s|\(\)]+!', $separator, $slug); + $slug = preg_replace('![_\|\s|\(\)]+!', $separator, (string)$slug); // Squeeze multiple delimiters and whitespace with a single separator - $slug = preg_replace('![' . $pregDelim . '\s]{2,}!', $separator, $slug); + $slug = preg_replace('![' . $pregDelim . '\s]{2,}!', $separator, (string)$slug); // Squeeze multiple URI path delimiters - $slug = preg_replace('![' . $pregDir . ']{2,}!', $separator, $slug); + $slug = preg_replace('![' . $pregDir . ']{2,}!', $separator, (string)$slug); // Remove delimiters surrouding URI path delimiters - $slug = preg_replace('!(?<=[' . $pregDir . '])[' . $pregDelim . ']|[' . $pregDelim . '](?=[' . $pregDir . '])!', '', $slug); + $slug = preg_replace('!(?<=[' . $pregDir . '])[' . $pregDelim . ']|[' . $pregDelim . '](?=[' . $pregDir . '])!', '', (string)$slug); // Strip leading and trailing dashes or underscores - $slug = trim($slug, $delimiters); + $slug = trim((string)$slug, $delimiters); // Cache the slugified string $sluggedArray[$str] = $slug; @@ -594,9 +585,8 @@ public function slugify($str) * * @param string $slug A slug. * @throws UnexpectedValueException If the slug affixes are invalid. - * @return string */ - protected function finalizeSlug($slug) + protected function finalizeSlug($slug): string { $prefix = $this->slugPrefix(); if ($prefix) { @@ -604,7 +594,7 @@ protected function finalizeSlug($slug) if ($slug === $prefix) { throw new UnexpectedValueException('The slug is the same as the prefix.'); } - $slug = $prefix . preg_replace('!^' . preg_quote($prefix) . '\b!', '', $slug); + $slug = $prefix . preg_replace('!^' . preg_quote((string)$prefix) . '\b!', '', $slug); } $suffix = $this->slugSuffix(); @@ -613,12 +603,10 @@ protected function finalizeSlug($slug) if ($slug === $suffix) { throw new UnexpectedValueException('The slug is the same as the suffix.'); } - $slug = preg_replace('!\b' . preg_quote($suffix) . '$!', '', $slug) . $suffix; + $slug = preg_replace('!\b' . preg_quote((string)$suffix) . '$!', '', $slug) . $suffix; } - $slug = rtrim($slug, '/'); - - return $slug; + return rtrim($slug, '/'); } /** @@ -628,7 +616,7 @@ protected function finalizeSlug($slug) * * @return boolean Success or failure. */ - protected function deleteObjectRoutes() + protected function deleteObjectRoutes(): bool { if (!$this->objType()) { return false; @@ -661,18 +649,14 @@ protected function deleteObjectRoutes() /** * Create a route collection loader. - * - * @return CollectionLoader */ - public function createRouteObjectCollectionLoader() + public function createRouteObjectCollectionLoader(): \Charcoal\Loader\CollectionLoader { - $loader = new CollectionLoader([ + return new CollectionLoader([ 'logger' => $this->logger, 'factory' => $this->modelFactory(), 'model' => $this->getRouteObjectPrototype(), ]); - - return $loader; } /** @@ -682,9 +666,7 @@ public function createRouteObjectCollectionLoader() */ public function createRouteObject() { - $route = $this->modelFactory()->create($this->getObjectRouteClass()); - - return $route; + return $this->modelFactory()->create($this->getObjectRouteClass()); } /** @@ -694,9 +676,7 @@ public function createRouteObject() */ public function getRouteObjectPrototype() { - $proto = $this->modelFactory()->get($this->getObjectRouteClass()); - - return $proto; + return $this->modelFactory()->get($this->getObjectRouteClass()); } /** @@ -799,7 +779,7 @@ public function routeOptionsIdent() public function isActiveRoute() { if (isset($this['active'])) { - return !!$this['active']; + return (bool)$this['active']; } else { return true; } diff --git a/packages/object/src/Charcoal/Object/TimestampableInterface.php b/packages/object/src/Charcoal/Object/TimestampableInterface.php index 5ce206bcc..08daadb38 100644 --- a/packages/object/src/Charcoal/Object/TimestampableInterface.php +++ b/packages/object/src/Charcoal/Object/TimestampableInterface.php @@ -1,5 +1,7 @@ ip = null; @@ -93,10 +89,8 @@ public function setIp($ip) /** * Retrieve the client IP address. - * - * @return integer|null */ - public function getIp() + public function getIp(): ?int { return $this->ip; } @@ -106,16 +100,13 @@ public function getIp() * * @param string $lang The language code. * @throws InvalidArgumentException If the argument is not a string. - * @return self */ - public function setLang($lang) + public function setLang($lang): static { - if ($lang !== null) { - if (!is_string($lang)) { - throw new InvalidArgumentException( - 'Language must be a string' - ); - } + if ($lang !== null && !is_string($lang)) { + throw new InvalidArgumentException( + 'Language must be a string' + ); } $this->lang = $lang; @@ -138,16 +129,13 @@ public function getLang() * * @param string $origin The source URL or identifier of the submission. * @throws InvalidArgumentException If the argument is not a string. - * @return self */ - public function setOrigin($origin) + public function setOrigin($origin): static { - if ($origin !== null) { - if (!is_string($origin)) { - throw new InvalidArgumentException( - 'Origin must be a string.' - ); - } + if ($origin !== null && !is_string($origin)) { + throw new InvalidArgumentException( + 'Origin must be a string.' + ); } $this->origin = $origin; @@ -173,9 +161,8 @@ public function resolveOrigin() $uri .= '://' . $host; } - $uri .= getenv('REQUEST_URI'); - return $uri; + return $uri . getenv('REQUEST_URI'); } /** @@ -195,9 +182,8 @@ public function getOrigin() * NULL is accepted and instances of DateTimeInterface are recommended; * any other value will be converted (if possible) into one. * @throws InvalidArgumentException If the timestamp is invalid. - * @return self */ - public function setTs($timestamp) + public function setTs($timestamp): static { if ($timestamp === null) { $this->ts = null; @@ -228,10 +214,8 @@ public function setTs($timestamp) /** * Retrieve the creation timestamp. - * - * @return DateTimeInterface|null */ - public function getTs() + public function getTs(): ?\DateTimeInterface { return $this->ts; } @@ -242,6 +226,7 @@ public function getTs() * @see Charcoal\Source\StorableTrait::preSave() For the "create" Event. * @return boolean */ + #[\Override] protected function preSave() { $result = parent::preSave(); @@ -252,7 +237,7 @@ protected function preSave() $this->setIp(getenv('REMOTE_ADDR')); } - if (!isset($this->origin)) { + if ($this->origin === null) { $this->setOrigin($this->resolveOrigin()); } diff --git a/packages/object/src/Charcoal/Object/UserDataInterface.php b/packages/object/src/Charcoal/Object/UserDataInterface.php index 71b0958a6..d75ed56b3 100644 --- a/packages/object/src/Charcoal/Object/UserDataInterface.php +++ b/packages/object/src/Charcoal/Object/UserDataInterface.php @@ -1,5 +1,7 @@ obj = $this->getMockForTrait(ArchivableTrait::class); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $this->assertTrue(true); } diff --git a/packages/object/tests/Charcoal/Object/CategorizableTraitTest.php b/packages/object/tests/Charcoal/Object/CategorizableTraitTest.php index 80cb10288..5c6df57f3 100644 --- a/packages/object/tests/Charcoal/Object/CategorizableTraitTest.php +++ b/packages/object/tests/Charcoal/Object/CategorizableTraitTest.php @@ -14,25 +14,20 @@ class CategorizableTraitTest extends AbstractTestCase { /** * Tested Class. - * - * @var CategorizableTrait */ private $obj; /** * Set up the test. - * - * @return void */ public function setUp(): void { - $this->obj = $this->getMockForTrait(CategorizableTrait::class); + $this->obj = new class { + use CategorizableTrait; + }; } - /** - * @return void - */ - public function testSetCategoryType() + public function testSetCategoryType(): void { $obj = $this->obj; $this->assertNull($obj->getCategoryType()); diff --git a/packages/object/tests/Charcoal/Object/CategoryTraitTest.php b/packages/object/tests/Charcoal/Object/CategoryTraitTest.php index 205f53bf7..094fdeba2 100644 --- a/packages/object/tests/Charcoal/Object/CategoryTraitTest.php +++ b/packages/object/tests/Charcoal/Object/CategoryTraitTest.php @@ -3,9 +3,8 @@ namespace Charcoal\Tests\Object; // From 'charcoal-object' -use Charcoal\Object\CategoryTrait; use Charcoal\Tests\AbstractTestCase; -use Charcoal\Tests\Object\ContainerProvider; +use Charcoal\Tests\Object\Mocks\CategoryTraitTestDouble; /** * @@ -14,18 +13,13 @@ class CategoryTraitTest extends AbstractTestCase { /** * Set up the test. - * - * @return CategoryTrait */ public function createTrait() { - return $this->getMockForTrait(CategoryTrait::class); + return $this->createPartialMock(CategoryTraitTestDouble::class, [ 'loadCategoryItems' ]); } - /** - * @return void - */ - public function testUnsetCategoryItemTypeThrowsException() + public function testUnsetCategoryItemTypeThrowsException(): void { $mock = $this->createTrait(); @@ -33,10 +27,7 @@ public function testUnsetCategoryItemTypeThrowsException() $mock->getCategoryItemType(); } - /** - * @return void - */ - public function testSetCategoryItemType() + public function testSetCategoryItemType(): void { $mock = $this->createTrait(); @@ -48,42 +39,36 @@ public function testSetCategoryItemType() $mock->setCategoryItemType(false); } - /** - * @return void - */ - public function testNumCategoryItems() + public function testNumCategoryItems(): void { $mock = $this->createTrait(); - $mock->expects($this->any()) + $mock->expects($this->once()) ->method('loadCategoryItems') - ->will($this->returnValue([])); + ->willReturn([]); $this->assertEquals(0, $mock->getNumCategoryItems()); $mock = $this->createTrait(); - $mock->expects($this->any()) + $mock->expects($this->once()) ->method('loadCategoryItems') - ->will($this->returnValue([ 'item' ])); + ->willReturn([ 'item' ]); $this->assertEquals(1, $mock->getNumCategoryItems()); } - /** - * @return void - */ - public function testHasCategoryItems() + public function testHasCategoryItems(): void { $mock = $this->createTrait(); - $mock->expects($this->any()) + $mock->expects($this->once()) ->method('loadCategoryItems') - ->will($this->returnValue([])); + ->willReturn([]); $this->assertFalse($mock->hasCategoryItems()); $mock = $this->createTrait(); - $mock->expects($this->any()) + $mock->expects($this->once()) ->method('loadCategoryItems') - ->will($this->returnValue([ 'item' ])); + ->willReturn([ 'item' ]); $this->assertTrue($mock->hasCategoryItems()); } diff --git a/packages/object/tests/Charcoal/Object/ContainerProvider.php b/packages/object/tests/Charcoal/Object/ContainerProvider.php index b930fa1a8..a718e72ab 100644 --- a/packages/object/tests/Charcoal/Object/ContainerProvider.php +++ b/packages/object/tests/Charcoal/Object/ContainerProvider.php @@ -34,9 +34,8 @@ class ContainerProvider * Register the unit tests required services. * * @param Container $container A DI container. - * @return void */ - public function registerBaseServices(Container $container) + public function registerBaseServices(Container $container): void { $this->registerDatabase($container); $this->registerLogger($container); @@ -50,11 +49,10 @@ public function registerBaseServices(Container $container) * Note: Uses SQLite to create a database in memory. * * @param Container $container A DI container. - * @return void */ - public function registerDatabase(Container $container) + public function registerDatabase(Container $container): void { - $container['database'] = function () { + $container['database'] = function (): \PDO { $pdo = new PDO('sqlite::memory:'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; @@ -65,167 +63,141 @@ public function registerDatabase(Container $container) * Setup the application's logging interface. * * @param Container $container A DI container. - * @return void */ - public function registerLogger(Container $container) + public function registerLogger(Container $container): void { - $container['logger'] = function () { - return new NullLogger(); - }; + $container['logger'] = (fn(): \Psr\Log\NullLogger => new NullLogger()); } /** * Setup the application's caching interface. * * @param Container $container A DI container. - * @return void */ - public function registerCache(Container $container) + public function registerCache(Container $container): void { - $container['cache'] = function () { - return new Pool(); - }; + $container['cache'] = (fn(): \Stash\Pool => new Pool()); } /** * Setup the framework's metadata loader interface. * * @param Container $container A DI container. - * @return void */ - public function registerMetadataLoader(Container $container) + public function registerMetadataLoader(Container $container): void { - $container['metadata/loader'] = function (Container $container) { - return new MetadataLoader([ - 'cache' => $container['cache'], - 'logger' => $container['logger'], - 'base_path' => realpath(__DIR__ . '/../../../'), - 'paths' => [ - 'metadata', - // Standalone repo - 'vendor/charcoal/property/metadata', - // Monorepo - '/../property/metadata' - ] - ]); - }; + $container['metadata/loader'] = (fn(Container $container): \Charcoal\Model\Service\MetadataLoader => new MetadataLoader([ + 'cache' => $container['cache'], + 'logger' => $container['logger'], + 'base_path' => realpath(__DIR__ . '/../../../'), + 'paths' => [ + 'metadata', + // Standalone repo + 'vendor/charcoal/property/metadata', + // Monorepo + '/../property/metadata' + ] + ])); } /** * Setup the framework's data source factory. * * @param Container $container A DI container. - * @return void */ - public function registerSourceFactory(Container $container) + public function registerSourceFactory(Container $container): void { $this->registerLogger($container); $this->registerCache($container); $this->registerDatabase($container); - $container['source/factory'] = function ($container) { - return new Factory([ - 'map' => [ - 'database' => DatabaseSource::class - ], - 'arguments' => [[ - 'logger' => $container['logger'], - 'cache' => $container['cache'], - 'pdo' => $container['database'] - ]] - ]); - }; + $container['source/factory'] = (fn($container): \Charcoal\Factory\GenericFactory => new Factory([ + 'map' => [ + 'database' => DatabaseSource::class + ], + 'arguments' => [[ + 'logger' => $container['logger'], + 'cache' => $container['cache'], + 'pdo' => $container['database'] + ]] + ])); } /** * Setup the framework's model factory. * * @param Container $container A DI container. - * @return void */ - public function registerModelFactory(Container $container) + public function registerModelFactory(Container $container): void { $this->registerSourceFactory($container); $this->registerMetadataLoader($container); $this->registerPropertyFactory($container); - $container['model/factory'] = function ($container) { - return new Factory([ - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'], - 'metadata_loader' => $container['metadata/loader'], - 'source_factory' => $container['source/factory'], - 'property_factory' => $container['property/factory'] - ]] - ]); - }; + $container['model/factory'] = (fn($container): \Charcoal\Factory\GenericFactory => new Factory([ + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'], + 'metadata_loader' => $container['metadata/loader'], + 'source_factory' => $container['source/factory'], + 'property_factory' => $container['property/factory'] + ]] + ])); } /** * Setup the framework's property factory. * * @param Container $container A DI container. - * @return void */ - public function registerPropertyFactory(Container $container) + public function registerPropertyFactory(Container $container): void { $this->registerLogger($container); $this->registerDatabase($container); $this->registerTranslator($container); - $container['property/factory'] = function (Container $container) { - return new Factory([ - 'resolver_options' => [ - 'prefix' => '\\Charcoal\\Property\\', - 'suffix' => 'Property' - ], - 'arguments' => [[ - 'container' => $container, - 'database' => $container['database'], - 'logger' => $container['logger'], - 'translator' => $container['translator'] - ]] - ]); - }; + $container['property/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'resolver_options' => [ + 'prefix' => '\\Charcoal\\Property\\', + 'suffix' => 'Property' + ], + 'arguments' => [[ + 'container' => $container, + 'database' => $container['database'], + 'logger' => $container['logger'], + 'translator' => $container['translator'] + ]] + ])); } /** * Setup the framework's collection loader interface. * * @param Container $container A DI container. - * @return void */ - public function registerModelCollectionLoader(Container $container) + public function registerModelCollectionLoader(Container $container): void { - $container['model/collection/loader'] = function (Container $container) { - return new CollectionLoader([ - 'logger' => $container['logger'], - 'cache' => $container['cache'] - ]); - }; + $container['model/collection/loader'] = (fn(Container $container): \Charcoal\Loader\CollectionLoader => new CollectionLoader([ + 'logger' => $container['logger'], + 'cache' => $container['cache'] + ])); } /** * Setup the framework's Translator. * * @param Container $container A DI container. - * @return void */ - public function registerTranslator(Container $container) + public function registerTranslator(Container $container): void { - $container['locales/manager'] = function () { - return new LocalesManager([ - 'locales' => [ - 'en' => [ 'locale' => 'en-US' ] - ] - ]); - }; - - $container['translator'] = function (Container $container) { - return new Translator([ - 'manager' => $container['locales/manager'] - ]); - }; + $container['locales/manager'] = (fn(): \Charcoal\Translator\LocalesManager => new LocalesManager([ + 'locales' => [ + 'en' => [ 'locale' => 'en-US' ] + ] + ])); + + $container['translator'] = (fn(Container $container): \Charcoal\Translator\Translator => new Translator([ + 'manager' => $container['locales/manager'] + ])); } } diff --git a/packages/object/tests/Charcoal/Object/ContentTest.php b/packages/object/tests/Charcoal/Object/ContentTest.php index d9f3e68c5..0b1adb6f6 100644 --- a/packages/object/tests/Charcoal/Object/ContentTest.php +++ b/packages/object/tests/Charcoal/Object/ContentTest.php @@ -19,22 +19,16 @@ class ContentTest extends AbstractTestCase { /** * Tested Class. - * - * @var Content */ - private $obj; + private \Charcoal\Object\Content $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -43,10 +37,7 @@ public function setUp(): void $this->obj = $container['model/factory']->create(Content::class); } - /** - * @return void - */ - public function testDefaults() + public function testDefaults(): void { $this->assertTrue($this->obj['active']); $this->assertEquals(0, $this->obj['position']); @@ -64,10 +55,7 @@ public function testDefaults() $this->assertTrue($this->obj['revisionEnabled']); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $ret = $this->obj->setData([ 'active' => false, @@ -90,10 +78,7 @@ public function testSetData() $this->assertEquals(['foo', 'bar'], $this->obj['requiredAclPermissions']); } - /** - * @return void - */ - public function testSetActive() + public function testSetActive(): void { $this->assertTrue($this->obj['active']); $ret = $this->obj->setActive(false); @@ -110,12 +95,8 @@ public function testSetActive() $this->assertTrue($this->obj['active']); } - /** - * @return void - */ - public function testSetPosition() + public function testSetPosition(): void { - $this->obj = $this->obj; $this->assertEquals(0, $this->obj['position']); $ret = $this->obj->setPosition(42); $this->assertSame($ret, $this->obj); @@ -134,10 +115,7 @@ public function testSetPosition() $this->obj->setPosition('foo'); } - /** - * @return void - */ - public function testSetCreated() + public function testSetCreated(): void { $ret = $this->obj->setCreated('2015-01-01 13:05:45'); $this->assertSame($ret, $this->obj); @@ -156,19 +134,13 @@ public function testSetCreated() $this->obj->setCreated(false); } - /** - * @return void - */ - public function testSetCreatedInvalidDate() + public function testSetCreatedInvalidDate(): void { $this->expectException('\Exception'); $this->obj->setCreated('foo.bar'); } - /** - * @return void - */ - public function testSetCreatedBy() + public function testSetCreatedBy(): void { $ret = $this->obj->setCreatedBy('Me'); $this->assertSame($ret, $this->obj); @@ -178,10 +150,7 @@ public function testSetCreatedBy() //$this->obj->setCreatedBy(false); } - /** - * @return void - */ - public function testSetLastModified() + public function testSetLastModified(): void { $ret = $this->obj->setLastModified('2015-01-01 13:05:45'); $this->assertSame($ret, $this->obj); @@ -200,19 +169,13 @@ public function testSetLastModified() $this->obj->setLastModified(false); } - /** - * @return void - */ - public function testSetLastModifiedInvalidDate() + public function testSetLastModifiedInvalidDate(): void { $this->expectException('\Exception'); $this->obj->setLastModified('foo.bar'); } - /** - * @return void - */ - public function testSetLastModifiedBy() + public function testSetLastModifiedBy(): void { $ret = $this->obj->setLastModifiedBy('Me'); $this->assertSame($ret, $this->obj); @@ -222,10 +185,7 @@ public function testSetLastModifiedBy() //$this->obj->setLastModifiedBy(false); } - /** - * @return void - */ - public function testSetRequiredAclPermissions() + public function testSetRequiredAclPermissions(): void { $ret = $this->obj->setRequiredAclPermissions(['a', 'b', 'c']); $this->assertSame($ret, $this->obj); @@ -247,12 +207,10 @@ public function testSetRequiredAclPermissions() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/object/tests/Charcoal/Object/HierarchicalTraitTest.php b/packages/object/tests/Charcoal/Object/HierarchicalTraitTest.php index 69f38fbed..1cbf45371 100644 --- a/packages/object/tests/Charcoal/Object/HierarchicalTraitTest.php +++ b/packages/object/tests/Charcoal/Object/HierarchicalTraitTest.php @@ -18,22 +18,17 @@ class HierarchicalTraitTest extends AbstractTestCase * * @var Hierarchical */ - private $obj; + private \Charcoal\Tests\Object\Mocks\HierarchicalClass $obj; /** * Set up the test. - * - * @return void */ public function setUp(): void { $this->obj = new HierarchicalObject(); } - /** - * @return void - */ - public function testSetMaster() + public function testSetMaster(): void { $obj = $this->obj; // $master = $this->createMock(get_class($obj)); @@ -43,49 +38,37 @@ public function testSetMaster() $this->assertSame($master, $obj->getMaster()); } - /** - * @return void - */ - public function testHasMaster() + public function testHasMaster(): void { $obj = $this->obj; $this->assertFalse($obj->hasMaster()); - $master = $this->createMock(get_class($obj)); + $master = $this->createStub($obj::class); $obj->setMaster($master); $this->assertTrue($obj->hasMaster()); } - /** - * @return void - */ - public function testIsTopLevel() + public function testIsTopLevel(): void { $obj = $this->obj; $this->assertTrue($obj->isTopLevel()); - $master = $this->createMock(get_class($obj)); + $master = $this->createStub($obj::class); $obj->setMaster($master); $this->assertFalse($obj->isTopLevel()); } - /** - * @return void - */ - public function testIsLastLevel() + public function testIsLastLevel(): void { $obj = $this->obj; $this->assertTrue($obj->isLastLevel()); - $children = array_fill(0, 4, $this->createMock(get_class($obj))); + $children = array_fill(0, 4, $this->createMock($obj::class)); $obj->setChildren($children); $this->assertFalse($obj->isLastLevel()); } - /** - * @return void - */ - public function testHierarchyLevel() + public function testHierarchyLevel(): void { $obj = $this->obj; @@ -93,7 +76,7 @@ public function testHierarchyLevel() $master = clone $obj; $master2 = clone $obj; - $children = array_fill(0, 4, $this->createMock(get_class($obj))); + $children = array_fill(0, 4, $this->createMock($obj::class)); $obj->setMaster($master); $obj->setChildren($children); @@ -107,17 +90,14 @@ public function testHierarchyLevel() $this->assertEquals(3, $obj->hierarchyLevel()); } - /** - * @return void - */ - public function testToplevelMaster() + public function testToplevelMaster(): void { $obj = $this->obj; $this->assertSame(null, $obj->toplevelMaster()); - $master1 = $this->createMock(get_class($obj)); - $master2 = $this->createMock(get_class($obj)); + $master1 = $this->createMock($obj::class); + $master2 = $this->createMock($obj::class); $obj->setMaster($master1->id()); // No longer easily testable because of modelLoader. @@ -129,16 +109,13 @@ public function testToplevelMaster() // $this->assertSame($master2, $obj->toplevelMaster()); } - /** - * @return void - */ - public function testHierarchy() + public function testHierarchy(): void { - $obj = $this->createPartialMock(get_class($this->obj), ['getMasterObject']); + $obj = $this->createPartialMock($this->obj::class, ['getMasterObject']); $this->assertEquals([], $obj->hierarchy()); - $master1 = $this->createPartialMock(get_class($this->obj), ['getMasterObject']); - $master2 = $this->createTestProxy(get_class($this->obj)); + $master1 = $this->createPartialMock($this->obj::class, ['getMasterObject']); + $master2 = $this->obj; $obj->setMaster($master1->getId()); $obj->method('getMasterObject')->willReturn($master1); @@ -152,10 +129,7 @@ public function testHierarchy() $this->assertSame([$master1, $master2], $obj->hierarchy()); } - /** - * @return void - */ - public function testInvertedHierarchy() + public function testInvertedHierarchy(): void { $obj = $this->obj; @@ -172,13 +146,10 @@ public function testInvertedHierarchy() $this->assertSame([$master2, $master1], $obj->invertedHierarchy()); } - /** - * @return void - */ - public function testIsMasterOf() + public function testIsMasterOf(): void { $obj = $this->obj; - $master = $this->createTestProxy(get_class($obj)); + $master = clone($this->obj); $this->assertFalse($master->isMasterOf($obj)); $obj->setMaster($master->getId()); @@ -186,57 +157,45 @@ public function testIsMasterOf() $this->assertFalse($obj->isMasterOf($master)); } - /** - * @return void - */ - public function testHasChildren() + public function testHasChildren(): void { $obj = $this->obj; $this->assertFalse($obj->hasChildren()); - $children = array_fill(0, 4, $this->createMock(get_class($obj))); + $children = array_fill(0, 4, $this->createMock($obj::class)); $obj->setChildren($children); $this->assertTrue($obj->hasChildren()); } - /** - * @return void - */ - public function testNumChildren() + public function testNumChildren(): void { $obj = $this->obj; $this->assertEquals(0, $obj->numChildren()); - $children = array_fill(0, 4, $this->createMock(get_class($obj))); + $children = array_fill(0, 4, $this->createMock($obj::class)); $obj->setChildren($children); $this->assertEquals(4, $obj->numChildren()); - $child5 = $this->createMock(get_class($obj)); + $child5 = $this->createStub($obj::class); $obj->addChild($child5); $this->assertEquals(5, $obj->numChildren()); } - /** - * @return void - */ - public function testIsChildOf() + public function testIsChildOf(): void { $obj = $this->obj; - $master = $this->createTestProxy(get_class($obj)); + $master = clone($obj); $this->assertFalse($obj->isChildOf($master)); $obj->setMaster($master->getId()); $this->assertTrue($obj->isChildOf($master)); } - /** - * @return void - */ - public function testRecurisveIsChildOf() + public function testRecursiveIsChildOf(): void { $obj = $this->obj; - $master = $this->createTestProxy(get_class($obj)); + $master = clone($obj); $this->assertFalse($obj->isChildOf($master)); $obj->setMaster($master->getId()); diff --git a/packages/object/tests/Charcoal/Object/Mocks/AbstractModel.php b/packages/object/tests/Charcoal/Object/Mocks/AbstractModel.php index 3455f735b..b7d68e94e 100644 --- a/packages/object/tests/Charcoal/Object/Mocks/AbstractModel.php +++ b/packages/object/tests/Charcoal/Object/Mocks/AbstractModel.php @@ -39,7 +39,7 @@ abstract public static function objType(); /** * @param array|null $data The model dependencies. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { if (isset($data['factory'])) { $this->setModelFactory($data['factory']); @@ -155,7 +155,7 @@ public function setData(array $data) * @param array|null $filters Retrieve a subset. * @return array */ - public function data(array $filters = null) + public function data(?array $filters = null) { return null; } @@ -188,9 +188,8 @@ public function defaultData() /** * @param array $propertyIdents Optional. List of property identifiers * for retrieving a subset of property objects. - * @return null */ - public function properties(array $propertyIdents = null) + public function properties(?array $propertyIdents = null) { return null; } diff --git a/packages/object/tests/Charcoal/Object/Mocks/CategoryTraitTestDouble.php b/packages/object/tests/Charcoal/Object/Mocks/CategoryTraitTestDouble.php new file mode 100644 index 000000000..748435b43 --- /dev/null +++ b/packages/object/tests/Charcoal/Object/Mocks/CategoryTraitTestDouble.php @@ -0,0 +1,15 @@ +obj = $container['model/factory']->create(ObjectRevision::class); } - /** - * @return void - */ - public function testSetObjType() + public function testSetObjType(): void { $this->assertNull($this->obj['targetType']); $ret = $this->obj->setTargetType('foobar'); @@ -57,10 +48,7 @@ public function testSetObjType() $this->obj->setTargetType(false); } - /** - * @return void - */ - public function testSetObjId() + public function testSetObjId(): void { $this->assertNull($this->obj['targetId']); $ret = $this->obj->setTargetId(42); @@ -68,10 +56,7 @@ public function testSetObjId() $this->assertEquals(42, $this->obj['targetId']); } - /** - * @return void - */ - public function testSetRevNum() + public function testSetRevNum(): void { $this->assertNull($this->obj['revNum']); $ret = $this->obj->setRevNum(66); @@ -85,10 +70,7 @@ public function testSetRevNum() $this->obj->setRevNum([]); } - /** - * @return void - */ - public function testSetRevTs() + public function testSetRevTs(): void { $obj = $this->obj; $this->assertNull($obj['revTs']); @@ -104,10 +86,7 @@ public function testSetRevTs() $obj->setRevTs(false); } - /** - * @return void - */ - public function testSetRevUser() + public function testSetRevUser(): void { $this->assertNull($this->obj['revUser']); $ret = $this->obj->setRevUser('me'); @@ -121,10 +100,7 @@ public function testSetRevUser() $this->obj->setRevUser(false); } - /** - * @return void - */ - public function testSetDataPrev() + public function testSetDataPrev(): void { $this->assertNull($this->obj['dataPrev']); $ret = $this->obj->setDataPrev(['foo'=>1]); @@ -135,10 +111,7 @@ public function testSetDataPrev() $this->assertEquals([], $this->obj->setDataPrev(null)['dataPrev']); } - /** - * @return void - */ - public function testSetDataObj() + public function testSetDataObj(): void { $this->assertNull($this->obj['dataObj']); $ret = $this->obj->setDataObj(['foo'=>1]); @@ -149,10 +122,7 @@ public function testSetDataObj() $this->assertEquals([], $this->obj->setDataObj(null)['dataObj']); } - /** - * @return void - */ - public function testSetDataDiff() + public function testSetDataDiff(): void { $this->assertNull($this->obj['dataDiff']); $ret = $this->obj->setDataDiff(['foo'=>1]); @@ -163,10 +133,7 @@ public function testSetDataDiff() $this->assertEquals([], $this->obj->setDataDiff(null)['dataDiff']); } - /** - * @return void - */ - public function testCreateDiff() + public function testCreateDiff(): void { $this->assertEquals([], $this->obj->createDiff([], [])); $ret = $this->obj->createDiff(['foo'=>1], ['foo'=>2]); @@ -185,12 +152,10 @@ public function testCreateDiff() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/object/tests/Charcoal/Object/ObjectRouteTest.php b/packages/object/tests/Charcoal/Object/ObjectRouteTest.php index 9451fe128..724bb4dcc 100644 --- a/packages/object/tests/Charcoal/Object/ObjectRouteTest.php +++ b/packages/object/tests/Charcoal/Object/ObjectRouteTest.php @@ -19,22 +19,16 @@ class ObjectRouteTest extends AbstractTestCase { /** * Tested Class. - * - * @var ObjectRoute */ - private $obj; + private \Charcoal\Object\ObjectRoute $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -43,18 +37,12 @@ public function setUp(): void $this->obj = $container['model/factory']->create(ObjectRoute::class); } - /** - * @return void - */ - public function testDefaults() + public function testDefaults(): void { $this->assertNull($this->obj['id']); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $ret = $this->obj->setData([ 'id' => 42, @@ -82,10 +70,7 @@ public function testSetData() $this->assertEquals('baz', $this->obj->getRouteTemplate()); } - /** - * @return void - */ - public function testSetId() + public function testSetId(): void { $ret = $this->obj->setId(3); $this->assertSame($ret, $this->obj); @@ -98,18 +83,12 @@ public function testSetId() $this->assertEquals(10, $this->obj['id']); } - /** - * @return void - */ - public function testSetCreationDate() + public function testSetCreationDate(): void { $this->assertNull($this->obj->getCreationDate()); } - /** - * @return void - */ - public function testLastModificationDate() + public function testLastModificationDate(): void { $date = $this->obj->getLastModificationDate(); $this->obj->update(); @@ -118,10 +97,7 @@ public function testLastModificationDate() $this->assertIsBool($date2 > $date); } - /** - * @return void - */ - public function testLang() + public function testLang(): void { $ret = $this->obj->setLang('en'); $this->assertSame($ret, $this->obj); @@ -134,10 +110,7 @@ public function testLang() $this->assertEquals('jp', $this->obj['lang']); } - /** - * @return void - */ - public function testSetSlug() + public function testSetSlug(): void { $this->assertNull($this->obj['slug']); $ret = $this->obj->setSlug('foo'); @@ -159,12 +132,10 @@ public function testSetSlug() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/object/tests/Charcoal/Object/ObjectScheduleTest.php b/packages/object/tests/Charcoal/Object/ObjectScheduleTest.php index 3a6a8a864..0516603f0 100644 --- a/packages/object/tests/Charcoal/Object/ObjectScheduleTest.php +++ b/packages/object/tests/Charcoal/Object/ObjectScheduleTest.php @@ -19,22 +19,16 @@ class ObjectScheduleTest extends AbstractTestCase { /** * Tested Class. - * - * @var ObjectSchedule */ - private $obj; + private \Charcoal\Object\ObjectSchedule $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -43,10 +37,7 @@ public function setUp(): void $this->obj = $container['model/factory']->create(ObjectSchedule::class); } - /** - * @return void - */ - public function testSetTargetType() + public function testSetTargetType(): void { $this->assertNull($this->obj->getTargetType()); $ret = $this->obj->setTargetType('foobar'); @@ -57,10 +48,7 @@ public function testSetTargetType() $this->obj->setTargetType(false); } - /** - * @return void - */ - public function testSetTargetId() + public function testSetTargetId(): void { $this->assertNull($this->obj->getTargetId()); $ret = $this->obj->setTargetId(42); @@ -68,10 +56,7 @@ public function testSetTargetId() $this->assertEquals(42, $this->obj->getTargetId()); } - /** - * @return void - */ - public function testSetDataDiff() + public function testSetDataDiff(): void { $this->assertEquals([], $this->obj->getDataDiff()); $ret = $this->obj->setDataDiff(['foo'=>42]); @@ -79,10 +64,7 @@ public function testSetDataDiff() $this->assertEquals(['foo'=>42], $this->obj->getDataDiff()); } - /** - * @return void - */ - public function testSetProcessed() + public function testSetProcessed(): void { $this->assertFalse($this->obj->getProcessed()); $ret = $this->obj->setProcessed(true); @@ -90,10 +72,7 @@ public function testSetProcessed() $this->assertTrue($this->obj->getProcessed()); } - /** - * @return void - */ - public function testSetScheduledDate() + public function testSetScheduledDate(): void { $obj = $this->obj; $this->assertNull($obj->getScheduledDate()); @@ -109,19 +88,13 @@ public function testSetScheduledDate() $obj->setScheduledDate(false); } - /** - * @return void - */ - public function testSetScheduledDateInvalidTime() + public function testSetScheduledDateInvalidTime(): void { $this->expectException('\InvalidArgumentException'); $this->obj->setScheduledDate('A totally invalid date time'); } - /** - * @return void - */ - public function testSetProcessedDate() + public function testSetProcessedDate(): void { $obj = $this->obj; $this->assertNull($obj->getProcessedDate()); @@ -137,19 +110,13 @@ public function testSetProcessedDate() $obj->setProcessedDate(false); } - /** - * @return void - */ - public function testSetProcessedDateInvalidTime() + public function testSetProcessedDateInvalidTime(): void { $this->expectException('\InvalidArgumentException'); $this->obj->setProcessedDate('A totally invalid date time'); } - /** - * @return void - */ - public function testProcess() + public function testProcess(): void { $container = $this->container(); $this->obj->setModelFactory($container['model/factory']); @@ -167,12 +134,10 @@ public function testProcess() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/object/tests/Charcoal/Object/PublishableTraitTest.php b/packages/object/tests/Charcoal/Object/PublishableTraitTest.php index 59cce1669..7ec9c37f0 100644 --- a/packages/object/tests/Charcoal/Object/PublishableTraitTest.php +++ b/packages/object/tests/Charcoal/Object/PublishableTraitTest.php @@ -26,19 +26,15 @@ class PublishableTraitTest extends AbstractTestCase * * @var PublishableTrait */ - private $obj; + private \Charcoal\Tests\Object\Mocks\PublishableClass $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -56,10 +52,8 @@ public function setUp(): void * - accepts a string representation of a date/time value * - accepts a {@see \DateTimeInterface} * - accepts an blank value - * - * @return void */ - public function testPublishDate() + public function testPublishDate(): void { $obj = $this->obj; $time = new DateTime('2015-01-01 00:00:00'); @@ -75,10 +69,7 @@ public function testPublishDate() $this->assertEquals($time, $obj->getPublishDate()); } - /** - * @return void - */ - public function testUnexpectedPublishDate() + public function testUnexpectedPublishDate(): void { $obj = $this->obj; @@ -86,10 +77,7 @@ public function testUnexpectedPublishDate() $obj->setPublishDate('foobar'); } - /** - * @return void - */ - public function testInvalidPublishDate() + public function testInvalidPublishDate(): void { $obj = $this->obj; @@ -103,10 +91,8 @@ public function testInvalidPublishDate() * - accepts a string representation of a date/time value * - accepts a {@see \DateTimeInterface} * - accepts an blank value - * - * @return void */ - public function testExpiryDate() + public function testExpiryDate(): void { $obj = $this->obj; $time = new DateTime('2015-01-01 00:00:00'); @@ -122,10 +108,7 @@ public function testExpiryDate() $this->assertEquals($time, $obj->getExpiryDate()); } - /** - * @return void - */ - public function testUnexpectedExpiryDate() + public function testUnexpectedExpiryDate(): void { $obj = $this->obj; @@ -133,10 +116,7 @@ public function testUnexpectedExpiryDate() $obj->setExpiryDate('foobar'); } - /** - * @return void - */ - public function testInvalidExpiryDate() + public function testInvalidExpiryDate(): void { $obj = $this->obj; @@ -144,10 +124,7 @@ public function testInvalidExpiryDate() $obj->setExpiryDate(false); } - /** - * @return void - */ - public function testPublishStatus() + public function testPublishStatus(): void { $obj = $this->obj; @@ -174,14 +151,13 @@ public function testPublishStatus() } /** - * @dataProvider providerPublishStatus * * @param mixed $publishDate A date/time value. * @param mixed $expiryDate A date/time value. * @param string $expectedStatus The expected publication status. - * @return void */ - public function testPublishStatusFromDates($publishDate, $expiryDate, $expectedStatus) + #[\PHPUnit\Framework\Attributes\DataProvider('providerPublishStatus')] + public function testPublishStatusFromDates(?string $publishDate, ?string $expiryDate, string $expectedStatus): void { $obj = $this->obj; if ($publishDate !== null) { @@ -204,10 +180,7 @@ public function testPublishStatusFromDates($publishDate, $expiryDate, $expectedS $this->assertEquals($expectedStatus, $obj->publishDateStatus()); } - /** - * @return array - */ - public function providerPublishStatus() + public static function providerPublishStatus(): array { return [ [ null, null, Publishable::STATUS_PUBLISHED ], @@ -220,10 +193,7 @@ public function providerPublishStatus() ]; } - /** - * @return void - */ - public function testIsPublished() + public function testIsPublished(): void { $obj = $this->obj; @@ -247,12 +217,10 @@ public function testIsPublished() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/object/tests/Charcoal/Object/RevisionableTraitTest.php b/packages/object/tests/Charcoal/Object/RevisionableTraitTest.php index b3d9bbc7f..174d7fd70 100644 --- a/packages/object/tests/Charcoal/Object/RevisionableTraitTest.php +++ b/packages/object/tests/Charcoal/Object/RevisionableTraitTest.php @@ -1 +1,3 @@ assertEquals('', $this->obj->slugPattern()); $ret = $this->obj->setSlugPattern('foo'); @@ -78,10 +69,7 @@ public function testSlugPattern() // $this->assertEquals('', $this->obj->slugPattern()); } - /** - * @return void - */ - public function testSlugPatternRoutable() + public function testSlugPatternRoutable(): void { $this->obj->setMetadata([ 'routable' => [ @@ -91,10 +79,7 @@ public function testSlugPatternRoutable() $this->assertEquals('foofoo', $this->obj->slugPattern()); } - /** - * @return void - */ - public function testSlugPatternWithoutRoutable() + public function testSlugPatternWithoutRoutable(): void { $this->obj->setMetadata([ 'routable' => null, @@ -103,10 +88,7 @@ public function testSlugPatternWithoutRoutable() $this->assertEquals('barbar', $this->obj->slugPattern()); } - /** - * @return void - */ - public function testSlugPatternWithoutMetadata() + public function testSlugPatternWithoutMetadata(): void { $this->obj->setMetadata([]); @@ -114,10 +96,7 @@ public function testSlugPatternWithoutMetadata() $this->obj->slugPattern(); } - /** - * @return void - */ - public function testSlugPrefix() + public function testSlugPrefix(): void { $this->assertEquals('', $this->obj->slugPrefix()); @@ -129,10 +108,7 @@ public function testSlugPrefix() $this->assertEquals('barfoo', $this->obj->slugPrefix()); } - /** - * @return void - */ - public function testSlugSuffix() + public function testSlugSuffix(): void { $this->assertEquals('', $this->obj->slugSuffix()); @@ -144,18 +120,12 @@ public function testSlugSuffix() $this->assertEquals('barfoo', $this->obj->slugSuffix()); } - /** - * @return void - */ - public function testIsSlugEditableIsFalseByDefault() + public function testIsSlugEditableIsFalseByDefault(): void { $this->assertFalse($this->obj->isSlugEditable()); } - /** - * @return void - */ - public function testIsSlugEditable() + public function testIsSlugEditable(): void { $this->obj->setMetadata([ 'routable' => [ @@ -165,10 +135,7 @@ public function testIsSlugEditable() $this->assertTrue($this->obj->isSlugEditable()); } - /** - * @return void - */ - public function testSlug() + public function testSlug(): void { $this->assertNull($this->obj->getSlug()); @@ -180,12 +147,9 @@ public function testSlug() $this->assertNull($this->obj->getSlug()); } - /** - * @return void - */ - public function testGenerateSlug() + public function testGenerateSlug(): void { - $container = $this->container(); + $this->container(); $this->obj->setMetadata([ 'routable' => [ @@ -200,21 +164,17 @@ public function testGenerateSlug() } /** - * @dataProvider providerSlugs * * @param string $str A dirty slug. * @param string $slug A clean $str. - * @return void */ - public function testSlugify($str, $slug) + #[\PHPUnit\Framework\Attributes\DataProvider('providerSlugs')] + public function testSlugify(string $str, string $slug): void { $this->assertEquals($slug, $this->obj->slugify($str)); } - /** - * @return array - */ - public function providerSlugs() + public static function providerSlugs(): array { return [ [ 'A B C', 'a-b-c' ], @@ -228,12 +188,9 @@ public function providerSlugs() ]; } - /** - * @return Translator - */ - private function translator() + private function translator(): \Charcoal\Translator\Translator { - if ($this->translator === null) { + if (!$this->translator instanceof \Charcoal\Translator\Translator) { $this->translator = new Translator([ 'manager' => new LocalesManager([ 'locales' => [ @@ -251,12 +208,10 @@ private function translator() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/object/tests/Charcoal/Object/UserDataTest.php b/packages/object/tests/Charcoal/Object/UserDataTest.php index cfb29210f..409500f7c 100644 --- a/packages/object/tests/Charcoal/Object/UserDataTest.php +++ b/packages/object/tests/Charcoal/Object/UserDataTest.php @@ -19,22 +19,16 @@ class UserDataTest extends AbstractTestCase { /** * Tested Class. - * - * @var UserData */ - private $obj; + private \Charcoal\Object\UserData $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ public function setUp(): void { @@ -43,20 +37,14 @@ public function setUp(): void $this->obj = $container['model/factory']->create(UserData::class); } - /** - * @return void - */ - public function testDefaults() + public function testDefaults(): void { $this->assertNull($this->obj['ip']); $this->assertNull($this->obj['lang']); $this->assertNull($this->obj['ts']); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $ret = $this->obj->setData([ 'ip'=>'192.168.1.1', @@ -70,12 +58,8 @@ public function testSetData() $this->assertEquals($expected, $this->obj['ts']); } - /** - * @return void - */ - public function testSetIp() + public function testSetIp(): void { - $this->obj = $this->obj; $ret = $this->obj->setIp('1.1.1.1'); $this->assertSame($ret, $this->obj); $this->assertEquals(ip2long('1.1.1.1'), $this->obj['ip']); @@ -84,12 +68,8 @@ public function testSetIp() $this->assertEquals(2349255, $this->obj['ip']); } - /** - * @return void - */ - public function testSetLang() + public function testSetLang(): void { - $this->obj = $this->obj; $ret = $this->obj->setLang('en'); $this->assertSame($ret, $this->obj); $this->assertEquals('en', $this->obj['lang']); @@ -98,12 +78,8 @@ public function testSetLang() $this->obj->setLang(false); } - /** - * @return void - */ - public function testSetTs() + public function testSetTs(): void { - $this->obj = $this->obj; $ret = $this->obj->setTs('July 1st, 2014'); $this->assertSame($ret, $this->obj); $expected = new DateTime('July 1st, 2014'); @@ -115,12 +91,10 @@ public function testSetTs() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/object/tests/bootstrap.php b/packages/object/tests/bootstrap.php new file mode 100644 index 000000000..90929e3b5 --- /dev/null +++ b/packages/object/tests/bootstrap.php @@ -0,0 +1,14 @@ + - -> + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/property/src/Charcoal/Property/AbstractProperty.php b/packages/property/src/Charcoal/Property/AbstractProperty.php index 2931d03e7..4b3f660a3 100644 --- a/packages/property/src/Charcoal/Property/AbstractProperty.php +++ b/packages/property/src/Charcoal/Property/AbstractProperty.php @@ -43,7 +43,8 @@ abstract class AbstractProperty extends AbstractEntity implements DescribablePropertyInterface, LoggerAwareInterface, StorablePropertyInterface, - ValidatableInterface + ValidatableInterface, + \Stringable { use LoggerAwareTrait; use DescribableTrait; @@ -62,10 +63,7 @@ abstract class AbstractProperty extends AbstractEntity implements public const DEFAULT_VALIDATABLE = true; public const DEFAULT_ACTIVE = true; - /** - * @var string - */ - private $ident = ''; + private string $ident = ''; /** * @var mixed @@ -77,15 +75,9 @@ abstract class AbstractProperty extends AbstractEntity implements */ private $label; - /** - * @var boolean - */ - private $l10n = self::DEFAULT_L10N; + private bool $l10n = self::DEFAULT_L10N; - /** - * @var boolean - */ - private $multiple = self::DEFAULT_MULTIPLE; + private bool $multiple = self::DEFAULT_MULTIPLE; /** * Array of options for multiple properties @@ -96,45 +88,34 @@ abstract class AbstractProperty extends AbstractEntity implements */ private $multipleOptions; - /** - * @var boolean - */ - private $hidden = self::DEFAULT_HIDDEN; + private bool $hidden = self::DEFAULT_HIDDEN; /** * If true, this property *must* have a value - * @var boolean */ - private $required = self::DEFAULT_REQUIRED; + private bool $required = self::DEFAULT_REQUIRED; /** * Unique properties should not share he same value across 2 objects - * @var boolean */ - private $unique = self::DEFAULT_UNIQUE; + private bool $unique = self::DEFAULT_UNIQUE; - /** - * @var boolean $allowNull - */ - private $allowNull = self::DEFAULT_ALLOW_NULL; + private bool $allowNull = self::DEFAULT_ALLOW_NULL; /** * Only the storable properties should be saved in storage. - * @var boolean */ - private $storable = self::DEFAULT_STORABLE; + private bool $storable = self::DEFAULT_STORABLE; /** * Whether to validate the property. - * @var boolean */ - private $validatable = self::DEFAULT_VALIDATABLE; + private bool $validatable = self::DEFAULT_VALIDATABLE; /** * Inactive properties should be hidden everywhere / unused - * @var boolean */ - private $active = self::DEFAULT_ACTIVE; + private bool $active = self::DEFAULT_ACTIVE; /** * @var Translation|null @@ -169,7 +150,7 @@ abstract class AbstractProperty extends AbstractEntity implements * * @param array $data Optional. Class Dependencies. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { $this->setLogger($data['logger']); $this->setPdo($data['database']); @@ -190,21 +171,16 @@ public function __construct(array $data = null) } } - /** - * @return string - * @deprecated - */ - public function __toString() + #[\Deprecated] + public function __toString(): string { $val = $this->val(); if (is_string($val)) { return $val; + } elseif (is_object($val)) { + return (string)$val; } else { - if (is_object($val)) { - return (string)$val; - } else { - return ''; - } + return ''; } } @@ -213,25 +189,17 @@ public function __toString() * * ## Notes * - Type can not be set, so it must be explicitely provided by each implementing property classes. - * - * @return string */ - abstract public function type(); + abstract public function type(): string; /** * Set the property's identifier. * - * @param string $ident The property identifier. + * @param string $ident The property identifier. * @throws InvalidArgumentException If the identifier is not a string. - * @return self */ - public function setIdent($ident) + public function setIdent(string $ident): static { - if (!is_string($ident)) { - throw new InvalidArgumentException( - 'Ident needs to be string.' - ); - } $this->ident = $ident; return $this; @@ -242,7 +210,7 @@ public function setIdent($ident) * * @return string */ - public function getIdent() + public function getIdent(): string { return $this->ident; } @@ -260,13 +228,12 @@ public function ident() /** * Retrieve the property's localized identifier. * - * @param string|null $lang The language code to return the identifier with. - * @throws LogicException If the property is not multilingual. + * @param string|null $lang The language code to return the identifier with. * @throws RuntimeException If the property has no identifier. * @throws InvalidArgumentException If the language code is invalid. - * @return string + * @throws LogicException If the property is not multilingual. */ - public function l10nIdent($lang = null) + public function l10nIdent(?string $lang = null): string { if ($this->ident === '') { throw new RuntimeException('Missing Property Identifier'); @@ -291,6 +258,31 @@ public function l10nIdent($lang = null) return sprintf('%1$s_%2$s', $this->ident, $lang); } + /** + * Retrieve the property's identifier formatted for field names. + * + * Overrides {@see StorablePropertyTrait::fieldIdent()} to satisfy + * {@see StorablePropertyInterface} which requires a non-nullable string. + * + * @param string|null $key The field key to suffix to the property identifier. + */ + public function fieldIdent(?string $key = null): string + { + if ($this->fieldIdent === null) { + $this->fieldIdent = $this->snakeize($this['ident']); + } + + if ($key === null || $key === '') { + return $this->fieldIdent; + } + + if ($this->isValidFieldKey($key)) { + return $this->fieldIdent . '_' . $this->snakeize($key); + } + + return ''; + } + /** * Set the property's value. * @@ -299,6 +291,7 @@ public function l10nIdent($lang = null) * @param mixed $val The property (raw) value. * @return self */ + #![\Deprecated] final public function setVal($val) { $this->val = $this->parseVal($val); @@ -313,6 +306,7 @@ final public function setVal($val) * * @return self */ + #![\Deprecated] final public function clearVal() { $this->val = null; @@ -327,6 +321,7 @@ final public function clearVal() * * @return mixed */ + #![\Deprecated] final public function val() { return $this->val; @@ -339,11 +334,11 @@ final public function val() * > Other properties can reimplement this method to parse their values, * > such as {@see \Charcoal\Property\ObjectProperty::parseVal()} who could parse objects into object IDs. * - * @param mixed $val The value to be parsed (normalized). - * @throws InvalidArgumentException If the value does not match property settings. + * @param mixed $val The value to be parsed (normalized). * @return mixed Returns the parsed value. + * @throws InvalidArgumentException If the value does not match property settings. */ - final public function parseVal($val) + final public function parseVal(mixed $val): mixed { if ($this['allowNull']) { if ($val === null || $val === '') { @@ -358,7 +353,6 @@ final public function parseVal($val) if ($this['multiple']) { $val = $this->parseValAsMultiple($val); - if (empty($val)) { if ($this['allowNull'] === false) { throw new InvalidArgumentException(sprintf( @@ -369,18 +363,14 @@ final public function parseVal($val) return $val; } - - $val = array_map([ $this, 'parseOne' ], $val); - } else { - if ($this['l10n']) { - $val = $this->parseValAsL10n($val); - - if ($val) { - $val->sanitize([ $this, 'parseOne' ]); - } - } else { - $val = $this->parseOne($val); + $val = array_map($this->parseOne(...), $val); + } elseif ($this['l10n']) { + $val = $this->parseValAsL10n($val); + if ($val instanceof \Charcoal\Translator\TranslatableInterface) { + $val->sanitize($this->parseOne(...)); } + } else { + $val = $this->parseOne($val); } return $val; @@ -390,7 +380,7 @@ final public function parseVal($val) * @param mixed $val A single value to parse. * @return mixed The parsed value. */ - public function parseOne($val) + public function parseOne(mixed $val): mixed { return $val; } @@ -398,9 +388,8 @@ public function parseOne($val) /** * @param mixed $val Optional. The value to to convert for input. * @param array $options Optional input options. - * @return string */ - public function inputVal($val, array $options = []) + public function inputVal($val, array $options = []): string { if ($val === null) { return ''; @@ -425,10 +414,8 @@ public function inputVal($val, array $options = []) } /** Parse multiple values / ensure they are of array type. */ - if ($this['multiple']) { - if (is_array($propertyValue)) { - $propertyValue = implode($this->multipleSeparator(), $propertyValue); - } + if ($this['multiple'] && is_array($propertyValue)) { + $propertyValue = implode($this->multipleSeparator(), $propertyValue); } if (!is_scalar($propertyValue)) { @@ -437,8 +424,7 @@ public function inputVal($val, array $options = []) } elseif (($options['pretty'] ?? false)) { $flags = JSON_PRETTY_PRINT; } - $propertyValue = json_encode($propertyValue, ($flags ?? 0)); - return $propertyValue; + return json_encode($propertyValue, ($flags ?? 0)); } return (string)$propertyValue; @@ -447,9 +433,8 @@ public function inputVal($val, array $options = []) /** * @param mixed $val The value to to convert for display. * @param array $options Optional display options. - * @return string */ - public function displayVal($val, array $options = []) + public function displayVal($val, array $options = []): string { if ($val === null || $val === '') { return ''; @@ -468,10 +453,8 @@ public function displayVal($val, array $options = []) } /** Parse multiple values / ensure they are of array type. */ - if ($this['multiple']) { - if (!is_array($propertyValue)) { - $propertyValue = $this->parseValAsMultiple($propertyValue); - } + if ($this['multiple'] && !is_array($propertyValue)) { + $propertyValue = $this->parseValAsMultiple($propertyValue); } if (is_array($propertyValue)) { @@ -488,19 +471,15 @@ public function displayVal($val, array $options = []) /** * @param mixed $label The property label. - * @return self */ - public function setLabel($label) + public function setLabel(mixed $label): static { $this->label = $this->translator()->translation($label); return $this; } - /** - * @return Translation - */ - public function getLabel() + public function getLabel(): mixed { if ($this->label === null) { return ucwords(str_replace([ '.', '_' ], ' ', $this->ident())); @@ -511,21 +490,18 @@ public function getLabel() /** * @param boolean $l10n The l10n, or "translatable" flag. - * @return self */ - public function setL10n($l10n) + public function setL10n(bool $l10n): static { - $this->l10n = !!$l10n; + $this->l10n = (bool)$l10n; return $this; } /** * The l10n flag sets the property as being translatable, meaning the data is held for multple languages. - * - * @return boolean */ - public function getL10n() + public function getL10n(): bool { return $this->l10n; } @@ -541,11 +517,10 @@ public function parseValAsL10n($val): ?TranslatableInterface /** * @param boolean $hidden The hidden flag. - * @return self */ - public function setHidden($hidden) + public function setHidden(bool $hidden): static { - $this->hidden = !!$hidden; + $this->hidden = (bool)$hidden; return $this; } @@ -553,7 +528,7 @@ public function setHidden($hidden) /** * @return boolean */ - public function getHidden() + public function getHidden(): bool { return $this->hidden; } @@ -561,10 +536,9 @@ public function getHidden() /** * Set whether this property accepts multiple values or a single value. * - * @param boolean $multiple The multiple flag. - * @return self + * @param boolean $multiple The multiple flag. */ - public function setMultiple($multiple) + public function setMultiple(bool $multiple): static { if (!is_bool($multiple)) { if (is_array($multiple)) { @@ -577,7 +551,7 @@ public function setMultiple($multiple) } } - $this->multiple = !!$multiple; + $this->multiple = $multiple; return $this; } @@ -593,7 +567,7 @@ public function setMultiple($multiple) * * @return boolean */ - public function getMultiple() + public function getMultiple(): bool { return $this->multiple; } @@ -607,9 +581,8 @@ public function getMultiple() * - `max` (integer) The maximum number of values. (0 = no limit). * * @param array $multipleOptions The property multiple options. - * @return self */ - public function setMultipleOptions(array $multipleOptions) + public function setMultipleOptions(array $multipleOptions): static { // The options are always merged with the defaults, to ensure minimum required array structure. $options = array_merge($this->defaultMultipleOptions(), $multipleOptions); @@ -621,11 +594,11 @@ public function setMultipleOptions(array $multipleOptions) /** * The options defining the property behavior when the multiple flag is set to true. * - * @see self::defaultMultipleOptions * @param string|null $key Optional setting to retrieve from the options. - * @return array|mixed|null + * @see self::defaultMultipleOptions */ - public function getMultipleOptions($key = null) + #[\Override ] + public function getMultipleOptions(?string $key = null): mixed { if ($this->multipleOptions === null) { $this->multipleOptions = $this->defaultMultipleOptions(); @@ -671,7 +644,7 @@ public function defaultMultipleOptions() * * @return string */ - public function multipleSeparator() + public function multipleSeparator(): string { return $this->getMultipleOptions('separator'); } @@ -699,11 +672,10 @@ public function parseValAsMultiple($val) /** * @param boolean $allow The property allow null flag. - * @return self */ - public function setAllowNull($allow) + public function setAllowNull(bool $allow): static { - $this->allowNull = !!$allow; + $this->allowNull = (bool)$allow; return $this; } @@ -713,21 +685,18 @@ public function setAllowNull($allow) * * ## Notes * - This flag typically modifies the storage database to also allow null values. - * - * @return boolean */ - public function getAllowNull() + public function getAllowNull(): bool { return $this->allowNull; } /** * @param boolean $required The property required flag. - * @return self */ - public function setRequired($required) + public function setRequired(bool $required): static { - $this->required = !!$required; + $this->required = (bool)$required; return $this; } @@ -737,132 +706,104 @@ public function setRequired($required) * * ## Notes * - The actual meaning of "required" might be different for implementing property class. - * - * @return boolean */ - public function getRequired() + public function getRequired(): bool { return $this->required; } /** * @param boolean $unique The property unique flag. - * @return self */ - public function setUnique($unique) + public function setUnique(bool $unique): static { - $this->unique = !!$unique; + $this->unique = (bool)$unique; return $this; } - /** - * @return boolean - */ - public function getUnique() + public function getUnique(): bool { return $this->unique; } /** * @param boolean $active The property active flag. Inactive properties should have no effects. - * @return self */ - public function setActive($active) + public function setActive(bool $active): static { - $this->active = !!$active; + $this->active = (bool)$active; return $this; } - /** - * @return boolean - */ - public function getActive() + public function getActive(): bool { return $this->active; } /** * Legacy support of active() instead of getActive(). - * - * @return string */ - public function active() + public function active(): bool|string { return $this->getActive(); } /** * @param boolean $validatable The validatable flag. - * @return self */ - public function setValidatable($validatable) + public function setValidatable($validatable): static { - $this->validatable = !!$validatable; + $this->validatable = (bool)$validatable; return $this; } - /** - * @return boolean - */ - public function getValidatable() + public function getValidatable(): bool { return $this->validatable; } /** * @param boolean $storable The storable flag. - * @return self */ - public function setStorable($storable) + public function setStorable(bool $storable): static { - $this->storable = !!$storable; + $this->storable = (bool)$storable; return $this; } - /** - * @return boolean - */ - public function getStorable() + public function getStorable(): bool { return $this->storable; } /** * @param mixed $description The property description. - * @return self */ - public function setDescription($description) + public function setDescription($description): static { $this->description = $this->translator()->translation($description); return $this; } - /** - * @return Translation|null - */ - public function getDescription() + public function getDescription(): ?Translation { return $this->description; } /** * @param mixed $notes The property notes. - * @return self */ - public function setNotes($notes) + public function setNotes($notes): static { $this->notes = $this->translator()->translation($notes); return $this; } - /** - * @return Translation|null - */ - public function getNotes() + public function getNotes(): ?Translation { return $this->notes; } @@ -879,7 +820,7 @@ public function getNotes() * * @return string[] */ - public function validationMethods() + public function validationMethods(): array { return [ 'required', @@ -888,10 +829,7 @@ public function validationMethods() ]; } - /** - * @return boolean - */ - public function validateRequired() + public function validateRequired(): bool { $val = $this->val(); if ($this['required'] && empty($val) && !is_numeric($val)) { @@ -903,23 +841,13 @@ public function validateRequired() return true; } - /** - * @return boolean - */ - public function validateUnique() + public function validateUnique(): bool { - if (!$this['unique']) { - return true; - } - /** @todo Check in the model's storage if the value already exists. */ return true; } - /** - * @return boolean - */ - public function validateAllowNull() + public function validateAllowNull(): bool { $val = $this->val(); if (!$this['allowNull'] && $val === null) { @@ -933,9 +861,8 @@ public function validateAllowNull() /** * @param mixed $val The value, at time of saving. - * @return mixed */ - public function save($val) + public function save(mixed $val): mixed { // By default, nothing to do return $this->parseVal($val); @@ -943,19 +870,15 @@ public function save($val) /** * @param string $type The display type. - * @return self */ - public function setDisplayType($type) + public function setDisplayType($type): static { $this->displayType = $type; return $this; } - /** - * @return string - */ - public function getDisplayType() + public function getDisplayType(): string { if (!$this->displayType) { $meta = $this->metadata(); @@ -1028,14 +951,10 @@ protected function setDependencies(Container $container) * @param mixed $lang The language to return the value in. * @return string|null */ - protected function l10nVal($val, $lang = null) + protected function l10nVal(mixed $val, mixed $lang = null): mixed { if (!is_string($lang)) { - if (is_array($lang) && isset($lang['lang'])) { - $lang = $lang['lang']; - } else { - $lang = $this->translator()->getLocale(); - } + $lang = is_array($lang) && isset($lang['lang']) ? $lang['lang'] : $this->translator()->getLocale(); } return ($val[$lang] ?? null); @@ -1048,7 +967,7 @@ protected function l10nVal($val, $lang = null) * @see DescribableTrait::createMetadata() * @return PropertyMetadata */ - protected function createMetadata(array $data = null) + protected function createMetadata(?array $data = null) { $class = $this->metadataClass(); return new $class($data); @@ -1073,16 +992,13 @@ protected function metadataClass() */ protected function createValidator() { - $validator = new PropertyValidator($this); - - return $validator; + return new PropertyValidator($this); } /** * @param PDO $pdo The database connection (PDO) instance. - * @return void */ - private function setPdo(PDO $pdo) + private function setPdo(PDO $pdo): void { $this->pdo = $pdo; } diff --git a/packages/property/src/Charcoal/Property/AudioProperty.php b/packages/property/src/Charcoal/Property/AudioProperty.php index 44267c9ca..e08d2df1d 100644 --- a/packages/property/src/Charcoal/Property/AudioProperty.php +++ b/packages/property/src/Charcoal/Property/AudioProperty.php @@ -1,5 +1,7 @@ minLength; } @@ -64,7 +57,7 @@ public function getMinLength() * @throws InvalidArgumentException If the length is not an integer. * @return AudioProperty Chainable */ - public function setMaxLength($maxLength) + public function setMaxLength($maxLength): static { if (!is_int($maxLength)) { throw new InvalidArgumentException( @@ -75,10 +68,7 @@ public function setMaxLength($maxLength) return $this; } - /** - * @return integer - */ - public function getMaxLength() + public function getMaxLength(): int { return $this->maxLength; } @@ -90,7 +80,8 @@ public function getMaxLength() * * @return string[] */ - public function getDefaultAcceptedMimetypes() + #[\Override] + public function getDefaultAcceptedMimetypes(): array { return [ 'audio/mp3', @@ -110,26 +101,15 @@ public function getDefaultAcceptedMimetypes() * @param string $type The MIME type to resolve. * @return string|null The extension based on the MIME type. */ - protected function resolveExtensionFromMimeType($type) + #[\Override] + protected function resolveExtensionFromMimeType($type): ?string { - switch ($type) { - case 'audio/mp3': - case 'audio/mpeg': - return 'mp3'; - - case 'audio/ogg': - return 'ogg'; - - case 'audio/webm': - return 'webm'; - - case 'audio/wav': - case 'audio/wave': - case 'audio/x-wav': - case 'audio/x-pn-wav': - return 'wav'; - } - - return null; + return match ($type) { + 'audio/mp3', 'audio/mpeg' => 'mp3', + 'audio/ogg' => 'ogg', + 'audio/webm' => 'webm', + 'audio/wav', 'audio/wave', 'audio/x-wav', 'audio/x-pn-wav' => 'wav', + default => null, + }; } } diff --git a/packages/property/src/Charcoal/Property/BooleanProperty.php b/packages/property/src/Charcoal/Property/BooleanProperty.php index d9bcec5ed..80af51b09 100644 --- a/packages/property/src/Charcoal/Property/BooleanProperty.php +++ b/packages/property/src/Charcoal/Property/BooleanProperty.php @@ -1,5 +1,7 @@ translator()->translate($label); @@ -77,16 +71,16 @@ public function displayVal($val, array $options = []) /** * Ensure multiple can never be true for boolean property. * - * @see AbstractProperty::setMultiple() - * * @param boolean $multiple The multiple flag. * @throws InvalidArgumentException If multiple is true. (must be false for boolean properties). - * @return self + * @see AbstractProperty::setMultiple() + * */ - public function setMultiple($multiple) + #[\Override] + public function setMultiple(bool $multiple): static { - $multiple = !!$multiple; - if ($multiple === true) { + $multiple = (bool)$multiple; + if ($multiple) { throw new InvalidArgumentException( 'Multiple can not be true for boolean property.' ); @@ -98,19 +92,17 @@ public function setMultiple($multiple) * Multiple is always false for boolean property. * * @see AbstractProperty::getMultiple() - * - * @return boolean */ - public function getMultiple() + #[\Override] + public function getMultiple(): bool { return false; } /** * @param mixed $label The true label. - * @return self */ - public function setTrueLabel($label) + public function setTrueLabel($label): static { $this->trueLabel = $this->translator()->translation($label); return $this; @@ -130,9 +122,8 @@ public function getTrueLabel() /** * @param mixed $label The false label. - * @return self */ - public function setFalseLabel($label) + public function setFalseLabel($label): static { $this->falseLabel = $this->translator()->translation($label); return $this; @@ -159,7 +150,7 @@ public function getFalseLabel() * * @return string The SQL type */ - public function sqlType() + public function sqlType(): string { $dbDriver = $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME); if ($dbDriver === 'sqlite') { @@ -171,26 +162,22 @@ public function sqlType() /** * @see StorablePropertyTrait::sqlPdoType() - * - * @return integer */ - public function sqlPdoType() + public function sqlPdoType(): int { return PDO::PARAM_BOOL; } /** * @see SelectablePropertyTrait::choices() - * - * @return array */ - public function choices() + public function choices(): array { $val = $this->val(); return [ [ 'label' => $this['trueLabel'], - 'selected' => !!$val, + 'selected' => (bool)$val, 'value' => 1, ], [ diff --git a/packages/property/src/Charcoal/Property/ColorProperty.php b/packages/property/src/Charcoal/Property/ColorProperty.php index f1fb13f36..600248383 100644 --- a/packages/property/src/Charcoal/Property/ColorProperty.php +++ b/packages/property/src/Charcoal/Property/ColorProperty.php @@ -14,15 +14,9 @@ class ColorProperty extends AbstractProperty { public const DEFAULT_SUPPORT_ALPHA = false; - /** - * @var boolean $supportAlpha - */ - private $supportAlpha = self::DEFAULT_SUPPORT_ALPHA; + private bool $supportAlpha = self::DEFAULT_SUPPORT_ALPHA; - /** - * @return string - */ - public function type() + public function type(): string { return 'color'; } @@ -31,29 +25,27 @@ public function type() * @param boolean $support The alpha support flag. * @return ColorProperty Chainable */ - public function setSupportAlpha($support) + public function setSupportAlpha($support): static { - $this->supportAlpha = !!$support; + $this->supportAlpha = (bool)$support; return $this; } - /** - * @return boolean - */ - public function getSupportAlpha() + public function getSupportAlpha(): bool { return $this->supportAlpha; } /** - * @see AbstractProperty::parseOne() - * @see AbstractProperty::parseVal() - * * @param mixed $val The value to set. - * @throws InvalidArgumentException If the value does not match property's options. * @return string|null + *@throws InvalidArgumentException If the value does not match property's options. + * @see AbstractProperty::parseVal() + * + * @see AbstractProperty::parseOne() */ - public function parseOne($val) + #[\Override] + public function parseOne(mixed $val): null|array|float|int|string|false { if ($val === null || $val === '') { if ($this['allowNull']) { @@ -71,7 +63,7 @@ public function parseOne($val) * @param string|array $val The color value to sanitize to an hexadecimal or rgba() value. * @return string The color string. Hexadecimal or rgba() if alpha is supported.. */ - public function colorVal($val) + public function colorVal($val): array|int|float|false|null|string { if (!$val) { return $val; @@ -99,7 +91,7 @@ public function colorVal($val) * * @return string The SQL type */ - public function sqlType() + public function sqlType(): string { // Multiple strings are always stored as TEXT because they can hold multiple values if ($this['multiple']) { @@ -115,10 +107,8 @@ public function sqlType() /** * @see StorablePropertyTrait::sqlPdoType() - * - * @return integer */ - public function sqlPdoType() + public function sqlPdoType(): int { return PDO::PARAM_STR; } @@ -129,7 +119,7 @@ public function sqlPdoType() * @param integer $b Blue value (0 to 255). * @return string Hexadecimal color value, as uppercased hexadecimal without the "#" prefix. */ - protected function rgbToHexadecimal($r, $g, $b) + protected function rgbToHexadecimal($r, $g, $b): string { $hex = ''; $hex .= str_pad(dechex($r), 2, '0', STR_PAD_LEFT); @@ -156,7 +146,7 @@ private function parseColorVal($val) * @throws InvalidArgumentException If the array does not have at least 3 items. * @return array The parsed `[r,g,b,a]` color array. */ - private function parseArray(array $val) + private function parseArray(array $val): array { if (count($val) < 3) { throw new InvalidArgumentException( @@ -168,12 +158,12 @@ private function parseArray(array $val) $r = $val['r']; $g = $val['g']; $b = $val['b']; - $a = isset($val['a']) ? $val['a'] : 0; + $a = ($val['a'] ?? 0); } else { $r = $val[0]; $g = $val[1]; $b = $val[2]; - $a = isset($val[3]) ? $val[3] : 0; + $a = ($val[3] ?? 0); } return [ @@ -213,11 +203,11 @@ private function parseString($val) * @param string $val The hexadecimal color string to parse. * @return array The parsed `[r,g,b,a]` color array. */ - private function parseHexadecimal($val) + private function parseHexadecimal(string $val): array { $val = str_replace('#', '', $val); - if (strlen($val) == 3) { + if (strlen($val) === 3) { return [ 'r' => hexdec(substr($val, 0, 1) . substr($val, 0, 1)), 'g' => hexdec(substr($val, 1, 1) . substr($val, 1, 1)), @@ -241,7 +231,7 @@ private function parseHexadecimal($val) * @throws InvalidArgumentException If the color can not be parsed. * @return array The parsed `[r,g,b,a]` color array. */ - private function parseRgb($val) + private function parseRgb(string $val): array { $match = preg_match('/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i', $val, $m); if (!$match) { @@ -263,7 +253,7 @@ private function parseRgb($val) * @throws InvalidArgumentException If The colors string is invalid (does not match rgba format). * @return array The parsed `[r,g,b,a]` color array. */ - private function parseRgba($val) + private function parseRgba(string $val): array { $match = preg_match('/rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\(\d+)\s*\)/i', $val, $m); if (!$match) { @@ -284,11 +274,11 @@ private function parseRgba($val) * @throws InvalidArgumentException If the string is not an existing SVG color. * @return array The parsed `[r,g,b,a]` color array. */ - private function parseNamedColor($val) + private function parseNamedColor(string|array $val) { static $colors; if (!$colors) { - $colors = include 'data/colors.php'; + $colors = include __DIR__ . '/data/colors.php'; } $val = strtolower($val); if (in_array($val, array_keys($colors))) { diff --git a/packages/property/src/Charcoal/Property/DateTimeProperty.php b/packages/property/src/Charcoal/Property/DateTimeProperty.php index 85f64f943..460d04457 100644 --- a/packages/property/src/Charcoal/Property/DateTimeProperty.php +++ b/packages/property/src/Charcoal/Property/DateTimeProperty.php @@ -19,25 +19,13 @@ class DateTimeProperty extends AbstractProperty public const DEFAULT_MAX = null; public const DEFAULT_FORMAT = 'Y-m-d H:i:s'; - /** - * @var DateTimeInterface|null - */ - private $min = self::DEFAULT_MIN; + private ?\DateTimeInterface $min = self::DEFAULT_MIN; - /** - * @var DateTimeInterface|null - */ - private $max = self::DEFAULT_MAX; + private ?\DateTimeInterface $max = self::DEFAULT_MAX; - /** - * @var string - */ - private $format = self::DEFAULT_FORMAT; + private string $format = self::DEFAULT_FORMAT; - /** - * @return string - */ - public function type() + public function type(): string { return 'date-time'; } @@ -45,16 +33,16 @@ public function type() /** * Ensure multiple can not be true for DateTime property. * - * @see AbstractProperty::setMultiple() - * * @param boolean $multiple Multiple flag. * @throws InvalidArgumentException If the multiple argument is true (must be false). - * @return self + *@see AbstractProperty::setMultiple() + * */ - public function setMultiple($multiple) + #[\Override] + public function setMultiple(bool $multiple): static { - $multiple = !!$multiple; - if ($multiple === true) { + $multiple = (bool)$multiple; + if ($multiple) { throw new InvalidArgumentException( 'Multiple can not be TRUE for date/time property.' ); @@ -66,10 +54,9 @@ public function setMultiple($multiple) * Multiple is always false for DateTime property. * * @see AbstractProperty::getMultiple() - * - * @return boolean */ - public function getMultiple() + #[\Override] + public function getMultiple(): bool { return false; } @@ -77,13 +64,13 @@ public function getMultiple() /** * Ensure `DateTime` object in val. * - * @see AbstractProperty::parseOne() - * @see AbstractProperty::parseVal() + * @param mixed $val The value to set. + *@see AbstractProperty::parseVal() * - * @param string|DateTimeInterface $val The value to set. - * @return DateTimeInterface|null + * @see AbstractProperty::parseOne() */ - public function parseOne($val) + #[\Override] + public function parseOne(mixed $val): ?\DateTimeInterface { return $this->dateTimeVal($val); } @@ -91,14 +78,14 @@ public function parseOne($val) /** * Convert `DateTime` to input-friendly string. * - * @see AbstractProperty::inputVal() - * * @param mixed $val The value to to convert for input. * @param array $options Unused, optional options. * @throws Exception If the date/time is invalid. - * @return string|null + *@see AbstractProperty::inputVal() + * */ - public function inputVal($val, array $options = []) + #[\Override] + public function inputVal($val, array $options = []): string { unset($options); $val = $this->dateTimeVal($val); @@ -113,13 +100,13 @@ public function inputVal($val, array $options = []) /** * Convert `DateTime` to SQL-friendly string. * + * @param mixed $val Optional. Value to convert to storage format. + * @throws Exception If the date/time is invalid. * @see StorablePropertyTrait::storageVal() * - * @param string|DateTime $val Optional. Value to convert to storage format. - * @throws Exception If the date/time is invalid. - * @return string|null */ - public function storageVal($val) + #[\Override] + public function storageVal(mixed $val): ?string { $val = $this->dateTimeVal($val); @@ -139,24 +126,21 @@ public function storageVal($val) /** * Format a date/time object to string. * + * @param mixed $val The value to to convert for display. * @see AbstractProperty::displayVal() * * @param mixed $val The value to to convert for display. * @param array $options Optional display options. - * @return string */ - public function displayVal($val, array $options = []) + #[\Override] + public function displayVal($val, array $options = []): string { $val = $this->dateTimeVal($val); - if ($val === null) { + if (!$val instanceof \DateTimeInterface) { return ''; } - if (isset($options['format'])) { - $format = $options['format']; - } else { - $format = $this->getFormat(); - } + $format = ($options['format'] ?? $this->getFormat()); return $val->format($format); } @@ -164,9 +148,8 @@ public function displayVal($val, array $options = []) /** * @param string|DateTime|null $min The minimum allowed value. * @throws InvalidArgumentException If the date/time is invalid. - * @return self */ - public function setMin($min) + public function setMin($min): static { try { $this->min = $this->dateTimeVal($min); @@ -176,10 +159,7 @@ public function setMin($min) } } - /** - * @return DateTimeInterface|null - */ - public function getMin() + public function getMin(): ?\DateTimeInterface { return $this->min; } @@ -187,9 +167,8 @@ public function getMin() /** * @param string|DateTime|null $max The maximum allowed value. * @throws InvalidArgumentException If the date/time is invalid. - * @return self */ - public function setMax($max) + public function setMax($max): static { try { $this->max = $this->dateTimeVal($max); @@ -199,10 +178,7 @@ public function setMax($max) } } - /** - * @return DateTimeInterface|null - */ - public function getMax() + public function getMax(): ?\DateTimeInterface { return $this->max; } @@ -212,7 +188,7 @@ public function getMax() * @throws InvalidArgumentException If the format is not a string. * @return DateTimeProperty Chainable */ - public function setFormat($format) + public function setFormat($format): static { if ($format === null) { $format = ''; @@ -226,18 +202,13 @@ public function setFormat($format) return $this; } - /** - * @return string - */ - public function getFormat() + public function getFormat(): string { return $this->format; } - /** - * @return array - */ - public function validationMethods() + #[\Override] + public function validationMethods(): array { $parentMethods = parent::validationMethods(); @@ -253,7 +224,7 @@ public function validationMethods() public function validateMin() { $min = $this->getMin(); - if (!$min) { + if (!$min instanceof \DateTimeInterface) { return true; } $valid = ($this->val() >= $min); @@ -269,7 +240,7 @@ public function validateMin() public function validateMax() { $max = $this->getMax(); - if (!$max) { + if (!$max instanceof \DateTimeInterface) { return true; } $valid = ($this->val() <= $max); @@ -281,18 +252,16 @@ public function validateMax() /** * @see StorablePropertyTrait::sqlType() - * @return string */ - public function sqlType() + public function sqlType(): string { return 'DATETIME'; } /** * @see StorablePropertyTrait::sqlPdoType() - * @return integer */ - public function sqlPdoType() + public function sqlPdoType(): int { return PDO::PARAM_STR; } @@ -300,14 +269,13 @@ public function sqlPdoType() /** * @param mixed $val Value to convert to DateTime. * @throws InvalidArgumentException If the value is not a valid datetime. - * @return DateTimeInterface|null */ - private function dateTimeVal($val) + private function dateTimeVal($val): ?\DateTimeInterface { if ( $val === null || (is_string($val) && ! strlen(trim($val))) || - (is_array($val) && ! count(array_filter($val, 'strlen'))) + (is_array($val) && ! count(array_filter($val, strlen(...)))) ) { return null; } @@ -332,9 +300,8 @@ private function dateTimeVal($val) /** * @param integer|string $timestamp Timestamp. - * @return boolean */ - private function isValidTimeStamp($timestamp) + private function isValidTimeStamp(int $timestamp): bool { return (is_int($timestamp)) && ($timestamp <= PHP_INT_MAX) diff --git a/packages/property/src/Charcoal/Property/DescribablePropertyInterface.php b/packages/property/src/Charcoal/Property/DescribablePropertyInterface.php index 234242c56..031be6db5 100644 --- a/packages/property/src/Charcoal/Property/DescribablePropertyInterface.php +++ b/packages/property/src/Charcoal/Property/DescribablePropertyInterface.php @@ -1,5 +1,7 @@ metadata(); @@ -39,10 +39,6 @@ public function properties(array $propertyIdents = null) $propertyIdents = array_keys($this->metadata()->properties()); } - if (empty($propertyIdents)) { - return; - } - foreach ($propertyIdents as $propertyIdent) { yield $propertyIdent => $this->property($propertyIdent); } @@ -61,7 +57,7 @@ public function property($propertyIdent) if (!is_string($propertyIdent)) { throw new InvalidArgumentException( '[%s] Property identifier must be a string', - get_class($this) + $this::class ); } @@ -99,14 +95,13 @@ public function p($propertyIdent = null) * * @param string $propertyIdent The property identifier to lookup. * @throws InvalidArgumentException If the property identifier is not a string. - * @return boolean */ - public function hasProperty($propertyIdent) + public function hasProperty($propertyIdent): bool { if (!is_string($propertyIdent)) { throw new InvalidArgumentException( '[%s] Property identifier must be a string', - get_class($this) + $this::class ); } @@ -158,7 +153,7 @@ protected function propertyFactory() if ($this->propertyFactory === null) { throw new RuntimeException(sprintf( '[%s] Model does not have a property factory', - get_class($this) + $this::class )); } @@ -178,8 +173,8 @@ protected function createProperty($propertyIdent) if (!is_string($propertyIdent)) { throw new InvalidArgumentException( '[%s] Property identifier must be a string, received %s', - get_class($this), - (is_object($propertyIdent) ? get_class($propertyIdent) : gettype($propertyIdent)) + $this::class, + (get_debug_type($propertyIdent)) ); } @@ -190,7 +185,7 @@ protected function createProperty($propertyIdent) if (empty($props)) { throw new RuntimeException(sprintf( '[%s] Invalid model metadata - No properties defined (must define at least "%s")', - get_class($this), + $this::class, $propertyIdent )); } @@ -198,7 +193,7 @@ protected function createProperty($propertyIdent) if (!isset($props[$propertyIdent])) { throw new RuntimeException(sprintf( '[%s] Invalid model metadata - Undefined property metadata for "%s"', - get_class($this), + $this::class, $propertyIdent )); } @@ -208,7 +203,7 @@ protected function createProperty($propertyIdent) if (!isset($propertyMetadata['type'])) { throw new RuntimeException(sprintf( '[%s] Invalid model metadata - Undefined property type for "%s"', - get_class($this), + $this::class, $propertyIdent )); } diff --git a/packages/property/src/Charcoal/Property/EmailProperty.php b/packages/property/src/Charcoal/Property/EmailProperty.php index 22536ba9d..1c82a9cd8 100644 --- a/packages/property/src/Charcoal/Property/EmailProperty.php +++ b/packages/property/src/Charcoal/Property/EmailProperty.php @@ -10,10 +10,8 @@ */ class EmailProperty extends StringProperty { - /** - * @return string - */ - public function type() + #[\Override] + public function type(): string { return 'email'; } @@ -22,18 +20,15 @@ public function type() * Email's maximum length is defined in RFC-3696 (+ errata) as 254 characters. * * This overrides PropertyString's maxLength() to ensure compliance with the email standards. - * - * @return integer */ - public function getMaxLength() + #[\Override] + public function getMaxLength(): int { return 254; } - /** - * @return array - */ - public function validationMethods() + #[\Override] + public function validationMethods(): array { $parentMethods = parent::validationMethods(); @@ -42,10 +37,7 @@ public function validationMethods() ]); } - /** - * @return boolean - */ - public function validateEmail() + public function validateEmail(): bool { if ($this['allowNull'] && !$this['required']) { return true; @@ -61,14 +53,15 @@ public function validateEmail() } /** - * @see AbstractProperty::parseOne() - * @see AbstractProperty::parseVal() - * * @param mixed $val A single value to parse. * @return string + *@see AbstractProperty::parseOne() + * @see AbstractProperty::parseVal() + * */ - public function parseOne($val) + #[\Override] + public function parseOne(mixed $val): string|false { - return filter_var(strip_tags($val), FILTER_SANITIZE_EMAIL); + return filter_var(strip_tags((string)$val), FILTER_SANITIZE_EMAIL); } } diff --git a/packages/property/src/Charcoal/Property/FileProperty.php b/packages/property/src/Charcoal/Property/FileProperty.php index d54562cf6..01e3714a1 100644 --- a/packages/property/src/Charcoal/Property/FileProperty.php +++ b/packages/property/src/Charcoal/Property/FileProperty.php @@ -37,17 +37,13 @@ class FileProperty extends AbstractProperty /** * Whether uploaded files should be accessible from the web root. - * - * @var boolean */ - private $publicAccess = self::DEFAULT_PUBLIC_ACCESS; + private bool $publicAccess = self::DEFAULT_PUBLIC_ACCESS; /** * The relative path to the storage directory. - * - * @var string */ - private $uploadPath = self::DEFAULT_UPLOAD_PATH; + private string $uploadPath = self::DEFAULT_UPLOAD_PATH; /** * The base path for the Charcoal installation. @@ -65,24 +61,20 @@ class FileProperty extends AbstractProperty /** * Whether existing destinations should be overwritten. - * - * @var boolean */ - private $overwrite = self::DEFAULT_OVERWRITE; + private bool $overwrite = self::DEFAULT_OVERWRITE; /** * Collection of accepted MIME types. * * @var string[] */ - private $acceptedMimetypes; + private ?array $acceptedMimetypes = null; /** * Current file mimetype - * - * @var string */ - private $mimetype; + private ?string $mimetype = null; /** * Maximum allowed file size, in bytes. @@ -117,10 +109,7 @@ class FileProperty extends AbstractProperty */ protected static $normalizePathCache = []; - /** - * @return string - */ - public function type() + public function type(): string { return 'file'; } @@ -129,21 +118,18 @@ public function type() * Set whether uploaded files should be publicly available. * * @param boolean $public Whether uploaded files should be accessible (TRUE) or not (FALSE) from the web root. - * @return self */ - public function setPublicAccess($public) + public function setPublicAccess($public): static { - $this->publicAccess = !!$public; + $this->publicAccess = (bool)$public; return $this; } /** * Determine if uploaded files should be publicly available. - * - * @return boolean */ - public function getPublicAccess() + public function getPublicAccess(): bool { return $this->publicAccess; } @@ -155,9 +141,8 @@ public function getPublicAccess() * * @param string $path The destination directory, relative to project's root. * @throws InvalidArgumentException If the path is not a string. - * @return self */ - public function setUploadPath($path) + public function setUploadPath($path): static { if (!is_string($path)) { throw new InvalidArgumentException( @@ -173,10 +158,8 @@ public function setUploadPath($path) /** * Retrieve the destination for the uploaded file(s). - * - * @return string */ - public function getUploadPath() + public function getUploadPath(): string { return $this->uploadPath; } @@ -185,21 +168,18 @@ public function getUploadPath() * Set whether existing destinations should be overwritten. * * @param boolean $overwrite Whether existing destinations should be overwritten (TRUE) or not (FALSE). - * @return self */ - public function setOverwrite($overwrite) + public function setOverwrite($overwrite): static { - $this->overwrite = !!$overwrite; + $this->overwrite = (bool)$overwrite; return $this; } /** * Determine if existing destinations should be overwritten. - * - * @return boolean */ - public function getOverwrite() + public function getOverwrite(): bool { return $this->overwrite; } @@ -209,14 +189,13 @@ public function getOverwrite() * * @param mixed $types One or many MIME types. * @throws InvalidArgumentException If the $types argument is not NULL or a list. - * @return self */ - public function setAcceptedMimetypes($types) + public function setAcceptedMimetypes($types): static { if (is_array($types)) { $types = array_filter($types); - if (empty($types)) { + if ($types === []) { $types = null; } } @@ -238,11 +217,11 @@ public function setAcceptedMimetypes($types) */ public function hasAcceptedMimetypes() { - if (!empty($this->acceptedMimetypes)) { + if ($this->acceptedMimetypes !== null && $this->acceptedMimetypes !== []) { return true; } - return !empty($this->getDefaultAcceptedMimetypes()); + return $this->getDefaultAcceptedMimetypes() !== []; } /** @@ -266,7 +245,7 @@ public function getAcceptedMimetypes() * * @return string[] */ - public function getDefaultAcceptedMimetypes() + public function getDefaultAcceptedMimetypes(): array { return []; } @@ -278,7 +257,7 @@ public function getDefaultAcceptedMimetypes() * @throws InvalidArgumentException If the MIME type argument is not a string. * @return FileProperty Chainable */ - public function setMimetype($type) + public function setMimetype($type): static { if ($type === null || $type === false) { $this->mimetype = null; @@ -302,11 +281,11 @@ public function setMimetype($type) * * @return integer Returns the MIME type for the first value. */ - public function getMimetype() + public function getMimetype(): ?string { if ($this->mimetype === null) { $files = $this->parseValAsFileList($this->val()); - if (empty($files)) { + if ($files === []) { return null; } @@ -355,7 +334,7 @@ public function getMimetypeFor($file) * @throws InvalidArgumentException If the size argument is not an integer. * @return FileProperty Chainable */ - public function setMaxFilesize($size) + public function setMaxFilesize($size): static { $this->maxFilesize = $this->parseIniSize($size); @@ -371,7 +350,7 @@ public function setMaxFilesize($size) */ public function getMaxFilesize() { - if (!isset($this->maxFilesize)) { + if ($this->maxFilesize === null) { return $this->maxFilesizeAllowedByPhp(); } @@ -407,7 +386,7 @@ public function maxFilesizeAllowedByPhp(&$iniDirective = null) * @throws InvalidArgumentException If the size argument is not an integer. * @return FileProperty Chainable */ - public function setFilesize($size) + public function setFilesize($size): static { if (!is_int($size) && $size !== null) { throw new InvalidArgumentException( @@ -430,7 +409,7 @@ public function getFilesize() { if ($this->filesize === null) { $files = $this->parseValAsFileList($this->val()); - if (empty($files)) { + if ($files === []) { return 0; } @@ -453,7 +432,7 @@ public function getFilesize() * @return integer|null Returns the file size in bytes, * or NULL in case of an error or the file is missing. */ - public function getFilesizeFor($file) + public function getFilesizeFor($file): ?int { if (!$this->isAbsolutePath($file)) { $file = $this->pathFor($file); @@ -478,13 +457,9 @@ public function getFilesizeFor($file) * @param integer $decimals Precision of number of decimal places. Default 0. * @return string|null Returns the formatted number or NULL. */ - public function formatFilesize($bytes, $decimals = 2) + public function formatFilesize($bytes, $decimals = 2): string { - if ($bytes === 0) { - $factor = 0; - } else { - $factor = floor((strlen($bytes) - 1) / 3); - } + $factor = $bytes === 0 ? 0 : floor((strlen((string)$bytes) - 1) / 3); $unit = [ 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ]; @@ -494,13 +469,11 @@ public function formatFilesize($bytes, $decimals = 2) $factor = 0; } - return sprintf('%.' . $decimals . 'f', ($bytes / pow(1024, $factor))) . ' ' . $unit[$factor]; + return sprintf('%.' . $decimals . 'f', ($bytes / 1024 ** $factor)) . ' ' . $unit[$factor]; } - /** - * @return array - */ - public function validationMethods() + #[\Override] + public function validationMethods(): array { $parentMethods = parent::validationMethods(); @@ -526,7 +499,7 @@ public function validateMimetypes() $files = $this->parseValAsFileList($this->val()); - if (empty($files)) { + if ($files === []) { return true; } @@ -572,7 +545,7 @@ public function validateFilesizes() $files = $this->parseValAsFileList($this->val()); - if (empty($files)) { + if ($files === []) { return true; } @@ -611,7 +584,7 @@ public function validateFilesizes() * @param mixed $value A multi-dimensional variable. * @return string[] The array of values. */ - public function parseValAsFileList($value) + public function parseValAsFileList($value): array { $files = []; @@ -620,14 +593,12 @@ public function parseValAsFileList($value) } $array = $this->parseValAsMultiple($value); - array_walk_recursive($array, function ($item) use (&$files) { + array_walk_recursive($array, function ($item) use (&$files): void { $array = $this->parseValAsMultiple($item); $files = array_merge($files, $array); }); - $files = array_filter($files, function ($file) { - return is_string($file) && isset($file[0]); - }); + $files = array_filter($files, fn($file): bool => is_string($file) && isset($file[0])); $files = array_unique($files); $files = array_values($files); @@ -642,7 +613,7 @@ public function parseValAsFileList($value) * @see StorablePropertyTrait::sqlType() * @return string The SQL type */ - public function sqlType() + public function sqlType(): string { // Multiple strings are always stored as TEXT because they can hold multiple values if ($this['multiple']) { @@ -654,9 +625,8 @@ public function sqlType() /** * @see StorablePropertyTrait::sqlPdoType() - * @return integer */ - public function sqlPdoType() + public function sqlPdoType(): int { return PDO::PARAM_STR; } @@ -664,16 +634,12 @@ public function sqlPdoType() /** * Process file uploads {@see AbstractProperty::save() parsing values}. * - * @param mixed $val The value, at time of saving. - * @return mixed + * @param mixed $val The value, at time of saving. */ - public function save($val) + #[\Override] + public function save(mixed $val): mixed { - if ($val instanceof Translation) { - $values = $val->data(); - } else { - $values = $val; - } + $values = $val instanceof Translation ? $val->data() : $val; $uploadedFiles = $this->getUploadedFiles(); @@ -689,7 +655,7 @@ public function save($val) $parsedFiles = $this->saveFileUploads($uploadedFiles[$lang]); } - if (empty($parsedFiles)) { + if ($parsedFiles === []) { $parsedFiles = $this->saveDataUploads($values[$lang]); } @@ -702,7 +668,7 @@ public function save($val) $parsedFiles = $this->saveFileUploads($uploadedFiles); } - if (empty($parsedFiles)) { + if ($parsedFiles === []) { $parsedFiles = $this->saveDataUploads($values); } @@ -719,7 +685,7 @@ public function save($val) * @param mixed $values One or more data URIs, data entries, or processed file paths. * @return string|string[] One or more paths to the processed uploaded files. */ - protected function saveDataUploads($values) + protected function saveDataUploads($values): array { // Bag value if singular if (!is_array($values) || isset($values['id'])) { @@ -731,21 +697,18 @@ protected function saveDataUploads($values) if ($this->isDataArr($value) || $this->isDataUri($value)) { try { $path = $this->dataUpload($value); - if ($path !== null) { - $parsed[] = $path; - - $this->logger->notice(sprintf( - 'File [%s] uploaded succesfully', - $path - )); - } + $parsed[] = $path; + $this->logger->notice(sprintf( + 'File [%s] uploaded succesfully', + $path + )); } catch (Exception $e) { $this->logger->warning(sprintf( 'Upload error on data URI: %s', $e->getMessage() )); } - } elseif (is_string($value) && !empty($value)) { + } elseif (is_string($value) && ($value !== '' && $value !== '0')) { $parsed[] = $value; } } @@ -759,7 +722,7 @@ protected function saveDataUploads($values) * @param mixed $files One or more normalized $_FILE entries. * @return string[] One or more paths to the processed uploaded files. */ - protected function saveFileUploads($files) + protected function saveFileUploads(array $files): array { // Bag value if singular if (isset($files['error'])) { @@ -771,14 +734,11 @@ protected function saveFileUploads($files) if (isset($file['error'])) { try { $path = $this->fileUpload($file); - if ($path !== null) { - $parsed[] = $path; - - $this->logger->notice(sprintf( - 'File [%s] uploaded succesfully', - $path - )); - } + $parsed[] = $path; + $this->logger->notice(sprintf( + 'File [%s] uploaded succesfully', + $path + )); } catch (Exception $e) { $this->logger->warning(sprintf( 'Upload error on file [%s]: %s', @@ -807,10 +767,8 @@ protected function parseSavedValues($saved, $default = null) if (!is_array($values)) { $values = empty($values) && !is_numeric($values) ? [] : [ $values ]; } - } else { - if (is_array($values)) { - $values = reset($values); - } + } elseif (is_array($values)) { + $values = reset($values); } return $values; @@ -825,7 +783,7 @@ protected function parseSavedValues($saved, $default = null) * @throws Exception If the upload fails or the $data is bad. * @return string|null The file path to the uploaded data. */ - public function dataUpload($data) + public function dataUpload($data): string { $filename = null; $contents = false; @@ -849,7 +807,7 @@ public function dataUpload($data) $contents = file_get_contents($tmpFile); - if (strlen($data['name']) > 0) { + if ((string)$data['name'] !== '') { $filename = $data['name']; } @@ -898,9 +856,8 @@ public function dataUpload($data) } $basePath = $this->basePath(); - $targetPath = str_replace($basePath, '', $targetPath); - return $targetPath; + return str_replace($basePath, '', $targetPath); } /** @@ -914,7 +871,7 @@ public function dataUpload($data) * @throws Exception If the upload fails or the $file is bad. * @return string|null The file path to the uploaded file. */ - public function fileUpload(array $file) + public function fileUpload(array $file): string { if (!isset($file['tmp_name'], $file['name'], $file['size'], $file['error'])) { throw new InvalidArgumentException( @@ -970,9 +927,8 @@ public function fileUpload(array $file) } $basePath = $this->basePath(); - $targetPath = str_replace($basePath, '', $targetPath); - return $targetPath; + return str_replace($basePath, '', $targetPath); } /** @@ -983,19 +939,14 @@ public function fileUpload(array $file) * * @param string|null $filename Optional. The filename to save as. * If NULL, a default filename will be generated. - * @return string */ - public function uploadTarget($filename = null) + public function uploadTarget($filename = null): string { $this->assertValidUploadPath(); $uploadPath = $this->pathFor($this['uploadPath']); - if ($filename === null) { - $filename = $this->generateFilename(); - } else { - $filename = $this->sanitizeFilename($filename); - } + $filename = $filename === null ? $this->generateFilename() : $this->sanitizeFilename($filename); $targetPath = $uploadPath . '/' . $filename; @@ -1021,9 +972,8 @@ public function uploadTarget($filename = null) * * @param string $file The full file to check. * @param boolean $caseInsensitive Case-insensitive by default. - * @return boolean */ - public function fileExists($file, $caseInsensitive = true) + public function fileExists($file, $caseInsensitive = true): bool { $file = (string)$file; @@ -1059,7 +1009,7 @@ public function fileExists($file, $caseInsensitive = true) * @throws Exception If the filename is invalid. * @return string The sanitized filename. */ - public function sanitizeFilename($filename) + public function sanitizeFilename($filename): string { // Remove blacklisted caharacters $blacklist = [ '/', '\\', '\0', '*', ':', '?', '"', '<', '>', '|', '#', '&', '!', '`', ' ' ]; @@ -1068,7 +1018,7 @@ public function sanitizeFilename($filename) // Avoid hidden file or trailing dot $filename = trim($filename, '.'); - if (strlen($filename) === 0) { + if ($filename === '') { throw new Exception( 'Bad file name after sanitization' ); @@ -1090,19 +1040,19 @@ public function sanitizeFilename($filename) * @throws UnexpectedValueException If the renaming failed. * @return string Returns the rendered target. */ - public function renderFileRenamePattern($from, $to, $args = null) + public function renderFileRenamePattern($from, $to, $args = null): string { if (!is_string($from)) { throw new InvalidArgumentException(sprintf( 'The target to rename must be a string, received %s', - (is_object($from) ? get_class($from) : gettype($from)) + (get_debug_type($from)) )); } if (!is_string($to)) { throw new InvalidArgumentException(sprintf( 'The rename pattern must be a string, received %s', - (is_object($to) ? get_class($to) : gettype($to)) + (get_debug_type($to)) )); } @@ -1110,7 +1060,7 @@ public function renderFileRenamePattern($from, $to, $args = null) $args = $this->renamePatternArgs($info, $args); $to = strtr($to, $args); - if (strpos($to, '{{') !== false) { + if (str_contains($to, '{{')) { preg_match_all('~\{\{\s*(.*?)\s*\}\}~i', $to, $matches); throw new UnexpectedValueException(sprintf( @@ -1119,18 +1069,15 @@ public function renderFileRenamePattern($from, $to, $args = null) )); } - $to = str_replace($info['basename'], $to, $from); - - return $to; + return str_replace($info['basename'], $to, $from); } /** * Generate a new filename from the property. * * @param string|null $extension An extension to append to the generated filename. - * @return string */ - public function generateFilename($extension = null) + public function generateFilename($extension = null): string { $filename = $this->sanitizeFilename($this['fallbackFilename']); $filename = $filename . ' ' . date('Y-m-d\TH-i-s'); @@ -1147,26 +1094,21 @@ public function generateFilename($extension = null) * * @param string|array $filename The filename to alter. * @throws InvalidArgumentException If the given filename is invalid. - * @return string */ - public function generateUniqueFilename($filename) + public function generateUniqueFilename($filename): string { - if (is_string($filename)) { - $info = pathinfo($filename); - } else { - $info = $filename; - } + $info = is_string($filename) ? pathinfo($filename) : $filename; - if (!isset($info['filename']) || strlen($info['filename']) === 0) { + if (!isset($info['filename']) || (string)$info['filename'] === '') { throw new InvalidArgumentException(sprintf( 'File must be a string [file path] or an array [pathfino()], received %s', - (is_object($filename) ? get_class($filename) : gettype($filename)) + (get_debug_type($filename)) )); } $filename = $info['filename'] . '-' . uniqid(); - if (isset($info['extension']) && strlen($info['extension']) > 0) { + if (isset($info['extension']) && (string)$info['extension'] !== '') { $filename .= '.' . $info['extension']; } @@ -1180,7 +1122,7 @@ public function generateUniqueFilename($filename) * * @return string Returns the file extension based on the MIME type for the first value. */ - public function generateExtension() + public function generateExtension(): ?string { $type = $this->getMimetype(); @@ -1213,7 +1155,7 @@ public function generateExtensionFromFile($file) return null; } - if (strpos($ext, '/') !== false) { + if (str_contains($ext, '/')) { $ext = explode('/', $ext); $ext = reset($ext); } @@ -1227,7 +1169,7 @@ public function generateExtensionFromFile($file) * @param string $type The MIME type to parse. * @return string|null The extension based on the MIME type. */ - public function generateExtensionFromMimeType($type) + public function generateExtensionFromMimeType($type): ?string { if (in_array($type, $this->getAcceptedMimetypes())) { return $this->resolveExtensionFromMimeType($type); @@ -1244,21 +1186,18 @@ public function generateExtensionFromMimeType($type) * @param string $type The MIME type to resolve. * @return string|null The extension based on the MIME type. */ - protected function resolveExtensionFromMimeType($type) + protected function resolveExtensionFromMimeType($type): ?string { - switch ($type) { - case 'text/plain': - return 'txt'; - } - - return null; + return match ($type) { + 'text/plain' => 'txt', + default => null, + }; } /** * @param mixed $fallback The fallback filename. - * @return self */ - public function setFallbackFilename($fallback) + public function setFallbackFilename($fallback): static { $this->fallbackFilename = $this->translator()->translation($fallback); return $this; @@ -1286,9 +1225,8 @@ public function getFilesystem() /** * @param string $filesystem The file system. - * @return self */ - public function setFilesystem($filesystem) + public function setFilesystem($filesystem): static { $this->filesystem = $filesystem; @@ -1301,6 +1239,7 @@ public function setFilesystem($filesystem) * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -1332,9 +1271,8 @@ protected function basePath() * it will be prepended. * * @param string $path The end path. - * @return string */ - protected function pathFor($path) + protected function pathFor($path): string { $path = trim($path, '/'); @@ -1392,7 +1330,7 @@ protected function parseIniSize($size) $size = preg_replace('/[^0-9\.]/', '', $size); if ($unit) { - $size = ($size * pow(1024, stripos($quant, $unit[0]))); + $size *= (1024 ** stripos($quant, $unit[0])); } return round($size); @@ -1407,7 +1345,7 @@ protected function parseIniSize($size) * @return boolean Returns TRUE if the MIME type is acceptable. * Otherwise, returns FALSE. */ - protected function isAcceptedMimeType($type, array $accepted = null) + protected function isAcceptedMimeType($type, ?array $accepted = null) { if ($accepted === null) { $accepted = $this['acceptedMimetypes']; @@ -1452,7 +1390,7 @@ protected function isAcceptedFilesize($size, $max = null) * @param string $file A file path. * @return boolean Returns TRUE if the given path is absolute. Otherwise, returns FALSE. */ - protected function isAbsolutePath($file) + protected function isAbsolutePath($file): bool { $file = (string)$file; @@ -1468,9 +1406,8 @@ protected function isAbsolutePath($file) * Determine if the given value is a data URI. * * @param mixed $val The value to check. - * @return boolean */ - protected function isDataUri($val) + protected function isDataUri($val): bool { return is_string($val) && preg_match('/^data:/i', $val); } @@ -1479,9 +1416,8 @@ protected function isDataUri($val) * Determine if the given value is a data array. * * @param mixed $val The value to check. - * @return boolean */ - protected function isDataArr($val) + protected function isDataArr($val): bool { return is_array($val) && isset($val['id']); } @@ -1495,20 +1431,16 @@ protected function isDataArr($val) * @throws UnexpectedValueException If the given path is invalid. * @return string Returns the rendered target. */ - private function renamePatternArgs($path, $args = null) + private function renamePatternArgs(string|array $path, $args = null) { if (!is_string($path) && !is_array($path)) { throw new InvalidArgumentException(sprintf( 'The target must be a string or an array from [pathfino()], received %s', - (is_object($path) ? get_class($path) : gettype($path)) + (get_debug_type($path)) )); } - if (is_string($path)) { - $info = pathinfo($path); - } else { - $info = $path; - } + $info = is_string($path) ? pathinfo($path) : $path; if (!isset($info['basename']) || $info['basename'] === '') { throw new UnexpectedValueException( @@ -1554,7 +1486,7 @@ private function renamePatternArgs($path, $args = null) } else { throw new InvalidArgumentException(sprintf( 'Arguments must be an array or a callable that returns an array, received %s', - (is_object($args) ? get_class($args) : gettype($args)) + (get_debug_type($args)) )); } } @@ -1571,12 +1503,9 @@ public function getUploadedFiles() { $propIdent = $this->ident(); - $filterErrNoFile = function (array $file) { - return $file['error'] !== UPLOAD_ERR_NO_FILE; - }; - $uploadedFiles = static::parseUploadedFiles($_FILES, $filterErrNoFile, $propIdent); + $filterErrNoFile = (fn(array $file): bool => $file['error'] !== UPLOAD_ERR_NO_FILE); - return $uploadedFiles; + return static::parseUploadedFiles($_FILES, $filterErrNoFile, $propIdent); } /** @@ -1592,7 +1521,7 @@ public function getUploadedFiles() * @param mixed $searchKey If specified, then only top-level keys containing these values are returned. * @return array A tree of normalized $_FILE entries. */ - public static function parseUploadedFiles(array $uploadedFiles, callable $filterCallback = null, $searchKey = null) + public static function parseUploadedFiles(array $uploadedFiles, ?callable $filterCallback = null, $searchKey = null) { if ($searchKey !== null) { if (is_array($searchKey)) { @@ -1637,15 +1566,15 @@ public static function parseUploadedFiles(array $uploadedFiles, callable $filter $parsedFiles[$field] = [ 'tmp_name' => $uploadedFile['tmp_name'], - 'name' => isset($uploadedFile['name']) ? $uploadedFile['name'] : null, - 'type' => isset($uploadedFile['type']) ? $uploadedFile['type'] : null, - 'size' => isset($uploadedFile['size']) ? $uploadedFile['size'] : null, + 'name' => ($uploadedFile['name'] ?? null), + 'type' => ($uploadedFile['type'] ?? null), + 'size' => ($uploadedFile['size'] ?? null), 'error' => $uploadedFile['error'], ]; } } else { $subArray = []; - foreach ($uploadedFile['error'] as $fileIdx => $error) { + foreach (array_keys($uploadedFile['error']) as $fileIdx) { // normalise subarray and re-parse to move the input's keyname up a level $subArray[$fileIdx] = [ 'tmp_name' => $uploadedFile['tmp_name'][$fileIdx], @@ -1682,7 +1611,7 @@ public static function parseUploadedFiles(array $uploadedFiles, callable $filter * @param string $encoding The name of the path iconv() encoding. * @return string The path, normalised. */ - public static function normalizePath($path, $encoding = 'UTF-8') + public static function normalizePath($path, string $encoding = 'UTF-8'): string|false { $key = $path; @@ -1693,12 +1622,12 @@ public static function normalizePath($path, $encoding = 'UTF-8') // Attempt to avoid path encoding problems. $path = iconv($encoding, $encoding . '//IGNORE//TRANSLIT', $path); - if (strpos($path, '..') !== false || strpos($path, './') !== false) { + if (str_contains($path, '..') || str_contains($path, './')) { // Process the components $parts = explode('/', $path); $safe = []; - foreach ($parts as $idx => $part) { - if ((empty($part) && !is_numeric($part)) || ($part === '.')) { + foreach ($parts as $part) { + if ((($part === '' || $part === '0') && !is_numeric($part)) || ($part === '.')) { continue; } elseif ($part === '..') { array_pop($safe); diff --git a/packages/property/src/Charcoal/Property/GenericProperty.php b/packages/property/src/Charcoal/Property/GenericProperty.php index 3028015a3..ce81a0a23 100644 --- a/packages/property/src/Charcoal/Property/GenericProperty.php +++ b/packages/property/src/Charcoal/Property/GenericProperty.php @@ -1,5 +1,7 @@ filesystem = $filesystem; @@ -57,9 +56,9 @@ public function setFilesystem($filesystem) * Unlike strings' default upper limit of 255, HTML has no default max length (0). * * @see StringProperty::defaultMaxLength() - * @return integer */ - public function defaultMaxLength() + #[\Override] + public function defaultMaxLength(): int { return 0; } @@ -68,9 +67,9 @@ public function defaultMaxLength() * Unlike the parent's String Property, HTML property obviously always allow HTML. * * @see StringProperty::allowHtml() - * @return boolean */ - public function getAllowHtml() + #[\Override] + public function getAllowHtml(): bool { return true; } diff --git a/packages/property/src/Charcoal/Property/IdProperty.php b/packages/property/src/Charcoal/Property/IdProperty.php index 732cc77f3..2bcd6e8d3 100644 --- a/packages/property/src/Charcoal/Property/IdProperty.php +++ b/packages/property/src/Charcoal/Property/IdProperty.php @@ -35,10 +35,8 @@ class IdProperty extends AbstractProperty /** * Retrieve the property type. - * - * @return string */ - public function type() + public function type(): string { return 'id'; } @@ -46,17 +44,17 @@ public function type() /** * Ensure multiple can not be TRUE for ID property (ID must be unique per object). * - * @see AbstractProperty::setMultiple() + * @param boolean $multiple The multiple flag. + * @throws InvalidArgumentException If the multiple argument is TRUE (must be FALSE). + *@see AbstractProperty::setMultiple() * * @see AbstractProperty::setMultiple() - * @param boolean $flag The multiple flag. - * @throws InvalidArgumentException If the multiple argument is TRUE (must be FALSE). - * @return self */ - public function setMultiple($flag) + #[\Override] + public function setMultiple(bool $multiple): static { - $flag = !!$flag; - if ($flag === true) { + $multiple = (bool)$multiple; + if ($multiple) { throw new InvalidArgumentException( 'The ID property does not support multiple values.' ); @@ -69,9 +67,9 @@ public function setMultiple($flag) * Multiple is always FALSE for ID property. * * @see AbstractProperty::getMultiple() - * @return boolean */ - public function getMultiple() + #[\Override] + public function getMultiple(): bool { return false; } @@ -79,16 +77,16 @@ public function getMultiple() /** * Ensure l10n can not be TRUE for ID property (ID must be unique per object). * - * @see AbstractProperty::setL10n() - * @param boolean $flag The l10n, or "translatable" flag. - * @throws InvalidArgumentException If the L10N argument is TRUE (must be FALSE). - * @return self + * @param boolean $l10n The l10n, or "translatable" flag. + * @throws InvalidArgumentException If the L10N argument is TRUE (must be FALSE). + *@see AbstractProperty::setL10n() */ - public function setL10n($flag) + #[\Override] + public function setL10n(bool $l10n): static { - $flag = !!$flag; + $l10n = (bool)$l10n; - if ($flag === true) { + if ($l10n) { throw new InvalidArgumentException( 'The ID property can not be translatable.' ); @@ -101,19 +99,17 @@ public function setL10n($flag) * L10N is always FALSE for ID property. * * @see AbstractProperty::getL10n() - * @return boolean */ - public function getL10n() + #[\Override] + public function getL10n(): bool { return false; } /** * Retrieve the available ID modes. - * - * @return array */ - public function availableModes() + public function availableModes(): array { return [ self::MODE_AUTO_INCREMENT, @@ -128,9 +124,8 @@ public function availableModes() * * @param string $mode The ID mode ("auto-increment", "custom", "uniqid" or "uuid"). * @throws InvalidArgumentException If the mode is not one of the 4 valid modes. - * @return self */ - public function setMode($mode) + public function setMode($mode): static { $availableModes = $this->availableModes(); if (!in_array($mode, $availableModes)) { @@ -161,9 +156,9 @@ public function getMode() * If no ID is set upon first save, then auto-generate it if necessary. * * @param mixed $val The value, at time of saving. - * @return mixed */ - public function save($val) + #[\Override] + public function save(mixed $val): mixed { if (!$val) { $val = $this->autoGenerate(); @@ -172,10 +167,8 @@ public function save($val) return $val; } - /** - * @return boolean - */ - public function validateRequired() + #[\Override] + public function validateRequired(): bool { $mode = $this->getMode(); @@ -199,9 +192,8 @@ public function validateRequired() * - A random RFC-4122 UUID value. * * @throws DomainException If the mode does not have a value generator. - * @return string|null */ - public function autoGenerate() + public function autoGenerate(): ?string { $mode = $this['mode']; @@ -218,9 +210,8 @@ public function autoGenerate() * Generate a RFC-4122 v4 Universally-Unique Identifier (UUID). * * @see http://tools.ietf.org/html/rfc4122#section-4.4 - * @return string */ - private function generateUuid() + private function generateUuid(): string { // Generate a uniq string identifer (valid v4 uuid) return sprintf( @@ -249,7 +240,7 @@ private function generateUuid() * @see StorablePropertyTrait::sqlExtra() * @return string */ - public function sqlExtra() + public function sqlExtra(): ?string { $mode = $this->getMode(); @@ -271,7 +262,7 @@ public function sqlExtra() * @see StorablePropertyTrait::sqlType() * @return string The SQL type. */ - public function sqlType() + public function sqlType(): ?string { $mode = $this->getMode(); @@ -289,15 +280,15 @@ public function sqlType() } elseif ($mode === self::MODE_CUSTOM) { return 'VARCHAR(255)'; } + return null; } /** * Get the PDO data type. * * @see StorablePropertyTrait::sqlPdoType() - * @return integer */ - public function sqlPdoType() + public function sqlPdoType(): int { $mode = $this->getMode(); diff --git a/packages/property/src/Charcoal/Property/ImageProperty.php b/packages/property/src/Charcoal/Property/ImageProperty.php index 970d30e0c..959279de4 100644 --- a/packages/property/src/Charcoal/Property/ImageProperty.php +++ b/packages/property/src/Charcoal/Property/ImageProperty.php @@ -42,34 +42,26 @@ class ImageProperty extends FileProperty /** * The type of image processing engine. - * - * @var string */ - private $driverType = self::DEFAULT_DRIVER_TYPE; + private string $driverType = self::DEFAULT_DRIVER_TYPE; /** * Internal storage of the image factory instance. - * - * @var ImageFactory */ - private $imageFactory; + private ?\Charcoal\Image\ImageFactory $imageFactory = null; - /** - * @return string - */ - public function type() + #[\Override] + public function type(): string { return 'image'; } /** * Retrieve the image factory. - * - * @return ImageFactory */ - public function imageFactory() + public function imageFactory(): \Charcoal\Image\ImageFactory { - if ($this->imageFactory === null) { + if (!$this->imageFactory instanceof \Charcoal\Image\ImageFactory) { $this->imageFactory = $this->createImageFactory(); } @@ -83,12 +75,12 @@ public function imageFactory() * @throws InvalidArgumentException If the drive type is not a string. * @return ImageProperty Chainable */ - public function setDriverType($type) + public function setDriverType($type): static { if (!is_string($type)) { throw new InvalidArgumentException(sprintf( 'Image driver type must be a string, received %s', - (is_object($type) ? get_class($type) : gettype($type)) + (get_debug_type($type)) )); } @@ -99,10 +91,8 @@ public function setDriverType($type) /** * Retrieve the name of the property's image processing driver. - * - * @return string */ - public function getDriverType() + public function getDriverType(): string { return $this->driverType; } @@ -114,7 +104,7 @@ public function getDriverType() * @throws OutOfBoundsException If the effects event does not exist. * @return ImageProperty Chainable */ - public function setApplyEffects($event) + public function setApplyEffects($event): static { if ($event === false) { $this->applyEffects = self::EFFECTS_EVENT_NEVER; @@ -128,7 +118,7 @@ public function setApplyEffects($event) if (!in_array($event, $this->acceptedEffectsEvents())) { if (!is_string($event)) { - $event = (is_object($event) ? get_class($event) : gettype($event)); + $event = (get_debug_type($event)); } throw new OutOfBoundsException(sprintf( 'Unsupported image property event "%s" provided', @@ -158,11 +148,11 @@ public function getApplyEffects() * @throws OutOfBoundsException If the effects event does not exist. * @return mixed Returns TRUE or FALSE if the property applies effects for the given event. */ - public function canApplyEffects($event) + public function canApplyEffects($event): bool { if (!in_array($event, $this->acceptedEffectsEvents())) { if (!is_string($event)) { - $event = (is_object($event) ? get_class($event) : gettype($event)); + $event = (get_debug_type($event)); } throw new OutOfBoundsException(sprintf( 'Unsupported image property event "%s" provided', @@ -175,10 +165,8 @@ public function canApplyEffects($event) /** * Retrieve the supported events where effects can be applied. - * - * @return array */ - public function acceptedEffectsEvents() + public function acceptedEffectsEvents(): array { return [ self::EFFECTS_EVENT_UPLOAD, @@ -193,7 +181,7 @@ public function acceptedEffectsEvents() * @param array $effects The effects to set to the image. * @return ImageProperty Chainable */ - public function setEffects(array $effects) + public function setEffects(array $effects): static { $this->effects = []; foreach ($effects as $effect) { @@ -206,7 +194,7 @@ public function setEffects(array $effects) * @param mixed $effect An image effect. * @return ImageProperty Chainable */ - public function addEffect($effect) + public function addEffect($effect): static { $this->effects[] = $effect; return $this; @@ -229,7 +217,7 @@ public function getEffects() * @return mixed Returns the given images. Depending on the effects applied, * certain images might be renamed. */ - public function processEffects($value, array $effects = null, ImageInterface $image = null) + public function processEffects($value, ?array $effects = null, ?ImageInterface $image = null) { $value = $this->parseVal($value); if ($value instanceof Translation) { @@ -240,8 +228,8 @@ public function processEffects($value, array $effects = null, ImageInterface $im $effects = $this->batchEffects(); } - if ($effects) { - if ($image === null) { + if ($effects !== []) { + if (!$image instanceof \Charcoal\Image\ImageInterface) { $image = $this->createImage(); } if (is_array($value)) { @@ -263,7 +251,8 @@ public function processEffects($value, array $effects = null, ImageInterface $im * * @return string[] */ - public function getDefaultAcceptedMimetypes() + #[\Override] + public function getDefaultAcceptedMimetypes(): array { return [ 'image/gif', @@ -283,36 +272,24 @@ public function getDefaultAcceptedMimetypes() * @param string $type The MIME type to resolve. * @return string|null The extension based on the MIME type. */ - protected function resolveExtensionFromMimeType($type) + #[\Override] + protected function resolveExtensionFromMimeType($type): ?string { - switch ($type) { - case 'image/gif': - return 'gif'; - - case 'image/jpg': - case 'image/jpeg': - case 'image/pjpeg': - return 'jpg'; - - case 'image/png': - return 'png'; - - case 'image/svg+xml': - case 'image/svg': - return 'svg'; - - case 'image/webp': - return 'webp'; - } - - return null; + return match ($type) { + 'image/gif' => 'gif', + 'image/jpg', 'image/jpeg', 'image/pjpeg' => 'jpg', + 'image/png' => 'png', + 'image/svg+xml', 'image/svg' => 'svg', + 'image/webp' => 'webp', + default => null, + }; } /** * @param mixed $val The value, at time of saving. - * @return mixed */ - public function save($val) + #[\Override] + public function save(mixed $val): mixed { $val = parent::save($val); @@ -328,9 +305,9 @@ public function save($val) * * @see FileProperty::fileUpload() * @param string $fileData The file data, raw. - * @return string */ - public function dataUpload($fileData) + #[\Override] + public function dataUpload($fileData): string { $target = parent::dataUpload($fileData); @@ -346,9 +323,9 @@ public function dataUpload($fileData) * * @see FileProperty::fileUpload() * @param array $fileData The file data to upload. - * @return string */ - public function fileUpload(array $fileData) + #[\Override] + public function fileUpload(array $fileData): string { $target = parent::fileUpload($fileData); @@ -363,9 +340,8 @@ public function fileUpload(array $fileData) * Set an image factory. * * @param ImageFactory $factory The image factory, to manipulate images. - * @return self */ - protected function setImageFactory(ImageFactory $factory) + protected function setImageFactory(ImageFactory $factory): static { $this->imageFactory = $factory; @@ -374,10 +350,8 @@ protected function setImageFactory(ImageFactory $factory) /** * Create an image factory. - * - * @return ImageFactory */ - protected function createImageFactory() + protected function createImageFactory(): \Charcoal\Image\ImageFactory { return new ImageFactory(); } @@ -392,10 +366,7 @@ protected function createImage() return $this->imageFactory()->create($this['driverType']); } - /** - * @return array - */ - protected function batchEffects() + protected function batchEffects(): array { $effects = $this['effects']; $grouped = []; @@ -438,7 +409,7 @@ protected function batchEffects() } } - if (empty($grouped)) { + if ($grouped === []) { $grouped[] = $fxGroup; } } @@ -455,7 +426,7 @@ protected function batchEffects() * @throws InvalidArgumentException If the $value is not a string. * @return mixed Returns the processed target or NULL. */ - private function processEffectsOne($value, array $effects = null, ImageInterface $image = null) + private function processEffectsOne($value, ?array $effects = null, ?ImageInterface $image = null): ?string { if ($value === null || $value === '') { return null; @@ -464,7 +435,7 @@ private function processEffectsOne($value, array $effects = null, ImageInterface if (!is_string($value)) { throw new InvalidArgumentException(sprintf( 'Target image must be a string, received %s', - (is_object($value) ? get_class($value) : gettype($value)) + (get_debug_type($value)) )); } @@ -472,7 +443,7 @@ private function processEffectsOne($value, array $effects = null, ImageInterface return $value; } - if ($image === null) { + if (!$image instanceof \Charcoal\Image\ImageInterface) { $image = $this->createImage(); } @@ -480,7 +451,7 @@ private function processEffectsOne($value, array $effects = null, ImageInterface $effects = $this->batchEffects(); } - if ($effects) { + if ($effects !== []) { $basePath = $this->basePath() . DIRECTORY_SEPARATOR; $isAbsolute = false; @@ -514,18 +485,16 @@ private function processEffectsOne($value, array $effects = null, ImageInterface } break; } + } elseif (is_string($fxGroup['condition'])) { + $this->logger->warning(sprintf( + '[Image Property] Unsupported conditional effect: \'%s\'', + $fxGroup['condition'] + )); } else { - if (is_string($fxGroup['condition'])) { - $this->logger->warning(sprintf( - '[Image Property] Unsupported conditional effect: \'%s\'', - $fxGroup['condition'] - )); - } else { - $this->logger->warning(sprintf( - '[Image Property] Invalid conditional effect: \'%s\'', - gettype($fxGroup['condition']) - )); - } + $this->logger->warning(sprintf( + '[Image Property] Invalid conditional effect: \'%s\'', + gettype($fxGroup['condition']) + )); } } elseif ($fxGroup['save']) { $rename = $fxGroup['rename']; diff --git a/packages/property/src/Charcoal/Property/IpProperty.php b/packages/property/src/Charcoal/Property/IpProperty.php index 3c0223eea..ec9c8e54d 100644 --- a/packages/property/src/Charcoal/Property/IpProperty.php +++ b/packages/property/src/Charcoal/Property/IpProperty.php @@ -19,17 +19,13 @@ class IpProperty extends AbstractProperty /** * The storage mode can be either "string" (default) or "int". - * - * @var string $storageMode */ - private $storageMode = self::DEFAULT_STORAGE_MODE; + private string $storageMode = self::DEFAULT_STORAGE_MODE; /** * Retrieve the property type. - * - * @return string */ - public function type() + public function type(): string { return 'ip'; } @@ -37,16 +33,17 @@ public function type() /** * Ensure multiple can not be TRUE for ID property. * - * @param boolean $flag The multiple flag. - * @throws InvalidArgumentException If the multiple argument is TRUE (must be FALSE). - * @see AbstractProperty::setMultiple() + * @param boolean $multiple The multiple flag. * @return IdProperty Chainable + *@throws InvalidArgumentException If the multiple argument is TRUE (must be FALSE). + * @see AbstractProperty::setMultiple() */ - public function setMultiple($flag) + #[\Override] + public function setMultiple(bool $multiple): static { - $flag = !!$flag; + $multiple = (bool)$multiple; - if ($flag === true) { + if ($multiple) { throw new InvalidArgumentException( 'The ID property does not support multiple values.' ); @@ -59,9 +56,9 @@ public function setMultiple($flag) * Multiple is always FALSE for ID property. * * @see AbstractProperty::getMultiple() - * @return boolean */ - public function getMultiple() + #[\Override] + public function getMultiple(): bool { return false; } @@ -69,16 +66,17 @@ public function getMultiple() /** * Ensure l10n can not be TRUE for IP property. * - * @param boolean $flag The l10n, or "translatable" flag. - * @throws InvalidArgumentException If the L10N argument is TRUE (must be FALSE). - * @see AbstractProperty::setL10n() + * @param boolean $l10n The l10n, or "translatable" flag. * @return IdProperty Chainable + *@throws InvalidArgumentException If the L10N argument is TRUE (must be FALSE). + * @see AbstractProperty::setL10n() */ - public function setL10n($flag) + #[\Override] + public function setL10n(bool $l10n): static { - $flag = !!$flag; + $l10n = (bool)$l10n; - if ($flag === true) { + if ($l10n) { throw new InvalidArgumentException( 'The ID property is not translatable.' ); @@ -91,9 +89,9 @@ public function setL10n($flag) * L10N is always FALSE for IP property. * * @see AbstractProperty::getL10n() - * @return boolean */ - public function getL10n() + #[\Override] + public function getL10n(): bool { return false; } @@ -101,9 +99,8 @@ public function getL10n() /** * @param string $mode Either "string" or "int". * @throws InvalidArgumentException If the storage mode is invalid. - * @return self */ - public function setStorageMode($mode) + public function setStorageMode($mode): static { $validModes = [ self::STORAGE_MODE_STRING, @@ -118,10 +115,7 @@ public function setStorageMode($mode) return $this; } - /** - * @return string - */ - public function getStorageMode() + public function getStorageMode(): string { return $this->storageMode; } @@ -132,7 +126,7 @@ public function getStorageMode() * @param mixed $val The value to convert (if necessary) to integer. * @return integer */ - public function intVal($val) + public function intVal($val): int|false { if (is_numeric($val)) { return (int)$val; @@ -145,9 +139,8 @@ public function intVal($val) * Get the IP value as an string (IPv4 dotted format). * * @param mixed $val The value to convert to string. - * @return string */ - public function stringVal($val) + public function stringVal($val): string { if (is_string($val)) { return $val; @@ -160,10 +153,11 @@ public function stringVal($val) * Get the IP value in the suitable format for storage. * * @param mixed $val The value to convert to string. - * @see StorablePropertyTrait::storageVal() * @return string + *@see StorablePropertyTrait::storageVal() */ - public function storageVal($val) + #[\Override] + public function storageVal(mixed $val): int|false|string { $mode = $this->getStorageMode(); @@ -180,7 +174,7 @@ public function storageVal($val) * @param mixed $val The value to convert to string. * @return string */ - public function hostname($val) + public function hostname($val): string|false { $val = $this->stringVal($val); return gethostbyaddr($val); @@ -188,9 +182,8 @@ public function hostname($val) /** * @see StorableProperyTrait:sqlType() - * @return string */ - public function sqlType() + public function sqlType(): string { $mode = $this->getStorageMode(); @@ -203,9 +196,8 @@ public function sqlType() /** * @see StorableProperyTrait::sqlPdoType() - * @return integer */ - public function sqlPdoType() + public function sqlPdoType(): int { $mode = $this->getStorageMode(); diff --git a/packages/property/src/Charcoal/Property/LangProperty.php b/packages/property/src/Charcoal/Property/LangProperty.php index 627a1c7df..7e5ce6a29 100644 --- a/packages/property/src/Charcoal/Property/LangProperty.php +++ b/packages/property/src/Charcoal/Property/LangProperty.php @@ -19,10 +19,7 @@ class LangProperty extends AbstractProperty implements SelectablePropertyInterfa { use SelectablePropertyTrait; - /** - * @return string - */ - public function type() + public function type(): string { return 'lang'; } @@ -32,9 +29,8 @@ public function type() * * @param array $choices One or more choice structures. * @see SelectablePropertyTrait::setChoices() - * @return self */ - public function setChoices(array $choices) + public function setChoices(array $choices): static { unset($choices); @@ -50,9 +46,8 @@ public function setChoices(array $choices) * * @param array $choices One or more choice structures. * @see SelectablePropertyTrait::setChoices() - * @return self */ - public function addChoices(array $choices) + public function addChoices(array $choices): static { unset($choices); @@ -71,7 +66,7 @@ public function addChoices(array $choices) * @see SelectablePropertyTrait::addChoice() * @return LangProperty Chainable. */ - public function addChoice($choiceIdent, $choice) + public function addChoice($choiceIdent, $choice): static { unset($choiceIdent, $choice); @@ -86,11 +81,10 @@ public function addChoice($choiceIdent, $choice) * Determine if choices are available. * * @see SelectablePropertyTrait::hasChoices() - * @return boolean */ - public function hasChoices() + public function hasChoices(): bool { - return !!$this->translator()->locales(); + return (bool)$this->translator()->locales(); } /** @@ -98,9 +92,8 @@ public function hasChoices() * * @param string $choiceIdent The choice identifier to lookup. * @see SelectablePropertyTrait::hasChoice() - * @return boolean */ - public function hasChoice($choiceIdent) + public function hasChoice($choiceIdent): bool { if (empty($this->choices)) { $this->choices(); @@ -133,7 +126,7 @@ public function choices() } else { $trans = 'locale.' . $langCode; if ($trans === $this->translator()->translate($trans)) { - $label = strtoupper($langCode); + $label = strtoupper((string)$langCode); } else { $label = $this->translator()->translation($trans); } @@ -155,12 +148,9 @@ public function choices() /** * Format the given value for display. - * - * @param mixed $val The value to to convert for display. - * @param array $options Optional display options. - * @return string */ - public function displayVal($val, array $options = []) + #[\Override] + public function displayVal(mixed $val, array $options = []): string { if ($val === null || $val === '') { return ''; @@ -179,10 +169,8 @@ public function displayVal($val, array $options = []) } /** Parse multiple values / ensure they are of array type. */ - if ($this['multiple']) { - if (!is_array($propertyValue)) { - $propertyValue = $this->parseValAsMultiple($propertyValue); - } + if ($this['multiple'] && !is_array($propertyValue)) { + $propertyValue = $this->parseValAsMultiple($propertyValue); } if (is_array($propertyValue)) { @@ -217,7 +205,7 @@ public function displayVal($val, array $options = []) * @see StorablePropertyTrait::sqlType() * @return string The SQL type */ - public function sqlType() + public function sqlType(): string { if ($this['multiple']) { return 'TEXT'; @@ -226,10 +214,7 @@ public function sqlType() return 'CHAR(2)'; } - /** - * @return integer - */ - public function sqlPdoType() + public function sqlPdoType(): int { return PDO::PARAM_STR; } diff --git a/packages/property/src/Charcoal/Property/MapStructureProperty.php b/packages/property/src/Charcoal/Property/MapStructureProperty.php index 47e8e0ca7..776bf0605 100644 --- a/packages/property/src/Charcoal/Property/MapStructureProperty.php +++ b/packages/property/src/Charcoal/Property/MapStructureProperty.php @@ -1,5 +1,7 @@ structureVal($val); $val = []; - if (!empty($objs)) { + if ($objs !== []) { $val = []; foreach ($objs as $obj) { if ($obj->validate() === false) { @@ -241,9 +230,8 @@ public function getStructureMetadata() * * @param MetadataInterface|array|null $data The property's structure (fields, data). * @throws InvalidArgumentException If the structure is invalid. - * @return self */ - public function setStructureMetadata($data) + public function setStructureMetadata($data): static { if ($data === null) { $this->structureMetadata = $data; @@ -260,7 +248,7 @@ public function setStructureMetadata($data) } else { throw new InvalidArgumentException(sprintf( 'Structure [%s] is invalid (must be array or an instance of %s).', - (is_object($data) ? get_class($data) : gettype($data)), + (get_debug_type($data)), StructureMetadata::class )); } @@ -272,12 +260,10 @@ public function setStructureMetadata($data) /** * Retrieve the metadata interfaces used by the property as a structure. - * - * @return array */ - public function getStructureInterfaces() + public function getStructureInterfaces(): array { - if (empty($this->structureInterfaces)) { + if ($this->structureInterfaces === []) { return $this->structureInterfaces; } @@ -286,21 +272,18 @@ public function getStructureInterfaces() /** * Determine if the property has any structure metadata interfaces. - * - * @return boolean */ - public function hasStructureInterfaces() + public function hasStructureInterfaces(): bool { - return !empty($this->structureInterfaces); + return $this->structureInterfaces !== []; } /** * Set the given metadata interfaces for the property to use as a structure. * * @param array $interfaces One or more metadata interfaces to use. - * @return self */ - public function setStructureInterfaces(array $interfaces) + public function setStructureInterfaces(array $interfaces): static { $this->structureInterfaces = []; @@ -313,9 +296,8 @@ public function setStructureInterfaces(array $interfaces) * Add the given metadata interfaces for the property to use as a structure. * * @param array $interfaces One or more metadata interfaces to use. - * @return self */ - public function addStructureInterfaces(array $interfaces) + public function addStructureInterfaces(array $interfaces): static { foreach ($interfaces as $interface) { $this->addStructureInterface($interface); @@ -329,18 +311,17 @@ public function addStructureInterfaces(array $interfaces) * * @param string $interface A metadata interface to use. * @throws InvalidArgumentException If the interface is not a string. - * @return self */ - public function addStructureInterface($interface) + public function addStructureInterface($interface): static { if (!is_string($interface)) { throw new InvalidArgumentException(sprintf( 'Structure interface must to be a string, received %s', - is_object($interface) ? get_class($interface) : gettype($interface) + get_debug_type($interface) )); } - if (!empty($interface)) { + if ($interface !== '' && $interface !== '0') { $interface = $this->parseStructureInterface($interface); $this->structureInterfaces[$interface] = true; @@ -368,7 +349,7 @@ protected function loadStructureMetadata() $structureInterfaces = (array)$this->getStructureModelType(); } - if (!empty($structureInterfaces)) { + if (isset($structureInterfaces) && is_array($structureInterfaces) && $structureInterfaces !== []) { $metadataLoader = $this->metadataLoader(); $metadataClass = $this->getStructureMetadataClass(); @@ -417,10 +398,8 @@ public function structureProto() /** * Retrieve the default data-model structure class name. - * - * @return string */ - public static function getDefaultStructureModelClass() + public static function getDefaultStructureModelClass(): string { return StructureModel::class; } @@ -432,9 +411,8 @@ public static function getDefaultStructureModelClass() * * @param string $className The class name of the structure. * @throws InvalidArgumentException If the class name is invalid. - * @return self */ - protected function setStructureModelClass($className) + protected function setStructureModelClass($className): static { if ($className === null) { $this->structureModelClass = static::getDefaultStructureModelClass(); @@ -448,11 +426,11 @@ protected function setStructureModelClass($className) ); } - if (strpos($className, '/') !== false) { + if (str_contains($className, '/')) { try { $this->structureModelType = $className; $prototype = $this->structureModelFactory()->get($className); - $className = get_class($prototype); + $className = $prototype::class; } catch (\Exception $e) { throw new InvalidArgumentException(sprintf( 'Invalid structure class name: %s', @@ -469,10 +447,8 @@ protected function setStructureModelClass($className) /** * Determine if the property is using a custom data-model. - * - * @return boolean */ - public function hasCustomStructureModelClass() + public function hasCustomStructureModelClass(): bool { return $this->getStructureModelClass() !== static::getDefaultStructureModelClass(); } @@ -489,10 +465,8 @@ public function getStructureModelClass() /** * Retrieve the class name of the data-model structure. - * - * @return string */ - public function getStructureModelType() + public function getStructureModelType(): string { if ($this->structureModelType === null) { $this->structureModelType = $this->parseStructureInterface($this->getStructureModelClass()); @@ -532,7 +506,7 @@ public function structureVal($val, $options = []) } else { throw new InvalidArgumentException(sprintf( 'Structure value options must to be an array or an instance of %2$s, received %1$s', - is_object($options) ? get_class($options) : gettype($options), + get_debug_type($options), StructureMetadata::class )); } @@ -600,10 +574,10 @@ public function toModel($model = null) /** * PropertyInterface::save(). - * @param mixed $val The value, at time of saving. - * @return mixed + * @param mixed $val The value, at time of saving. */ - public function save($val) + #[\Override] + public function save(mixed $val): mixed { $val = parent::save($val); @@ -612,7 +586,7 @@ public function save($val) if ($proto instanceof ModelInterface) { $objs = (array)$this->structureVal($val); $val = []; - if (!empty($objs)) { + if ($objs !== []) { $val = []; foreach ($objs as $obj) { $obj->saveProperties(); @@ -634,9 +608,9 @@ public function save($val) /** * @param mixed $val The value to to convert for display. * @param array $options Optional display options. - * @return string */ - public function displayVal($val, array $options = []) + #[\Override] + public function displayVal($val, array $options = []): string { if ($val === null || $val === '') { return ''; @@ -667,6 +641,7 @@ public function displayVal($val, array $options = []) * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -682,10 +657,10 @@ protected function setDependencies(Container $container) */ protected function structureModelFactory() { - if (!isset($this->structureModelFactory)) { + if ($this->structureModelFactory === null) { throw new RuntimeException(sprintf( 'Model Factory is not defined for "%s"', - get_class($this) + static::class )); } @@ -696,9 +671,8 @@ protected function structureModelFactory() * Set an structure model factory. * * @param FactoryInterface $factory The model factory, to create objects. - * @return self */ - private function setStructureModelFactory(FactoryInterface $factory) + private function setStructureModelFactory(FactoryInterface $factory): static { $this->structureModelFactory = $factory; @@ -711,14 +685,12 @@ private function setStructureModelFactory(FactoryInterface $factory) * Change `\` and `.` to `/` and force lowercase * * @param string $interface A metadata interface to convert. - * @return string */ - protected function parseStructureInterface($interface) + protected function parseStructureInterface($interface): string { $ident = preg_replace('/([a-z])([A-Z])/', '$1-$2', $interface); - $ident = strtolower(str_replace('\\', '/', $ident)); - return $ident; + return strtolower(str_replace('\\', '/', $ident)); } /** @@ -736,10 +708,8 @@ protected function createStructureMetadata() /** * Retrieve the class name of the metadata object. - * - * @return string */ - protected function getStructureMetadataClass() + protected function getStructureMetadataClass(): string { return StructureMetadata::class; } @@ -783,17 +753,15 @@ private function createStructureModelWith( if (!$model instanceof DescribableInterface) { throw new UnexpectedValueException(sprintf( 'Structure [%s] must implement [%s]', - get_class($model), + $model::class, DescribableInterface::class )); } $model->setMetadata($metadata); - if ($datasets) { - foreach ($datasets as $data) { - $model->setData($data); - } + foreach ($datasets as $data) { + $model->setData($data); } return $model; diff --git a/packages/property/src/Charcoal/Property/MultiObjectProperty.php b/packages/property/src/Charcoal/Property/MultiObjectProperty.php index 107471a40..4b5849bdc 100644 --- a/packages/property/src/Charcoal/Property/MultiObjectProperty.php +++ b/packages/property/src/Charcoal/Property/MultiObjectProperty.php @@ -9,26 +9,15 @@ */ class MultiObjectProperty extends AbstractProperty { - /** - * @var array $allowedTypes - */ - private $allowedTypes; - - /** - * @var boolean $groupedByType - */ - private $groupedByType = true; + private ?array $allowedTypes = null; - /** - * @var string $joinTable - */ - private $joinTable = 'charcoal_multi_objects'; + private string $joinTable = 'charcoal_multi_objects'; /** * @param array $types The allowed types map. * @return MultiObjectProperty Chainable */ - public function setAllowedTypes(array $types) + public function setAllowedTypes(array $types): static { foreach ($types as $type => $typeOptions) { $this->addAllowedType($type, $typeOptions); @@ -41,7 +30,7 @@ public function setAllowedTypes(array $types) * @param array $typeOptions Extra options for the type. * @return MultiObjectProperty Chainable */ - public function addAllowedType($type, array $typeOptions = []) + public function addAllowedType($type, array $typeOptions = []): static { $this->allowedTypes[$type] = $typeOptions; return $this; @@ -50,7 +39,7 @@ public function addAllowedType($type, array $typeOptions = []) /** * @return array */ - public function getAllowedTypes() + public function getAllowedTypes(): ?array { return $this->allowedTypes; } @@ -60,7 +49,7 @@ public function getAllowedTypes() * @throws InvalidArgumentException If the table is not a string or contains invalid table characters. * @return MultiObjectProperty Chainable */ - public function setJoinTable($table) + public function setJoinTable($table): static { if (!is_string($table)) { throw new InvalidArgumentException( @@ -69,7 +58,7 @@ public function setJoinTable($table) } // For security reason, only alphanumeric characters (+ underscores) are valid table names. // Although SQL can support more, there's really no reason to. - if (!preg_match('/[A-Za-z0-9_]/', $table)) { + if (!preg_match('/\w/', $table)) { throw new InvalidArgumentException( sprintf('Table name "%s" is invalid: must be alphanumeric / underscore.', $table) ); @@ -78,22 +67,17 @@ public function setJoinTable($table) return $this; } - /** - * @return string - */ - public function getJoinTable() + public function getJoinTable(): string { return $this->joinTable; } /** * Create the join table on the database source, if it does not exist. - * - * @return void */ - public function createJoinTable() + public function createJoinTable(): void { - if ($this->joinTableExists() === true) { + if ($this->joinTableExists()) { return; } @@ -109,23 +93,17 @@ public function createJoinTable() $this->source()->db()->query($q); } - /** - * @return boolean - */ - public function joinTableExists() + public function joinTableExists(): bool { $q = 'SHOW TABLES LIKE \'' . $this->getJoinTable() . '\''; $this->logger->debug($q); $res = $this->source()->db()->query($q); $tableExists = $res->fetchColumn(0); - return !!$tableExists; + return (bool)$tableExists; } - /** - * @return string - */ - public function type() + public function type(): string { return 'multi-object'; } @@ -133,15 +111,12 @@ public function type() /** * @return string|null */ - public function sqlType() + public function sqlType(): null { return null; } - /** - * @return integer - */ - public function sqlPdoType() + public function sqlPdoType(): int { return 0; } diff --git a/packages/property/src/Charcoal/Property/NumberProperty.php b/packages/property/src/Charcoal/Property/NumberProperty.php index 87b60ea82..3340f4890 100644 --- a/packages/property/src/Charcoal/Property/NumberProperty.php +++ b/packages/property/src/Charcoal/Property/NumberProperty.php @@ -29,10 +29,7 @@ class NumberProperty extends AbstractProperty */ private $max; - /** - * @return string - */ - public function type() + public function type(): string { return 'number'; } @@ -41,9 +38,8 @@ public function type() * Set the minimal value. * * @param mixed|null $min The minimal value. - * @return self */ - public function setMin($min) + public function setMin($min): static { $this->min = $min; return $this; @@ -63,9 +59,8 @@ public function getMin() * Set the maximal value. * * @param mixed|null $max The maximal value. - * @return self */ - public function setMax($max) + public function setMax($max): static { $this->max = $max; return $this; @@ -86,7 +81,8 @@ public function getMax() * * @return string[] */ - public function validationMethods() + #[\Override] + public function validationMethods(): array { $parentMethods = parent::validationMethods(); @@ -96,10 +92,8 @@ public function validationMethods() ]); } - /** - * @return boolean - */ - public function validateRequired() + #[\Override] + public function validateRequired(): bool { if ($this['required'] && !is_numeric($this->val())) { $this->validator()->error('Value is required.', 'required'); @@ -150,7 +144,7 @@ public function validateMax() * @see StorablePropertyTrait::sqlType() * @return string The SQL type */ - public function sqlType() + public function sqlType(): string { // Multiple number are stocked as TEXT because we do not know the maximum length if ($this['multiple']) { @@ -162,9 +156,8 @@ public function sqlType() /** * @see StorablePropertyTrait::sqlPdoType() - * @return integer */ - public function sqlPdoType() + public function sqlPdoType(): int { return PDO::PARAM_STR; } diff --git a/packages/property/src/Charcoal/Property/ObjectProperty.php b/packages/property/src/Charcoal/Property/ObjectProperty.php index 2a54c3b83..4781ef33e 100644 --- a/packages/property/src/Charcoal/Property/ObjectProperty.php +++ b/packages/property/src/Charcoal/Property/ObjectProperty.php @@ -33,21 +33,17 @@ */ class ObjectProperty extends AbstractProperty implements SelectablePropertyInterface { - public const DEFAULT_PATTERN = '{{name}}'; + public const string DEFAULT_PATTERN = '{{name}}'; /** * The object type to build the choices from. - * - * @var string */ - private $objType; + private ?string $objType = null; /** * The pattern for rendering the choice as a label. - * - * @var string */ - private $pattern = self::DEFAULT_PATTERN; + private string $pattern = self::DEFAULT_PATTERN; /** * The available selectable choices. @@ -60,10 +56,8 @@ class ObjectProperty extends AbstractProperty implements SelectablePropertyInter /** * Store the collection loader for the current class. - * - * @var CollectionLoader */ - private $collectionLoader; + private ?\Charcoal\Loader\CollectionLoader $collectionLoader = null; /** * The field which defines the data's model. @@ -95,10 +89,8 @@ class ObjectProperty extends AbstractProperty implements SelectablePropertyInter /** * Store the PSR-6 caching service. - * - * @var CacheItemPoolInterface */ - private $cachePool; + private ?\Psr\Cache\CacheItemPoolInterface $cachePool = null; /** * Store all model loaders. @@ -109,15 +101,10 @@ class ObjectProperty extends AbstractProperty implements SelectablePropertyInter /** * Store the factory instance for the current class. - * - * @var FactoryInterface */ - private $modelFactory; + private ?\Charcoal\Factory\FactoryInterface $modelFactory = null; - /** - * @return string - */ - public function type() + public function type(): string { return 'object'; } @@ -127,9 +114,8 @@ public function type() * * @param string $objType The object type. * @throws InvalidArgumentException If the object type is not a string. - * @return self */ - public function setObjType($objType) + public function setObjType($objType): static { if (!is_string($objType)) { throw new InvalidArgumentException(sprintf( @@ -148,9 +134,8 @@ public function setObjType($objType) * Retrieve the object type to build the choices from. * * @throws RuntimeException If the object type was not previously set. - * @return string */ - public function getObjType() + public function getObjType(): string { if ($this->objType === null) { throw new RuntimeException(sprintf( @@ -167,7 +152,7 @@ public function getObjType() * @throws InvalidArgumentException If the pattern is not a string. * @return ObjectProperty Chainable */ - public function setPattern($pattern) + public function setPattern($pattern): static { if (!is_string($pattern)) { throw new InvalidArgumentException( @@ -180,10 +165,7 @@ public function setPattern($pattern) return $this; } - /** - * @return string - */ - public function getPattern() + public function getPattern(): string { return $this->pattern; } @@ -191,7 +173,7 @@ public function getPattern() /** * @return string */ - public function sqlType() + public function sqlType(): string { if ($this['multiple'] === true) { return 'TEXT'; @@ -204,10 +186,7 @@ public function sqlType() } } - /** - * @return integer - */ - public function sqlPdoType() + public function sqlPdoType(): int { if ($this['multiple'] === true) { return PDO::PARAM_STR; @@ -223,10 +202,10 @@ public function sqlPdoType() /** * Always return IDs. * - * @param mixed $val Value to be parsed. - * @return mixed + * @param mixed $val Value to be parsed. */ - public function parseOne($val) + #[\Override] + public function parseOne(mixed $val): mixed { if ($val instanceof StorableInterface) { return $val->id(); @@ -238,10 +217,10 @@ public function parseOne($val) /** * Get the property's value in a format suitable for storage. * - * @param mixed $val Optional. The value to convert to storage value. - * @return mixed + * @param mixed $val Optional. The value to convert to storage value. */ - public function storageVal($val) + #[\Override] + public function storageVal(mixed $val): mixed { if ($val === null || $val === '') { // Do not serialize NULL values @@ -250,10 +229,8 @@ public function storageVal($val) $val = $this->parseVal($val); - if ($this['multiple']) { - if (is_array($val)) { - $val = implode($this->multipleSeparator(), $val); - } + if ($this['multiple'] && is_array($val)) { + $val = implode($this->multipleSeparator(), $val); } if (!is_scalar($val)) { @@ -276,9 +253,9 @@ public function proto() /** * @param mixed $val Optional. The value to to convert for input. * @param array $options Unused input options. - * @return string */ - public function inputVal($val, array $options = []) + #[\Override] + public function inputVal($val, array $options = []): string { unset($options); @@ -292,10 +269,8 @@ public function inputVal($val, array $options = []) $val = $this->parseVal($val); - if ($this['multiple']) { - if (is_array($val)) { - $val = implode($this->multipleSeparator(), $val); - } + if ($this['multiple'] && is_array($val)) { + $val = implode($this->multipleSeparator(), $val); } if (!is_scalar($val)) { @@ -308,30 +283,22 @@ public function inputVal($val, array $options = []) /** * @param mixed $val The value to to convert for display. * @param array $options Optional display options. - * @return string */ - public function displayVal($val, array $options = []) + #[\Override] + public function displayVal($val, array $options = []): string { if ($val === null) { return ''; } - if (isset($options['pattern'])) { - $pattern = $options['pattern']; - } else { - $pattern = null; - } + $pattern = ($options['pattern'] ?? null); - if (isset($options['lang'])) { - $lang = $options['lang']; - } else { - $lang = null; - } + $lang = ($options['lang'] ?? null); if ($val instanceof ModelInterface) { $propertyVal = $this->renderObjPattern($val, $pattern, $lang); - if (empty($propertyVal) && !is_numeric($propertyVal)) { + if (($propertyVal === [] || ($propertyVal === '' || $propertyVal === '0') || $propertyVal === null) && !is_numeric($propertyVal)) { $propertyVal = $val->id(); } @@ -371,7 +338,7 @@ public function displayVal($val, array $options = []) } } - if (empty($label) && !is_numeric($label)) { + if (($label === [] || ($label === '' || $label === '0') || $label === null) && !is_numeric($label)) { $label = $val; } @@ -390,9 +357,8 @@ public function displayVal($val, array $options = []) * Set the available choices. * * @param array $choices One or more choice structures. - * @return self */ - public function setChoices(array $choices) + public function setChoices(array $choices): static { unset($choices); @@ -407,9 +373,8 @@ public function setChoices(array $choices) * Merge the available choices. * * @param array $choices One or more choice structures. - * @return self */ - public function addChoices(array $choices) + public function addChoices(array $choices): static { unset($choices); @@ -425,9 +390,8 @@ public function addChoices(array $choices) * * @param string $choiceIdent The choice identifier (will be key / default ident). * @param string|array $choice A string representing the choice label or a structure. - * @return self */ - public function addChoice($choiceIdent, $choice) + public function addChoice($choiceIdent, $choice): static { unset($choiceIdent, $choice); @@ -451,9 +415,8 @@ public function dynamicTypeField() /** * @param string|null $field The field to use for dynamic object type. * @throws InvalidArgumentException If the field is not a string. - * @return self */ - public function setDynamicTypeField($field) + public function setDynamicTypeField($field): static { if (!is_string($field) && !is_null($field)) { throw new InvalidArgumentException( @@ -472,7 +435,7 @@ public function setDynamicTypeField($field) * @param array $pagination Pagination settings. * @return ObjectProperty Chainable */ - public function setPagination(array $pagination) + public function setPagination(array $pagination): static { $this->pagination = $pagination; @@ -495,7 +458,7 @@ public function pagination() * @param array $orders An array of orders. * @return ObjectProperty Chainable */ - public function setOrders(array $orders) + public function setOrders(array $orders): static { $this->orders = $orders; @@ -518,7 +481,7 @@ public function orders() * @param array $filters An array of filters. * @return ObjectProperty Chainable */ - public function setFilters(array $filters) + public function setFilters(array $filters): static { $this->filters = $filters; @@ -553,9 +516,8 @@ public function hasChoices() * Retrieve the available choice structures. * * @see SelectablePropertyInterface::choices() - * @return array */ - public function choices() + public function choices(): array { $proto = $this->proto(); if (!$proto->source()->tableExists()) { @@ -563,9 +525,8 @@ public function choices() } $objects = $this->collectionModelLoader()->load(); - $choices = $this->parseChoices($objects); - return $choices; + return $this->parseChoices($objects); } /** @@ -573,9 +534,8 @@ public function choices() * * @see SelectablePropertyInterface::hasChoice() * @param string $choiceIdent The choice identifier to lookup. - * @return boolean */ - public function hasChoice($choiceIdent) + public function hasChoice($choiceIdent): bool { $obj = $this->loadObject($choiceIdent); @@ -591,7 +551,7 @@ public function hasChoice($choiceIdent) * @param string $choiceIdent The choice identifier to lookup or object to format. * @return mixed The matching choice. */ - public function choice($choiceIdent) + public function choice($choiceIdent): ?array { $obj = $this->loadObject($choiceIdent); @@ -599,9 +559,7 @@ public function choice($choiceIdent) return null; } - $choice = $this->parseChoice($obj); - - return $choice; + return $this->parseChoice($obj); } /** @@ -645,6 +603,7 @@ public function choiceLabel($choice) * @param Container $container A dependencies container instance. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -658,14 +617,13 @@ protected function setDependencies(Container $container) * Retrieve the cache service. * * @throws RuntimeException If the cache service was not previously set. - * @return CacheItemPoolInterface */ - protected function cachePool() + protected function cachePool(): \Psr\Cache\CacheItemPoolInterface { - if (!isset($this->cachePool)) { + if (!$this->cachePool instanceof \Psr\Cache\CacheItemPoolInterface) { throw new RuntimeException(sprintf( 'Cache Pool is not defined for "%s"', - get_class($this) + static::class )); } @@ -679,7 +637,7 @@ protected function cachePool() * @throws InvalidArgumentException If the collection of objects is not iterable. * @return array Returns a collection of choice structures. */ - protected function parseChoices($objs) + protected function parseChoices($objs): array { if (!is_array($objs) && !$objs instanceof Traversable) { throw new InvalidArgumentException('Must be iterable'); @@ -688,10 +646,8 @@ protected function parseChoices($objs) $parsed = []; foreach ($objs as $choice) { $choice = $this->parseChoice($choice); - if ($choice !== null) { - $choiceIdent = $choice['value']; - $parsed[$choiceIdent] = $choice; - } + $choiceIdent = $choice['value']; + $parsed[$choiceIdent] = $choice; } return $parsed; @@ -703,7 +659,7 @@ protected function parseChoices($objs) * @param ModelInterface $obj An object to format. * @return array Returns a choice structure. */ - protected function parseChoice(ModelInterface $obj) + protected function parseChoice(ModelInterface $obj): array { $label = $this->renderObjPattern($obj); $choice = [ @@ -724,14 +680,13 @@ protected function parseChoice(ModelInterface $obj) * Retrieve the model collection loader. * * @throws RuntimeException If the collection loader was not previously set. - * @return CollectionLoader */ - protected function collectionLoader() + protected function collectionLoader(): \Charcoal\Loader\CollectionLoader { - if ($this->collectionLoader === null) { + if (!$this->collectionLoader instanceof \Charcoal\Loader\CollectionLoader) { throw new RuntimeException(sprintf( 'Collection Loader is not defined for "%s"', - get_class($this) + static::class )); } @@ -784,7 +739,7 @@ protected function collectionModelLoader() * @throws InvalidArgumentException If the pattern is not a string. * @return string */ - protected function renderObjPattern(ModelInterface $obj, $pattern = null, $lang = null) + protected function renderObjPattern(ModelInterface $obj, $pattern = null, $lang = null): string|array|null { if ($pattern === null) { $pattern = $this->getPattern(); @@ -809,13 +764,13 @@ protected function renderObjPattern(ModelInterface $obj, $pattern = null, $lang $origLang = $this->translator()->getLocale(); $this->translator()->setLocale($lang); - if (strpos($pattern, '{{') === false) { + if (!str_contains($pattern, '{{')) { $output = (string)$obj[$pattern]; } elseif (($obj instanceof ViewableInterface) && $obj->view()) { $output = $obj->renderTemplate($pattern); } else { - $callback = function ($matches) use ($obj) { - $prop = trim($matches[1]); + $callback = function ($matches) use ($obj): string { + $prop = trim((string)$matches[1]); return (string)$obj[$prop]; }; @@ -884,14 +839,13 @@ protected function modelLoader($objType = null) * Retrieve the object model factory. * * @throws RuntimeException If the model factory was not previously set. - * @return FactoryInterface */ - protected function modelFactory() + protected function modelFactory(): \Charcoal\Factory\FactoryInterface { - if (!isset($this->modelFactory)) { + if (!$this->modelFactory instanceof \Charcoal\Factory\FactoryInterface) { throw new RuntimeException(sprintf( 'Model Factory is not defined for "%s"', - get_class($this) + static::class )); } @@ -902,9 +856,8 @@ protected function modelFactory() * Set an object model factory. * * @param FactoryInterface $factory The model factory, to create objects. - * @return void */ - private function setModelFactory(FactoryInterface $factory) + private function setModelFactory(FactoryInterface $factory): void { $this->modelFactory = $factory; } @@ -913,9 +866,8 @@ private function setModelFactory(FactoryInterface $factory) * Set a model collection loader. * * @param CollectionLoader $loader The collection loader. - * @return void */ - private function setCollectionLoader(CollectionLoader $loader) + private function setCollectionLoader(CollectionLoader $loader): void { $this->collectionLoader = $loader; } @@ -924,9 +876,8 @@ private function setCollectionLoader(CollectionLoader $loader) * Set the cache service. * * @param CacheItemPoolInterface $cache A PSR-6 compliant cache pool instance. - * @return void */ - private function setCachePool(CacheItemPoolInterface $cache) + private function setCachePool(CacheItemPoolInterface $cache): void { $this->cachePool = $cache; } diff --git a/packages/property/src/Charcoal/Property/PasswordProperty.php b/packages/property/src/Charcoal/Property/PasswordProperty.php index 563d0d3e5..7fd161162 100644 --- a/packages/property/src/Charcoal/Property/PasswordProperty.php +++ b/packages/property/src/Charcoal/Property/PasswordProperty.php @@ -12,10 +12,8 @@ */ class PasswordProperty extends StringProperty { - /** - * @return string - */ - public function type() + #[\Override] + public function type(): string { return 'password'; } @@ -25,18 +23,19 @@ public function type() * * If the hash is corruped or the algorithm is not recognized, the value will be rehashed. * - * @todo Implement proper hashing/rehashing/validation. * @param mixed $val The value, at time of saving. * @return string + * @todo Implement proper hashing/rehashing/validation. */ - public function save($val) + #[\Override] + public function save(mixed $val): mixed { if ($val === null || $val === '') { return $val; } if (!$this->isHashed($val)) { - $val = password_hash($val, PASSWORD_DEFAULT); + $val = password_hash((string)$val, PASSWORD_DEFAULT); } return $val; @@ -44,17 +43,12 @@ public function save($val) /** * Retrieve the maximum number of characters allowed. - * - * @return integer */ - public function getMaxLength() + #[\Override] + public function getMaxLength(): int { - if (PASSWORD_DEFAULT === PASSWORD_BCRYPT) { - /** @link https://www.php.net/manual/en/function.password-hash.php */ - return 72; - } - - return parent::getMaxLength(); + /** @link https://www.php.net/manual/en/function.password-hash.php */ + return 72; } /** @@ -63,12 +57,11 @@ public function getMaxLength() * If the hash is corruped or the algorithm is not recognized, the value is assumed to be plain-text (not hashed). * * @param string $hash The value to test. - * @return boolean */ - public function isHashed($hash) + public function isHashed($hash): bool { $info = password_get_info($hash); - return strtolower($info['algoName']) !== 'unknown'; + return strtolower((string)$info['algoName']) !== 'unknown'; } /** diff --git a/packages/property/src/Charcoal/Property/PhoneProperty.php b/packages/property/src/Charcoal/Property/PhoneProperty.php index 03d5c047c..fc9430ea0 100644 --- a/packages/property/src/Charcoal/Property/PhoneProperty.php +++ b/packages/property/src/Charcoal/Property/PhoneProperty.php @@ -12,10 +12,8 @@ */ class PhoneProperty extends StringProperty { - /** - * @return string - */ - public function type() + #[\Override] + public function type(): string { return 'phone'; } @@ -24,9 +22,9 @@ public function type() * Set StringProperty's `defaultMaxLength` to 16 for phone numbers. * * @see StringProperty::defaultMaxLength() - * @return integer */ - public function defaultMaxLength() + #[\Override] + public function defaultMaxLength(): int { return 16; } @@ -37,28 +35,27 @@ public function defaultMaxLength() * @param mixed $val Optional. The value to sanitize. If none provided, use `val()`. * @return string */ - public function sanitize($val) + public function sanitize($val): ?string { - return preg_replace('/[^0-9]/', '', $val); + return preg_replace('/[^0-9]/', '', (string)$val); } /** + * @param mixed $val The value to to convert for display. * @see AbstractProperty::displayVal() * - * @param mixed $val The value to to convert for display. - * @param array $options Unused display options. - * @return string */ - public function displayVal($val, array $options = []) + #[\Override] + public function displayVal(mixed $val, array $options = []): string { unset($options); $val = $this->sanitize($val); - if (strlen($val) == 10) { - $areaCode = substr($val, 0, 3); - $part1 = substr($val, 3, 3); - $part2 = substr($val, 6, 4); + if (strlen((string)$val) === 10) { + $areaCode = substr((string)$val, 0, 3); + $part1 = substr((string)$val, 3, 3); + $part2 = substr((string)$val, 6, 4); return '(' . $areaCode . ') ' . $part1 . '-' . $part2; } else { return $val; diff --git a/packages/property/src/Charcoal/Property/PropertyFactory.php b/packages/property/src/Charcoal/Property/PropertyFactory.php index e780a52e0..2c701766c 100644 --- a/packages/property/src/Charcoal/Property/PropertyFactory.php +++ b/packages/property/src/Charcoal/Property/PropertyFactory.php @@ -1,5 +1,7 @@ setIdent($data['ident']); @@ -104,7 +92,7 @@ public function setData(array $data) * @throws InvalidArgumentException If the identifier is not a string. * @return PropertyField Chainable */ - public function setIdent($ident) + public function setIdent($ident): static { if (!is_string($ident)) { throw new InvalidArgumentException( @@ -115,10 +103,7 @@ public function setIdent($ident) return $this; } - /** - * @return string|null - */ - public function ident() + public function ident(): ?string { return $this->ident; } @@ -128,7 +113,7 @@ public function ident() * @throws InvalidArgumentException If the label is not a string. * @return PropertyField Chainable */ - public function setLabel($label) + public function setLabel($label): static { if (!is_string($label) && $label !== null) { throw new InvalidArgumentException( @@ -152,7 +137,7 @@ public function label() * @throws InvalidArgumentException If the SQL type is not a string. * @return PropertyField Chainable */ - public function setSqlType($sqlType) + public function setSqlType($sqlType): static { if (!is_string($sqlType) && $sqlType !== null) { throw new InvalidArgumentException( @@ -176,9 +161,9 @@ public function sqlType() * @throws InvalidArgumentException If the PDO type is not an integer. * @return PropertyField Chainable */ - public function setSqlPdoType($sqlPdoType) + public function setSqlPdoType($sqlPdoType): static { - if (!is_integer($sqlPdoType)) { + if (!is_int($sqlPdoType)) { throw new InvalidArgumentException( 'PDO Type must be an integer' ); @@ -190,7 +175,7 @@ public function setSqlPdoType($sqlPdoType) /** * @return integer */ - public function sqlPdoType() + public function sqlPdoType(): ?int { if ($this->val() === null) { return PDO::PARAM_NULL; @@ -204,7 +189,7 @@ public function sqlPdoType() * @throws InvalidArgumentException If the extra is not a string. * @return PropertyField Chainable */ - public function setExtra($extra) + public function setExtra($extra): static { if (!is_string($extra) && $extra !== null) { throw new InvalidArgumentException( @@ -215,10 +200,7 @@ public function setExtra($extra) return $this; } - /** - * @return string|null - */ - public function extra() + public function extra(): ?string { return $this->extra; } @@ -228,7 +210,7 @@ public function extra() * @throws InvalidArgumentException If the encoding is not a string. * @return PropertyField Chainable */ - public function setSqlEncoding($encoding) + public function setSqlEncoding($encoding): static { if (!is_string($encoding) && $encoding !== null) { throw new InvalidArgumentException( @@ -251,7 +233,7 @@ public function sqlEncoding() * @param mixed $val The field value. * @return PropertyField Chainable */ - public function setVal($val) + public function setVal($val): static { $this->val = $val; return $this; @@ -269,7 +251,7 @@ public function val() * @param mixed $defaultVal The default field value. * @return PropertyField Chainable */ - public function setDefaultVal($defaultVal) + public function setDefaultVal($defaultVal): static { $this->defaultVal = $defaultVal; return $this; @@ -287,26 +269,24 @@ public function defaultVal() * @param boolean $allowNull The field allow null flag. * @return PropertyField Chainable */ - public function setAllowNull($allowNull) + public function setAllowNull($allowNull): static { - $this->allowNull = !!$allowNull; + $this->allowNull = (bool)$allowNull; return $this; } /** * @return boolean */ - public function allowNull() + public function allowNull(): ?bool { return $this->allowNull; } /** * Generates the SQL table column. - * - * @return string|null */ - public function sql() + public function sql(): ?string { $ident = $this->ident(); if (!$ident) { @@ -339,7 +319,7 @@ public function sql() $default = $this->defaultVal(); if ($default) { - $parts[] = sprintf('DEFAULT \'%s\'', addslashes($default)); + $parts[] = sprintf('DEFAULT \'%s\'', addslashes((string)$default)); } $comment = $this->label(); @@ -356,7 +336,7 @@ public function sql() * @param string $value The string to snakeize. * @return string The snake_case string. */ - protected function snakeize($value) + protected function snakeize($value): string { $key = $value; @@ -364,7 +344,7 @@ protected function snakeize($value) return static::$snakeCache[$key]; } - $value = strtolower(preg_replace('/(?ident; } diff --git a/packages/property/src/Charcoal/Property/SelectablePropertyInterface.php b/packages/property/src/Charcoal/Property/SelectablePropertyInterface.php index 28dbc9071..5e14d3c9a 100644 --- a/packages/property/src/Charcoal/Property/SelectablePropertyInterface.php +++ b/packages/property/src/Charcoal/Property/SelectablePropertyInterface.php @@ -1,5 +1,7 @@ choices; + return (bool)$this->choices; } /** @@ -89,9 +87,8 @@ public function choices() * Determine if the given choice is available. * * @param string $choiceIdent The choice identifier to lookup. - * @return boolean */ - public function hasChoice($choiceIdent) + public function hasChoice($choiceIdent): bool { return isset($this->choices[$choiceIdent]); } @@ -159,7 +156,7 @@ public function choiceLabel($choice) * @param array $choices One or more values to format. * @return array Returns a collection of choice structures. */ - protected function parseChoices(array $choices) + protected function parseChoices(array $choices): array { $parsed = []; foreach ($choices as $choiceIdent => $choice) { diff --git a/packages/property/src/Charcoal/Property/SpriteProperty.php b/packages/property/src/Charcoal/Property/SpriteProperty.php index 86687c24a..7850972a5 100644 --- a/packages/property/src/Charcoal/Property/SpriteProperty.php +++ b/packages/property/src/Charcoal/Property/SpriteProperty.php @@ -24,20 +24,15 @@ class SpriteProperty extends AbstractProperty implements SelectablePropertyInter /** * The sprite svg to build the choices from. - * - * @var string */ - private $sprite; + private ?string $sprite = null; /** * @var ViewInterface */ private $view; - /** - * @return string - */ - public function type() + public function type(): string { return 'sprite'; } @@ -47,9 +42,9 @@ public function type() * * @uses self::offsetSet() * @param array $data Key-value array of data to append. - * @return self */ - public function setData(array $data) + #[\Override] + public function setData(array $data): static { parent::setData($data); @@ -60,10 +55,8 @@ public function setData(array $data) /** * Retrievs the spritesheet SVG file path. - * - * @return string|null */ - public function getSprite() + public function getSprite(): ?string { return $this->sprite; } @@ -73,9 +66,8 @@ public function getSprite() * * @param string $sprite The SVG file path. * @throws InvalidArgumentException If the argument is not a string. - * @return self */ - public function setSprite($sprite) + public function setSprite($sprite): static { if (!is_string($sprite)) { throw new InvalidArgumentException( @@ -95,7 +87,7 @@ public function setSprite($sprite) * * @return string The SQL type */ - public function sqlType() + public function sqlType(): string { // Multiple strings are always stored as TEXT because they can hold multiple values if ($this['multiple']) { @@ -105,10 +97,7 @@ public function sqlType() return 'VARCHAR(255)'; } - /** - * @return integer - */ - public function sqlPdoType() + public function sqlPdoType(): int { return PDO::PARAM_STR; } @@ -117,9 +106,8 @@ public function sqlPdoType() * Retrieve the available choice structures. * * @see SelectablePropertyInterface::choices() - * @return array */ - public function buildChoicesFromSprite() + public function buildChoicesFromSprite(): array { $spritePath = $this['sprite']; @@ -134,8 +122,8 @@ public function buildChoicesFromSprite() $choices = []; - if (!isset($xml->symbol)) { - if (isset($xml->defs->symbol)) { + if (!property_exists($xml, 'symbol') || $xml->symbol === null) { + if (property_exists($xml->defs, 'symbol') && $xml->defs->symbol !== null) { $xml = $xml->defs; } else { throw new RuntimeException( @@ -150,7 +138,7 @@ public function buildChoicesFromSprite() $id = (string)$node->attributes()->id; - if (!$id) { + if ($id === '' || $id === '0') { $this->logger->warning(sprintf( 'Invalid SVG/XML spritesheet: Missing or empty ID attribute on: %s', $node->asXML() @@ -195,12 +183,12 @@ public function buildChoicesFromSprite() } /** - * @param mixed $val The value to to convert for display. - * @param array $options Optional display options. - * @see AbstractPropery::displayVal() + * @param mixed $val The value to to convert for display. * @return string + *@see AbstractPropery::displayVal() */ - public function displayVal($val, array $options = []) + #[\Override] + public function displayVal(mixed $val, array $options = []): string { $val = parent::displayVal($val, $options); @@ -244,6 +232,7 @@ public function spriteVal($val) * @param Container $container A Pimple DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); @@ -279,11 +268,11 @@ protected function parseChoice($choice, $choiceIdent) } if (!isset($choice['spritePathWithHash'])) { - $choice['spritePathWithHash'] = (string)$this['sprite'] . '#' . $choiceIdent; + $choice['spritePathWithHash'] = $this['sprite'] . '#' . $choiceIdent; } if (!isset($choice['spritePathWithHash'])) { - $choice['spritePathWithHash'] = (string)$this['sprite'] . '#' . $choiceIdent; + $choice['spritePathWithHash'] = $this['sprite'] . '#' . $choiceIdent; $choice['label'] = $this->translator()->translation($choiceIdent); } } else { diff --git a/packages/property/src/Charcoal/Property/StorablePropertyInterface.php b/packages/property/src/Charcoal/Property/StorablePropertyInterface.php index 547384916..0c620f157 100644 --- a/packages/property/src/Charcoal/Property/StorablePropertyInterface.php +++ b/packages/property/src/Charcoal/Property/StorablePropertyInterface.php @@ -1,5 +1,7 @@ fields)) { - $this->fields = $this->generateFields($val); - } else { - $this->fields = $this->updatedFields($this->fields, $val); - } + $this->fields = empty($this->fields) ? $this->generateFields($val) : $this->updatedFields($this->fields, $val); return $this->fields; } @@ -68,11 +65,11 @@ public function fields($val = null) /** * Retrieve the property's identifier formatted for field names. * - * @param string|null $key The field key to suffix to the property identifier. + * @param string|null $key The field key to suffix to the property identifier. * @return string|null Returns the property's field name. * If $key is provided, returns the namespaced field name otherwise NULL. */ - public function fieldIdent($key = null) + public function fieldIdent(?string $key = null): ?string { if ($this->fieldIdent === null) { $this->fieldIdent = $this->snakeize($this['ident']); @@ -100,7 +97,7 @@ public function fieldIdent($key = null) * * @return string[] */ - public function fieldNames() + public function fieldNames(): array { if ($this->fieldNames === null) { $names = []; @@ -122,11 +119,10 @@ public function fieldNames() /** * Retrieve the property's value in a format suitable for the given field key. * - * @param string $key The property field key. + * @param string $key The property field key. * @param mixed $val The value to set as field value. - * @return mixed */ - protected function fieldValue($key, $val) + protected function fieldValue(string $key, mixed $val): mixed { if ($val === null) { return null; @@ -150,10 +146,9 @@ protected function fieldValue($key, $val) /** * Retrieve the property's value in a format suitable for storage. * - * @param mixed $val The value to convert for storage. - * @return mixed + * @param mixed $val The value to convert for storage. */ - public function storageVal($val) + public function storageVal(mixed $val): mixed { if ($val === null) { // Do not serialize NULL values @@ -169,16 +164,12 @@ public function storageVal($val) if ($val === '') { return $val; } - } else { - if ($this['allowNull'] && $val === '') { - return null; - } + } elseif ($this['allowNull'] && $val === '') { + return null; } - if ($this['multiple']) { - if (is_array($val)) { - $val = implode($this->multipleSeparator(), $val); - } + if ($this['multiple'] && is_array($val)) { + $val = implode($this->multipleSeparator(), $val); } if (!is_scalar($val)) { @@ -197,9 +188,8 @@ public function storageVal($val) * returns a complex array. * * @param array $flatData The model data subset. - * @return mixed */ - public function parseFromFlatData(array $flatData) + public function parseFromFlatData(array $flatData): mixed { $value = null; @@ -226,9 +216,9 @@ public function parseFromFlatData(array $flatData) * @param mixed $val The value to set as field value. * @return PropertyField[] */ - protected function updatedFields(array $fields, $val) + protected function updatedFields(array $fields, mixed $val): array { - if (empty($fields)) { + if ($fields === []) { $fields = $this->generateFields($val); } @@ -242,10 +232,10 @@ protected function updatedFields(array $fields, $val) /** * Reset the property's storage fields. * - * @param mixed $val The value to set as field value. + * @param mixed|null $val The value to set as field value. * @return PropertyField[] */ - protected function generateFields($val = null) + protected function generateFields(mixed $val = null): array { $fields = []; @@ -270,9 +260,8 @@ protected function generateFields($val = null) /** * @param array $data Optional. Field data. - * @return PropertyField */ - protected function createPropertyField(array $data = null) + protected function createPropertyField(?array $data = null): \Charcoal\Property\PropertyField { $field = new PropertyField(); @@ -287,9 +276,8 @@ protected function createPropertyField(array $data = null) * Determine if the given value is a valid field key suffix. * * @param mixed $key The key to test. - * @return boolean */ - protected function isValidFieldKey($key) + protected function isValidFieldKey(mixed $key): bool { return (!empty($key) || is_numeric($key)); } @@ -300,7 +288,7 @@ protected function isValidFieldKey($key) * @param string $value The string to snakeize. * @return string The snake_case string. */ - protected function snakeize($value) + protected function snakeize(string $value): string { $key = $value; @@ -308,7 +296,7 @@ protected function snakeize($value) return static::$snakeCache[$key]; } - $value = strtolower(preg_replace('/(?sqlEncoding; } - /** - * @return string|null - */ - public function sqlExtra() + public function sqlExtra(): ?string { return null; } - /** - * @return string|null - */ - public function sqlDefaultVal() + public function sqlDefaultVal(): ?string { return null; } - /** - * @return string|null - */ - abstract public function sqlType(); - - /** - * @return integer - */ - abstract public function sqlPdoType(); - - /** - * @return string - */ - abstract public function getIdent(); - - /** - * @return boolean - */ - abstract public function getL10n(); - - /** - * @return boolean - */ - abstract public function getMultiple(); - - /** - * @return string - */ - abstract public function multipleSeparator(); - - /** - * @return boolean - */ - abstract public function getAllowNull(); - - /** - * @return \Charcoal\Translator\Translator - */ - abstract protected function translator(); + abstract public function sqlType(): ?string; + abstract public function sqlPdoType(): int; + abstract public function getIdent(): string; + abstract public function getL10n(): bool; + abstract public function getMultiple(): bool; + abstract public function multipleSeparator(): string; + abstract public function getAllowNull(): bool; + abstract protected function translator(): Translator; } diff --git a/packages/property/src/Charcoal/Property/StringProperty.php b/packages/property/src/Charcoal/Property/StringProperty.php index 9591e8840..c0ade6b3e 100644 --- a/packages/property/src/Charcoal/Property/StringProperty.php +++ b/packages/property/src/Charcoal/Property/StringProperty.php @@ -26,41 +26,27 @@ class StringProperty extends AbstractProperty implements SelectablePropertyInter /** * The minimum number of characters allowed. - * - * @var integer */ - private $minLength; + private ?int $minLength = null; /** * The maximum number of characters allowed. - * - * @var integer */ - private $maxLength; + private ?int $maxLength = null; /** * The regular expression the value is checked against. - * - * @var string */ - private $regexp; + private ?string $regexp = null; /** * Whether the value is allowed to be empty. - * - * @var boolean */ - private $allowEmpty = self::DEFAULT_ALLOW_EMPTY; + private bool $allowEmpty = self::DEFAULT_ALLOW_EMPTY; - /** - * @var boolean - */ - private $allowHtml = self::DEFAULT_ALLOW_HTML; + private bool $allowHtml = self::DEFAULT_ALLOW_HTML; - /** - * @return string - */ - public function type() + public function type(): string { return 'string'; } @@ -70,9 +56,9 @@ public function type() * * @param mixed $val The value to to convert for display. * @param array $options Optional display options. - * @return string */ - public function displayVal($val, array $options = []) + #[\Override] + public function displayVal($val, array $options = []): string { if ($val === null || $val === '') { return ''; @@ -91,10 +77,8 @@ public function displayVal($val, array $options = []) } /** Parse multiple values / ensure they are of array type. */ - if ($this['multiple']) { - if (!is_array($propertyValue)) { - $propertyValue = $this->parseValAsMultiple($propertyValue); - } + if ($this['multiple'] && !is_array($propertyValue)) { + $propertyValue = $this->parseValAsMultiple($propertyValue); } if (is_array($propertyValue)) { @@ -120,11 +104,10 @@ public function displayVal($val, array $options = []) * * @param integer $maxLength The max length allowed. * @throws InvalidArgumentException If the parameter is not an integer or < 0. - * @return self */ - public function setMaxLength($maxLength) + public function setMaxLength($maxLength): static { - if (!is_integer($maxLength)) { + if (!is_int($maxLength)) { throw new InvalidArgumentException( 'Max length must be an integer.' ); @@ -143,10 +126,8 @@ public function setMaxLength($maxLength) /** * Retrieve the maximum number of characters allowed. - * - * @return integer */ - public function getMaxLength() + public function getMaxLength(): int { if ($this->maxLength === null) { $this->maxLength = $this->defaultMaxLength(); @@ -157,10 +138,8 @@ public function getMaxLength() /** * Retrieve the default maximum number of characters allowed. - * - * @return integer */ - public function defaultMaxLength() + public function defaultMaxLength(): int { return self::DEFAULT_MAX_LENGTH; } @@ -170,11 +149,10 @@ public function defaultMaxLength() * * @param integer $minLength The minimum length allowed. * @throws InvalidArgumentException If the parameter is not an integer or < 0. - * @return self */ - public function setMinLength($minLength) + public function setMinLength($minLength): static { - if (!is_integer($minLength)) { + if (!is_int($minLength)) { throw new InvalidArgumentException( 'Min length must be an integer.' ); @@ -193,10 +171,8 @@ public function setMinLength($minLength) /** * Retrieve the minimum number of characters allowed. - * - * @return integer */ - public function getMinLength() + public function getMinLength(): int { if ($this->minLength === null) { $this->minLength = $this->defaultMinLength(); @@ -207,10 +183,8 @@ public function getMinLength() /** * Retrieve the default minimum number of characters allowed. - * - * @return integer */ - public function defaultMinLength() + public function defaultMinLength(): int { return 0; } @@ -220,9 +194,8 @@ public function defaultMinLength() * * @param string $regexp A regular expression. * @throws InvalidArgumentException If the parameter is not a string. - * @return self */ - public function setRegexp($regexp) + public function setRegexp($regexp): static { if (!is_string($regexp)) { throw new InvalidArgumentException( @@ -237,10 +210,8 @@ public function setRegexp($regexp) /** * Retrieve the regular expression to check the value against. - * - * @return string */ - public function getRegexp() + public function getRegexp(): string { if ($this->regexp === null) { $this->regexp = self::DEFAULT_REGEXP; @@ -253,21 +224,18 @@ public function getRegexp() * Set whether the value is allowed to be empty. * * @param boolean $allowEmpty The allow empty flag. - * @return self */ - public function setAllowEmpty($allowEmpty) + public function setAllowEmpty($allowEmpty): static { - $this->allowEmpty = !!$allowEmpty; + $this->allowEmpty = (bool)$allowEmpty; return $this; } /** * Determine if the value is allowed to be empty. - * - * @return boolean */ - public function getAllowEmpty() + public function getAllowEmpty(): bool { return $this->allowEmpty; } @@ -276,19 +244,15 @@ public function getAllowEmpty() * Set whether the value is allowed to contain HTML. * * @param boolean $allowHtml The allow HTML flag. - * @return self */ - public function setAllowHtml($allowHtml) + public function setAllowHtml($allowHtml): static { - $this->allowHtml = !!$allowHtml; + $this->allowHtml = (bool)$allowHtml; return $this; } - /** - * @return boolean - */ - public function getAllowHtml() + public function getAllowHtml(): bool { return $this->allowHtml; } @@ -301,9 +265,8 @@ public function getAllowHtml() * 2. If the property is a multiton, all values are counted together. * * @todo Support `multiple` / `l10n` - * @return integer */ - public function length() + public function length(): int { $val = $this->displayVal($this->val()); @@ -315,7 +278,8 @@ public function length() * * @return string[] */ - public function validationMethods() + #[\Override] + public function validationMethods(): array { $parentMethods = parent::validationMethods(); @@ -342,7 +306,7 @@ public function validateMaxLength() } $maxLength = $this->getMaxLength(); - if ($maxLength == 0) { + if ($maxLength === 0) { return true; } @@ -354,7 +318,7 @@ public function validateMaxLength() } else { $valid = true; foreach ($val as $v) { - $valid = (mb_strlen($v) <= $maxLength); + $valid = (mb_strlen((string)$v) <= $maxLength); if (!$valid) { $this->validator()->error('Maximum length error', 'maxLength'); return $valid; @@ -397,7 +361,7 @@ public function validateMinLength() } else { $valid = true; foreach ($val as $v) { - $valid = (mb_strlen($v) >= $minLength); + $valid = (mb_strlen((string)$v) >= $minLength); if (!$valid) { $this->validator()->error('Minimum length error', 'minLength'); return $valid; @@ -422,7 +386,7 @@ public function validateRegexp() return true; } - $valid = !!preg_match($regexp, $val); + $valid = (bool)preg_match($regexp, (string)$val); if (!$valid) { $this->validator()->error('Regexp error', 'regexp'); } @@ -432,10 +396,8 @@ public function validateRegexp() /** * Validate if the property's value is allowed to be empty. - * - * @return boolean */ - public function validateAllowEmpty() + public function validateAllowEmpty(): bool { $val = $this->val(); if (!$this['allowEmpty'] && empty($val) && !is_numeric($val)) { @@ -452,17 +414,16 @@ public function validateAllowEmpty() * * Strip HTML if it is not allowed. * - * @see AbstractProperty::parseVal() - * * @param mixed $val A single value to parse. * @return mixed The parsed value. + * @see AbstractProperty::parseVal() + * */ - public function parseOne($val) + #[\Override] + public function parseOne(mixed $val): mixed { - if ($this['allowHtml'] === false) { - if (is_string($val)) { - return strip_tags($val); - } + if ($this['allowHtml'] === false && is_string($val)) { + return strip_tags($val); } return $val; @@ -476,7 +437,7 @@ public function parseOne($val) * @see StorablePropertyTrait::sqlType() * @return string The SQL type */ - public function sqlType() + public function sqlType(): string { // Multiple strings are always stored as TEXT because they can hold multiple values if ($this['multiple']) { @@ -494,9 +455,8 @@ public function sqlType() /** * @see StorablePropertyTrait::sqlPdoType() - * @return integer */ - public function sqlPdoType() + public function sqlPdoType(): int { return PDO::PARAM_STR; } diff --git a/packages/property/src/Charcoal/Property/Structure/StructureMetadata.php b/packages/property/src/Charcoal/Property/Structure/StructureMetadata.php index 7f1d36c78..fde9f0216 100644 --- a/packages/property/src/Charcoal/Property/Structure/StructureMetadata.php +++ b/packages/property/src/Charcoal/Property/Structure/StructureMetadata.php @@ -13,17 +13,13 @@ class StructureMetadata extends AbstractMetadata { /** * The metadata identifier. - * - * @var string|null */ - private $ident; + private ?string $ident = null; /** * Store the admin module config. - * - * @var array */ - private $admin = []; + private array $admin = []; /** * Set the metadata identifier. @@ -32,7 +28,7 @@ class StructureMetadata extends AbstractMetadata * @throws InvalidArgumentException If identifier is not a string. * @return StructureMetadata Chainable */ - public function setIdent($ident) + public function setIdent($ident): static { if ($ident === null) { $this->ident = null; @@ -43,8 +39,8 @@ public function setIdent($ident) throw new InvalidArgumentException( sprintf( '[%s] Identifier must be a string; received %s', - get_called_class(), - (is_object($ident) ? get_class($ident) : gettype($ident)) + static::class, + (get_debug_type($ident)) ) ); } @@ -56,10 +52,8 @@ public function setIdent($ident) /** * Retrieve the metadata identifier. - * - * @return string|null */ - public function ident() + public function ident(): ?string { return $this->ident; } @@ -68,9 +62,9 @@ public function ident() * Set the object's default values. * * @param array $data An associative array. - * @return StructureMetadata */ - public function setDefaultData(array $data) + #[\Override] + public function setDefaultData(array $data): static { foreach ($data as $key => $val) { $key = $this->camelize($key); @@ -84,9 +78,9 @@ public function setDefaultData(array $data) * Set the properties. * * @param array $properties One or more properties. - * @return StructureMetadata */ - public function setProperties(array $properties) + #[\Override] + public function setProperties(array $properties): static { foreach ($properties as $propertyIdent => $propertyMetadata) { $propertyIdent = $this->camelize($propertyIdent); @@ -108,9 +102,8 @@ public function setProperties(array $properties) * * @param string $propertyIdent The property identifier to lookup. * @throws InvalidArgumentException If the identifier argument is not a string. - * @return boolean */ - public function hasProperty($propertyIdent) + public function hasProperty($propertyIdent): bool { if (!is_string($propertyIdent)) { throw new InvalidArgumentException( @@ -124,10 +117,8 @@ public function hasProperty($propertyIdent) /** * Retrieve the admin module's metadata. - * - * @return array */ - public function admin() + public function admin(): array { return $this->admin; } @@ -136,9 +127,8 @@ public function admin() * Set the admin module's metadata. * * @param array $data Metadata. - * @return StructureMetadata */ - public function setAdmin(array $data) + public function setAdmin(array $data): static { $this->admin = array_replace_recursive($this->admin, $data); diff --git a/packages/property/src/Charcoal/Property/Structure/StructureModel.php b/packages/property/src/Charcoal/Property/Structure/StructureModel.php index b71b80b21..d5b14817a 100644 --- a/packages/property/src/Charcoal/Property/Structure/StructureModel.php +++ b/packages/property/src/Charcoal/Property/Structure/StructureModel.php @@ -1,5 +1,7 @@ translator()->getLocale(); - } + $lang = is_array($lang) && isset($lang['lang']) ? $lang['lang'] : $this->translator()->getLocale(); } if ($val instanceof TranslatableValue) { @@ -152,11 +144,12 @@ public function toJson($options = 0) /** * AbstractProperty > setVal(). Ensure val is an array * - * @param string|array $val The value to set. - * @throws InvalidArgumentException If the value is invalid. + * @param mixed $val The value to set. * @return array + * @throws InvalidArgumentException If the value is invalid. */ - public function parseOne($val) + #[\Override] + public function parseOne(mixed $val): mixed { if ($val === null || $val === '') { if ($this['allowNull']) { @@ -182,6 +175,7 @@ public function parseOne($val) * @param mixed $val A L10N variable. * @return TranslatableInterface|null The translation value. */ + #[\Override] public function parseValAsL10n($val): ?TranslatableInterface { return new TranslatableValue($val); @@ -192,9 +186,8 @@ public function parseValAsL10n($val): ?TranslatableInterface * * @param string $sqlType The field SQL column type. * @throws InvalidArgumentException If the SQL type is invalid. - * @return self */ - public function setSqlType($sqlType) + public function setSqlType($sqlType): static { if (!is_string($sqlType)) { throw new InvalidArgumentException( @@ -202,31 +195,15 @@ public function setSqlType($sqlType) ); } - switch (strtoupper($sqlType)) { - case 'TEXT': - $sqlType = 'TEXT'; - break; - - case 'TINY': - case 'TINYTEXT': - $sqlType = 'TINYTEXT'; - break; - - case 'MEDIUM': - case 'MEDIUMTEXT': - $sqlType = 'MEDIUMTEXT'; - break; - - case 'LONG': - case 'LONGTEXT': - $sqlType = 'LONGTEXT'; - break; - - default: - throw new InvalidArgumentException( - 'SQL Type must be one of TEXT, TINYTEXT, MEDIUMTEXT, LONGTEXT.' - ); - } + $sqlType = match (strtoupper($sqlType)) { + 'TEXT' => 'TEXT', + 'TINY', 'TINYTEXT' => 'TINYTEXT', + 'MEDIUM', 'MEDIUMTEXT' => 'MEDIUMTEXT', + 'LONG', 'LONGTEXT' => 'LONGTEXT', + default => throw new InvalidArgumentException( + 'SQL Type must be one of TEXT, TINYTEXT, MEDIUMTEXT, LONGTEXT.' + ), + }; $this->sqlType = $sqlType; @@ -239,7 +216,6 @@ public function setSqlType($sqlType) * For a lack of better array support in mysql, data is stored as encoded JSON in a TEXT. * * @see StorableProperyTrait::sqlType() - * @return string */ public function sqlType(): string { @@ -250,9 +226,8 @@ public function sqlType(): string * Retrieve the property's PDO data type. * * @see StorablePropertyTrait::sqlPdoType() - * @return integer */ - public function sqlPdoType() + public function sqlPdoType(): int { return PDO::PARAM_STR; } diff --git a/packages/property/src/Charcoal/Property/TextProperty.php b/packages/property/src/Charcoal/Property/TextProperty.php index e6af8b062..56c981243 100644 --- a/packages/property/src/Charcoal/Property/TextProperty.php +++ b/packages/property/src/Charcoal/Property/TextProperty.php @@ -1,5 +1,7 @@ long = !!$long; + $this->long = (bool)$long; return $this; } @@ -48,9 +47,9 @@ public function getLong() * (0 = no max length). * * @see StringProperty::defaultMaxLength() - * @return integer */ - public function defaultMaxLength() + #[\Override] + public function defaultMaxLength(): int { return 0; } @@ -61,7 +60,8 @@ public function defaultMaxLength() * @see StorablePropertyTrait::sqlType() * @return string The SQL type */ - public function sqlType() + #[\Override] + public function sqlType(): string { if ($this['long'] === true) { return 'LONGTEXT'; diff --git a/packages/property/src/Charcoal/Property/UrlProperty.php b/packages/property/src/Charcoal/Property/UrlProperty.php index c752af9c4..fa14aa53c 100644 --- a/packages/property/src/Charcoal/Property/UrlProperty.php +++ b/packages/property/src/Charcoal/Property/UrlProperty.php @@ -1,5 +1,7 @@ 'mp4', + 'video/webm' => 'webm', + 'video/ogg', 'video/ogv' => 'ogv', + 'video/x-matroska' => 'mkv', + default => null, + }; } } diff --git a/packages/property/src/Charcoal/Property/data/colors.php b/packages/property/src/Charcoal/Property/data/colors.php index 7a492f67a..28e61a384 100644 --- a/packages/property/src/Charcoal/Property/data/colors.php +++ b/packages/property/src/Charcoal/Property/data/colors.php @@ -1,5 +1,7 @@ */ - private $fileMapOfFixtures; + private static ?array $fileMapOfFixtures = null; - /** - * @return void - */ protected function setUp(): void { $this->obj = $this->createProperty(); @@ -54,16 +60,16 @@ protected function setUp(): void /** * @return array */ - public function getFileMapOfFixtures() + public static function getFileMapOfFixtures() { - if ($this->fileMapOfFixtures === null) { - $this->fileMapOfFixtures = []; + if (self::$fileMapOfFixtures === null) { + self::$fileMapOfFixtures = []; foreach (self::FIXTURES as $filename) { - $this->fileMapOfFixtures[$filename] = $this->getPathToFixture('files/'.$filename); + self::$fileMapOfFixtures[$filename] = self::getPathToFixture('files/'.$filename); } } - return $this->fileMapOfFixtures; + return self::$fileMapOfFixtures; } /** @@ -71,9 +77,8 @@ public function getFileMapOfFixtures() * * @param array $expected The expected results. * @param array $actual The actual results. - * @return void */ - public function assertValidatorHasResults($expected, $actual) + public function assertValidatorHasResults(array|\ArrayAccess $expected, $actual): void { foreach ($actual as $level => $results) { $this->assertArrayHasKey( @@ -102,21 +107,17 @@ public function assertValidatorHasResults($expected, $actual) /** * Asserts that the property implements {@see FileProperty}. - * - * @coversNothing - * @return void */ - public function testFilePropertyInterface() + #[\PHPUnit\Framework\Attributes\CoversNothing] + public function testFilePropertyInterface(): void { $this->assertInstanceOf(FileProperty::class, $this->obj); } /** * Asserts that the property adheres to file property defaults. - * - * @return void */ - public function testPropertyDefaults() + public function testPropertyDefaults(): void { $obj = $this->obj; @@ -132,13 +133,12 @@ public function testPropertyDefaults() * Asserts that the file property will generate * the expected extension from a given dataset. * - * @dataProvider provideDataForGenerateExtension * * @param string $mime A MIME type. * @param string $ext The expected file extension. - * @return void */ - public function testGenerateExtensionFromDataProvider($mime, $ext) + #[\PHPUnit\Framework\Attributes\DataProvider('provideDataForGenerateExtension')] + public function testGenerateExtensionFromDataProvider($mime, $ext): void { $this->obj['mimetype'] = $mime; $this->assertEquals($mime, $this->obj['mimetype']); @@ -148,10 +148,8 @@ public function testGenerateExtensionFromDataProvider($mime, $ext) /** * Asserts that the file property will generate an extension * for all default accepted MIME types. - * - * @return void */ - public function testGenerateExtensionFromDefaultAcceptedMimeTypes() + public function testGenerateExtensionFromDefaultAcceptedMimeTypes(): void { $mimes = $this->obj['defaultAcceptedMimetypes']; if (empty($mimes)) { @@ -174,10 +172,8 @@ public function testGenerateExtensionFromDefaultAcceptedMimeTypes() /** * Asserts that the uploadPath always ends with a trailing "/". - * - * @return void */ - public function testUploadPath() + public function testUploadPath(): void { $obj = $this->obj; @@ -194,12 +190,8 @@ public function testUploadPath() /** * Asserts that the property can store a filesize. - * - * @covers \Charcoal\Property\FileProperty::setFilesize() - * @covers \Charcoal\Property\FileProperty::getFilesize() - * @return void */ - public function testFilesize() + public function testFilesize(): void { $return = $this->obj->setFilesize(1024); $this->assertSame($this->obj, $return); @@ -214,11 +206,8 @@ public function testFilesize() /** * Asserts that the property returns NULL if it can not resolve the filesize from its value. - * - * @covers \Charcoal\Property\FileProperty::getFilesize() - * @return void */ - public function testFilesizeFromBadVal() + public function testFilesizeFromBadVal(): void { $obj = $this->obj; @@ -230,12 +219,8 @@ public function testFilesizeFromBadVal() /** * Asserts that the property can store a MIME type. - * - * @covers \Charcoal\Property\FileProperty::setMimetype() - * @covers \Charcoal\Property\FileProperty::getMimetype() - * @return void */ - public function testMimetype() + public function testMimetype(): void { $return = $this->obj->setMimetype('foo'); $this->assertSame($this->obj, $return); @@ -253,11 +238,8 @@ public function testMimetype() /** * Asserts that the property returns NULL if it can not resolve the MIME type from its value. - * - * @covers \Charcoal\Property\FileProperty::getMimetype() - * @return void */ - public function testMimetypeFromBadVal() + public function testMimetypeFromBadVal(): void { $obj = $this->obj; @@ -269,11 +251,8 @@ public function testMimetypeFromBadVal() /** * Asserts that the property returns x-empty the file is empty. - * - * @covers \Charcoal\Property\FileProperty::getMimetype() - * @return void */ - public function testMimetypeFromEmptyFile() + public function testMimetypeFromEmptyFile(): void { $obj = $this->obj; @@ -285,12 +264,8 @@ public function testMimetypeFromEmptyFile() /** * Asserts that the property supports accepted MIME types. - * - * @covers \Charcoal\Property\FileProperty::setAcceptedMimetypes() - * @covers \Charcoal\Property\FileProperty::getAcceptedMimetypes() - * @return void */ - public function testAcceptedMimeTypes() + public function testAcceptedMimeTypes(): void { $obj = $this->obj; @@ -322,16 +297,14 @@ public function testAcceptedMimeTypes() /** * Asserts that the property adheres to file property defaults. * - * @covers \Charcoal\Property\FileProperty::getDefaultAcceptedMimetypes() * @return void */ - abstract public function testDefaulAcceptedMimeTypes(); + abstract public function testDefaultAcceptedMimeTypes(); /** * Asserts that the property properly checks if * any acceptable MIME types are available. * - * @covers \Charcoal\Property\FileProperty::hasAcceptedMimetypes() * @return void */ abstract public function testHasAcceptedMimeTypes(); @@ -353,7 +326,6 @@ abstract public function testMimetypeFromVal(); /** * Asserts that the `type()` method is "file". * - * @covers \Charcoal\Property\FileProperty::type() * @return void */ abstract public function testPropertyType(); @@ -371,5 +343,5 @@ abstract public function createProperty(); * @used-by self::testGenerateExtension() * @return array Format: `[ "mime-type", "extension" ]` */ - abstract public function provideDataForGenerateExtension(); + abstract public static function provideDataForGenerateExtension(); } diff --git a/packages/property/tests/Charcoal/Property/AbstractPropertyTest.php b/packages/property/tests/Charcoal/Property/AbstractPropertyTest.php index 8a840cd0d..d0cdae870 100644 --- a/packages/property/tests/Charcoal/Property/AbstractPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/AbstractPropertyTest.php @@ -4,6 +4,7 @@ use Exception; use LogicException; +use PDO; use RuntimeException; use InvalidArgumentException; @@ -24,21 +25,30 @@ class AbstractPropertyTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); - $this->obj = $this->getMockForAbstractClass(AbstractProperty::class, [[ + $this->obj = new class ([ 'database' => $container['database'], 'logger' => $container['logger'], 'translator' => $container['translator'] - ]]); + ]) extends AbstractProperty { + public function type(): string { + return 'test'; + } + + public function sqlType(): ?string { + return null; + } + + public function sqlPdoType(): int { + return PDO::PARAM_STR; + } + }; } - public function testDefaults() + public function testDefaults(): void { $this->assertEquals('', $this->obj['ident']); $this->assertFalse($this->obj['multiple']); @@ -50,10 +60,7 @@ public function testDefaults() $this->assertTrue($this->obj['allowNull']); } - /** - * @return void - */ - public function testIdent() + public function testIdent(): void { $this->assertEquals('', $this->obj->ident()); @@ -66,15 +73,9 @@ public function testIdent() $this->obj->set('ident', 'example'); $this->assertEquals('example', $this->obj['ident']); - - $this->expectException(InvalidArgumentException::class); - $this->obj->setIdent([]); } - /** - * @return void - */ - public function testL10nIdent() + public function testL10nIdent(): void { $this->obj->setIdent(''); $this->expectException(RuntimeException::class); @@ -83,13 +84,13 @@ public function testL10nIdent() $this->obj->setL10n(true); $this->assertEquals('foobar_en', $this->obj->l10nIdent()); $this->assertEquals('foobar_fr', $this->obj->l10nIdent('fr')); - $this->assertEquals('foobar_en', $this->obj->l10nIdent(null)); + $this->assertEquals('foobar_en', $this->obj->l10nIdent()); $this->expectException(InvalidArgumentException::class); $this->obj->l10nIdent(false); } - public function testL1onIdentThrowsExceptionIfL10nIsFalse() + public function testL1onIdentThrowsExceptionIfL10nIsFalse(): void { $this->expectException(LogicException::class); $this->obj->setL10n(false); @@ -97,7 +98,7 @@ public function testL1onIdentThrowsExceptionIfL10nIsFalse() $this->obj->l10nIdent(); } - public function testSetLabel() + public function testSetLabel(): void { $this->assertEquals('', $this->obj['label']); @@ -110,10 +111,8 @@ public function testSetLabel() * Asserts that the basic displayVal method: * - returns an empty string if the value is null * - returns the string as is (when not l10n / multiple) - * - * @return void */ - public function testDisplayVal() + public function testDisplayVal(): void { $this->assertFalse($this->obj['multiple']); $this->assertFalse($this->obj['l10n']); @@ -122,10 +121,7 @@ public function testDisplayVal() $this->assertEquals('foo', $this->obj->displayVal('foo')); } - /** - * @return void - */ - public function testDisplayValL10n() + public function testDisplayValL10n(): void { $this->obj['l10n'] = true; @@ -136,10 +132,7 @@ public function testDisplayValL10n() //$this->assertEquals('foo', $this->obj->displayVal(['fr'=>'foo'])); } - /** - * @return void - */ - public function testSetInputVal() + public function testSetInputVal(): void { $this->assertEquals('', $this->obj->inputVal(null)); @@ -149,10 +142,7 @@ public function testSetInputVal() $this->assertEquals('{"foo":"bar"}', str_replace([ "\n", "\r", "\t", ' ' ], '', $ret)); } - /** - * @return void - */ - public function testSetInputValL10n() + public function testSetInputValL10n(): void { $this->obj->setL10n(true); @@ -160,10 +150,7 @@ public function testSetInputValL10n() $this->assertEquals('foo', $this->obj->inputVal('foo')); } - /** - * @return void - */ - public function testSetInputValMultiple() + public function testSetInputValMultiple(): void { $this->obj->setMultiple(true); @@ -171,10 +158,7 @@ public function testSetInputValMultiple() $this->assertEquals('foo', $this->obj->inputVal('foo')); } - /** - * @return void - */ - public function testSetInputValL10nMultiple() + public function testSetInputValL10nMultiple(): void { $this->obj->setL10n(true); $this->obj->setMultiple(true); @@ -183,10 +167,7 @@ public function testSetInputValL10nMultiple() $this->assertEquals('foo', $this->obj->inputVal('foo')); } - /** - * @return void - */ - public function testSetL10n() + public function testSetL10n(): void { $this->assertFalse($this->obj['l10n']); @@ -204,10 +185,7 @@ public function testSetL10n() $this->assertFalse($this->obj['l10n']); } - /** - * @return void - */ - public function testSetHidden() + public function testSetHidden(): void { $this->assertFalse($this->obj['hidden']); @@ -225,10 +203,7 @@ public function testSetHidden() $this->assertFalse($this->obj['hidden']); } - /** - * @return void - */ - public function testSetMultiple() + public function testSetMultiple(): void { $this->assertFalse($this->obj['multiple']); @@ -246,10 +221,7 @@ public function testSetMultiple() $this->assertFalse($this->obj['multiple']); } - /** - * @return void - */ - public function testMultipleSeparator() + public function testMultipleSeparator(): void { $this->assertEquals(',', $this->obj->multipleSeparator()); @@ -259,10 +231,7 @@ public function testMultipleSeparator() $this->assertEquals('/', $this->obj->multipleSeparator()); } - /** - * @return void - */ - public function testSetRequired() + public function testSetRequired(): void { $this->assertFalse($this->obj['required']); @@ -280,10 +249,7 @@ public function testSetRequired() $this->assertFalse($this->obj['required']); } - /** - * @return void - */ - public function testSetUnique() + public function testSetUnique(): void { $this->assertFalse($this->obj['unique']); @@ -301,10 +267,7 @@ public function testSetUnique() $this->assertFalse($this->obj['unique']); } - /** - * @return void - */ - public function testSetAllowNull() + public function testSetAllowNull(): void { $this->assertTrue($this->obj['allowNull']); @@ -322,10 +285,7 @@ public function testSetAllowNull() $this->assertFalse($this->obj['allowNull']); } - /** - * @return void - */ - public function testSetStorable() + public function testSetStorable(): void { $this->assertTrue($this->obj['storable']); @@ -343,26 +303,17 @@ public function testSetStorable() $this->assertFalse($this->obj['storable']); } - /** - * @return void - */ - public function testValidationMethods() + public function testValidationMethods(): void { $this->assertIsArray($this->obj->validationMethods()); } - /** - * @return void - */ - public function testSetSqlEncoding() + public function testSetSqlEncoding(): void { $this->assertEquals('', $this->obj->sqlEncoding()); $ret = $this->obj->setSqlEncoding('utf8mb4'); $this->assertSame($ret, $this->obj); $this->assertEquals('CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci', $this->obj->sqlEncoding()); - - $this->expectException(InvalidArgumentException::class); - $this->obj->setSqlEncoding(false); } } diff --git a/packages/property/tests/Charcoal/Property/AudioPropertyTest.php b/packages/property/tests/Charcoal/Property/AudioPropertyTest.php index 9516c518f..53770cdf1 100644 --- a/packages/property/tests/Charcoal/Property/AudioPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/AudioPropertyTest.php @@ -5,17 +5,15 @@ // From 'charcoal-property' use Charcoal\Property\AudioProperty; -/** - * - */ +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Property\AudioProperty::class, 'type()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Property\AudioProperty::class, 'getDefaultAcceptedMimetypes()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Property\AudioProperty::class, 'hasAcceptedMimetypes()')] class AudioPropertyTest extends AbstractFilePropertyTestCase { /** * Create a file property instance. - * - * @return AudioProperty */ - public function createProperty() + public function createProperty(): \Charcoal\Property\AudioProperty { $container = $this->getContainer(); @@ -29,21 +27,17 @@ public function createProperty() /** * Asserts that the `type()` method is "file". - * - * @covers \Charcoal\Property\AudioProperty::type() - * @return void */ - public function testPropertyType() + public function testPropertyType(): void { $this->assertEquals('audio', $this->obj->type()); } /** * Asserts that the property adheres to file property defaults. - * - * @return void */ - public function testPropertyDefaults() + #[\Override] + public function testPropertyDefaults(): void { parent::testPropertyDefaults(); @@ -53,11 +47,8 @@ public function testPropertyDefaults() /** * Asserts that the property adheres to file property defaults. - * - * @covers \Charcoal\Property\AudioProperty::getDefaultAcceptedMimetypes() - * @return void */ - public function testDefaulAcceptedMimeTypes() + public function testDefaultAcceptedMimeTypes(): void { $this->assertIsArray($this->obj['defaultAcceptedMimetypes']); $this->assertNotEmpty($this->obj['defaultAcceptedMimetypes']); @@ -66,11 +57,8 @@ public function testDefaulAcceptedMimeTypes() /** * Asserts that the property properly checks if * any acceptable MIME types are available. - * - * @covers \Charcoal\Property\AudioProperty::hasAcceptedMimetypes() - * @return void */ - public function testHasAcceptedMimeTypes() + public function testHasAcceptedMimeTypes(): void { $this->assertTrue($this->obj->hasAcceptedMimetypes()); @@ -80,10 +68,8 @@ public function testHasAcceptedMimeTypes() /** * Asserts that the property can resolve a filesize from its value. - * - * @return void */ - public function testFilesizeFromVal() + public function testFilesizeFromVal(): void { $obj = $this->obj; @@ -97,10 +83,8 @@ public function testFilesizeFromVal() * Asserts that the property can resolve a MIME type from its value. * * Ignore issues under PHP 7.0 and PHP 7.1, see https://bugs.php.net/bug.php?id=78183 - * - * @return void */ - public function testMimetypeFromVal() + public function testMimetypeFromVal(): void { $obj = $this->obj; @@ -120,10 +104,7 @@ public function testMimetypeFromVal() } } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $data = [ @@ -137,10 +118,7 @@ public function testSetData() $this->assertEquals(500, $obj['maxLength']); } - /** - * @return void - */ - public function testSetDataSnakecase() + public function testSetDataSnakecase(): void { $obj = $this->obj; $data = [ @@ -154,10 +132,7 @@ public function testSetDataSnakecase() $this->assertEquals(500, $obj['maxLength']); } - /** - * @return void - */ - public function testSetMinLength() + public function testSetMinLength(): void { $ret = $this->obj->setMinLength(5); $this->assertSame($ret, $this->obj); @@ -168,10 +143,7 @@ public function testSetMinLength() $this->obj->setMinLength(false); } - /** - * @return void - */ - public function testSetMaxLength() + public function testSetMaxLength(): void { $ret = $this->obj->setMaxLength(5); $this->assertSame($ret, $this->obj); @@ -182,10 +154,8 @@ public function testSetMaxLength() $this->obj->setMaxLength(false); } - /** - * @return void - */ - public function testAcceptedMimetypes() + #[\Override] + public function testAcceptedMimetypes(): void { $ret = $this->obj['acceptedMimetypes']; $this->assertContains('audio/mp3', $ret); @@ -198,9 +168,8 @@ public function testAcceptedMimetypes() * Provide property data for {@see AudioProperty::generateExtension()}. * * @used-by AbstractFilePropertyTestCase::testGenerateExtensionFromDataProvider() - * @return array */ - public function provideDataForGenerateExtension() + public static function provideDataForGenerateExtension(): array { return [ [ 'audio/mp3', 'mp3' ], diff --git a/packages/property/tests/Charcoal/Property/BooleanPropertyTest.php b/packages/property/tests/Charcoal/Property/BooleanPropertyTest.php index bbe46f710..acd1139df 100644 --- a/packages/property/tests/Charcoal/Property/BooleanPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/BooleanPropertyTest.php @@ -21,9 +21,6 @@ class BooleanPropertyTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -35,10 +32,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('boolean', $this->obj->type()); } @@ -46,10 +40,8 @@ public function testType() /** * Assert that the boolean property 's `displayVal()` method: * - return the proper label - * - * @return void */ - public function testDisplayVal() + public function testDisplayVal(): void { $this->obj->setTrueLabel('Oui'); $this->obj->setFalseLabel('Non'); @@ -72,10 +64,8 @@ public function testDisplayVal() * - set the multiple to false, if false or falsish value * - throws exception otherwise (truthish or invalid value) * - is chainable - * - * @return void */ - public function testSetMultiple() + public function testSetMultiple(): void { $obj = $this->obj; $ret = $obj->setMultiple(0); @@ -88,19 +78,14 @@ public function testSetMultiple() /** * Asserts that the boolean property is multiple by default - * - * @return void */ - public function testMultiple() + public function testMultiple(): void { $obj = $this->obj; $this->assertFalse($obj['multiple']); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $data = [ @@ -115,10 +100,7 @@ public function testSetData() $this->assertEquals('bar', $obj['falseLabel']); } - /** - * @return void - */ - public function testSetTrueLabel() + public function testSetTrueLabel(): void { $obj = $this->obj; $ret = $obj->setTrueLabel('foo'); @@ -127,10 +109,7 @@ public function testSetTrueLabel() $this->assertEquals('foo', $obj['trueLabel']); } - /** - * @return void - */ - public function testSetFalseLabel() + public function testSetFalseLabel(): void { $obj = $this->obj; $ret = $obj->setFalseLabel('foo'); @@ -139,36 +118,24 @@ public function testSetFalseLabel() $this->assertEquals('foo', $obj['falseLabel']); } - /** - * @return void - */ - public function testSqlExtra() + public function testSqlExtra(): void { $obj = $this->obj; $this->assertSame(null, $obj->sqlExtra()); } - /** - * @return void - */ - public function testSqlType() + public function testSqlType(): void { //$this->assertEquals('TINYINT(1) UNSIGNED', $this->obj->sqlType()); $this->assertEquals('INT', $this->obj->sqlType()); } - /** - * @return void - */ - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->assertEquals(PDO::PARAM_BOOL, $this->obj->sqlPdoType()); } - /** - * @return void - */ - public function testChoices() + public function testChoices(): void { $obj = $this->obj; $obj->setVal(false); @@ -187,10 +154,7 @@ public function testChoices() $this->assertEquals($choices, $obj->choices()); } - /** - * @return void - */ - public function testSave() + public function testSave(): void { $this->assertTrue($this->obj->save(true)); $this->assertFalse($this->obj->save(false)); diff --git a/packages/property/tests/Charcoal/Property/ColorPropertyTest.php b/packages/property/tests/Charcoal/Property/ColorPropertyTest.php index 1a11f7daf..066300ac7 100644 --- a/packages/property/tests/Charcoal/Property/ColorPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/ColorPropertyTest.php @@ -23,9 +23,6 @@ class ColorPropertyTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -37,15 +34,12 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('color', $this->obj->type()); } - public function testParseOneNull() + public function testParseOneNull(): void { $this->obj->setAllowNull(true); $this->assertNull($this->obj->parseOne(null)); @@ -55,7 +49,7 @@ public function testParseOneNull() $this->obj->parseOne(null); } - public function testParseOneEmpty() + public function testParseOneEmpty(): void { $this->obj->setAllowNull(true); $this->assertNull($this->obj->parseOne('')); @@ -65,13 +59,13 @@ public function testParseOneEmpty() $this->obj->parseOne(''); } - public function parseOneFalse() + public function parseOneFalse(): void { $this->expectException(InvalidArgumentException::class); $this->obj->parseOne(false); } - public function parseOneArray() + public function parseOneArray(): void { $this->assertEquals(['r'=>255, 'g'=>255, 'b'=>255], $this->obj->parseOne([255,255,255])); $this->expectException(InvalidArgumentException::class); @@ -80,18 +74,13 @@ public function parseOneArray() /** * Hello world - * - * @return void */ - public function testDefaults() + public function testDefaults(): void { $this->assertEquals(false, $this->obj['supportAlpha']); } - /** - * @return void - */ - public function testSetSupportAlpha() + public function testSetSupportAlpha(): void { $ret = $this->obj->setSupportAlpha(true); $this->assertSame($ret, $this->obj); @@ -108,35 +97,30 @@ public function testSetSupportAlpha() } /** - * @dataProvider colorProviderNoAlpha * * @param string $color A color to test. * @param string $expected The expected mutation of $color. - * @return void */ - public function testColorValueNoAlpha($color, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('colorProviderNoAlpha')] + public function testColorValueNoAlpha(string|array $color, string $expected): void { $this->obj->setSupportAlpha(false); $this->assertEquals($expected, $this->obj->colorVal($color)); } /** - * @dataProvider colorProviderAlpha * * @param string $color A color to test. * @param string $expected The expected mutation of $color. - * @return void */ - public function testColorValueAlpha($color, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('colorProviderAlpha')] + public function testColorValueAlpha(string|array $color, string $expected): void { $this->obj->setSupportAlpha(true); $this->assertEquals($expected, $this->obj->colorVal($color)); } - /** - * @return void - */ - public function testColorValInvalidThrowsException() + public function testColorValInvalidThrowsException(): void { $this->expectException('\InvalidArgumentException'); $this->obj->colorVal('invalid'); @@ -144,10 +128,8 @@ public function testColorValInvalidThrowsException() /** * Provider for hexadcimalValue, in `[$color, $expected]` pairs. - * - * @return array */ - public function colorProviderNoAlpha() + public static function colorProviderNoAlpha(): array { return [ ['#FF00FF', '#FF00FF'], @@ -170,10 +152,8 @@ public function colorProviderNoAlpha() /** * Provider for hexadcimalValue, in `[$color, $result]` pairs. - * - * @return array */ - public function colorProviderAlpha() + public static function colorProviderAlpha(): array { return [ ['#FF00FF', 'rgba(255,0,255,0)'], @@ -193,29 +173,20 @@ public function colorProviderAlpha() ]; } - /** - * @return void - */ - public function testSqlExtra() + public function testSqlExtra(): void { $obj = $this->obj; $this->assertEquals('', $obj->sqlExtra()); } - /** - * @return void - */ - public function testSqlTypeMultiple() + public function testSqlTypeMultiple(): void { $obj = $this->obj; $obj->setMultiple(true); $this->assertEquals('TEXT', $obj->sqlType()); } - /** - * @return void - */ - public function testSqlType() + public function testSqlType(): void { $obj = $this->obj; @@ -226,7 +197,7 @@ public function testSqlType() $this->assertEquals('CHAR(7)', $obj->sqlType()); } - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->assertEquals(PDO::PARAM_STR, $this->obj->sqlPdoType()); } diff --git a/packages/property/tests/Charcoal/Property/ContainerIntegrationTrait.php b/packages/property/tests/Charcoal/Property/ContainerIntegrationTrait.php index 5af9bbfba..153244bc5 100644 --- a/packages/property/tests/Charcoal/Property/ContainerIntegrationTrait.php +++ b/packages/property/tests/Charcoal/Property/ContainerIntegrationTrait.php @@ -51,9 +51,8 @@ protected function getContainerProvider() /** * @see ContainerProvider - * @return void */ - private function setupContainer() + private function setupContainer(): void { $provider = new ContainerProvider(); $container = new Container(); diff --git a/packages/property/tests/Charcoal/Property/ContainerProvider.php b/packages/property/tests/Charcoal/Property/ContainerProvider.php index 59512fc74..600df92c0 100644 --- a/packages/property/tests/Charcoal/Property/ContainerProvider.php +++ b/packages/property/tests/Charcoal/Property/ContainerProvider.php @@ -46,9 +46,8 @@ class ContainerProvider * Register the unit tests required services. * * @param Container $container A DI container. - * @return void */ - public function registerBaseServices(Container $container) + public function registerBaseServices(Container $container): void { $this->registerConfig($container); $this->registerSource($container); @@ -60,9 +59,8 @@ public function registerBaseServices(Container $container) * Setup the application configset. * * @param Container $container A DI container. - * @return void */ - public function registerConfig(Container $container) + public function registerConfig(Container $container): void { $container['config'] = [ 'base_path' => realpath(__DIR__.'/../../..'), @@ -76,11 +74,10 @@ public function registerConfig(Container $container) * Note: Uses SQLite to create a database in memory. * * @param Container $container A DI container. - * @return void */ - public function registerSource(Container $container) + public function registerSource(Container $container): void { - $container['database'] = function () { + $container['database'] = function (): \PDO { $pdo = new PDO('sqlite::memory:'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; @@ -91,71 +88,57 @@ public function registerSource(Container $container) * Setup the application's logging interface. * * @param Container $container A DI container. - * @return void */ - public function registerLogger(Container $container) + public function registerLogger(Container $container): void { - $container['logger'] = function () { - return new NullLogger(); - }; + $container['logger'] = (fn(): \Psr\Log\NullLogger => new NullLogger()); } /** * Setup the application's caching interface. * * @param Container $container A DI container. - * @return void */ - public function registerCache(Container $container) + public function registerCache(Container $container): void { - $container['cache'] = function () { - return new Pool(); - }; + $container['cache'] = (fn(): \Stash\Pool => new Pool()); } /** * Setup the framework's view renderer. * * @param Container $container A DI container. - * @return void */ - public function registerView(Container $container) + public function registerView(Container $container): void { - $container['view/loader'] = function (Container $container) { - return new MustacheLoader([ - 'logger' => $container['logger'], - 'base_path' => $container['config']['base_path'], - 'paths' => [ - 'views' - ] - ]); - }; - - $container['view/engine'] = function (Container $container) { - return new MustacheEngine([ - 'logger' => $container['logger'], - 'cache' => MustacheEngine::DEFAULT_CACHE_PATH, - 'loader' => $container['view/loader'] - ]); - }; - - $container['view'] = function (Container $container) { - return new GenericView([ - 'logger' => $container['logger'], - 'engine' => $container['view/engine'] - ]); - }; + $container['view/loader'] = (fn(Container $container): \Charcoal\View\Mustache\MustacheLoader => new MustacheLoader([ + 'logger' => $container['logger'], + 'base_path' => $container['config']['base_path'], + 'paths' => [ + 'views' + ] + ])); + + $container['view/engine'] = (fn(Container $container): \Charcoal\View\Mustache\MustacheEngine => new MustacheEngine([ + 'logger' => $container['logger'], + 'cache' => MustacheEngine::DEFAULT_CACHE_PATH, + 'loader' => $container['view/loader'] + ])); + + $container['view'] = (fn(Container $container): \Charcoal\View\GenericView => new GenericView([ + 'logger' => $container['logger'], + 'engine' => $container['view/engine'] + ])); } /** * Setup the application's translator service. * * @param Container $container A DI container. - * @return void */ - public function registerTranslator(Container $container) + public function registerTranslator(Container $container): void { - $container['locales/manager'] = function () { + $container['locales/manager'] = function (): \Charcoal\Translator\LocalesManager { $manager = new LocalesManager([ 'locales' => [ 'en' => [ 'locale' => 'en-US' ] @@ -167,22 +150,19 @@ public function registerTranslator(Container $container) return $manager; }; - $container['translator'] = function (Container $container) { - return new Translator([ - 'manager' => $container['locales/manager'] - ]); - }; + $container['translator'] = (fn(Container $container): \Charcoal\Translator\Translator => new Translator([ + 'manager' => $container['locales/manager'] + ])); } /** * Setup the application's translator service. * * @param Container $container A DI container. - * @return void */ - public function registerMultilingualTranslator(Container $container) + public function registerMultilingualTranslator(Container $container): void { - $container['locales/manager'] = function () { + $container['locales/manager'] = function (): \Charcoal\Translator\LocalesManager { $manager = new LocalesManager([ 'locales' => [ 'en' => [ @@ -217,7 +197,7 @@ public function registerMultilingualTranslator(Container $container) return $manager; }; - $container['translator'] = function (Container $container) { + $container['translator'] = function (Container $container): \Charcoal\Translator\Translator { $translator = new Translator([ 'manager' => $container['locales/manager'] ]); @@ -237,103 +217,88 @@ public function registerMultilingualTranslator(Container $container) * Setup the framework's metadata loader interface. * * @param Container $container A DI container. - * @return void */ - public function registerMetadataLoader(Container $container) + public function registerMetadataLoader(Container $container): void { - $container['metadata/loader'] = function (Container $container) { - return new MetadataLoader([ - 'cache' => $container['cache'], - 'logger' => $container['logger'], - 'base_path' => $container['config']['base_path'], - 'paths' => [ - 'metadata' - ] - ]); - }; + $container['metadata/loader'] = (fn(Container $container): \Charcoal\Model\Service\MetadataLoader => new MetadataLoader([ + 'cache' => $container['cache'], + 'logger' => $container['logger'], + 'base_path' => $container['config']['base_path'], + 'paths' => [ + 'metadata' + ] + ])); } /** * Setup the framework's data source factory. * * @param Container $container A DI container. - * @return void */ - public function registerSourceFactory(Container $container) + public function registerSourceFactory(Container $container): void { - $container['source/factory'] = function ($container) { - return new Factory([ - 'map' => [ - 'database' => DatabaseSource::class - ], - 'arguments' => [[ - 'logger' => $container['logger'], - 'cache' => $container['cache'], - 'pdo' => $container['database'] - ]] - ]); - }; + $container['source/factory'] = (fn($container): \Charcoal\Factory\GenericFactory => new Factory([ + 'map' => [ + 'database' => DatabaseSource::class + ], + 'arguments' => [[ + 'logger' => $container['logger'], + 'cache' => $container['cache'], + 'pdo' => $container['database'] + ]] + ])); } /** * Setup the framework's model factory. * * @param Container $container A DI container. - * @return void */ - public function registerModelFactory(Container $container) + public function registerModelFactory(Container $container): void { - $container['model/factory'] = function ($container) { - return new Factory([ - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'], - 'metadata_loader' => $container['metadata/loader'], - 'source_factory' => $container['source/factory'], - 'property_factory' => $container['property/factory'] - ]] - ]); - }; + $container['model/factory'] = (fn($container): \Charcoal\Factory\GenericFactory => new Factory([ + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'], + 'metadata_loader' => $container['metadata/loader'], + 'source_factory' => $container['source/factory'], + 'property_factory' => $container['property/factory'] + ]] + ])); } /** * Setup the framework's property factory. * * @param Container $container A DI container. - * @return void */ - public function registerPropertyFactory(Container $container) + public function registerPropertyFactory(Container $container): void { - $container['property/factory'] = function (Container $container) { - return new Factory([ - 'resolver_options' => [ - 'prefix' => '\\Charcoal\\Property\\', - 'suffix' => 'Property' - ], - 'arguments' => [[ - 'container' => $container, - 'database' => $container['database'], - 'logger' => $container['logger'], - 'translator' => $container['translator'] - ]] - ]); - }; + $container['property/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'resolver_options' => [ + 'prefix' => '\\Charcoal\\Property\\', + 'suffix' => 'Property' + ], + 'arguments' => [[ + 'container' => $container, + 'database' => $container['database'], + 'logger' => $container['logger'], + 'translator' => $container['translator'] + ]] + ])); } /** * Setup the framework's collection loader interface. * * @param Container $container A DI container. - * @return void */ - public function registerModelCollectionLoader(Container $container) + public function registerModelCollectionLoader(Container $container): void { - $container['model/collection/loader'] = function (Container $container) { - return new CollectionLoader([ - 'logger' => $container['logger'], - 'cache' => $container['cache'], - 'factory' => $container['model/factory'] - ]); - }; + $container['model/collection/loader'] = (fn(Container $container): \Charcoal\Loader\CollectionLoader => new CollectionLoader([ + 'logger' => $container['logger'], + 'cache' => $container['cache'], + 'factory' => $container['model/factory'] + ])); } } diff --git a/packages/property/tests/Charcoal/Property/DateTimePropertyTest.php b/packages/property/tests/Charcoal/Property/DateTimePropertyTest.php index eb0b1c001..5ad45f277 100644 --- a/packages/property/tests/Charcoal/Property/DateTimePropertyTest.php +++ b/packages/property/tests/Charcoal/Property/DateTimePropertyTest.php @@ -22,9 +22,6 @@ class DateTimePropertyTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -39,10 +36,8 @@ protected function setUp(): void /** * Assert that the `type` method: * - returns "date-time" - * - * @return void */ - public function testType() + public function testType(): void { $this->assertEquals('date-time', $this->obj->type()); } @@ -51,10 +46,8 @@ public function testType() * Assert that the `setData` method: * - is chainable * - sets the data - * - * @return void */ - public function testSetData() + public function testSetData(): void { $ret = $this->obj->setData([ 'min' => '2015-01-01 00:00:00', @@ -77,10 +70,8 @@ public function testSetData() * - Is chainable * - Set the value to null if "allowNull" is true * - Throw an exception if "allowNull" is false - * - * @return void */ - public function testSetValWithNullValue() + public function testSetValWithNullValue(): void { $this->obj->setAllowNull(true); @@ -98,10 +89,8 @@ public function testSetValWithNullValue() * - Is chainable * - Sets the value when the parameter is a string or a DateTime object * - Throws an exception otherwise - * - * @return void */ - public function testSetVal() + public function testSetVal(): void { $ret = $this->obj->setVal('2000-01-01 00:00:00'); $this->assertSame($ret, $this->obj); @@ -115,10 +104,7 @@ public function testSetVal() $this->assertEquals($dt, $this->obj->val()); } - /** - * @return void - */ - public function testStorageVal() + public function testStorageVal(): void { $this->assertEquals('1984-10-01 00:00:00', $this->obj->storageVal('October 1st, 1984')); @@ -131,10 +117,7 @@ public function testStorageVal() $this->obj->storageVal(null); } - /** - * @return void - */ - public function testDisplayVal() + public function testDisplayVal(): void { // Test default format $this->assertEquals('2015-10-01 15:00:00', $this->obj->displayVal('October 1st, 2015 15:00:00')); @@ -150,7 +133,7 @@ public function testDisplayVal() $this->assertEquals('', $this->obj->displayVal(null)); } - public function testInputVal() + public function testInputVal(): void { // Test default format $this->assertEquals('2015-10-01 15:00:00', $this->obj->inputVal('October 1st, 2015 15:00:00')); @@ -167,10 +150,8 @@ public function testInputVal() * - set the multiple to false, if false or falsish value * - throws exception otherwise (truthish or invalid value) * - is chainable - * - * @return void */ - public function testSetMultiple() + public function testSetMultiple(): void { $ret = $this->obj->setMultiple(0); $this->assertSame($ret, $this->obj); @@ -180,10 +161,7 @@ public function testSetMultiple() $this->obj->setMultiple(1); } - /** - * @return void - */ - public function testMultiple() + public function testMultiple(): void { $this->assertSame(false, $this->obj['multiple']); } @@ -194,10 +172,8 @@ public function testMultiple() * - sets the min value from a string or DateTime object * - accepts null as parameter * - throws exception when the argument is invalid - * - * @return void */ - public function testSetMin() + public function testSetMin(): void { // Setting by string $ret = $this->obj->setMin('2020-01-01 01:02:03'); @@ -225,7 +201,7 @@ public function testSetMin() $this->obj->setMin('foo'); } - public function testSetMinInvalidObjectThrowsException() + public function testSetMinInvalidObjectThrowsException(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setMin(new \StdClass()); @@ -237,10 +213,8 @@ public function testSetMinInvalidObjectThrowsException() * - sets the max value * - accepts null as a parameter * - throws exception when the argument is invalid - * - * @return void */ - public function testSetMax() + public function testSetMax(): void { $ret = $this->obj->setMax('2020-01-01 01:02:03'); $this->assertSame($ret, $this->obj); @@ -267,7 +241,7 @@ public function testSetMax() $this->obj->setMax('foo'); } - public function testSetMaxInvalidObjectThrowsException() + public function testSetMaxInvalidObjectThrowsException(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setMax(new \StdClass()); @@ -282,10 +256,8 @@ public function testSetMaxInvalidObjectThrowsException() * - accepts empty string * - accepts null as a parameter (convert to empty string) * - throws an exception if not a string - * - * @return void */ - public function testSetFormat() + public function testSetFormat(): void { $this->assertEquals('Y-m-d H:i:s', $this->obj['format']); @@ -309,10 +281,7 @@ public function testSetFormat() $this->obj->setFormat(false); } - /** - * @return void - */ - public function testSave() + public function testSave(): void { $this->assertEquals(null, $this->obj->save(null)); @@ -320,7 +289,7 @@ public function testSave() $this->assertEquals($expected, $this->obj->save('2015-01-01')); } - public function testValidationMethods() + public function testValidationMethods(): void { $this->assertContains('min', $this->obj->validationMethods()); $this->assertContains('max', $this->obj->validationMethods()); @@ -331,10 +300,8 @@ public function testValidationMethods() * - Returns true if no "min" is set * - Returns true when the value is equal or bigger * - Returns false when the value is smaller - * - * @return void */ - public function testValidateMin() + public function testValidateMin(): void { $this->assertTrue($this->obj->validateMin()); @@ -358,10 +325,8 @@ public function testValidateMin() * - Returns true if no "max" is set * - Returns true when the value is equal or smaller * - Returns false when the value is bigger - * - * @return void */ - public function testValidateMax() + public function testValidateMax(): void { $this->assertTrue($this->obj->validateMax()); @@ -380,26 +345,17 @@ public function testValidateMax() $this->assertNotTrue($this->obj->validateMax()); } - /** - * @return void - */ - public function testSqlExtra() + public function testSqlExtra(): void { $this->assertSame(null, $this->obj->sqlExtra()); } - /** - * @return void - */ - public function testSqlType() + public function testSqlType(): void { $this->assertEquals('DATETIME', $this->obj->sqlType()); } - /** - * @return void - */ - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->assertEquals(PDO::PARAM_STR, $this->obj->sqlPdoType()); } diff --git a/packages/property/tests/Charcoal/Property/EmailPropertyTest.php b/packages/property/tests/Charcoal/Property/EmailPropertyTest.php index 593631ee0..2860cbeac 100644 --- a/packages/property/tests/Charcoal/Property/EmailPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/EmailPropertyTest.php @@ -18,9 +18,6 @@ class EmailPropertyTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -34,18 +31,13 @@ protected function setUp(): void /** * Asserts that the `type()` method returns "url". - * - * @return void */ - public function testType() + public function testType(): void { $this->assertEquals('email', $this->obj->type()); } - /** - * @return void - */ - public function testMaxLength() + public function testMaxLength(): void { $this->assertEquals(254, $this->obj['maxLength']); @@ -53,10 +45,7 @@ public function testMaxLength() $this->assertEquals(254, $this->obj['maxLength']); } - /** - * @return void - */ - public function testValidateEmail() + public function testValidateEmail(): void { $this->obj['allowNull'] = false; $this->obj['required'] = true; @@ -76,30 +65,27 @@ public function testValidateEmail() $this->assertFalse($this->obj->validateEmail()); } - /** - * @return void - */ - public function testValidationMethods() + public function testValidationMethods(): void { $this->assertContains('email', $this->obj->validationMethods()); } - public function testParseVal() + public function testParseVal(): void { $this->assertEquals('charcoal@example.com', $this->obj->parseVal('charcoal@example.com')); } - public function testDisplayVal() + public function testDisplayVal(): void { $this->assertEquals('charcoal@example.com', $this->obj->displayVal('charcoal@example.com')); } - public function testInputVal() + public function testInputVal(): void { $this->assertEquals('charcoal@example.com', $this->obj->inputVal('charcoal@example.com')); } - public function testStorageVal() + public function testStorageVal(): void { $this->assertEquals('charcoal@example.com', $this->obj->storageVal('charcoal@example.com')); } diff --git a/packages/property/tests/Charcoal/Property/FilePropertyTest.php b/packages/property/tests/Charcoal/Property/FilePropertyTest.php index 2978d68ca..e1f3e8d3e 100644 --- a/packages/property/tests/Charcoal/Property/FilePropertyTest.php +++ b/packages/property/tests/Charcoal/Property/FilePropertyTest.php @@ -12,17 +12,15 @@ // From 'charcoal-property' use Charcoal\Property\FileProperty; -/** - * - */ +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Property\FileProperty::class, 'type()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Property\FileProperty::class, 'getDefaultAcceptedMimetypes()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Property\FileProperty::class, 'hasAcceptedMimetypes()')] class FilePropertyTest extends AbstractFilePropertyTestCase { /** * Create a file property instance. - * - * @return FileProperty */ - public function createProperty() + public function createProperty(): \Charcoal\Property\FileProperty { $container = $this->getContainer(); @@ -36,22 +34,16 @@ public function createProperty() /** * Asserts that the `type()` method is "file". - * - * @covers \Charcoal\Property\FileProperty::type() - * @return void */ - public function testPropertyType() + public function testPropertyType(): void { $this->assertEquals('file', $this->obj->type()); } /** * Asserts that the property adheres to file property defaults. - * - * @covers \Charcoal\Property\FileProperty::getDefaultAcceptedMimetypes() - * @return void */ - public function testDefaulAcceptedMimeTypes() + public function testDefaultAcceptedMimeTypes(): void { $this->assertIsArray($this->obj['defaultAcceptedMimetypes']); $this->assertEmpty($this->obj['defaultAcceptedMimetypes']); @@ -60,11 +52,8 @@ public function testDefaulAcceptedMimeTypes() /** * Asserts that the property properly checks if * any acceptable MIME types are available. - * - * @covers \Charcoal\Property\FileProperty::hasAcceptedMimetypes() - * @return void */ - public function testHasAcceptedMimeTypes() + public function testHasAcceptedMimeTypes(): void { $obj = $this->obj; @@ -84,10 +73,8 @@ public function testHasAcceptedMimeTypes() /** * Asserts that the property can resolve a filesize from its value. - * - * @return void */ - public function testFilesizeFromVal() + public function testFilesizeFromVal(): void { $obj = $this->obj; @@ -99,10 +86,8 @@ public function testFilesizeFromVal() /** * Asserts that the property can resolve a MIME type from its value. - * - * @return void */ - public function testMimetypeFromVal() + public function testMimetypeFromVal(): void { $obj = $this->obj; @@ -112,10 +97,7 @@ public function testMimetypeFromVal() $this->assertEquals('text/plain', $obj['mimetype']); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ @@ -134,10 +116,7 @@ public function testSetData() $this->assertEquals((32 * 1024 * 1024), $this->obj['maxFilesize']); } - /** - * @return void - */ - public function testSetOverwrite() + public function testSetOverwrite(): void { $ret = $this->obj->setOverwrite(true); $this->assertSame($ret, $this->obj); @@ -150,10 +129,7 @@ public function testSetOverwrite() $this->assertTrue($this->obj['overwrite']); } - /** - * @return void - */ - public function testVaidationMethods() + public function testValidationMethods(): void { $methods = $this->obj->validationMethods(); $this->assertContains('mimetypes', $methods); @@ -163,7 +139,6 @@ public function testVaidationMethods() /** * Test validation file MIME types on property. * - * @dataProvider provideDataForValidateMimetypes * * @param mixed $val The value(s) to be validated. * @param boolean $l10n Whether the property value is multilingual. @@ -171,16 +146,16 @@ public function testVaidationMethods() * @param mixed $acceptedMimetypes The accepted MIME types. * @param boolean $expectedReturn The expected return value of the method. * @param array $expectedResults The expected validation results. - * @return void */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideDataForValidateMimetypes')] public function testValidateMimetypes( - $val, - $l10n, - $multiple, - $acceptedMimetypes, - $expectedReturn, + string|array|null $val, + bool $l10n, + bool $multiple, + ?array $acceptedMimetypes, + bool $expectedReturn, array $expectedResults = [] - ) { + ): void { $obj = $this->obj; $obj['uploadPath'] = $this->getPathToFixtures().'/files'; @@ -200,7 +175,6 @@ public function testValidateMimetypes( /** * Test validation file sizes on property. * - * @dataProvider provideDataForValidateFilesizes * * @param mixed $val The value(s) to be validated. * @param boolean $l10n Whether the property value is multilingual. @@ -208,16 +182,16 @@ public function testValidateMimetypes( * @param integer $maxFilesize The maximum file size accepted. * @param boolean $expectedReturn The expected return value of the method. * @param array $expectedResults The expected validation results. - * @return void */ + #[\PHPUnit\Framework\Attributes\DataProvider('provideDataForValidateFilesizes')] public function testValidateFilesizes( - $val, - $l10n, - $multiple, - $maxFilesize, - $expectedReturn, + string|array|null $val, + bool $l10n, + bool $multiple, + int $maxFilesize, + bool $expectedReturn, array $expectedResults = [] - ) { + ): void { $obj = $this->obj; $obj['uploadPath'] = $this->getPathToFixtures().'/files'; @@ -234,10 +208,7 @@ public function testValidateFilesizes( ); } - /** - * @return void - */ - public function testFileExists() + public function testFileExists(): void { $obj = $this->obj; $this->assertTrue($obj->fileExists(__FILE__)); @@ -249,22 +220,18 @@ public function testFileExists() } /** - * @dataProvider providePathsForIsAbsolutePath * * @param string $path A path to test. * @param string $expected Whether the path is absolute (TRUE) or relative (FALSE). - * @return void */ - public function testIsAbsolutePath($path, $expected) + #[\PHPUnit\Framework\Attributes\DataProvider('providePathsForIsAbsolutePath')] + public function testIsAbsolutePath(?string $path, bool $expected): void { $result = $this->callMethodWith($this->obj, 'isAbsolutePath', $path); $this->assertEquals($expected, $result); } - /** - * @return array - */ - public function providePathsForIsAbsolutePath() + public static function providePathsForIsAbsolutePath(): array { return [ [ '/var/lib', true ], @@ -278,22 +245,18 @@ public function providePathsForIsAbsolutePath() } /** - * @dataProvider filenameProvider * * @param string $filename A dirty filename. * @param string $sanitized A clean version of $filename. - * @return void */ - public function testSanitizeFilename($filename, $sanitized) + #[\PHPUnit\Framework\Attributes\DataProvider('filenameProvider')] + public function testSanitizeFilename(string $filename, string $sanitized): void { $obj = $this->obj; $this->assertEquals($sanitized, $obj->sanitizeFilename($filename)); } - /** - * @return array - */ - public function filenameProvider() + public static function filenameProvider(): array { return [ [ 'foobar', 'foobar' ], @@ -303,10 +266,7 @@ public function filenameProvider() ]; } - /** - * @return void - */ - public function testGenerateFilename() + public function testGenerateFilename(): void { $obj = $this->obj; $obj->setIdent('foo'); @@ -319,7 +279,7 @@ public function testGenerateFilename() $this->assertStringContainsString('foobar', $ret); } - public function testGenerateUniqueFilename() + public function testGenerateUniqueFilename(): void { $ret = $this->obj->generateUniqueFilename('foo.png'); $this->assertStringContainsString('foo', $ret); @@ -327,7 +287,7 @@ public function testGenerateUniqueFilename() $this->assertNotEquals($ret, 'foo'); } - public function testFilesystem() + public function testFilesystem(): void { $this->assertEquals('public', $this->obj['filesystem']); @@ -336,18 +296,12 @@ public function testFilesystem() $this->assertEquals('foo', $this->obj['filesystem']); } - /** - * @return void - */ - public function testSqlExtra() + public function testSqlExtra(): void { $this->assertEquals('', $this->obj->sqlExtra()); } - /** - * @return void - */ - public function testSqlType() + public function testSqlType(): void { $this->obj->setMultiple(false); $this->assertEquals('VARCHAR(255)', $this->obj->sqlType()); @@ -356,10 +310,7 @@ public function testSqlType() $this->assertEquals('TEXT', $this->obj->sqlType()); } - /** - * @return void - */ - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->assertEquals(PDO::PARAM_STR, $this->obj->sqlPdoType()); } @@ -368,147 +319,146 @@ public function testSqlPdoType() * Provide property data for {@see FileProperty::validateMimetypes()}. * * @used-by self::testValidateMimetypes() - * @return array */ - public function provideDataForValidateMimetypes() + public static function provideDataForValidateMimetypes(): array { - $paths = $this->getFileMapOfFixtures(); + $paths = self::getFileMapOfFixtures(); return [ 'any MIME types, no value' => [ - 'propertyValues' => null, - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => null, + 'l10n' => false, + 'multiple' => false, 'acceptedMimetypes' => null, - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'any MIME types, text file' => [ - 'propertyValues' => $paths['document.txt'], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => $paths['document.txt'], + 'l10n' => false, + 'multiple' => false, 'acceptedMimetypes' => null, - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'any MIME types, image file' => [ - 'propertyValues' => $paths['panda.png'], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => $paths['panda.png'], + 'l10n' => false, + 'multiple' => false, 'acceptedMimetypes' => null, - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'text/plain, no value' => [ - 'propertyValues' => null, - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => null, + 'l10n' => false, + 'multiple' => false, 'acceptedMimetypes' => [ 'text/plain' ], - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'text/plain, single text file' => [ - 'propertyValues' => $paths['document.txt'], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => $paths['document.txt'], + 'l10n' => false, + 'multiple' => false, 'acceptedMimetypes' => [ 'text/plain' ], - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'text/plain, single image file' => [ - 'propertyValues' => $paths['panda.png'], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => $paths['panda.png'], + 'l10n' => false, + 'multiple' => false, 'acceptedMimetypes' => [ 'text/plain' ], - 'assertValidationReturn' => false, - 'assertValidationResults' => [ + 'expectedReturn' => false, + 'expectedResults' => [ Validator::ERROR => [ 'File ['.$paths['panda.png'].'] has unacceptable MIME type [image/png]', ], ], ], 'text/plain, nonexistent file' => [ - 'propertyValues' => $paths['nonexistent.txt'], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => $paths['nonexistent.txt'], + 'l10n' => false, + 'multiple' => false, 'acceptedMimetypes' => [ 'text/plain' ], - 'assertValidationReturn' => false, - 'assertValidationResults' => [ + 'expectedReturn' => false, + 'expectedResults' => [ Validator::ERROR => [ 'File ['.$paths['nonexistent.txt'].'] not found or MIME type unrecognizable', ], ], ], 'text/plain, l10n, text file' => [ - 'propertyValues' => $paths['document.txt'], - 'propertyL10n' => true, - 'propertyMultiple' => false, + 'val' => $paths['document.txt'], + 'l10n' => true, + 'multiple' => false, 'acceptedMimetypes' => [ 'text/plain' ], - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'text/plain, l10n, text + image file' => [ - 'propertyValues' => [ + 'val' => [ 'en' => $paths['document.txt'], 'fr' => $paths['panda.png'], ], - 'propertyL10n' => true, - 'propertyMultiple' => false, + 'l10n' => true, + 'multiple' => false, 'acceptedMimetypes' => [ 'text/plain' ], - 'assertValidationReturn' => false, - 'assertValidationResults' => [ + 'expectedReturn' => false, + 'expectedResults' => [ Validator::ERROR => [ 'File ['.$paths['panda.png'].'] has unacceptable MIME type [image/png]', ], ], ], 'text/plain, multiple, text files' => [ - 'propertyValues' => [ + 'val' => [ $paths['document.txt'], $paths['todo.txt'], ], - 'propertyL10n' => false, - 'propertyMultiple' => true, + 'l10n' => false, + 'multiple' => true, 'acceptedMimetypes' => [ 'text/plain' ], - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'text/plain, multiple, text + image file' => [ - 'propertyValues' => [ + 'val' => [ $paths['document.txt'], $paths['panda.png'], ], - 'propertyL10n' => false, - 'propertyMultiple' => true, + 'l10n' => false, + 'multiple' => true, 'acceptedMimetypes' => [ 'text/plain' ], - 'assertValidationReturn' => false, - 'assertValidationResults' => [ + 'expectedReturn' => false, + 'expectedResults' => [ Validator::ERROR => [ 'File ['.$paths['panda.png'].'] has unacceptable MIME type [image/png]', ], ], ], 'text/plain, l10n + multiple #1' => [ - 'propertyValues' => [ + 'val' => [ 'en' => $paths['document.txt'].','.$paths['todo.txt'], 'fr' => [ $paths['stuff.txt'], $paths['draft.txt'] ], ], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'l10n' => false, + 'multiple' => false, 'acceptedMimetypes' => [ 'text/plain' ], - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'text/plain, l10n + multiple #2' => [ - 'propertyValues' => [ + 'val' => [ 'en' => $paths['document.txt'].','.$paths['scream.wav'], 'fr' => [ $paths['stuff.txt'], $paths['cat.jpg'] ], ], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'l10n' => false, + 'multiple' => false, 'acceptedMimetypes' => [ 'text/plain' ], - 'assertValidationReturn' => false, - 'assertValidationResults' => [ + 'expectedReturn' => false, + 'expectedResults' => [ Validator::ERROR => [ 'File ['.$paths['scream.wav'].'] has unacceptable MIME type [audio/%s]', 'File ['.$paths['cat.jpg'].'] has unacceptable MIME type [image/%s]', @@ -522,139 +472,138 @@ public function provideDataForValidateMimetypes() * Provide property data for {@see FileProperty::validateFilesizes()}. * * @used-by self::testValidateFilesizes() - * @return array */ - public function provideDataForValidateFilesizes() + public static function provideDataForValidateFilesizes(): array { - $paths = $this->getFileMapOfFixtures(); + $paths = self::getFileMapOfFixtures(); return [ 'any size, no value' => [ - 'propertyValues' => null, - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => null, + 'l10n' => false, + 'multiple' => false, 'maxFilesize' => 0, - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'any size, text file' => [ - 'propertyValues' => $paths['document.txt'], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => $paths['document.txt'], + 'l10n' => false, + 'multiple' => false, 'maxFilesize' => 0, - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'max 10kB, no value' => [ - 'propertyValues' => null, - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => null, + 'l10n' => false, + 'multiple' => false, 'maxFilesize' => 10240, - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'max 10kB, single text file' => [ - 'propertyValues' => $paths['document.txt'], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => $paths['document.txt'], + 'l10n' => false, + 'multiple' => false, 'maxFilesize' => 10240, - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'max 10kB, single image file' => [ - 'propertyValues' => $paths['panda.png'], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => $paths['panda.png'], + 'l10n' => false, + 'multiple' => false, 'maxFilesize' => 10240, - 'assertValidationReturn' => false, - 'assertValidationResults' => [ + 'expectedReturn' => false, + 'expectedResults' => [ Validator::ERROR => [ 'File ['.$paths['panda.png'].'] exceeds maximum file size [%s]', ], ], ], 'max 10kB, nonexistent file' => [ - 'propertyValues' => $paths['nonexistent.txt'], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'val' => $paths['nonexistent.txt'], + 'l10n' => false, + 'multiple' => false, 'maxFilesize' => 10240, - 'assertValidationReturn' => false, - 'assertValidationResults' => [ + 'expectedReturn' => false, + 'expectedResults' => [ Validator::ERROR => [ 'File ['.$paths['nonexistent.txt'].'] not found or size unknown', ], ], ], 'max 10kB, l10n, text file' => [ - 'propertyValues' => $paths['document.txt'], - 'propertyL10n' => true, - 'propertyMultiple' => false, + 'val' => $paths['document.txt'], + 'l10n' => true, + 'multiple' => false, 'maxFilesize' => 10240, - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'max 10kB, l10n, text + image file' => [ - 'propertyValues' => [ + 'val' => [ 'en' => $paths['document.txt'], 'fr' => $paths['panda.png'], ], - 'propertyL10n' => true, - 'propertyMultiple' => false, + 'l10n' => true, + 'multiple' => false, 'maxFilesize' => 10240, - 'assertValidationReturn' => false, - 'assertValidationResults' => [ + 'expectedReturn' => false, + 'expectedResults' => [ Validator::ERROR => [ 'File ['.$paths['panda.png'].'] exceeds maximum file size [%s]', ], ], ], 'max 10kB, multiple, text files' => [ - 'propertyValues' => [ + 'val' => [ $paths['document.txt'], $paths['todo.txt'], ], - 'propertyL10n' => false, - 'propertyMultiple' => true, + 'l10n' => false, + 'multiple' => true, 'maxFilesize' => 10240, - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'max 10kB, multiple, text + image file' => [ - 'propertyValues' => [ + 'val' => [ $paths['document.txt'], $paths['panda.png'], ], - 'propertyL10n' => false, - 'propertyMultiple' => true, + 'l10n' => false, + 'multiple' => true, 'maxFilesize' => 10240, - 'assertValidationReturn' => false, - 'assertValidationResults' => [ + 'expectedReturn' => false, + 'expectedResults' => [ Validator::ERROR => [ 'File ['.$paths['panda.png'].'] exceeds maximum file size [%s]', ], ], ], 'max 10kB, l10n + multiple #1' => [ - 'propertyValues' => [ + 'val' => [ 'en' => $paths['document.txt'].','.$paths['todo.txt'], 'fr' => [ $paths['stuff.txt'], $paths['draft.txt'] ], ], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'l10n' => false, + 'multiple' => false, 'maxFilesize' => 10240, - 'assertValidationReturn' => true, - 'assertValidationResults' => [], + 'expectedReturn' => true, + 'expectedResults' => [], ], 'max 10kB, l10n + multiple #2' => [ - 'propertyValues' => [ + 'val' => [ 'en' => $paths['document.txt'].','.$paths['scream.wav'], 'fr' => [ $paths['stuff.txt'], $paths['panda.png'] ], ], - 'propertyL10n' => false, - 'propertyMultiple' => false, + 'l10n' => false, + 'multiple' => false, 'maxFilesize' => 10240, - 'assertValidationReturn' => false, - 'assertValidationResults' => [ + 'expectedReturn' => false, + 'expectedResults' => [ Validator::ERROR => [ 'File ['.$paths['scream.wav'].'] exceeds maximum file size [%s]', 'File ['.$paths['panda.png'].'] exceeds maximum file size [%s]', @@ -668,9 +617,8 @@ public function provideDataForValidateFilesizes() * Provide property data for {@see ImageProperty::generateExtension()}. * * @used-by AbstractFilePropertyTestCase::testGenerateExtensionFromDataProvider() - * @return array */ - public function provideDataForGenerateExtension() + public static function provideDataForGenerateExtension(): array { return [ [ 'text/plain', 'txt' ], diff --git a/packages/property/tests/Charcoal/Property/FixturesTrait.php b/packages/property/tests/Charcoal/Property/FixturesTrait.php index e04cdbb25..fb901f8a7 100644 --- a/packages/property/tests/Charcoal/Property/FixturesTrait.php +++ b/packages/property/tests/Charcoal/Property/FixturesTrait.php @@ -13,9 +13,9 @@ trait FixturesTrait * @param string $file The file path relative to the Fixture directory. * @return string The file path to the fixture relative to the base directory. */ - public function getPathToFixture($file) + public static function getPathToFixture(string $file): string { - return $this->getPathToFixtures().'/'.ltrim($file, '/'); + return self::getPathToFixtures().'/'.ltrim($file, '/'); } /** @@ -23,7 +23,7 @@ public function getPathToFixture($file) * * @return string The path to the fixtures directory relative to the base directory. */ - public function getPathToFixtures() + public static function getPathToFixtures(): string { return 'tests/Charcoal/Property/Fixture'; } diff --git a/packages/property/tests/Charcoal/Property/GenericPropertyTest.php b/packages/property/tests/Charcoal/Property/GenericPropertyTest.php index b602aa6c2..5cb7bcbfc 100644 --- a/packages/property/tests/Charcoal/Property/GenericPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/GenericPropertyTest.php @@ -1,5 +1,7 @@ getContainer(); @@ -32,27 +31,24 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('generic', $this->obj->type()); } - public function testSqlExtra() + public function testSqlExtra(): void { $this->assertEquals('', $this->obj->sqlExtra()); } - public function testSqlType() + public function testSqlType(): void { $this->assertEquals('VARCHAR(255)', $this->obj->sqlType()); $this->obj->setMultiple(true); $this->assertEquals('TEXT', $this->obj->sqlType()); } - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->assertEquals(\PDO::PARAM_STR, $this->obj->sqlPdoType()); } diff --git a/packages/property/tests/Charcoal/Property/HtmlPropertyTest.php b/packages/property/tests/Charcoal/Property/HtmlPropertyTest.php index ef5f162a7..ab53fa4c5 100644 --- a/packages/property/tests/Charcoal/Property/HtmlPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/HtmlPropertyTest.php @@ -18,9 +18,6 @@ class HtmlPropertyTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -32,15 +29,12 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('html', $this->obj->type()); } - public function testDefaults() + public function testDefaults(): void { $this->assertFalse($this->obj['required']); $this->assertFalse($this->obj['unique']); @@ -53,19 +47,13 @@ public function testDefaults() $this->assertTrue($this->obj['long']); } - /** - * @return void - */ - public function testDefaultMaxLength() + public function testDefaultMaxLength(): void { $this->assertEquals(0, $this->obj['maxLength']); $this->assertEquals(0, $this->obj->defaultMaxLength()); } - /** - * @return void - */ - public function testSqlType() + public function testSqlType(): void { $this->obj->setLong(false); $this->assertEquals('TEXT', $this->obj->sqlType()); @@ -74,7 +62,7 @@ public function testSqlType() $this->assertEquals('LONGTEXT', $this->obj->sqlType()); } - public function testFilesystem() + public function testFilesystem(): void { $this->assertEquals('', $this->obj['filesystem']); diff --git a/packages/property/tests/Charcoal/Property/IdPropertyTest.php b/packages/property/tests/Charcoal/Property/IdPropertyTest.php index ff05b7748..2641e649a 100644 --- a/packages/property/tests/Charcoal/Property/IdPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/IdPropertyTest.php @@ -18,14 +18,8 @@ class IdPropertyTest extends AbstractTestCase { use \Charcoal\Tests\Property\ContainerIntegrationTrait; - /** - * @var IdProperty - */ - private $obj; + private \Charcoal\Property\IdProperty|array $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -37,18 +31,12 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('id', $this->obj->type()); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $ret = $this->obj->setData( [ @@ -62,10 +50,8 @@ public function testSetData() /** * Asserts that the default mode: * - Defaults to auto-increment - * - * @return void */ - public function testDefaultMode() + public function testDefaultMode(): void { $this->assertEquals(IdProperty::DEFAULT_MODE, $this->obj['mode']); $this->assertEquals('auto-increment', $this->obj['mode']); @@ -76,10 +62,8 @@ public function testDefaultMode() * - is chainable * - properly sets the mode * - throws an invalid argument exception for any string modes - * - * @return void */ - public function testSetMode() + public function testSetMode(): void { $ret = $this->obj->setMode('uuid'); $this->assertSame($ret, $this->obj); @@ -99,19 +83,14 @@ public function testSetMode() * Asserts that calling the `setMode()` method with a NULL argument: * - is chainable * - properly resets the mode to detault - * - * @return void */ - public function testSetModeNullThrowsException() + public function testSetModeNullThrowsException(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setMode(null); } - /** - * @return void - */ - public function testMultipleCannotBeTrue() + public function testMultipleCannotBeTrue(): void { $this->assertFalse($this->obj['multiple']); @@ -120,10 +99,7 @@ public function testMultipleCannotBeTrue() $this->obj->setMultiple(true); } - /** - * @return void - */ - public function testL10nCannotBeTrue() + public function testL10nCannotBeTrue(): void { $this->assertFalse($this->obj['l10n']); @@ -132,10 +108,7 @@ public function testL10nCannotBeTrue() $this->obj->setL10n(true); } - /** - * @return void - */ - public function testSaveAndAutoGenerateAutoIncrement() + public function testSaveAndAutoGenerateAutoIncrement(): void { $obj = $this->obj; $obj->setMode('auto-increment'); @@ -143,32 +116,23 @@ public function testSaveAndAutoGenerateAutoIncrement() $this->assertEquals('', $id); } - /** - * @return void - */ - public function testSaveAndAutoGenerateUniqid() + public function testSaveAndAutoGenerateUniqid(): void { $obj = $this->obj; $obj->setMode('uniqid'); $id = $obj->save(null); - $this->assertEquals(13, strlen($id)); + $this->assertEquals(13, strlen((string) $id)); } - /** - * @return void - */ - public function testSaveAndAutoGenerateUuid() + public function testSaveAndAutoGenerateUuid(): void { $obj = $this->obj; $obj->setMode('uuid'); $id = $obj->save(null); - $this->assertEquals(36, strlen($id)); + $this->assertEquals(36, strlen((string) $id)); } - /** - * @return void - */ - public function testSqlExtra() + public function testSqlExtra(): void { $obj = $this->obj; $obj->setMode('auto-increment'); @@ -180,12 +144,9 @@ public function testSqlExtra() $this->assertEquals('', $ret); } - /** - * @return void - */ - public function testSqlType() + public function testSqlType(): void { - $container = $this->getContainer(); + $this->getContainer(); $obj = $this->obj; $obj->setMode('auto-increment'); @@ -206,10 +167,7 @@ public function testSqlType() $this->assertEquals('VARCHAR(255)', $ret); } - /** - * @return void - */ - public function testSqlPdoType() + public function testSqlPdoType(): void { $obj = $this->obj; $obj->setMode('auto-increment'); diff --git a/packages/property/tests/Charcoal/Property/ImagePropertyTest.php b/packages/property/tests/Charcoal/Property/ImagePropertyTest.php index 845c5208d..0a4da9109 100644 --- a/packages/property/tests/Charcoal/Property/ImagePropertyTest.php +++ b/packages/property/tests/Charcoal/Property/ImagePropertyTest.php @@ -7,17 +7,15 @@ // From 'charcoal-property' use Charcoal\Property\ImageProperty; -/** - * - */ +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Property\ImageProperty::class, 'type()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Property\ImageProperty::class, 'getDefaultAcceptedMimetypes()')] +#[\PHPUnit\Framework\Attributes\CoversMethod(\Charcoal\Property\ImageProperty::class, 'hasAcceptedMimetypes()')] class ImagePropertyTest extends AbstractFilePropertyTestCase { /** * Create a file property instance. - * - * @return ImageProperty */ - public function createProperty() + public function createProperty(): \Charcoal\Property\ImageProperty { $container = $this->getContainer(); @@ -31,21 +29,17 @@ public function createProperty() /** * Asserts that the `type()` method is "file". - * - * @covers \Charcoal\Property\ImageProperty::type() - * @return void */ - public function testPropertyType() + public function testPropertyType(): void { $this->assertEquals('image', $this->obj->type()); } /** * Asserts that the property adheres to file property defaults. - * - * @return void */ - public function testPropertyDefaults() + #[\Override] + public function testPropertyDefaults(): void { parent::testPropertyDefaults(); @@ -58,11 +52,8 @@ public function testPropertyDefaults() /** * Asserts that the property adheres to file property defaults. - * - * @covers \Charcoal\Property\ImageProperty::getDefaultAcceptedMimetypes() - * @return void */ - public function testDefaulAcceptedMimeTypes() + public function testDefaultAcceptedMimeTypes(): void { $this->assertIsArray($this->obj['defaultAcceptedMimetypes']); $this->assertNotEmpty($this->obj['defaultAcceptedMimetypes']); @@ -71,11 +62,8 @@ public function testDefaulAcceptedMimeTypes() /** * Asserts that the property properly checks if * any acceptable MIME types are available. - * - * @covers \Charcoal\Property\ImageProperty::hasAcceptedMimetypes() - * @return void */ - public function testHasAcceptedMimeTypes() + public function testHasAcceptedMimeTypes(): void { $this->assertTrue($this->obj->hasAcceptedMimetypes()); @@ -85,10 +73,8 @@ public function testHasAcceptedMimeTypes() /** * Asserts that the property can resolve a filesize from its value. - * - * @return void */ - public function testFilesizeFromVal() + public function testFilesizeFromVal(): void { $obj = $this->obj; @@ -100,10 +86,8 @@ public function testFilesizeFromVal() /** * Asserts that the property can resolve a MIME type from its value. - * - * @return void */ - public function testMimetypeFromVal() + public function testMimetypeFromVal(): void { $obj = $this->obj; @@ -113,10 +97,7 @@ public function testMimetypeFromVal() $this->assertEquals('image/png', $obj['mimetype']); } - /** - * @return void - */ - public function testSetEffects() + public function testSetEffects(): void { $this->assertEquals([], $this->obj['effects']); $ret = $this->obj->setEffects([['type'=>'blur', 'sigma'=>'1']]); @@ -131,10 +112,7 @@ public function testSetEffects() $this->assertEquals(1, count($this->obj['effects'])); } - /** - * @return void - */ - public function testAddEffect() + public function testAddEffect(): void { $this->assertEquals(0, count($this->obj['effects'])); @@ -146,7 +124,7 @@ public function testAddEffect() $this->assertEquals(2, count($this->obj['effects'])); } - public function testSetApplyEffects() + public function testSetApplyEffects(): void { $this->assertEquals('save', $this->obj['applyEffects']); $this->assertTrue($this->obj->canApplyEffects('save')); @@ -174,7 +152,7 @@ public function testSetApplyEffects() $this->obj->setApplyEffects('foobar'); } - public function testDriverType() + public function testDriverType(): void { $this->assertEquals(ImageProperty::DEFAULT_DRIVER_TYPE, $this->obj['driverType']); $ret = $this->obj->setDriverType('foo'); @@ -185,13 +163,14 @@ public function testDriverType() $this->obj->setDriverType(false); } - public function testProcessEffects() + public function testProcessEffects(): void { $ret = $this->obj->processEffects(null, []); $this->assertNull($ret); } - public function testAcceptedMimetypes() + #[\Override] + public function testAcceptedMimetypes(): void { $ret = $this->obj['acceptedMimetypes']; $this->assertContains('image/png', $ret); @@ -202,9 +181,8 @@ public function testAcceptedMimetypes() * Provide property data for {@see ImageProperty::generateExtension()}. * * @used-by AbstractFilePropertyTestCase::testGenerateExtensionFromDataProvider() - * @return array */ - public function provideDataForGenerateExtension() + public static function provideDataForGenerateExtension(): array { return [ [ 'image/gif', 'gif' ], diff --git a/packages/property/tests/Charcoal/Property/IpPropertyTest.php b/packages/property/tests/Charcoal/Property/IpPropertyTest.php index 63056fe5f..7e6c799c5 100644 --- a/packages/property/tests/Charcoal/Property/IpPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/IpPropertyTest.php @@ -20,9 +20,6 @@ class IpPropertyTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -34,26 +31,17 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('ip', $this->obj->type()); } - /** - * @return void - */ - public function testDefaults() + public function testDefaults(): void { $this->assertEquals('string', $this->obj['storageMode']); } - /** - * @return void - */ - public function testMultipleCannotBeTrue() + public function testMultipleCannotBeTrue(): void { $this->assertFalse($this->obj['multiple']); @@ -62,10 +50,7 @@ public function testMultipleCannotBeTrue() $this->obj->setMultiple(true); } - /** - * @return void - */ - public function testL10nCannotBeTrue() + public function testL10nCannotBeTrue(): void { $this->assertFalse($this->obj['l10n']); @@ -74,10 +59,7 @@ public function testL10nCannotBeTrue() $this->obj->setL10n(true); } - /** - * @return void - */ - public function testSetStorageMode() + public function testSetStorageMode(): void { $this->assertEquals('string', $this->obj['storageMode']); $ret = $this->obj->setStorageMode('int'); @@ -88,10 +70,7 @@ public function testSetStorageMode() $this->obj->setStorageMode('foobar'); } - /** - * @return void - */ - public function testIntVal() + public function testIntVal(): void { $this->assertEquals(0, $this->obj->intVal('0.0.0.0')); $this->assertEquals(2130706433, $this->obj->intVal('127.0.0.1')); @@ -100,10 +79,7 @@ public function testIntVal() $this->assertEquals(3232235777, $this->obj->intVal('3232235777')); } - /** - * @return void - */ - public function testStringVal() + public function testStringVal(): void { $this->assertEquals('0.0.0.0', $this->obj->stringVal(0)); $this->assertEquals('127.0.0.1', $this->obj->stringVal(2130706433)); @@ -111,14 +87,14 @@ public function testStringVal() $this->assertEquals('8.8.8.8', $this->obj->stringVal('8.8.8.8')); } - public function testStorageVal() + public function testStorageVal(): void { $this->assertEquals('0.0.0.0', $this->obj->storageVal('0.0.0.0')); $this->assertEquals('127.0.0.1', $this->obj->storageVal('127.0.0.1')); $this->assertEquals('127.0.0.1', $this->obj->stringVal('127.0.0.1')); } - public function testHostname() + public function testHostname(): void { $this->assertEquals('0.0.0.0', $this->obj->hostname(0)); $this->assertThat($this->obj->hostname('8.8.8.8'), $this->logicalOr( @@ -127,10 +103,7 @@ public function testHostname() )); } - /** - * @return void - */ - public function testSqlExtra() + public function testSqlExtra(): void { $this->assertEquals('', $this->obj->sqlExtra()); } @@ -139,10 +112,8 @@ public function testSqlExtra() * Asserts that the `sqlType()` method: * - returns "VARCHAR(15)" if the storage mode is "string" (default). * - returns "BIGINT" if the storage mode is "int". - * - * @return void */ - public function testSqlType() + public function testSqlType(): void { $this->obj->setStorageMode('string'); $this->assertEquals('VARCHAR(15)', $this->obj->sqlType()); @@ -151,10 +122,7 @@ public function testSqlType() $this->assertEquals('BIGINT', $this->obj->sqlType()); } - /** - * @return void - */ - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->obj->setStorageMode('string'); $this->assertEquals(PDO::PARAM_STR, $this->obj->sqlPdoType()); diff --git a/packages/property/tests/Charcoal/Property/LangPropertyTest.php b/packages/property/tests/Charcoal/Property/LangPropertyTest.php index bdf9ac286..aee766669 100644 --- a/packages/property/tests/Charcoal/Property/LangPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/LangPropertyTest.php @@ -25,8 +25,6 @@ class LangPropertyTest extends AbstractTestCase /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -42,26 +40,17 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('lang', $this->obj->type()); } - /** - * @return void - */ - public function testSqlExtra() + public function testSqlExtra(): void { $this->assertEquals('', $this->obj->sqlExtra()); } - /** - * @return void - */ - public function testSqlType() + public function testSqlType(): void { $this->obj->setMultiple(false); $this->assertEquals('CHAR(2)', $this->obj->sqlType()); @@ -70,18 +59,12 @@ public function testSqlType() $this->assertEquals('TEXT', $this->obj->sqlType()); } - /** - * @return void - */ - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->assertEquals(PDO::PARAM_STR, $this->obj->sqlPdoType()); } - /** - * @return void - */ - public function testChoices() + public function testChoices(): void { $container = $this->getContainer(); $translator = $container['translator']; @@ -99,10 +82,7 @@ public function testChoices() $this->assertEquals(array_keys($locales), array_keys($choices)); } - /** - * @return void - */ - public function testDisplayVal() + public function testDisplayVal(): void { $container = $this->getContainer(); $translator = $container['translator']; diff --git a/packages/property/tests/Charcoal/Property/MapStructurePropertyTest.php b/packages/property/tests/Charcoal/Property/MapStructurePropertyTest.php index 1701e1003..b44e96456 100644 --- a/packages/property/tests/Charcoal/Property/MapStructurePropertyTest.php +++ b/packages/property/tests/Charcoal/Property/MapStructurePropertyTest.php @@ -1,5 +1,7 @@ getContainer(); @@ -33,10 +32,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('map-structure', $this->obj->type()); } diff --git a/packages/property/tests/Charcoal/Property/Mocks/GenericModel.php b/packages/property/tests/Charcoal/Property/Mocks/GenericModel.php index ae900ac45..f3241ed3d 100644 --- a/packages/property/tests/Charcoal/Property/Mocks/GenericModel.php +++ b/packages/property/tests/Charcoal/Property/Mocks/GenericModel.php @@ -34,7 +34,7 @@ class GenericModel extends AbstractModel /** * @param array $data Dependencies. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { $data['metadata'] = [ 'default_data' => [ @@ -69,18 +69,17 @@ public function __construct(array $data = null) /** * @param Container $container DI Container. - * @return void */ - public function setDependencies(Container $container) + #[\Override] + public function setDependencies(Container $container): void { $this->setTranslator($container['translator']); } /** * @param mixed $name The name of the model. - * @return self */ - public function setName($name) + public function setName($name): static { $this->name = $this->translator()->translation($name); @@ -95,10 +94,7 @@ public function name() return $this->name; } - /** - * @return string - */ - public function icon() + public function icon(): string { return ''; } diff --git a/packages/property/tests/Charcoal/Property/Mocks/SelectablePropertyTestDouble.php b/packages/property/tests/Charcoal/Property/Mocks/SelectablePropertyTestDouble.php new file mode 100644 index 000000000..f9b23ea5d --- /dev/null +++ b/packages/property/tests/Charcoal/Property/Mocks/SelectablePropertyTestDouble.php @@ -0,0 +1,15 @@ +getContainer(); @@ -32,15 +29,12 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('model-structure', $this->obj->type()); } - public function testSetStructureMetadata() + public function testSetStructureMetadata(): void { $ret = $this->obj->setStructureMetadata(null); $this->assertSame($ret, $this->obj); @@ -51,7 +45,7 @@ public function testSetStructureMetadata() $this->obj->setStructureMetadata('foo'); } - public function setStructureInterfaces() + public function setStructureInterfaces(): void { $ret = $this->obj->setStructureInterfaces([]); $this->assertSame($ret, $this->obj); diff --git a/packages/property/tests/Charcoal/Property/NumberPropertyTest.php b/packages/property/tests/Charcoal/Property/NumberPropertyTest.php index be17d444c..b4e1bfd3b 100644 --- a/packages/property/tests/Charcoal/Property/NumberPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/NumberPropertyTest.php @@ -18,9 +18,6 @@ class NumberPropertyTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -32,21 +29,18 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('number', $this->obj->type()); } - public function testDefaults() + public function testDefaults(): void { $this->assertNull($this->obj->getMin()); $this->assertNull($this->obj->getMax()); } - public function testSetData() + public function testSetData(): void { $this->obj->setData([ 'min' => 0, @@ -56,7 +50,7 @@ public function testSetData() $this->assertEquals(100, $this->obj->getMax()); } - public function testValidationMethods() + public function testValidationMethods(): void { $ret = $this->obj->validationMethods(); $this->assertContains('min', $ret); diff --git a/packages/property/tests/Charcoal/Property/ObjectPropertyTest.php b/packages/property/tests/Charcoal/Property/ObjectPropertyTest.php index 43e67c399..26814f234 100644 --- a/packages/property/tests/Charcoal/Property/ObjectPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/ObjectPropertyTest.php @@ -48,8 +48,6 @@ class ObjectPropertyTest extends AbstractTestCase /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -72,7 +70,7 @@ protected function setUp(): void * collection of models for testing. * @return array Returns the collection of object data for testing. */ - public function setUpObjects(&$models = null) + public function setUpObjects(&$models = null): array { $container = $this->getContainer(); $translator = $container['translator']; @@ -104,13 +102,12 @@ public function setUpObjects(&$models = null) } /** - * @dataProvider provideMissingDependencies * * @param string $method The name of a method accessor. * @param string $expectedException The expected Exception thrown by $method. - * @return void */ - public function testConstructorWithoutDependencies($method, $expectedException) + #[\PHPUnit\Framework\Attributes\DataProvider('provideMissingDependencies')] + public function testConstructorWithoutDependencies(string $method, string $expectedException): void { $container = $this->getContainer(); @@ -124,10 +121,7 @@ public function testConstructorWithoutDependencies($method, $expectedException) $this->callMethod($prop, $method); } - /** - * @return array - */ - public function provideMissingDependencies() + public static function provideMissingDependencies(): array { return [ [ 'modelFactory', RuntimeException::class ], @@ -137,24 +131,20 @@ public function provideMissingDependencies() } /** - * @dataProvider provideSatisfiedDependencies * * @param string $method The name of a method accessor. * @param string $expectedObject The expected instance returned by $method. - * @return void */ - public function testConstructorWithDependencies($method, $expectedObject) + #[\PHPUnit\Framework\Attributes\DataProvider('provideSatisfiedDependencies')] + public function testConstructorWithDependencies(string $method, string $expectedObject): void { - $container = $this->getContainer(); + $this->getContainer(); $dependency = $this->callMethod($this->obj, $method); $this->assertInstanceOf($expectedObject, $dependency); } - /** - * @return array - */ - public function provideSatisfiedDependencies() + public static function provideSatisfiedDependencies(): array { return [ [ 'modelFactory', FactoryInterface::class ], @@ -163,26 +153,17 @@ public function provideSatisfiedDependencies() ]; } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('object', $this->obj->type()); } - /** - * @return void - */ - public function testSqlExtra() + public function testSqlExtra(): void { $this->assertEquals('', $this->obj->sqlExtra()); } - /** - * @return void - */ - public function testSqlType() + public function testSqlType(): void { $this->obj->setObjType(GenericModel::class); $this->assertEquals('CHAR(13)', $this->obj->sqlType()); @@ -191,19 +172,13 @@ public function testSqlType() $this->assertEquals('TEXT', $this->obj->sqlType()); } - /** - * @return void - */ - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->obj->setObjType(GenericModel::class); $this->assertEquals(PDO::PARAM_STR, $this->obj->sqlPdoType()); } - /** - * @return void - */ - public function testSetObjType() + public function testSetObjType(): void { $return = $this->obj->setObjType('foo'); $this->assertSame($return, $this->obj); @@ -213,19 +188,13 @@ public function testSetObjType() $this->obj->setObjType(false); } - /** - * @return void - */ - public function testAccessingObjTypeBeforeSetterThrowsException() + public function testAccessingObjTypeBeforeSetterThrowsException(): void { $this->expectException('\Exception'); $this->obj['objType']; } - /** - * @return void - */ - public function testSetPattern() + public function testSetPattern(): void { $return = $this->obj->setPattern('{{foo}}'); $this->assertSame($return, $this->obj); @@ -235,10 +204,7 @@ public function testSetPattern() $this->obj->setPattern([]); } - /** - * @return void - */ - public function testParseOneWithScalarValue() + public function testParseOneWithScalarValue(): void { $this->assertEquals('foobar', $this->obj->parseOne('foobar')); @@ -246,37 +212,26 @@ public function testParseOneWithScalarValue() $this->assertNull($this->obj->parseOne($mock)); // Force ID to 'foo'. - $mock->expects($this->any()) - ->method('id') - ->will($this->returnValue('foo')); + $mock->method('id') + ->willReturn('foo'); $this->assertEquals('foo', $this->obj->parseOne($mock)); } - /** - * @return void - */ - public function testParseOneWithObjectWithoutIdReturnsNull() + public function testParseOneWithObjectWithoutIdReturnsNull(): void { - $mock = $this->createMock(StorableInterface::class); + $mock = $this->createStub(StorableInterface::class); $this->assertNull($this->obj->parseOne($mock)); } - /** - * @return void - */ - public function testParseOneWithObjectWithIdReturnsId() + public function testParseOneWithObjectWithIdReturnsId(): void { $mock = $this->createMock(StorableInterface::class); - $mock->expects($this->any()) - ->method('id') - ->will($this->returnValue('foo')); + $mock->method('id') + ->willReturn('foo'); $this->assertEquals('foo', $this->obj->parseOne($mock)); } - /** - * @return void - */ - public function testDisplayVal() + public function testDisplayVal(): void { $objs = $this->setUpObjects($models); $first = $models[self::OBJ_1]; @@ -323,10 +278,7 @@ public function testDisplayVal() $this->assertEquals($expected, $actual); } - /** - * @return void - */ - public function testInputVal() + public function testInputVal(): void { $container = $this->getContainer(); @@ -345,10 +297,7 @@ public function testInputVal() $this->assertEquals('foo,baz,qux', $this->obj->inputVal([ 'foo', 'baz', 'qux' ])); } - /** - * @return void - */ - public function testStorageVal() + public function testStorageVal(): void { $container = $this->getContainer(); @@ -367,12 +316,9 @@ public function testStorageVal() $this->assertEquals('foo,baz,qux', $this->obj->storageVal([ 'foo', 'baz', 'qux' ])); } - /** - * @return void - */ - public function testRenderObjPattern() + public function testRenderObjPattern(): void { - $objs = $this->setUpObjects($models); + $this->setUpObjects($models); $return = $this->callMethod($this->obj, 'renderObjPattern', [ $models[self::OBJ_1], '' ]); $this->assertEmpty($return); @@ -388,10 +334,7 @@ public function testRenderObjPattern() $this->assertEquals($models[self::OBJ_1]['name']['en'], $return); } - /** - * @return void - */ - public function testRenderViewableObjPattern() + public function testRenderViewableObjPattern(): void { $container = $this->getContainer(); $this->getContainerProvider()->registerView($container); @@ -403,43 +346,34 @@ public function testRenderViewableObjPattern() $factory->setArguments($depends); - $objs = $this->setUpObjects($models); + $this->setUpObjects($models); /** Test 'charcoal-view' renderer */ $return = $this->callMethod($this->obj, 'renderObjPattern', [ $models[self::OBJ_1] ]); $this->assertEquals($models[self::OBJ_1]['name']['en'], $return); } - /** - * @return void - */ - public function testRenderObjPatternThrowsExceptionWithBadPattern() + public function testRenderObjPatternThrowsExceptionWithBadPattern(): void { $container = $this->getContainer(); $model = $container['model/factory']->create(GenericModel::class); $this->expectException(InvalidArgumentException::class); - $return = $this->callMethod($this->obj, 'renderObjPattern', [ $model, false ]); + $this->callMethod($this->obj, 'renderObjPattern', [ $model, false ]); } - /** - * @return void - */ - public function testRenderObjPatternThrowsExceptionWithBadLang() + public function testRenderObjPatternThrowsExceptionWithBadLang(): void { $container = $this->getContainer(); $model = $container['model/factory']->create(GenericModel::class); $this->expectException(InvalidArgumentException::class); - $return = $this->callMethod($this->obj, 'renderObjPattern', [ $model, null, false ]); + $this->callMethod($this->obj, 'renderObjPattern', [ $model, null, false ]); } - /** - * @return void - */ - public function testChoices() + public function testChoices(): void { $this->obj->setObjType(GenericModel::class); @@ -448,7 +382,7 @@ public function testChoices() $this->assertEmpty($this->obj->choices()); /** Database table created */ - $objs = $this->setUpObjects($models); + $this->setUpObjects($models); /** Test available choices */ $this->assertTrue($this->obj->hasChoices()); @@ -480,31 +414,21 @@ public function testChoices() $this->assertEquals($fakeId, $this->obj->choiceLabel($fakeId)); } - /** - * @return void - */ - public function testChoiceLabelStructException() + public function testChoiceLabelStructException(): void { $this->expectException(InvalidArgumentException::class); $this->obj->choiceLabel([]); } - /** - * @return void - */ - public function testParseChoicesThrowsException() + public function testParseChoicesThrowsException(): void { $this->expectException(InvalidArgumentException::class); - $return = $this->callMethod($this->obj, 'parseChoices', [ false ]); + $this->callMethod($this->obj, 'parseChoices', [ false ]); } - /** - * @return void - */ - public function testCollectionLoading() + public function testCollectionLoading(): void { - $container = $this->getContainer(); - $translator = $container['translator']; + $this->getContainer(); $this->setUpObjects(); @@ -533,10 +457,7 @@ public function testCollectionLoading() $this->assertEquals($expectedCollection, $collection->keys()); } - /** - * @return void - */ - public function testLoadObject() + public function testLoadObject(): void { $container = $this->getContainer(); @@ -557,12 +478,9 @@ public function testLoadObject() $this->assertNull($return); } - /** - * @return void - */ - public function testModelLoader() + public function testModelLoader(): void { - $objs = $this->setUpObjects(); + $this->setUpObjects(); $this->obj->setObjType(GenericModel::class); @@ -570,14 +488,11 @@ public function testModelLoader() $this->assertInstanceOf(ModelLoader::class, $return); } - /** - * @return void - */ - public function testModelLoaderThrowsException() + public function testModelLoaderThrowsException(): void { $this->obj->setObjType(GenericModel::class); $this->expectException(InvalidArgumentException::class); - $return = $this->callMethod($this->obj, 'modelLoader', [ false ]); + $this->callMethod($this->obj, 'modelLoader', [ false ]); } } diff --git a/packages/property/tests/Charcoal/Property/PasswordPropertyTest.php b/packages/property/tests/Charcoal/Property/PasswordPropertyTest.php index 68c4c878e..fcfe9a56f 100644 --- a/packages/property/tests/Charcoal/Property/PasswordPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/PasswordPropertyTest.php @@ -1,5 +1,7 @@ getContainer(); @@ -31,15 +27,12 @@ protected function setUp(): void 'translator' => $container['translator'] ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('password', $this->obj->type()); } - public function testSave() + public function testSave(): void { $v1 = $this->obj->save('xxx'); $this->assertNotEquals($v1, 'xxx'); diff --git a/packages/property/tests/Charcoal/Property/PhonePropertyTest.php b/packages/property/tests/Charcoal/Property/PhonePropertyTest.php index 42e0ef0e6..d12dff336 100644 --- a/packages/property/tests/Charcoal/Property/PhonePropertyTest.php +++ b/packages/property/tests/Charcoal/Property/PhonePropertyTest.php @@ -1,5 +1,7 @@ getContainer(); @@ -34,35 +33,24 @@ protected function setUp(): void /** * Hello world - * - * @return void */ - public function testDefaultValues() + public function testDefaultValues(): void { $this->assertEquals(0, $this->obj['minLength']); $this->assertEquals(16, $this->obj['maxLength']); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('phone', $this->obj->type()); } - /** - * @return void - */ - public function testSanitize() + public function testSanitize(): void { $this->assertEquals('5145551234', $this->obj->sanitize('(514) 555-1234')); } - /** - * @return void - */ - public function testDisplayVal() + public function testDisplayVal(): void { $this->assertEquals('(514) 555-1234', $this->obj->displayVal('5145551234')); $this->assertEquals('(514) 555-1234', $this->obj->displayVal('514-555-1234')); diff --git a/packages/property/tests/Charcoal/Property/PropertyFieldTest.php b/packages/property/tests/Charcoal/Property/PropertyFieldTest.php index c97f77728..978a3faf3 100644 --- a/packages/property/tests/Charcoal/Property/PropertyFieldTest.php +++ b/packages/property/tests/Charcoal/Property/PropertyFieldTest.php @@ -21,9 +21,6 @@ class PropertyFieldTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -33,10 +30,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testData() + public function testData(): void { $data = [ 'ident' => 'test', @@ -65,10 +59,7 @@ public function testData() $this->assertEquals($sql, $this->obj->sql()); } - /** - * @return void - */ - public function testIdent() + public function testIdent(): void { $ret = $this->obj->setIdent('title'); $this->assertSame($this->obj, $ret); @@ -79,19 +70,13 @@ public function testIdent() $this->obj->setIdent(null); } - /** - * @return void - */ - public function testSqlReturnsEmptyIfEmptyIdent() + public function testSqlReturnsEmptyIfEmptyIdent(): void { $this->obj->setIdent(''); $this->assertEquals('', $this->obj->sql()); } - /** - * @return void - */ - public function testLabel() + public function testLabel(): void { $this->assertEquals(null, $this->obj->label()); @@ -100,13 +85,10 @@ public function testLabel() $label = $this->obj->label(); $this->assertIsString($label); - $this->assertEquals('Cooking', (string)$label); + $this->assertEquals('Cooking', $label); } - /** - * @return void - */ - public function testPdoType() + public function testPdoType(): void { $this->assertEquals(PDO::PARAM_NULL, $this->obj->sqlPdoType()); @@ -122,10 +104,7 @@ public function testPdoType() $this->obj->setSqlPdoType(null); } - /** - * @return void - */ - public function testSqlType() + public function testSqlType(): void { $ret = $this->obj->setSqlType('INT(10)'); $this->assertSame($this->obj, $ret); @@ -136,10 +115,7 @@ public function testSqlType() $this->obj->setSqlType(0); } - /** - * @return void - */ - public function testSqlExtra() + public function testSqlExtra(): void { $this->assertEquals(null, $this->obj->extra()); @@ -152,10 +128,7 @@ public function testSqlExtra() $this->obj->setExtra(0); } - /** - * @return void - */ - public function testSqlEncoding() + public function testSqlEncoding(): void { $this->assertEquals(null, $this->obj->sqlEncoding()); diff --git a/packages/property/tests/Charcoal/Property/PropertyMetadataTest.php b/packages/property/tests/Charcoal/Property/PropertyMetadataTest.php index f2dc33819..bb91dff5e 100644 --- a/packages/property/tests/Charcoal/Property/PropertyMetadataTest.php +++ b/packages/property/tests/Charcoal/Property/PropertyMetadataTest.php @@ -16,18 +16,12 @@ class PropertyMetadataTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $this->obj = new PropertyMetadata(); } - /** - * @return void - */ - public function testSetIdent() + public function testSetIdent(): void { $this->assertEquals('', $this->obj->ident()); $ret = $this->obj->setIdent('foo'); diff --git a/packages/property/tests/Charcoal/Property/SelectablePropertyTraitTest.php b/packages/property/tests/Charcoal/Property/SelectablePropertyTraitTest.php index 162435816..4e61e0ce7 100644 --- a/packages/property/tests/Charcoal/Property/SelectablePropertyTraitTest.php +++ b/packages/property/tests/Charcoal/Property/SelectablePropertyTraitTest.php @@ -2,6 +2,7 @@ namespace Charcoal\Tests\Property; +use Charcoal\Tests\Property\Mocks\SelectablePropertyTestDouble; use ReflectionClass; // From 'charcoal-translator' @@ -23,31 +24,25 @@ class SelectablePropertyTraitTest extends AbstractTestCase /** * Tested Class. - * - * @var SelectablePropertyTrait */ - private $obj; + private SelectablePropertyTestDouble $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { $container = $this->getContainer(); - $this->obj = $this->getMockForTrait(SelectablePropertyTrait::class); - $this->obj->expects($this->any()) - ->method('translator') - ->will($this->returnValue($container['translator'])); + $this->obj = $this->createPartialMock(SelectablePropertyTestDouble::class, ['translator']); + $this->obj->method('translator') + ->willReturn($container['translator']); } /** * @param mixed $val The translation string. - * @return Translation */ - public function translation($val) + public function translation($val): \Charcoal\Translator\Translation { $container = $this->getContainer(); $locales = $container['locales/manager']; @@ -55,10 +50,7 @@ public function translation($val) return new Translation($val, $locales); } - /** - * @return void - */ - public function testEmptyChoices() + public function testEmptyChoices(): void { $this->assertEquals([], $this->obj->choices()); @@ -77,10 +69,7 @@ public function testEmptyChoices() $this->assertEquals('qux', $this->obj->choiceLabel('qux')); } - /** - * @return void - */ - public function testChoices() + public function testChoices(): void { $choices = [ 'foo' => 'oof', @@ -116,28 +105,19 @@ public function testChoices() $this->assertEquals($expected['bar']['label'], $this->obj->choiceLabel('bar')); } - /** - * @return void - */ - public function testChoiceLabelStructException() + public function testChoiceLabelStructException(): void { $this->expectException('\InvalidArgumentException'); $this->obj->choiceLabel([]); } - /** - * @return void - */ - public function testChoiceLabelKeyException() + public function testChoiceLabelKeyException(): void { $this->expectException('\InvalidArgumentException'); $this->obj->choiceLabel(0); } - /** - * @return void - */ - public function testParseChoices() + public function testParseChoices(): void { $choices = [ 'foo' => 'oof', @@ -180,19 +160,13 @@ public function testParseChoices() $this->assertEquals($baz, $parsed); } - /** - * @return void - */ - public function testParseChoiceStructException() + public function testParseChoiceStructException(): void { $this->expectException('\InvalidArgumentException'); $this->callMethod($this->obj, 'parseChoice', [ null, 'foo' ]); } - /** - * @return void - */ - public function testParseChoiceKeyException() + public function testParseChoiceKeyException(): void { $this->expectException('\InvalidArgumentException'); $this->callMethod($this->obj, 'parseChoice', [ 'foo', 0 ]); diff --git a/packages/property/tests/Charcoal/Property/SpritePropertyTest.php b/packages/property/tests/Charcoal/Property/SpritePropertyTest.php index 4de3258f2..a55038511 100644 --- a/packages/property/tests/Charcoal/Property/SpritePropertyTest.php +++ b/packages/property/tests/Charcoal/Property/SpritePropertyTest.php @@ -20,9 +20,6 @@ class SpritePropertyTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -36,20 +33,17 @@ protected function setUp(): void ]); } - public function testDefaults() + public function testDefaults(): void { $this->assertNull($this->obj['sprite']); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('sprite', $this->obj->type()); } - public function testSetSprite() + public function testSetSprite(): void { $this->assertNull($this->obj['sprite']); $ret = $this->obj->setSprite('foo'); @@ -60,7 +54,7 @@ public function testSetSprite() $this->obj->setSprite(false); } - public function testBuildChoices() + public function testBuildChoices(): void { $ret = $this->obj->buildChoicesFromSprite(); $this->assertEquals([], $ret); @@ -70,19 +64,19 @@ public function testBuildChoices() $this->assertEquals([], $ret); } - public function testSqlExtra() + public function testSqlExtra(): void { $this->assertEquals('', $this->obj->sqlExtra()); } - public function testSqlType() + public function testSqlType(): void { $this->assertEquals('VARCHAR(255)', $this->obj->sqlType()); $this->obj->setMultiple(true); $this->assertEquals('TEXT', $this->obj->sqlType()); } - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->assertEquals(\PDO::PARAM_STR, $this->obj->sqlPdoType()); } diff --git a/packages/property/tests/Charcoal/Property/StorablePropertyTraitTest.php b/packages/property/tests/Charcoal/Property/StorablePropertyTraitTest.php index 4dcf5a96f..7d1489608 100644 --- a/packages/property/tests/Charcoal/Property/StorablePropertyTraitTest.php +++ b/packages/property/tests/Charcoal/Property/StorablePropertyTraitTest.php @@ -26,9 +26,6 @@ class StorablePropertyTraitTest extends AbstractTestCase */ private $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -73,10 +70,7 @@ public function createMultiValueProperty() return $prop; } - /** - * @return void - */ - public function testStorageVal() + public function testStorageVal(): void { $container = $this->getContainer(); @@ -97,10 +91,8 @@ public function testStorageVal() /** * Test Unilingual Property Fields - * - * @return void */ - public function testFields() + public function testFields(): void { $fields = $this->obj->fields('Cooking'); @@ -118,10 +110,7 @@ public function testFields() $this->assertEquals('[]', $field->val()); } - /** - * @return void - */ - public function testUpdateFields() + public function testUpdateFields(): void { $fields = $this->callMethod($this->obj, 'updatedFields', [ [], 'Cooking' ]); $this->assertEquals(['Cooking'], array_map(fn($field) => $field->val(), array_values($fields))); @@ -129,12 +118,10 @@ public function testUpdateFields() /** * Test Multilingual Property Fields - * - * @return void */ - public function testMultilingualFields() + public function testMultilingualFields(): void { - $container = $this->getContainer(); + $this->getContainer(); $obj = $this->createMultilingualProperty(); @@ -163,10 +150,8 @@ public function testMultilingualFields() /** * Test Unilingual Property Field Names - * - * @return void */ - public function testFieldNames() + public function testFieldNames(): void { $names = $this->obj->fieldNames(); @@ -181,10 +166,8 @@ public function testFieldNames() /** * Test Multilingual Property Field Names - * - * @return void */ - public function testMultilingualFieldNames() + public function testMultilingualFieldNames(): void { $obj = $this->createMultilingualProperty(); diff --git a/packages/property/tests/Charcoal/Property/StringPropertyTest.php b/packages/property/tests/Charcoal/Property/StringPropertyTest.php index 18bcc58ce..27c8c6879 100644 --- a/packages/property/tests/Charcoal/Property/StringPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/StringPropertyTest.php @@ -27,8 +27,6 @@ class StringPropertyTest extends AbstractTestCase /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -43,15 +41,12 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('string', $this->obj->type()); } - public function testDefaults() + public function testDefaults(): void { $this->assertFalse($this->obj['required']); $this->assertFalse($this->obj['unique']); @@ -63,18 +58,12 @@ public function testDefaults() $this->assertTrue($this->obj['active']); } - /** - * @return void - */ - public function testSqlExtra() + public function testSqlExtra(): void { $this->assertEquals('', $this->obj->sqlExtra()); } - /** - * @return void - */ - public function testSqlType() + public function testSqlType(): void { $this->obj->setMultiple(false); $this->assertEquals('VARCHAR(255)', $this->obj->sqlType()); @@ -89,23 +78,17 @@ public function testSqlType() $this->assertEquals('TEXT', $this->obj->sqlType()); } - /** - * @return void - */ - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->assertEquals(PDO::PARAM_STR, $this->obj->sqlPdoType()); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $data = [ 'min_length' => 5, 'max_length' => 42, - 'regexp' => '/[0-9]*/', + 'regexp' => '/\d*/', 'allow_empty' => false, 'allow_html' => true ]; @@ -115,15 +98,12 @@ public function testSetData() $this->assertEquals(5, $this->obj['minLength']); $this->assertEquals(42, $this->obj['maxLength']); - $this->assertEquals('/[0-9]*/', $this->obj['regexp']); + $this->assertEquals('/\d*/', $this->obj['regexp']); $this->assertFalse($this->obj['allowEmpty']); $this->assertTrue($this->obj['allowHtml']); } - /** - * @return void - */ - public function testDisplayVal() + public function testDisplayVal(): void { $container = $this->getContainer(); $translator = $container['translator']; @@ -157,10 +137,7 @@ public function testDisplayVal() $this->assertEquals('foo, bar, baz', $this->obj->displayVal([ 'foo', 'bar', 'baz' ])); } - /** - * @return void - */ - public function testDisplayChoices() + public function testDisplayChoices(): void { $choices = $this->getDisplayChoices(); $this->obj->setChoices($choices); @@ -187,9 +164,8 @@ public function testDisplayChoices() /** * @used-by testDisplayChoices() * @used-by testRenderedDisplayChoices() - * @return array */ - public function getDisplayChoices() + public function getDisplayChoices(): array { $container = $this->getContainer(); $translator = $container['translator']; @@ -213,14 +189,13 @@ public function getDisplayChoices() } /** - * @dataProvider getDisplayChoicesProvider * * @param string $expected The displayed $value. * @param mixed $value The value to display. * @param array $options The display options. - * @return void */ - public function testRenderedDisplayChoices($expected, $value, array $options = []) + #[\PHPUnit\Framework\Attributes\DataProvider('getDisplayChoicesProvider')] + public function testRenderedDisplayChoices(string $expected, string|array $value, array $options = []): void { $this->obj->setChoices($this->getDisplayChoices()); $this->obj->setL10n(false); @@ -231,9 +206,8 @@ public function testRenderedDisplayChoices($expected, $value, array $options = [ /** * @used-by testRenderedDisplayChoices() - * @return array */ - public function getDisplayChoicesProvider() + public static function getDisplayChoicesProvider(): array { return [ [ 'Brown fox, Lazy dog, wolf', [ 'fox', 'dog', 'wolf' ] ], @@ -243,10 +217,7 @@ public function getDisplayChoicesProvider() ]; } - /** - * @return void - */ - public function testSetMinLength() + public function testSetMinLength(): void { $ret = $this->obj->setMinLength(5); $this->assertSame($ret, $this->obj); @@ -262,19 +233,13 @@ public function testSetMinLength() $this->obj->setMinLength('foo'); } - /** - * @return void - */ - public function testSetMinLenghtNegativeThrowsException() + public function testSetMinLenghtNegativeThrowsException(): void { $this->expectException('\InvalidArgumentException'); $this->obj->setMinLength(-1); } - /** - * @return void - */ - public function testSetMaxLength() + public function testSetMaxLength(): void { $ret = $this->obj->setMaxLength(5); $this->assertSame($ret, $this->obj); @@ -290,19 +255,13 @@ public function testSetMaxLength() $this->obj->setMaxLength('foo'); } - /** - * @return void - */ - public function testSetMaxLenghtNegativeThrowsException() + public function testSetMaxLenghtNegativeThrowsException(): void { $this->expectException('\InvalidArgumentException'); $this->obj->setMaxLength(-1); } - /** - * @return void - */ - public function testSetRegexp() + public function testSetRegexp(): void { $ret = $this->obj->setRegexp('[a-z]'); $this->assertSame($ret, $this->obj); @@ -318,10 +277,7 @@ public function testSetRegexp() $this->obj->setRegexp(null); } - /** - * @return void - */ - public function testSetAllowEmpty() + public function testSetAllowEmpty(): void { $this->assertEquals(true, $this->obj['allowEmpty']); @@ -336,10 +292,7 @@ public function testSetAllowEmpty() $this->assertFalse($this->obj['allow_empty']); } - /** - * @return void - */ - public function testLength() + public function testLength(): void { $this->obj->setVal('foo'); $this->assertEquals(3, $this->obj->length()); @@ -357,7 +310,7 @@ public function testLength() $this->assertEquals(13, $this->obj->length()); } - public function testParseOne() + public function testParseOne(): void { $this->obj->setAllowHtml(false); $ret = $this->obj->parseOne('

with html

'); @@ -368,18 +321,12 @@ public function testParseOne() $this->assertEquals('

with html

', $ret); } - /** - * @return void - */ - public function testValidationMethods() + public function testValidationMethods(): void { $this->assertIsArray($this->obj->validationMethods()); } - /** - * @return void - */ - public function testValidateMaxLength() + public function testValidateMaxLength(): void { $this->obj->setMaxLength(5); $this->obj->setVal('1234'); @@ -407,10 +354,7 @@ public function testValidateMaxLength() $this->assertNotTrue($this->obj->validateMaxLength()); } - /** - * @return void - */ - public function testValidateMaxLengthWithZeroMaxLengthReturnsTrue() + public function testValidateMaxLengthWithZeroMaxLengthReturnsTrue(): void { $this->obj->setMaxLength(0); @@ -420,10 +364,7 @@ public function testValidateMaxLengthWithZeroMaxLengthReturnsTrue() $this->assertTrue($this->obj->validateMaxLength()); } - /** - * @return void - */ - public function testValidateMinLength() + public function testValidateMinLength(): void { $this->obj->setMinLength(5); @@ -452,10 +393,7 @@ public function testValidateMinLength() $this->assertNotTrue($this->obj->validateMinLength()); } - /** - * @return void - */ - public function testValidateMinLengthAllowEmpty() + public function testValidateMinLengthAllowEmpty(): void { $this->obj->setAllowNull(false); $this->obj->setMinLength(5); @@ -468,10 +406,7 @@ public function testValidateMinLengthAllowEmpty() $this->assertNotTrue($this->obj->validateMinLength()); } - /** - * @return void - */ - public function testValidateMinLengthWithoutValReturnsFalse() + public function testValidateMinLengthWithoutValReturnsFalse(): void { $this->obj->setAllowNull(false); $this->obj->setMinLength(5); @@ -479,10 +414,7 @@ public function testValidateMinLengthWithoutValReturnsFalse() $this->assertNotTrue($this->obj->validateMinLength()); } - /** - * @return void - */ - public function testValidateMinLengthWithoutMinLengthReturnsTrue() + public function testValidateMinLengthWithoutMinLengthReturnsTrue(): void { $this->assertTrue($this->obj->validateMinLength()); @@ -490,10 +422,7 @@ public function testValidateMinLengthWithoutMinLengthReturnsTrue() $this->assertTrue($this->obj->validateMinLength()); } - /** - * @return void - */ - public function testValidateRegexp() + public function testValidateRegexp(): void { /** Without RegExp */ $this->assertTrue($this->obj->validateRegexp()); @@ -502,7 +431,7 @@ public function testValidateRegexp() $this->assertTrue($this->obj->validateRegexp()); /** With RegExp */ - $this->obj->setRegexp('/[0-9]+/'); + $this->obj->setRegexp('/\d+/'); $this->obj->setVal('123'); $this->assertTrue($this->obj->validateRegexp()); @@ -511,10 +440,7 @@ public function testValidateRegexp() $this->assertNotTrue($this->obj->validateRegexp()); } - /** - * @return void - */ - public function testValidateAllowEmpty() + public function testValidateAllowEmpty(): void { $this->obj->setAllowEmpty(false); diff --git a/packages/property/tests/Charcoal/Property/StructurePropertyTest.php b/packages/property/tests/Charcoal/Property/StructurePropertyTest.php index f103fb186..219688a67 100644 --- a/packages/property/tests/Charcoal/Property/StructurePropertyTest.php +++ b/packages/property/tests/Charcoal/Property/StructurePropertyTest.php @@ -21,9 +21,6 @@ class StructurePropertyTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -35,15 +32,12 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('structure', $this->obj->type()); } - public function testParseOneNull() + public function testParseOneNull(): void { $this->obj->setAllowNull(true); $this->assertNull($this->obj->parseOne(null)); @@ -53,7 +47,7 @@ public function testParseOneNull() $this->obj->parseOne(null); } - public function testParseOneString() + public function testParseOneString(): void { $this->assertEquals('', $this->obj->parseOne('')); // $this->assertEquals('foo', $this->obj->parseOne('foo')); @@ -61,7 +55,7 @@ public function testParseOneString() $this->assertEquals(['foo'=>'bar'], $this->obj->parseOne('{"foo":"bar"}')); } - public function testSqlType() + public function testSqlType(): void { $this->assertEquals('TEXT', $this->obj->sqlType()); @@ -85,23 +79,23 @@ public function testSqlType() $this->obj->setSqlType('foobar'); } - public function testSetSqlTypeNullException() + public function testSetSqlTypeNullException(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setSqlType(false); } - public function testSqlPdoType() + public function testSqlPdoType(): void { $this->assertEquals(\PDO::PARAM_STR, $this->obj->sqlPdoType()); } - public function testSqlExtra() + public function testSqlExtra(): void { $this->assertEquals('', $this->obj->sqlExtra()); } - public function testInputVal() + public function testInputVal(): void { $this->assertEquals('', $this->obj->inputVal('')); $this->assertEquals('', $this->obj->inputVal(null)); @@ -109,7 +103,7 @@ public function testInputVal() $this->assertEquals('[]', $this->obj->inputVal([])); } - public function testStorageVal() + public function testStorageVal(): void { $this->assertEquals('', $this->obj->inputVal('')); $this->assertEquals(null, $this->obj->inputVal(null)); diff --git a/packages/property/tests/Charcoal/Property/TextPropertyTest.php b/packages/property/tests/Charcoal/Property/TextPropertyTest.php index 8be63c1f1..624feab63 100644 --- a/packages/property/tests/Charcoal/Property/TextPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/TextPropertyTest.php @@ -1,5 +1,7 @@ getContainer(); @@ -34,15 +33,13 @@ protected function setUp(): void /** * Asserts that the `type()` method returns "text". - * - * @return void */ - public function testType() + public function testType(): void { $this->assertEquals('text', $this->obj->type()); } - public function testDefaults() + public function testDefaults(): void { $this->assertFalse($this->obj['required']); $this->assertFalse($this->obj['unique']); @@ -57,20 +54,16 @@ public function testDefaults() /** * Asserts that the `defaultMaxLength` method returns 0 (no limit). - * - * @return void */ - public function testDefaultMaxLength() + public function testDefaultMaxLength(): void { $this->assertEquals(0, $this->obj->defaultMaxLength()); } /** * Asserts that the `sqlType()` method returns "TEXT". - * - * @return void */ - public function testSqlType() + public function testSqlType(): void { $this->assertEquals('TEXT', $this->obj->sqlType()); diff --git a/packages/property/tests/Charcoal/Property/UrlPropertyTest.php b/packages/property/tests/Charcoal/Property/UrlPropertyTest.php index b7b0a5242..f71c77a3a 100644 --- a/packages/property/tests/Charcoal/Property/UrlPropertyTest.php +++ b/packages/property/tests/Charcoal/Property/UrlPropertyTest.php @@ -1,5 +1,7 @@ getContainer(); @@ -33,15 +32,13 @@ protected function setUp(): void /** * Asserts that the `type()` method returns "url". - * - * @return void */ - public function testType() + public function testType(): void { $this->assertEquals('url', $this->obj->type()); } - public function testParseOne() + public function testParseOne(): void { $this->assertEquals('example.com', $this->obj->parseOne('example.com')); $this->assertEquals('https://example.com:2020', $this->obj->parseOne('https:// example.com:2020 ')); diff --git a/packages/property/tests/Charcoal/ReflectionsTrait.php b/packages/property/tests/Charcoal/ReflectionsTrait.php index 3a63ff2b1..047d2c172 100644 --- a/packages/property/tests/Charcoal/ReflectionsTrait.php +++ b/packages/property/tests/Charcoal/ReflectionsTrait.php @@ -18,13 +18,10 @@ trait ReflectionsTrait * * @param mixed $class The class name or object that contains the method. * @param string $name The method name to reflect. - * @return ReflectionMethod */ - public function getMethod($class, $name) + public function getMethod($class, $name): \ReflectionMethod { - $reflected = new ReflectionMethod($class, $name); - $reflected->setAccessible(true); - return $reflected; + return new ReflectionMethod($class, $name); } /** @@ -38,7 +35,7 @@ public function getMethod($class, $name) public function callMethod($object, $name, array $args = []) { $method = $this->getMethod($object, $name); - if (empty($args)) { + if ($args === []) { return $method->invoke($object); } else { return $method->invokeArgs($object, $args); @@ -65,13 +62,10 @@ public function callMethodWith($object, $name, ...$args) * * @param mixed $class The class name or object that contains the property. * @param string $name The property name to reflect. - * @return ReflectionProperty */ - public function getProperty($class, $name) + public function getProperty($class, $name): \ReflectionProperty { - $reflected = new ReflectionProperty($class, $name); - $reflected->setAccessible(true); - return $reflected; + return new ReflectionProperty($class, $name); } /** @@ -92,9 +86,8 @@ public function getPropertyValue($object, $name) * @param mixed $object The object to access. * @param string $name The property name to affect. * @param mixed $value The new value. - * @return void */ - public function setPropertyValue($object, $name, $value) + public function setPropertyValue($object, $name, $value): void { $this->getProperty($object, $name)->setValue($object, $value); } diff --git a/packages/property/tests/bootstrap.php b/packages/property/tests/bootstrap.php new file mode 100644 index 000000000..90929e3b5 --- /dev/null +++ b/packages/property/tests/bootstrap.php @@ -0,0 +1,14 @@ + - -> + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + + - + - - - - - diff --git a/packages/queue/src/Charcoal/Queue/AbstractQueueManager.php b/packages/queue/src/Charcoal/Queue/AbstractQueueManager.php index cf51036a4..bb8baab6d 100644 --- a/packages/queue/src/Charcoal/Queue/AbstractQueueManager.php +++ b/packages/queue/src/Charcoal/Queue/AbstractQueueManager.php @@ -47,24 +47,18 @@ abstract class AbstractQueueManager implements /** * The queue processing rate (throttle), in items per second. - * - * @var integer */ - private $rate = 0; + private int $rate = 0; /** * The batch limit. - * - * @var integer */ - private $limit = 0; + private int $limit = 0; /** * The chunk size to batch the queue with. - * - * @var integer */ - private $chunkSize = 0; + private int $chunkSize = 0; /** * The queue ID. @@ -125,10 +119,7 @@ abstract class AbstractQueueManager implements */ private $processedCallback; - /** - * @var FactoryInterface $queueItemFactory - */ - private $queueItemFactory; + private \Charcoal\Factory\FactoryInterface $queueItemFactory; /** * Construct new queue manager. @@ -302,7 +293,7 @@ public function setProcessedCallback(callable $callback) * after all queue items are processed. * @return boolean Success / Failure */ - public function processQueue(callable $callback = null) + public function processQueue(?callable $callback = null) { if (!is_callable($callback)) { $callback = $this->processedCallback; @@ -337,14 +328,14 @@ public function processQueue(callable $callback = null) $queueId, $summary ), [ - 'manager' => get_called_class(), + 'manager' => static::class, ]); } else { $this->logger->notice(sprintf( 'Completed processing of queues: %s', $summary ), [ - 'manager' => get_called_class(), + 'manager' => static::class, ]); } @@ -353,9 +344,8 @@ public function processQueue(callable $callback = null) /** * @param mixed $queuedItems The items to process. - * @return void */ - private function processItems($queuedItems) + private function processItems($queuedItems): void { /** @var QueueItemInterface $q */ foreach ($queuedItems as $q) { @@ -390,7 +380,7 @@ private function processItems($queuedItems) $this->logger->error( sprintf('Could not process a queue item: %s', $e->getMessage()), [ - 'manager' => get_called_class(), + 'manager' => static::class, 'queueId' => $q['queueId'], 'itemId' => $q['id'], ] @@ -405,10 +395,8 @@ private function processItems($queuedItems) /** * Throttle processing of items. - * - * @return void */ - private function throttle() + private function throttle(): void { if ($this->rate > 0) { usleep(1000000 / $this->rate); @@ -422,13 +410,11 @@ private function throttle() */ public function createQueueItemsLoader() { - $loader = new CollectionLoader([ + return new CollectionLoader([ 'logger' => $this->logger, 'factory' => $this->queueItemFactory(), 'model' => $this->queueItemProto(), ]); - - return $loader; } /** @@ -544,9 +530,8 @@ protected function queueItemFactory() /** * @param FactoryInterface $factory The factory used to create queue items. - * @return self */ - private function setQueueItemFactory(FactoryInterface $factory) + private function setQueueItemFactory(FactoryInterface $factory): static { $this->queueItemFactory = $factory; return $this; diff --git a/packages/queue/src/Charcoal/Queue/QueueItemInterface.php b/packages/queue/src/Charcoal/Queue/QueueItemInterface.php index 37c2c587e..1474277f4 100644 --- a/packages/queue/src/Charcoal/Queue/QueueItemInterface.php +++ b/packages/queue/src/Charcoal/Queue/QueueItemInterface.php @@ -1,5 +1,7 @@ logger->error( sprintf('Could not process a queue item: %s', $e->getMessage()), [ - 'manager' => get_called_class(), + 'manager' => static::class, 'queueId' => $this->queueId(), 'itemId' => $this->id(), ] @@ -163,7 +163,7 @@ public function queueId() */ public function setProcessed($processed) { - $this->processed = !!$processed; + $this->processed = (bool)$processed; return $this; } @@ -195,9 +195,7 @@ public function setQueuedDate($ts) try { $ts = new DateTime($ts); } catch (Exception $e) { - throw new InvalidArgumentException( - sprintf('Can not set queued date: %s', $e->getMessage()) - ); + throw new InvalidArgumentException(sprintf('Can not set queued date: %s', $e->getMessage()), $e->getCode(), $e); } } @@ -240,9 +238,7 @@ public function setProcessingDate($ts) try { $ts = new DateTime($ts); } catch (Exception $e) { - throw new InvalidArgumentException( - sprintf('%s (%s)', $e->getMessage(), $ts) - ); + throw new InvalidArgumentException(sprintf('%s (%s)', $e->getMessage(), $ts), $e->getCode(), $e); } } @@ -285,9 +281,7 @@ public function setProcessedDate($ts) try { $ts = new DateTime($ts); } catch (Exception $e) { - throw new InvalidArgumentException( - sprintf('%s (%s)', $e->getMessage(), $ts) - ); + throw new InvalidArgumentException(sprintf('%s (%s)', $e->getMessage(), $ts), $e->getCode(), $e); } } @@ -340,9 +334,7 @@ public function setExpiryDate($ts) try { $ts = new DateTime($ts); } catch (Exception $e) { - throw new InvalidArgumentException( - sprintf('%s (%s)', $e->getMessage(), $ts) - ); + throw new InvalidArgumentException(sprintf('%s (%s)', $e->getMessage(), $ts), $e->getCode(), $e); } } diff --git a/packages/queue/src/Charcoal/Queue/QueueManagerInterface.php b/packages/queue/src/Charcoal/Queue/QueueManagerInterface.php index 8bc749d53..bf1876f90 100644 --- a/packages/queue/src/Charcoal/Queue/QueueManagerInterface.php +++ b/packages/queue/src/Charcoal/Queue/QueueManagerInterface.php @@ -1,5 +1,7 @@ - -> + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/translator/src/Charcoal/Translator/LocalesConfig.php b/packages/translator/src/Charcoal/Translator/LocalesConfig.php index 7640c6111..8ed65d380 100644 --- a/packages/translator/src/Charcoal/Translator/LocalesConfig.php +++ b/packages/translator/src/Charcoal/Translator/LocalesConfig.php @@ -1,5 +1,7 @@ [ @@ -57,7 +45,7 @@ public function defaults() * @param array $languages The languages configuration. * @return LocalesConfig Chainable */ - public function setLanguages(array $languages) + public function setLanguages(array $languages): static { $this->languages = $languages; return $this; @@ -66,7 +54,7 @@ public function setLanguages(array $languages) /** * @return array */ - public function languages() + public function languages(): ?array { return $this->languages; } @@ -76,7 +64,7 @@ public function languages() * @throws InvalidArgumentException If the default language is not a string. * @return LocalesConfig Chainable */ - public function setDefaultLanguage($lang) + public function setDefaultLanguage($lang): static { if (!is_string($lang)) { throw new InvalidArgumentException( @@ -90,7 +78,7 @@ public function setDefaultLanguage($lang) /** * @return string */ - public function defaultLanguage() + public function defaultLanguage(): ?string { return $this->defaultLanguage; } @@ -99,7 +87,7 @@ public function defaultLanguage() * @param array $languages The fallback languages, used when a translation is not set in a language. * @return LocalesConfig Chainable */ - public function setFallbackLanguages(array $languages) + public function setFallbackLanguages(array $languages): static { $this->fallbackLanguages = $languages; return $this; @@ -108,7 +96,7 @@ public function setFallbackLanguages(array $languages) /** * @return array */ - public function fallbackLanguages() + public function fallbackLanguages(): ?array { return $this->fallbackLanguages; } @@ -117,16 +105,16 @@ public function fallbackLanguages() * @param boolean $autoDetect The auto-detect flag. * @return LocalesConfig Chainable */ - public function setAutoDetect($autoDetect) + public function setAutoDetect($autoDetect): static { - $this->autoDetect = !!$autoDetect; + $this->autoDetect = (bool)$autoDetect; return $this; } /** * @return boolean */ - public function autoDetect() + public function autoDetect(): ?bool { return $this->autoDetect; } diff --git a/packages/translator/src/Charcoal/Translator/LocalesManager.php b/packages/translator/src/Charcoal/Translator/LocalesManager.php index 235f5e763..157f38e52 100644 --- a/packages/translator/src/Charcoal/Translator/LocalesManager.php +++ b/packages/translator/src/Charcoal/Translator/LocalesManager.php @@ -31,7 +31,7 @@ class LocalesManager * * @var string[] */ - private $languages; + private array $languages; /** * Language code for the default locale. @@ -66,10 +66,10 @@ public function __construct(array $data) { $this->setLocales($data['locales']); - $default = isset($data['default_language']) ? $data['default_language'] : null; + $default = ($data['default_language'] ?? null); $this->setDefaultLocale($default); - $current = isset($data['current_language']) ? $data['current_language'] : null; + $current = ($data['current_language'] ?? null); $this->setCurrentLocale($current); } @@ -88,7 +88,7 @@ public function locales() * * @return string[] */ - public function availableLocales() + public function availableLocales(): array { return $this->languages; } @@ -99,9 +99,8 @@ public function availableLocales() * @param string|null $lang The default language code. * If NULL, the first language is assigned. * @throws InvalidArgumentException If the language is invalid. - * @return void */ - private function setDefaultLocale($lang) + private function setDefaultLocale($lang): void { if ($lang === null) { $this->defaultLanguage = $this->languages[0]; @@ -110,7 +109,7 @@ private function setDefaultLocale($lang) if (!$this->hasLocale($lang)) { if (!is_string($lang)) { - $lang = is_object($lang) ? get_class($lang) : gettype($lang); + $lang = get_debug_type($lang); } throw new InvalidArgumentException(sprintf( @@ -139,9 +138,8 @@ public function defaultLocale() * @param string|null $lang The current language code. * If NULL, the current language is unset. * @throws InvalidArgumentException If the language is invalid. - * @return void */ - public function setCurrentLocale($lang) + public function setCurrentLocale($lang): void { if ($lang === null) { $this->currentLanguage = null; @@ -150,7 +148,7 @@ public function setCurrentLocale($lang) if (!$this->hasLocale($lang)) { if (!is_string($lang)) { - $lang = is_object($lang) ? get_class($lang) : gettype($lang); + $lang = get_debug_type($lang); } throw new InvalidArgumentException(sprintf( @@ -180,9 +178,8 @@ public function currentLocale() * Determine if a locale is available. * * @param string $lang The language code to check. - * @return boolean */ - public function hasLocale($lang) + public function hasLocale($lang): bool { return isset($this->locales[$lang]); } @@ -197,12 +194,11 @@ public function hasLocale($lang) * * @param array $locales The locales configuration structure. * @throws InvalidArgumentException If there are no active locales. - * @return void */ - private function setLocales(array $locales) + private function setLocales(array $locales): void { $locales = $this->filterLocales($locales); - uasort($locales, [ $this, 'sortLocalesByPriority' ]); + uasort($locales, $this->sortLocalesByPriority(...)); $this->locales = []; $this->languages = []; @@ -211,7 +207,7 @@ private function setLocales(array $locales) $this->languages[] = $langCode; } - if (empty($this->locales)) { + if ($this->locales === []) { throw new InvalidArgumentException( 'Locales can not be empty.' ); @@ -229,7 +225,7 @@ private function setLocales(array $locales) * @param array $locales The locales configuration structure. * @return array The parsed language structures. */ - private function filterLocales(array $locales) + private function filterLocales(array $locales): array { $z = self::DEFAULT_SORT_PRIORITY; @@ -258,16 +254,11 @@ private function filterLocales(array $locales) * * @param array $a Sortable action A. * @param array $b Sortable action B. - * @return integer */ - private function sortLocalesByPriority(array $a, array $b) + private function sortLocalesByPriority(array $a, array $b): int { - $a = isset($a['priority']) ? $a['priority'] : 0; - $b = isset($b['priority']) ? $b['priority'] : 0; - - if ($a === $b) { - return 0; - } - return ($a < $b) ? (-1) : 1; + $a = ($a['priority'] ?? 0); + $b = ($b['priority'] ?? 0); + return ($a <=> $b); } } diff --git a/packages/translator/src/Charcoal/Translator/Middleware/LanguageMiddleware.php b/packages/translator/src/Charcoal/Translator/Middleware/LanguageMiddleware.php index 388157429..34d5f6ee4 100644 --- a/packages/translator/src/Charcoal/Translator/Middleware/LanguageMiddleware.php +++ b/packages/translator/src/Charcoal/Translator/Middleware/LanguageMiddleware.php @@ -29,60 +29,36 @@ class LanguageMiddleware */ private $browserLanguage; - /** - * @var array - */ - private $excludedPath; + private array $excludedPath; - /** - * @var boolean - */ - private $usePath; + private bool $usePath; /** * @var string */ private $pathRegexp; - /** - * @var boolean - */ - private $useBrowser; + private bool $useBrowser; - /** - * @var boolean - */ - private $useSession; + private bool $useSession; /** * @var string[] */ - private $sessionKey; + private array $sessionKey; - /** - * @var boolean - */ - private $useParams; + private bool $useParams; /** * @var string[] */ - private $paramKey; + private array $paramKey; - /** - * @var boolean - */ - private $useHost; + private bool $useHost; - /** - * @var array - */ - private $hostMap; + private array $hostMap; - /** - * @var boolean - */ - private $setLocale; + private bool $setLocale; /** * @param array $data The middleware options. @@ -96,30 +72,28 @@ public function __construct(array $data) $this->defaultLanguage = $data['default_language']; $this->browserLanguage = $data['browser_language']; - $this->usePath = !!$data['use_path']; + $this->usePath = (bool)$data['use_path']; $this->excludedPath = (array)$data['excluded_path']; $this->pathRegexp = $data['path_regexp']; - $this->useParams = !!$data['use_params']; + $this->useParams = (bool)$data['use_params']; $this->paramKey = (array)$data['param_key']; - $this->useSession = !!$data['use_session']; + $this->useSession = (bool)$data['use_session']; $this->sessionKey = (array)$data['session_key']; - $this->useBrowser = !!$data['use_browser']; + $this->useBrowser = (bool)$data['use_browser']; - $this->useHost = !!$data['use_host']; + $this->useHost = (bool)$data['use_host']; $this->hostMap = (array)$data['host_map']; - $this->setLocale = !!$data['set_locale']; + $this->setLocale = (bool)$data['set_locale']; } /** * Default middleware options. - * - * @return array */ - public function defaults() + public function defaults(): array { return [ 'default_language' => null, @@ -173,35 +147,35 @@ public function __invoke(RequestInterface $request, ResponseInterface $response, */ private function getLanguage(RequestInterface $request) { - if ($this->useHost === true) { + if ($this->useHost) { $lang = $this->getLanguageFromHost($request); if ($lang) { return $lang; } } - if ($this->usePath === true) { + if ($this->usePath) { $lang = $this->getLanguageFromPath($request); - if ($lang) { + if ($lang !== '' && $lang !== '0') { return $lang; } } - if ($this->useParams === true) { + if ($this->useParams) { $lang = $this->getLanguageFromParams($request); if ($lang) { return $lang; } } - if ($this->useSession === true) { + if ($this->useSession) { $lang = $this->getLanguageFromSession(); if ($lang) { return $lang; } } - if ($this->useBrowser === true) { + if ($this->useBrowser) { $lang = $this->getLanguageFromBrowser(); if ($lang) { return $lang; @@ -215,11 +189,11 @@ private function getLanguage(RequestInterface $request) * @param RequestInterface $request The PSR-7 HTTP request. * @return string */ - private function getLanguageFromHost(RequestInterface $request) + private function getLanguageFromHost(RequestInterface $request): int|string { $uriHost = $request->getUri()->getHost(); foreach ($this->hostMap as $lang => $host) { - if (stripos($uriHost, $host) !== false) { + if (stripos($uriHost, (string)$host) !== false) { return $lang; } } @@ -229,9 +203,8 @@ private function getLanguageFromHost(RequestInterface $request) /** * @param RequestInterface $request The PSR-7 HTTP request. - * @return string */ - private function getLanguageFromPath(RequestInterface $request) + private function getLanguageFromPath(RequestInterface $request): string { $path = $request->getRequestTarget(); if (preg_match('@' . $this->pathRegexp . '@', $path, $matches)) { @@ -291,28 +264,26 @@ private function getLanguageFromBrowser() /** * @param string $lang The language code to set. - * @return void */ - private function setLanguage($lang) + private function setLanguage($lang): void { $this->translator()->setLocale($lang); - if ($this->useSession === true) { + if ($this->useSession) { foreach ($this->sessionKey as $key) { $_SESSION[$key] = $this->translator()->getLocale(); } } - if ($this->setLocale === true) { + if ($this->setLocale) { $this->setLocale($lang); } } /** * @param string $lang The language code to set. - * @return void */ - private function setLocale($lang) + private function setLocale($lang): void { $translator = $this->translator(); $available = $translator->locales(); @@ -329,14 +300,14 @@ private function setLocale($lang) $choices = (array)$locale['locales']; array_push($locales, ...$choices); } elseif (isset($locale['locale'])) { - array_push($locales, $locale['locale']); + $locales[] = $locale['locale']; } } } $locales = array_unique($locales); - if (!empty($locales)) { + if ($locales !== []) { setlocale(LC_ALL, $locales); } } diff --git a/packages/translator/src/Charcoal/Translator/Script/TranslationParserScript.php b/packages/translator/src/Charcoal/Translator/Script/TranslationParserScript.php index b671ffdf0..0789a09ca 100644 --- a/packages/translator/src/Charcoal/Translator/Script/TranslationParserScript.php +++ b/packages/translator/src/Charcoal/Translator/Script/TranslationParserScript.php @@ -66,9 +66,9 @@ class TranslationParserScript extends AdminScript /** * @param Container $container Pimple DI container. - * @return void */ - public function setDependencies(Container $container) + #[\Override] + public function setDependencies(Container $container): void { $this->appConfig = $container['config']; $this->setTranslator($container['translator']); @@ -89,9 +89,9 @@ public function setDependencies(Container $container) * - type : file type (either mustache or php) * * @todo Support php file type. - * @return array */ - public function defaultArguments() + #[\Override] + public function defaultArguments(): array { $arguments = [ 'output' => [ @@ -135,17 +135,14 @@ public function defaultArguments() 'defaultValue' => '_t' ] ]; - - $arguments = array_merge(parent::defaultArguments(), $arguments); - return $arguments; + return array_merge(parent::defaultArguments(), $arguments); } /** * @param RequestInterface $request A PSR-7 compatible Request instance. * @param ResponseInterface $response A PSR-7 compatible Response instance. - * @return ResponseInterface */ - public function run(RequestInterface $request, ResponseInterface $response) + public function run(RequestInterface $request, ResponseInterface $response): ResponseInterface { // Unused unset($request); @@ -173,13 +170,12 @@ public function run(RequestInterface $request, ResponseInterface $response) /** * @param array $trans The translations array. - * @return array */ - protected function parseTranslations(array $trans) + protected function parseTranslations(array $trans): array { // Must be the first occurrence of the the key. - foreach ($trans as $lang => &$value) { - array_walk($value, function (&$val, $key) { + foreach ($trans as &$value) { + array_walk($value, function (&$val, $key): void { // remove key template ident in translation value. if (preg_match('|^\[([^\]]*)\]|', $key, $translationContext)) { $val = str_replace($translationContext[0], '', $val); @@ -199,7 +195,7 @@ protected function parseTranslations(array $trans) * Give feedback about what's going on. * @return self Chainable. */ - protected function displayInformations() + protected function displayInformations(): static { $this->climate()->underline()->out( 'Initializing translations parser script...' @@ -244,7 +240,7 @@ protected function filePath() * Available locales (languages) * @return array Locales. */ - protected function locales() + protected function locales(): array { return $this->translator()->availableLocales(); } @@ -252,7 +248,7 @@ protected function locales() /** * @return string Current locale. */ - protected function locale() + protected function locale(): string { return $this->translator()->getLocale(); } @@ -274,7 +270,7 @@ public function output() * Domain which is the csv file name prefix * @return string domain. */ - public function domain() + public function domain(): string { return (string)$this->argOrInput('domain'); } @@ -285,7 +281,7 @@ public function domain() * @param string $type File type (mustache|php). * @return string Regex string. */ - public function regEx($type) + public function regEx($type): string { switch ($type) { case 'php': @@ -326,15 +322,14 @@ public function regEx($type) * ] * @return array Translations. */ - public function getTranslations() + public function getTranslations(): array { $path = $this->path(); if ($path) { $this->climate()->green()->out('Parsing files in ' . $path . ''); $translations = $this->getTranslationsFromPath($path, 'mustache'); - $translations = array_replace($translations, $this->getTranslationsFromPath($path, 'php')); - return $translations; + return array_replace($translations, $this->getTranslationsFromPath($path, 'php')); } $paths = $this->paths(); @@ -355,7 +350,7 @@ public function getTranslations() * @param string $fileType The file extension|type. * @return array Translations. */ - public function getTranslationsFromPath($path, $fileType) + public function getTranslationsFromPath(string $path, string $fileType): array { // Remove vendor/charcoal/app $base = $this->appConfig->get('base_path'); @@ -411,7 +406,7 @@ public function getTranslationsFromPath($path, $fileType) * @return array * @see http://in.php.net/manual/en/function.glob.php#106595 */ - public function globRecursive($pattern, $flags = 0) + public function globRecursive($pattern, $flags = 0): array|false { // $max = $this->maxRecursiveLevel(); $i = 1; @@ -469,9 +464,8 @@ public function fileTypes() /** * @param array $translations The translations to save in CSV. - * @return self */ - public function toCSV(array $translations) + public function toCSV(array $translations): static { if (!count($translations)) { $this->climate()->error(' @@ -502,7 +496,7 @@ public function toCSV(array $translations) foreach ($trans as $key => $translation) { $data = [ $key, $translation ]; - fputcsv($file, $data, $separator, $enclosure); + fputcsv($file, $data, $separator, $enclosure, escape: '\\'); } fclose($file); } @@ -510,26 +504,17 @@ public function toCSV(array $translations) return $this; } - /** - * @return string - */ - public function enclosure() + public function enclosure(): string { return '"'; } - /** - * @return string - */ - public function separator() + public function separator(): string { return ';'; } - /** - * @return integer - */ - public function maxRecursiveLevel() + public function maxRecursiveLevel(): int { if ($this->climate()->arguments->defined('recursive')) { return (int)$this->climate()->arguments->get('recursive'); @@ -540,7 +525,7 @@ public function maxRecursiveLevel() /** * @return string Php function */ - private function phpFunction() + private function phpFunction(): string { if ($this->climate()->arguments->defined('php_function')) { return (string)$this->climate()->arguments->get('php_function'); @@ -552,7 +537,7 @@ private function phpFunction() /** * @return string Mustache tag */ - private function mustacheTag() + private function mustacheTag(): string { if ($this->climate()->arguments->defined('mustache_tag')) { return (string)$this->climate()->arguments->get('mustache_tag'); diff --git a/packages/translator/src/Charcoal/Translator/ServiceProvider/TranslatorServiceProvider.php b/packages/translator/src/Charcoal/Translator/ServiceProvider/TranslatorServiceProvider.php index 273601087..4e61615c0 100644 --- a/packages/translator/src/Charcoal/Translator/ServiceProvider/TranslatorServiceProvider.php +++ b/packages/translator/src/Charcoal/Translator/ServiceProvider/TranslatorServiceProvider.php @@ -19,7 +19,6 @@ use Symfony\Component\Translation\Loader\JsonFileLoader; use Symfony\Component\Translation\Loader\YamlFileLoader; use Symfony\Component\Translation\Formatter\MessageFormatter; -use Symfony\Component\Translation\MessageSelector; // From 'charcoal-translator' use Charcoal\Translator\LocalesConfig; use Charcoal\Translator\LocalesManager; @@ -37,9 +36,8 @@ class TranslatorServiceProvider implements ServiceProviderInterface { /** * @param Container $container Pimple DI container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { $this->registerLocales($container); $this->registerTranslator($container); @@ -48,9 +46,8 @@ public function register(Container $container) /** * @param Container $container Pimple DI container. - * @return void */ - private function registerLocales(Container $container) + private function registerLocales(Container $container): void { /** * Instance of the Locales Configset. @@ -58,9 +55,9 @@ private function registerLocales(Container $container) * @param Container $container Pimple DI container. * @return LocalesConfig */ - $container['locales/config'] = function (Container $container) { - $appConfig = isset($container['config']) ? $container['config'] : []; - $localesConfig = isset($appConfig['locales']) ? $appConfig['locales'] : null; + $container['locales/config'] = function (Container $container): \Charcoal\Translator\LocalesConfig { + $appConfig = ($container['config'] ?? []); + $localesConfig = ($appConfig['locales'] ?? null); return new LocalesConfig($localesConfig); }; @@ -72,10 +69,8 @@ private function registerLocales(Container $container) */ $container['locales/default-language'] = function (Container $container) { $localesConfig = $container['locales/config']; - if (isset($localesConfig['auto_detect']) && $localesConfig['auto_detect']) { - if ($container['locales/browser-language'] !== null) { - return $container['locales/browser-language']; - } + if (isset($localesConfig['auto_detect']) && $localesConfig['auto_detect'] && $container['locales/browser-language'] !== null) { + return $container['locales/browser-language']; } return $localesConfig['default_language']; }; @@ -93,7 +88,7 @@ private function registerLocales(Container $container) * @param Container $container Pimple DI container. * @return string|null */ - $container['locales/browser-language'] = function (Container $container) { + $container['locales/browser-language'] = function (Container $container): ?string { if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { return null; } @@ -104,11 +99,9 @@ private function registerLocales(Container $container) * as the default language. */ $localesConfig = $container['locales/config']; - $supportedLocales = array_filter($localesConfig['languages'], function ($locale) { - return !(isset($locale['active']) && !$locale['active']); - }); + $supportedLocales = array_filter($localesConfig['languages'], fn(array $locale): bool => !(isset($locale['active']) && !$locale['active'])); - $acceptableLanguages = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); + $acceptableLanguages = explode(',', (string)$_SERVER['HTTP_ACCEPT_LANGUAGE']); foreach ($acceptableLanguages as $acceptedLang) { $lang = explode(';', $acceptedLang); $lang = trim($lang[0]); @@ -161,7 +154,7 @@ private function registerLocales(Container $container) * @param Container $container Pimple DI container. * @return LocalesManager */ - $container['locales/manager'] = function (Container $container) { + $container['locales/manager'] = function (Container $container): \Charcoal\Translator\LocalesManager { $localesConfig = $container['locales/config']; return new LocalesManager([ 'locales' => $localesConfig['languages'], @@ -172,9 +165,8 @@ private function registerLocales(Container $container) /** * @param Container $container Pimple DI container. - * @return void */ - private function registerTranslator(Container $container) + private function registerTranslator(Container $container): void { /** * Instance of the Translator Configset. @@ -182,9 +174,9 @@ private function registerTranslator(Container $container) * @param Container $container Pimple DI container. * @return TranslatorConfig */ - $container['translator/config'] = function (Container $container) { - $appConfig = isset($container['config']) ? $container['config'] : []; - $transConfig = isset($appConfig['translator']) ? $appConfig['translator'] : null; + $container['translator/config'] = function (Container $container): \Charcoal\Translator\TranslatorConfig { + $appConfig = ($container['config'] ?? []); + $transConfig = ($appConfig['translator'] ?? null); if (isset($transConfig['paths'])) { $transConfig['paths'] = $appConfig->resolveValues($transConfig['paths']); @@ -198,7 +190,7 @@ private function registerTranslator(Container $container) $modules = $container['module/classes']; foreach ($modules as $module) { if (defined(sprintf('%s::APP_CONFIG', $module))) { - $configPath = ltrim($module::APP_CONFIG, '/'); + $configPath = ltrim((string)$module::APP_CONFIG, '/'); $configPath = $basePath . DIRECTORY_SEPARATOR . $configPath; $configData = $appConfig->loadFile($configPath); @@ -211,7 +203,7 @@ private function registerTranslator(Container $container) }; } - if ($extraPaths) { + if ($extraPaths !== []) { $transConfig->addPaths($extraPaths); } } @@ -230,24 +222,12 @@ private function registerTranslator(Container $container) return $transConfig['translations']; }; - /** - * Instance of the Message Selector, that is used to resolve a translation. - * - * @return MessageSelector - */ - $container['translator/message-selector'] = function () { - return new MessageSelector(); - }; - /** * Instance of the Message Formatter, that is used to format a localized message. * - * @param Container $container Pimple DI container. * @return MessageFormatter */ - $container['translator/message-formatter'] = function (Container $container) { - return new MessageFormatter($container['translator/message-selector']); - }; + $container['translator/message-formatter'] = (fn(): \Symfony\Component\Translation\Formatter\MessageFormatter => new MessageFormatter()); /** * Instance of the Translator, that is used for translation. @@ -256,11 +236,10 @@ private function registerTranslator(Container $container) * @param Container $container Pimple DI container. * @return Translator */ - $container['translator'] = function (Container $container) { + $container['translator'] = function (Container $container): \Charcoal\Translator\Translator { $transConfig = $container['translator/config']; $translator = new Translator([ 'manager' => $container['locales/manager'], - 'message_selector' => $container['translator/message-selector'], 'message_formatter' => $container['translator/message-formatter'], 'cache_dir' => $transConfig['cache_dir'], 'debug' => $transConfig['debug'], @@ -310,106 +289,80 @@ private function registerTranslator(Container $container) /** * @param Container $container Pimple DI container. - * @return void */ - private function registerTranslatorLoaders(Container $container) + private function registerTranslatorLoaders(Container $container): void { /** * @return ArrayLoader */ - $container['translator/loader/array'] = function () { - return new ArrayLoader(); - }; + $container['translator/loader/array'] = (fn(): \Symfony\Component\Translation\Loader\ArrayLoader => new ArrayLoader()); /** * @return CsvFileLoader */ - $container['translator/loader/file/csv'] = function () { - return new CsvFileLoader(); - }; + $container['translator/loader/file/csv'] = (fn(): \Symfony\Component\Translation\Loader\CsvFileLoader => new CsvFileLoader()); /** * @return IcuDatFileLoader */ - $container['translator/loader/file/dat'] = function () { - return new IcuDatFileLoader(); - }; + $container['translator/loader/file/dat'] = (fn(): \Symfony\Component\Translation\Loader\IcuDatFileLoader => new IcuDatFileLoader()); /** * @return IcuResFileLoader */ - $container['translator/loader/file/res'] = function () { - return new IcuResFileLoader(); - }; + $container['translator/loader/file/res'] = (fn(): \Symfony\Component\Translation\Loader\IcuResFileLoader => new IcuResFileLoader()); /** * @return IniFileLoader */ - $container['translator/loader/file/ini'] = function () { - return new IniFileLoader(); - }; + $container['translator/loader/file/ini'] = (fn(): \Symfony\Component\Translation\Loader\IniFileLoader => new IniFileLoader()); /** * @return JsonFileLoader */ - $container['translator/loader/file/json'] = function () { - return new JsonFileLoader(); - }; + $container['translator/loader/file/json'] = (fn(): \Symfony\Component\Translation\Loader\JsonFileLoader => new JsonFileLoader()); /** * @return MoFileLoader */ - $container['translator/loader/file/mo'] = function () { - return new MoFileLoader(); - }; + $container['translator/loader/file/mo'] = (fn(): \Symfony\Component\Translation\Loader\MoFileLoader => new MoFileLoader()); /** * @return PhpFileLoader */ - $container['translator/loader/file/php'] = function () { - return new PhpFileLoader(); - }; + $container['translator/loader/file/php'] = (fn(): \Symfony\Component\Translation\Loader\PhpFileLoader => new PhpFileLoader()); /** * @return PoFileLoader */ - $container['translator/loader/file/po'] = function () { - return new PoFileLoader(); - }; + $container['translator/loader/file/po'] = (fn(): \Symfony\Component\Translation\Loader\PoFileLoader => new PoFileLoader()); /** * @return QtFileLoader */ - $container['translator/loader/file/qt'] = function () { - return new QtFileLoader(); - }; + $container['translator/loader/file/qt'] = (fn(): \Symfony\Component\Translation\Loader\QtFileLoader => new QtFileLoader()); /** * @return XliffFileLoader */ - $container['translator/loader/file/xliff'] = function () { - return new XliffFileLoader(); - }; + $container['translator/loader/file/xliff'] = (fn(): \Symfony\Component\Translation\Loader\XliffFileLoader => new XliffFileLoader()); /** * @return YamlFileLoader */ - $container['translator/loader/file/yaml'] = function () { - return new YamlFileLoader(); - }; + $container['translator/loader/file/yaml'] = (fn(): \Symfony\Component\Translation\Loader\YamlFileLoader => new YamlFileLoader()); } /** * @param Container $container Pimple DI container. - * @return void */ - private function registerMiddleware(Container $container) + private function registerMiddleware(Container $container): void { /** * @param Container $container * @return LanguageMiddleware */ - $container['middlewares/charcoal/translator/middleware/language'] = function (Container $container) { + $container['middlewares/charcoal/translator/middleware/language'] = function (Container $container): \Charcoal\Translator\Middleware\LanguageMiddleware { $middlewareConfig = $container['config']['middlewares']['charcoal/translator/middleware/language']; $middlewareConfig = array_replace( [ diff --git a/packages/translator/src/Charcoal/Translator/TranslatableInterface.php b/packages/translator/src/Charcoal/Translator/TranslatableInterface.php index dd5fb0a69..3cc81b007 100644 --- a/packages/translator/src/Charcoal/Translator/TranslatableInterface.php +++ b/packages/translator/src/Charcoal/Translator/TranslatableInterface.php @@ -1,8 +1,10 @@ translations; } - /** - * @return string - */ public function __toString(): string { return $this->toJson(); @@ -94,7 +91,6 @@ public function __toString(): string /** * @param integer $options From {@see \json_encode()} flags. - * @return string */ public function toJson(int $options = 0): string { @@ -128,10 +124,9 @@ public function map(callable $callback): self * This method is to maintain compatibility with {@see Translation}. * * @param (callable(mixed, string): mixed) $callback Function to apply to each value. - * @return self - * * @deprecated Will be removed in future version in favor of keeping this class Immutable. */ + #![\Deprecated(message: 'Will be removed in future version in favor of keeping this class Immutable.')] public function each(callable $callback): self { foreach ($this->translations as $locale => $translation) { @@ -146,10 +141,9 @@ public function each(callable $callback): self * This method is to maintain compatibility with {@see Translation}. * * @param (callable(mixed): mixed) $callback Function to apply to each value. - * @return self - * * @deprecated Will be removed in future version in favor of keeping this class Immutable. */ + #![\Deprecated(message: 'Will be removed in future version in favor of keeping this class Immutable.')] public function sanitize(callable $callback): self { foreach ($this->translations as $locale => $translation) { @@ -181,7 +175,6 @@ public function trans(TranslatorInterface $translator, ?string $locale = null) /** * @param string $offset The requested offset to test. - * @return boolean * @throws InvalidArgumentException If array key isn't a string. * @see ArrayAccess::offsetExists() */ @@ -190,7 +183,7 @@ public function offsetExists($offset): bool if (!is_string($offset)) { throw new InvalidArgumentException(sprintf( 'Invalid language; must be a string, received %s', - (is_object($offset) ? get_class($offset) : gettype($offset)) + (get_debug_type($offset)) )); } @@ -204,12 +197,12 @@ public function offsetExists($offset): bool * @throws DomainException If the array key is not found. * @see ArrayAccess::offsetGet() */ - public function offsetGet($offset) + public function offsetGet($offset): mixed { if (!is_string($offset)) { throw new InvalidArgumentException(sprintf( 'Invalid language; must be a string, received %s', - (is_object($offset) ? get_class($offset) : gettype($offset)) + (get_debug_type($offset)) )); } @@ -226,23 +219,22 @@ public function offsetGet($offset) /** * @param string $offset The lang offset to set. * @param mixed $value The value to store. - * @return void * @throws InvalidArgumentException If array key isn't a string. * @see ArrayAccess::offsetSet() */ - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { if (!is_string($offset)) { throw new InvalidArgumentException(sprintf( 'Invalid language; must be a string, received %s', - (is_object($offset) ? get_class($offset) : gettype($offset)) + (get_debug_type($offset)) )); } if (!is_string($value)) { throw new InvalidArgumentException(sprintf( 'Translation must be a string, received %s', - (is_object($value) ? get_class($value) : gettype($value)) + (get_debug_type($value)) )); } @@ -251,15 +243,14 @@ public function offsetSet($offset, $value) /** * @param string $offset The language offset to unset. - * @return void * @throws InvalidArgumentException If array key isn't a string. */ - public function offsetUnset($offset) + public function offsetUnset($offset): void { if (!is_string($offset)) { throw new InvalidArgumentException(sprintf( 'Invalid language; must be a string, received %s', - (is_object($offset) ? get_class($offset) : gettype($offset)) + (get_debug_type($offset)) )); } diff --git a/packages/translator/src/Charcoal/Translator/Translation.php b/packages/translator/src/Charcoal/Translator/Translation.php index 1cf59f6c7..e3a486f3a 100644 --- a/packages/translator/src/Charcoal/Translator/Translation.php +++ b/packages/translator/src/Charcoal/Translator/Translation.php @@ -7,17 +7,19 @@ use DomainException; use InvalidArgumentException; use JsonSerializable; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; /** * A translation object holds a localized message in all available locales. * * Available locales is provided with a locales manager. */ +#[\AllowDynamicProperties] class Translation implements TranslatableInterface, ArrayAccess, - JsonSerializable + JsonSerializable, + \Stringable { /** * The object's translations. @@ -28,26 +30,18 @@ class Translation implements */ private $val = []; - /** - * @var LocalesManager - */ - private $manager; - /** * @param Translation|array|string $val The translation values. * @param LocalesManager $manager A LocalesManager instance. */ - public function __construct($val, LocalesManager $manager) + public function __construct($val, private readonly LocalesManager $manager) { - $this->manager = $manager; $this->setVal($val); } /** * Output the current language's value, when cast to string. - * - * @return string */ - public function __toString() + public function __toString(): string { $lang = $this->manager->currentLocale(); if (isset($this->val[$lang])) { @@ -69,16 +63,15 @@ public function data() /** * @param string $lang A language identifier. - * @return boolean * @see ArrayAccess::offsetExists() * @throws InvalidArgumentException If array key isn't a string. */ - public function offsetExists($lang) + public function offsetExists($lang): bool { if (!is_string($lang)) { throw new InvalidArgumentException(sprintf( 'Invalid language; must be a string, received %s', - (is_object($lang) ? get_class($lang) : gettype($lang)) + (get_debug_type($lang)) )); } @@ -92,12 +85,12 @@ public function offsetExists($lang) * @throws InvalidArgumentException If array key isn't a string. * @throws DomainException If the array key is not found. */ - public function offsetGet($lang) + public function offsetGet($lang): string { if (!is_string($lang)) { throw new InvalidArgumentException(sprintf( 'Invalid language; must be a string, received %s', - (is_object($lang) ? get_class($lang) : gettype($lang)) + (get_debug_type($lang)) )); } @@ -114,23 +107,22 @@ public function offsetGet($lang) /** * @param string $lang A language identifier. * @param string $val A translation value. - * @return void * @see ArrayAccess::offsetSet() * @throws InvalidArgumentException If array key isn't a string. */ - public function offsetSet($lang, $val) + public function offsetSet($lang, $val): void { if (!is_string($lang)) { throw new InvalidArgumentException(sprintf( 'Invalid language; must be a string, received %s', - (is_object($lang) ? get_class($lang) : gettype($lang)) + (get_debug_type($lang)) )); } if (!is_string($val)) { throw new InvalidArgumentException(sprintf( 'Translation must be a string, received %s', - (is_object($val) ? get_class($val) : gettype($val)) + (get_debug_type($val)) )); } @@ -139,16 +131,15 @@ public function offsetSet($lang, $val) /** * @param string $lang A language identifier. - * @return void * @see ArrayAccess::offsetUnset() * @throws InvalidArgumentException If array key isn't a string. */ - public function offsetUnset($lang) + public function offsetUnset($lang): void { if (!is_string($lang)) { throw new InvalidArgumentException(sprintf( 'Invalid language; must be a string, received %s', - (is_object($lang) ? get_class($lang) : gettype($lang)) + (get_debug_type($lang)) )); } @@ -161,7 +152,7 @@ public function offsetUnset($lang) * @return string[] * @see JsonSerializable::jsonSerialize() */ - public function jsonSerialize() + public function jsonSerialize(): array { return $this->data(); } @@ -171,9 +162,8 @@ public function jsonSerialize() * * @param callable $callback The callback function to run for each value. * The callback takes on the value only. - * @return self */ - public function sanitize(callable $callback) + public function sanitize(callable $callback): static { foreach ($this->val as $lang => $val) { $this->val[$lang] = call_user_func($callback, $val); @@ -186,9 +176,8 @@ public function sanitize(callable $callback) * * @param callable $callback The callback function to run for each value. * The callback takes on two parameters. The value being the first, and the language code second. - * @return self */ - public function each(callable $callback) + public function each(callable $callback): static { foreach ($this->val as $lang => $val) { $this->val[$lang] = call_user_func($callback, $val, $lang); @@ -219,10 +208,9 @@ public function trans(TranslatorInterface $translator, ?string $locale = null) * - array: All languages available in the array. The format of the array should * be a hash in the `lang` => `string` format. * - string: The value will be assigned to the current language. - * @return self * @throws InvalidArgumentException If language or value are invalid. */ - private function setVal($val) + private function setVal($val): static { if ($val instanceof Translation) { $this->val = $val->data(); @@ -232,7 +220,7 @@ private function setVal($val) if (!is_string($lang)) { throw new InvalidArgumentException(sprintf( 'Invalid language; must be a string, received %s', - (is_object($lang) ? get_class($lang) : gettype($lang)) + (get_debug_type($lang)) )); } diff --git a/packages/translator/src/Charcoal/Translator/Translator.php b/packages/translator/src/Charcoal/Translator/Translator.php index 20a86ba54..b3b292beb 100644 --- a/packages/translator/src/Charcoal/Translator/Translator.php +++ b/packages/translator/src/Charcoal/Translator/Translator.php @@ -2,11 +2,11 @@ namespace Charcoal\Translator; +use AllowDynamicProperties; use RuntimeException; // From 'symfony/translation' use Symfony\Component\Translation\Formatter\MessageFormatter; use Symfony\Component\Translation\Formatter\MessageFormatterInterface; -use Symfony\Component\Translation\MessageSelector; use Symfony\Component\Translation\Translator as SymfonyTranslator; // From 'charcoal-translator' use Charcoal\Translator\LocalesManager; @@ -18,35 +18,25 @@ * Extends the Symfony translator to allow returned values in a "Translation" oject, * containing localizations for all locales. */ +#[AllowDynamicProperties] class Translator extends SymfonyTranslator { /** * The locales manager. - * - * @var LocalesManager - */ - private $manager; - - /** - * The message selector. - * - * @var MessageSelector */ - private $selector; + private \Charcoal\Translator\LocalesManager $manager; /** * The message formatter. - * - * @var MessageFormatterInterface */ - private $formatter; + private \Symfony\Component\Translation\Formatter\MessageFormatterInterface $formatter; /** * The loaded domains. * * @var string[] */ - private $domains = [ 'messages' ]; + private array $domains = [ 'messages' ]; /** * @param array $data Translator dependencies. @@ -55,15 +45,9 @@ public function __construct(array $data) { $this->setManager($data['manager']); - // Ensure Charcoal has control of the message selector. - if (!isset($data['message_selector'])) { - $data['message_selector'] = new MessageSelector(); - } - $this->setSelector($data['message_selector']); - // Ensure Charcoal has control of the message formatter. if (!isset($data['message_formatter'])) { - $data['message_formatter'] = new MessageFormatter($data['message_selector']); + $data['message_formatter'] = new MessageFormatter(); } $this->setFormatter($data['message_formatter']); @@ -75,7 +59,7 @@ public function __construct(array $data) $data = array_merge($defaults, $data); // If 'symfony/config' is not installed, DON'T use cache. - if (!class_exists('\Symfony\Component\Config\ConfigCacheFactory', false)) { + if (!class_exists(\Symfony\Component\Config\ConfigCacheFactory::class, false)) { $data['cache_dir'] = null; } @@ -95,9 +79,9 @@ public function __construct(array $data) * @param mixed $resource The resource name. * @param string $locale The locale. * @param string|null $domain The domain. - * @return void */ - public function addResource($format, $resource, $locale, $domain = null) + #[\Override] + public function addResource(string $format, mixed $resource, string $locale, ?string $domain = null): void { if (null !== $domain) { $this->domains[] = $domain; @@ -111,7 +95,7 @@ public function addResource($format, $resource, $locale, $domain = null) * * @return string[] */ - public function availableDomains() + public function availableDomains(): array { return $this->domains; } @@ -125,7 +109,7 @@ public function availableDomains() * @param string|null $domain The domain for the message or NULL to use the default. * @return Translation|null The translation object or NULL if the value is not translatable. */ - public function translation($val, array $parameters = [], $domain = null) + public function translation($val, array $parameters = [], ?string $domain = null): ?\Charcoal\Translator\Translation { if ($this->isValidTranslation($val) === false) { return null; @@ -158,7 +142,7 @@ public function translation($val, array $parameters = [], $domain = null) * @param string|null $locale The locale or NULL to use the default. * @return string The translated string */ - public function translate($val, array $parameters = [], $domain = null, $locale = null) + public function translate($val, array $parameters = [], ?string $domain = null, $locale = null): string { if ($locale === null) { $locale = $this->getLocale(); @@ -198,7 +182,7 @@ public function translate($val, array $parameters = [], $domain = null, $locale * @param string|null $domain The domain for the message or NULL to use the default. * @return Translation|null The translation object or NULL if the value is not translatable. */ - public function translationChoice($val, $number, array $parameters = [], $domain = null) + public function translationChoice($val, $number, array $parameters = [], ?string $domain = null): ?\Charcoal\Translator\Translation { if ($this->isValidTranslation($val) === false) { return null; @@ -212,12 +196,9 @@ public function translationChoice($val, $number, array $parameters = [], $domain $localized = (string)$translation; foreach ($this->availableLocales() as $lang) { if (!isset($translation[$lang]) || $translation[$lang] === $val) { - $translation[$lang] = $this->transChoice($localized, $number, $parameters, $domain, $lang); + $translation[$lang] = $this->trans($localized, $parameters, $domain, $lang); } else { - $translation[$lang] = strtr( - $this->selector()->choose($translation[$lang], (int)$number, $lang), - $parameters - ); + $translation[$lang] = $this->formatter()->format($translation[$lang], $lang, $parameters); } } @@ -236,7 +217,7 @@ public function translationChoice($val, $number, array $parameters = [], $domain * @param string|null $locale The locale or NULL to use the default. * @return string The translated string */ - public function translateChoice($val, $number, array $parameters = [], $domain = null, $locale = null) + public function translateChoice($val, $number, array $parameters = [], $domain = null, $locale = null): string { if ($locale === null) { $locale = $this->getLocale(); @@ -247,10 +228,7 @@ public function translateChoice($val, $number, array $parameters = [], $domain = '%count%' => $number, ], $parameters); - return strtr( - $this->selector()->choose($val[$locale], (int)$number, $locale), - $parameters - ); + return $this->formatter()->format($val[$locale], $locale, $parameters); } if (is_object($val) && method_exists($val, '__toString')) { @@ -259,7 +237,7 @@ public function translateChoice($val, $number, array $parameters = [], $domain = if (is_string($val)) { if ($val !== '') { - return $this->transChoice($val, $number, $parameters, $domain, $locale); + return $this->trans($val, array_merge(['%count%' => $number], $parameters), $domain, $locale); } return ''; @@ -288,7 +266,7 @@ public function locales() * * @return string[] */ - public function availableLocales() + public function availableLocales(): array { return $this->manager()->availableLocales(); } @@ -298,9 +276,9 @@ public function availableLocales() * * @see SymfonyTranslator::setLocale() Ensure that the method also changes the locales manager's language. * @param string $locale The locale. - * @return void */ - public function setLocale($locale) + #[\Override] + public function setLocale(string $locale): void { parent::setLocale($locale); @@ -311,47 +289,20 @@ public function setLocale($locale) * Set the locales manager. * * @param LocalesManager $manager The locales manager. - * @return void */ - private function setManager(LocalesManager $manager) + private function setManager(LocalesManager $manager): void { $this->manager = $manager; } /** * Retrieve the locales manager. - * - * @return LocalesManager */ - protected function manager() + protected function manager(): \Charcoal\Translator\LocalesManager { return $this->manager; } - /** - * Set the message selector. - * - * The {@see SymfonyTranslator} keeps the message selector private (as of 3.3.2), - * thus we must explicitly require it in this class to guarantee access. - * - * @param MessageSelector $selector The selector. - * @return void - */ - public function setSelector(MessageSelector $selector) - { - $this->selector = $selector; - } - - /** - * Retrieve the message selector. - * - * @return MessageSelector - */ - protected function selector() - { - return $this->selector; - } - /** * Set the message formatter. * @@ -359,19 +310,16 @@ protected function selector() * thus we must explicitly require it in this class to guarantee access. * * @param MessageFormatterInterface $formatter The formatter. - * @return void */ - public function setFormatter(MessageFormatterInterface $formatter) + public function setFormatter(MessageFormatterInterface $formatter): void { $this->formatter = $formatter; } /** * Retrieve the message formatter. - * - * @return MessageFormatterInterface */ - protected function formatter() + protected function formatter(): \Symfony\Component\Translation\Formatter\MessageFormatterInterface { return $this->formatter; } @@ -384,7 +332,7 @@ protected function formatter() * @param string|null $locale The locale or NULL to use the default. * @return boolean TRUE if the message has a translation, FALSE otherwise. */ - public function hasTrans($id, $domain = null, $locale = null) + public function hasTrans(string $id, $domain = null, ?string $locale = null): bool { if (null === $domain) { $domain = 'messages'; @@ -401,7 +349,7 @@ public function hasTrans($id, $domain = null, $locale = null) * @param string|null $locale The locale or NULL to use the default. * @return boolean TRUE if the message has a translation, FALSE otherwise. */ - public function transExists($id, $domain = null, $locale = null) + public function transExists(string $id, $domain = null, ?string $locale = null): bool { if (null === $domain) { $domain = 'messages'; @@ -423,7 +371,7 @@ protected function isValidTranslation($val) } if (is_string($val)) { - return !empty(trim($val)); + return !in_array(trim($val), ['', '0'], true); } if ($val instanceof Translation) { @@ -431,17 +379,9 @@ protected function isValidTranslation($val) } if (is_array($val)) { - return !!array_filter( + return (bool)array_filter( $val, - function ($v, $k) { - if (is_string($k) && strlen($k) > 0) { - if (is_string($v) && strlen($v) > 0) { - return true; - } - } - - return false; - }, + fn($v, $k): bool => is_string($k) && $k !== '' && (is_string($v) && $v !== ''), ARRAY_FILTER_USE_BOTH ); } diff --git a/packages/translator/src/Charcoal/Translator/TranslatorAwareTrait.php b/packages/translator/src/Charcoal/Translator/TranslatorAwareTrait.php index b25924f3c..6ce75a14d 100644 --- a/packages/translator/src/Charcoal/Translator/TranslatorAwareTrait.php +++ b/packages/translator/src/Charcoal/Translator/TranslatorAwareTrait.php @@ -23,9 +23,8 @@ trait TranslatorAwareTrait * Set the translator service. * * @param Translator $translator The Translator service. - * @return void */ - protected function setTranslator(Translator $translator) + protected function setTranslator(Translator $translator): void { $this->translator = $translator; } @@ -34,9 +33,8 @@ protected function setTranslator(Translator $translator) * Retrieve the translator service. * * @throws RuntimeException If the translator is accessed before having been set. - * @return Translator */ - protected function translator() + protected function translator(): Translator { if ($this->translator === null) { throw new RuntimeException( diff --git a/packages/translator/src/Charcoal/Translator/TranslatorConfig.php b/packages/translator/src/Charcoal/Translator/TranslatorConfig.php index 9063debdb..a9c231b33 100644 --- a/packages/translator/src/Charcoal/Translator/TranslatorConfig.php +++ b/packages/translator/src/Charcoal/Translator/TranslatorConfig.php @@ -26,33 +26,25 @@ class TranslatorConfig extends AbstractConfig * * @var string[] */ - private $paths; + private ?array $paths = null; /** * Mapping of domains/locales/messages. - * - * @var array */ - private $translations; + private ?array $translations = null; /** * Debug mode. - * - * @var boolean */ - private $debug; + private ?bool $debug = null; /** * The directory to use for the cache. - * - * @var string */ - private $cacheDir; + private ?string $cacheDir = null; - /** - * @return array - */ - public function defaults() + #[\Override] + public function defaults(): array { return [ 'loaders' => [ @@ -72,7 +64,7 @@ public function defaults() * @throws InvalidArgumentException If the loader is invalid. * @return TranslatorConfig Chainable */ - public function setLoaders(array $loaders) + public function setLoaders(array $loaders): static { $this->loaders = []; foreach ($loaders as $loader) { @@ -99,7 +91,7 @@ public function loaders() * @param string[] $paths The "paths" (search pattern) to look into for translation resources. * @return TranslatorConfig Chainable */ - public function setPaths(array $paths) + public function setPaths(array $paths): static { $this->paths = []; $this->addPaths($paths); @@ -111,7 +103,7 @@ public function setPaths(array $paths) * @throws InvalidArgumentException If the path is not a string. * @return TranslatorConfig Chainable */ - public function addPaths(array $paths) + public function addPaths(array $paths): static { foreach ($paths as $path) { if (!is_string($path)) { @@ -127,7 +119,7 @@ public function addPaths(array $paths) /** * @return string[] */ - public function paths() + public function paths(): ?array { return $this->paths; } @@ -150,17 +142,17 @@ public function paths() * @throws InvalidArgumentException If the path is not a string. * @return TranslatorConfig Chainable */ - public function setTranslations(array $translations) + public function setTranslations(array $translations): static { $this->translations = []; - foreach ($translations as $domain => $data) { + foreach ($translations as $data) { if (!is_array($data)) { throw new InvalidArgumentException( 'Translator translations must be a 3-level array' ); } - foreach ($data as $locale => $messages) { + foreach ($data as $messages) { if (!is_array($messages)) { throw new InvalidArgumentException( 'Translator translations must be a 3-level array' @@ -179,7 +171,7 @@ public function setTranslations(array $translations) * * @return array */ - public function translations() + public function translations(): ?array { return $this->translations; } @@ -188,16 +180,16 @@ public function translations() * @param boolean $debug The debug flag. * @return TranslatorConfig Chainable */ - public function setDebug($debug) + public function setDebug($debug): static { - $this->debug = !!$debug; + $this->debug = (bool)$debug; return $this; } /** * @return boolean */ - public function debug() + public function debug(): ?bool { return $this->debug; } @@ -207,7 +199,7 @@ public function debug() * @throws InvalidArgumentException If the cache dir argument is not a string. * @return TranslatorConfig Chainable */ - public function setCacheDir($cacheDir) + public function setCacheDir($cacheDir): static { if (!is_string($cacheDir)) { throw new InvalidArgumentException( @@ -221,15 +213,12 @@ public function setCacheDir($cacheDir) /** * @return string */ - public function cacheDir() + public function cacheDir(): ?string { return $this->cacheDir; } - /** - * @return array - */ - private function availableLoaders() + private function availableLoaders(): array { return [ 'csv', diff --git a/packages/translator/tests/Charcoal/Translator/AbstractTestCase.php b/packages/translator/tests/Charcoal/Translator/AbstractTestCase.php index 0cb15733f..800e0c5a6 100644 --- a/packages/translator/tests/Charcoal/Translator/AbstractTestCase.php +++ b/packages/translator/tests/Charcoal/Translator/AbstractTestCase.php @@ -1,5 +1,7 @@ registerConfig($container); $this->registerBaseUrl($container); @@ -70,9 +66,8 @@ public function registerBaseServices(Container $container) * Register the unit tests required services. * * @param Container $container A DI container. - * @return void */ - public function registerModelServices(Container $container) + public function registerModelServices(Container $container): void { $this->registerLogger($container); $this->registerTranslator($container); @@ -86,9 +81,8 @@ public function registerModelServices(Container $container) * Register the unit tests required services. * * @param Container $container A DI container. - * @return void */ - public function registerAdminServices(Container $container) + public function registerAdminServices(Container $container): void { $this->registerClimate($container); $this->registerAdminBaseUrl($container); @@ -98,71 +92,62 @@ public function registerAdminServices(Container $container) * Setup the application's base URI. * * @param Container $container A DI container. - * @return void */ - public function registerBaseUrl(Container $container) + public function registerBaseUrl(Container $container): void { - $container['base-url'] = function () { - return Uri::createFromString('https://example.com:8080/foo/bar?abc=123'); - }; + $container['base-url'] = (fn() => Uri::createFromString('https://example.com:8080/foo/bar?abc=123')); } /** * Setup the admin's base URI. * * @param Container $container A DI container. - * @return void */ - public function registerAdminBaseUrl(Container $container) + public function registerAdminBaseUrl(Container $container): void { - $container['admin/base-url'] = function () { - return Uri::createFromString('https://example.com:8080/admin/qux?abc=123'); - }; + $container['admin/base-url'] = (fn() => Uri::createFromString('https://example.com:8080/admin/qux?abc=123')); } /** * Setup the application configset. * * @param Container $container A DI container. - * @return void */ - public function registerConfig(Container $container) + public function registerConfig(Container $container): void { - $container['config'] = function () { - return new AppConfig([ - 'base_path' => realpath(__DIR__ . '/../../..'), - 'locales' => [ - 'languages' => [ - 'en' => [ 'locale' => 'en-US', 'locales' => [ 'en_US.UTF-8', 'en_US.utf8', 'en_US' ] ], - 'fr' => [ 'locale' => 'fr-FR' ] - ], - 'default_language' => 'en', - 'fallback_languages' => [ 'en' ] + $container['config'] = (fn(): \Charcoal\App\AppConfig => new AppConfig([ + 'base_path' => realpath(__DIR__ . '/../../..'), + 'locales' => [ + 'languages' => [ + 'en' => [ 'locale' => 'en-US', 'locales' => [ 'en_US.UTF-8', 'en_US.utf8', 'en_US' ] ], + 'fr' => [ 'locale' => 'fr-FR' ] ], - 'translator' => [ - 'paths' => [ - '/Charcoal/Translator/Fixture/translations' - ], - 'translations' => [ - 'messages' => [ - 'en' => [ - 'foo' => 'FOO' - ], - 'fr' => [ - 'foo' => 'OOF' - ] - ] - ], - 'auto_detect' => true, - 'debug' => false + 'default_language' => 'en', + 'fallback_languages' => [ 'en' ] + ], + 'translator' => [ + 'paths' => [ + '/Charcoal/Translator/Fixture/translations' ], - 'view' => [ - 'paths' => [ - '/Charcoal/Translator/Fixture/views' + 'translations' => [ + 'messages' => [ + 'en' => [ + 'foo' => 'FOO' + ], + 'fr' => [ + 'foo' => 'OOF' + ] ] + ], + 'auto_detect' => true, + 'debug' => false + ], + 'view' => [ + 'paths' => [ + '/Charcoal/Translator/Fixture/views' ] - ]); - }; + ] + ])); } /** @@ -171,11 +156,10 @@ public function registerConfig(Container $container) * Note: Uses SQLite to create a database in memory. * * @param Container $container A DI container. - * @return void */ - public function registerSource(Container $container) + public function registerSource(Container $container): void { - $container['database'] = function () { + $container['database'] = function (): \PDO { $pdo = new PDO('sqlite::memory:'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; @@ -186,56 +170,42 @@ public function registerSource(Container $container) * Setup the application's logging interface. * * @param Container $container A DI container. - * @return void */ - public function registerLogger(Container $container) + public function registerLogger(Container $container): void { - $container['logger'] = function () { - return new NullLogger(); - }; + $container['logger'] = (fn(): \Psr\Log\NullLogger => new NullLogger()); } /** * Setup the application's caching interface. * * @param Container $container A DI container. - * @return void */ - public function registerCache(Container $container) + public function registerCache(Container $container): void { - $container['cache'] = function () { - return new Pool(new Ephemeral()); - }; + $container['cache'] = (fn(): \Stash\Pool => new Pool(new Ephemeral())); } /** * Setup the application's translator service. * * @param Container $container A DI container. - * @return void */ - public function registerTranslator(Container $container) + public function registerTranslator(Container $container): void { - $container['locales/config'] = function (Container $container) { - return new LocalesConfig($container['config']['locales']); - }; + $container['locales/config'] = (fn(Container $container): \Charcoal\Translator\LocalesConfig => new LocalesConfig($container['config']['locales'])); - $container['locales/manager'] = function (Container $container) { - return new LocalesManager([ - 'locales' => $container['locales/config']['languages'], - 'default_language' => $container['locales/config']['default_language'], - 'fallback_languages' => $container['locales/config']['fallback_languages'] - ]); - }; + $container['locales/manager'] = (fn(Container $container): \Charcoal\Translator\LocalesManager => new LocalesManager([ + 'locales' => $container['locales/config']['languages'], + 'default_language' => $container['locales/config']['default_language'], + 'fallback_languages' => $container['locales/config']['fallback_languages'] + ])); - $container['translator/config'] = function (Container $container) { - return new TranslatorConfig($container['config']['translator']); - }; + $container['translator/config'] = (fn(Container $container): \Charcoal\Translator\TranslatorConfig => new TranslatorConfig($container['config']['translator'])); - $container['translator'] = function (Container $container) { + $container['translator'] = function (Container $container): \Charcoal\Translator\Translator { $translator = new Translator([ 'manager' => $container['locales/manager'], - 'message_selector' => new MessageSelector(), 'cache_dir' => null, 'debug' => $container['translator/config']['debug'] ]); @@ -250,100 +220,87 @@ public function registerTranslator(Container $container) * Setup the framework's metadata loader interface. * * @param Container $container A DI container. - * @return void */ - public function registerMetadataLoader(Container $container) + public function registerMetadataLoader(Container $container): void { - $container['metadata/loader'] = function (Container $container) { - return new MetadataLoader([ - 'cache' => $container['cache'], - 'logger' => $container['logger'], - 'base_path' => $container['config']['base_path'], - 'paths' => [ - 'metadata', - // Standalone - 'vendor/charcoal/property/metadata', - // Monorepo - '/../property/metadata' - ] - ]); - }; + $container['metadata/loader'] = (fn(Container $container): \Charcoal\Model\Service\MetadataLoader => new MetadataLoader([ + 'cache' => $container['cache'], + 'logger' => $container['logger'], + 'base_path' => $container['config']['base_path'], + 'paths' => [ + 'metadata', + // Standalone + 'vendor/charcoal/property/metadata', + // Monorepo + '/../property/metadata' + ] + ])); } /** * Setup the framework's data source factory. * * @param Container $container A DI container. - * @return void */ - public function registerSourceFactory(Container $container) + public function registerSourceFactory(Container $container): void { - $container['source/factory'] = function (Container $container) { - return new Factory([ - 'map' => [ - 'database' => DatabaseSource::class - ], - 'arguments' => [[ - 'logger' => $container['logger'], - 'cache' => $container['cache'], - 'pdo' => $container['database'] - ]] - ]); - }; + $container['source/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'map' => [ + 'database' => DatabaseSource::class + ], + 'arguments' => [[ + 'logger' => $container['logger'], + 'cache' => $container['cache'], + 'pdo' => $container['database'] + ]] + ])); } /** * Setup the framework's model factory. * * @param Container $container A DI container. - * @return void */ - public function registerModelFactory(Container $container) + public function registerModelFactory(Container $container): void { - $container['model/factory'] = function (Container $container) { - return new Factory([ - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'], - 'metadata_loader' => $container['metadata/loader'], - 'source_factory' => $container['source/factory'], - 'property_factory' => $container['property/factory'] - ]] - ]); - }; + $container['model/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'], + 'metadata_loader' => $container['metadata/loader'], + 'source_factory' => $container['source/factory'], + 'property_factory' => $container['property/factory'] + ]] + ])); } /** * Setup the framework's property factory. * * @param Container $container A DI container. - * @return void */ - public function registerPropertyFactory(Container $container) + public function registerPropertyFactory(Container $container): void { - $container['property/factory'] = function (Container $container) { - return new Factory([ - 'resolver_options' => [ - 'prefix' => '\\Charcoal\\Property\\', - 'suffix' => 'Property' - ], - 'arguments' => [[ - 'container' => $container, - 'database' => $container['database'], - 'logger' => $container['logger'], - 'translator' => $container['translator'] - ]] - ]); - }; + $container['property/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'resolver_options' => [ + 'prefix' => '\\Charcoal\\Property\\', + 'suffix' => 'Property' + ], + 'arguments' => [[ + 'container' => $container, + 'database' => $container['database'], + 'logger' => $container['logger'], + 'translator' => $container['translator'] + ]] + ])); } /** * Setup the CLImate library. * * @param Container $container A DI container. - * @return void */ - public function registerClimate(Container $container) + public function registerClimate(Container $container): void { $container['climate/system'] = function () { $system = Mockery::mock(Linux::class); @@ -370,11 +327,9 @@ public function registerClimate(Container $container) return $reader; }; - $container['climate/util'] = function (Container $container) { - return new UtilFactory($container['climate/system']); - }; + $container['climate/util'] = (fn(Container $container): \League\CLImate\Util\UtilFactory => new UtilFactory($container['climate/system'])); - $container['climate'] = function (Container $container) { + $container['climate'] = function (Container $container): \League\CLImate\CLImate { $climate = new CLImate(); $climate->setOutput($container['climate/output']); diff --git a/packages/translator/tests/Charcoal/Translator/LocalesConfigTest.php b/packages/translator/tests/Charcoal/Translator/LocalesConfigTest.php index a6490274d..6a7e2f346 100644 --- a/packages/translator/tests/Charcoal/Translator/LocalesConfigTest.php +++ b/packages/translator/tests/Charcoal/Translator/LocalesConfigTest.php @@ -15,25 +15,18 @@ class LocalesConfigTest extends AbstractTestCase { /** * Tested Class. - * - * @var LocalesConfig */ - private $obj; + private \Charcoal\Translator\LocalesConfig|array $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { $this->obj = new LocalesConfig(); } - /** - * @return void - */ - public function testDefaultsArrayAccess() + public function testDefaultsArrayAccess(): void { $this->assertArrayHasKey('en', $this->obj['languages']); $this->assertEquals('en', $this->obj['default_language']); @@ -41,10 +34,7 @@ public function testDefaultsArrayAccess() $this->assertFalse($this->obj['auto_detect']); } - /** - * @return void - */ - public function testSetLanguages() + public function testSetLanguages(): void { $langs = [ 'foo' => [ @@ -64,10 +54,7 @@ public function testSetLanguages() $this->assertEquals($langs, $this->obj['languages']); } - /** - * @return void - */ - public function testSetDefaultLanguage() + public function testSetDefaultLanguage(): void { $ret = $this->obj->setDefaultLanguage('foo'); $this->assertSame($ret, $this->obj); @@ -80,10 +67,7 @@ public function testSetDefaultLanguage() $this->obj->setDefaultLanguage(false); } - /** - * @return void - */ - public function testSetFallbackLanguages() + public function testSetFallbackLanguages(): void { $ret = $this->obj->setFallbackLanguages(['foo']); $this->assertSame($ret, $this->obj); diff --git a/packages/translator/tests/Charcoal/Translator/LocalesManagerTest.php b/packages/translator/tests/Charcoal/Translator/LocalesManagerTest.php index 7adad23d6..f7bcbd83d 100644 --- a/packages/translator/tests/Charcoal/Translator/LocalesManagerTest.php +++ b/packages/translator/tests/Charcoal/Translator/LocalesManagerTest.php @@ -15,15 +15,11 @@ class LocalesManagerTest extends AbstractTestCase { /** * Tested Class. - * - * @var LocalesManager */ - private $obj; + private \Charcoal\Translator\LocalesManager $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -37,10 +33,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testConstructorWithDefaultLanguage() + public function testConstructorWithDefaultLanguage(): void { $this->obj = new LocalesManager([ 'locales' => [ @@ -54,13 +47,10 @@ public function testConstructorWithDefaultLanguage() $this->assertEquals('bar', $this->obj->defaultLocale()); } - /** - * @return void - */ - public function testConstructorDefaultLanguageWithInvalidType() + public function testConstructorDefaultLanguageWithInvalidType(): void { $this->expectException(InvalidArgumentException::class); - $obj = new LocalesManager([ + new LocalesManager([ 'locales' => [ 'foo' => [] ], @@ -68,13 +58,10 @@ public function testConstructorDefaultLanguageWithInvalidType() ]); } - /** - * @return void - */ - public function testConstructorDefaultLanguageWithInvalidLocale() + public function testConstructorDefaultLanguageWithInvalidLocale(): void { $this->expectException(InvalidArgumentException::class); - $obj = new LocalesManager([ + new LocalesManager([ 'locales' => [ 'foo' => [] ], @@ -82,21 +69,15 @@ public function testConstructorDefaultLanguageWithInvalidLocale() ]); } - /** - * @return void - */ - public function testConstructorWithoutActiveLocales() + public function testConstructorWithoutActiveLocales(): void { $this->expectException(InvalidArgumentException::class); - $obj = new LocalesManager([ + new LocalesManager([ 'locales' => [] ]); } - /** - * @return void - */ - public function testLocales() + public function testLocales(): void { $locales = $this->obj->locales(); $this->assertArrayHasKey('foo', $locales); @@ -106,21 +87,15 @@ public function testLocales() $this->assertArrayNotHasKey('baz', $locales); } - /** - * @requires PHP >= 7.0 - * @return void - */ - public function testSortedLocalesInPhp7() + #[\PHPUnit\Framework\Attributes\RequiresPhp('>= 8.1.0')] + public function testSortedLocalesInPhp7(): void { $obj = $this->getLocalesManagerForSortedLocales(); $this->assertEquals([ 'xyz', 'zyx', 'qux', 'foo', 'bar' ], $obj->availableLocales()); } - /** - * @return LocalesManager - */ - public function getLocalesManagerForSortedLocales() + public function getLocalesManagerForSortedLocales(): \Charcoal\Translator\LocalesManager { return new LocalesManager([ 'locales' => [ @@ -134,18 +109,12 @@ public function getLocalesManagerForSortedLocales() ]); } - /** - * @return void - */ - public function testAvailableLocales() + public function testAvailableLocales(): void { $this->assertEquals([ 'foo', 'bar' ], $this->obj->availableLocales()); } - /** - * @return void - */ - public function testSetCurrentLocale() + public function testSetCurrentLocale(): void { $this->assertEquals('foo', $this->obj->currentLocale()); @@ -156,19 +125,13 @@ public function testSetCurrentLocale() $this->assertEquals('foo', $this->obj->currentLocale()); } - /** - * @return void - */ - public function testSetCurrentLocaleWithInvalidType() + public function testSetCurrentLocaleWithInvalidType(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setCurrentLocale(false); } - /** - * @return void - */ - public function testSetCurrentLocaleWithInvalidLocale() + public function testSetCurrentLocaleWithInvalidLocale(): void { $this->expectException(InvalidArgumentException::class); $this->obj->setCurrentLocale('qux'); diff --git a/packages/translator/tests/Charcoal/Translator/Middleware/LanguageMiddlewareTest.php b/packages/translator/tests/Charcoal/Translator/Middleware/LanguageMiddlewareTest.php index 3e09b5309..3b461da7f 100644 --- a/packages/translator/tests/Charcoal/Translator/Middleware/LanguageMiddlewareTest.php +++ b/packages/translator/tests/Charcoal/Translator/Middleware/LanguageMiddlewareTest.php @@ -27,21 +27,14 @@ class LanguageMiddlewareTest extends AbstractTestCase { /** * Tested Class. - * - * @var LanguageMiddleware */ - private $obj; + private \Charcoal\Translator\Middleware\LanguageMiddleware $obj; /** * Service Container. - * - * @var Container */ - private $container; + private \Pimple\Container|array|null $container = null; - /** - * @return void - */ public static function setupBeforeClass(): void { if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { @@ -49,9 +42,6 @@ public static function setupBeforeClass(): void } } - /** - * @return void - */ public static function teardownAfterClass(): void { if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { @@ -61,12 +51,10 @@ public static function teardownAfterClass(): void /** * Set up the test. - * - * @return void */ protected function setUp(): void { - $container = $this->getContainer(); + $this->getContainer(); $this->obj = $this->middlewareFactory([ 'use_params' => true @@ -77,9 +65,8 @@ protected function setUp(): void * Create LanguageMiddleware. * * @param array $data Extra options to pass to the middleare. - * @return LanguageMiddleware */ - protected function middlewareFactory(array $data = []) + protected function middlewareFactory(array $data = []): \Charcoal\Translator\Middleware\LanguageMiddleware { $container = $this->getContainer(); @@ -89,15 +76,13 @@ protected function middlewareFactory(array $data = []) 'default_language' => $container['translator']->getLocale(), ]; - $middleware = new LanguageMiddleware(array_replace($defaults, $data)); - - return $middleware; + return new LanguageMiddleware(array_replace($defaults, $data)); } /** * @return Container */ - private function getContainer() + private function getContainer(): \Pimple\Container|array { if ($this->container === null) { $this->container = new Container(); @@ -142,12 +127,12 @@ private function getContainer() * @param array $params The URI query string parameters. * @return UriInterface */ - private function mockUri($path = '', array $params = []) + private function mockUri(string $path = '', array $params = []): \PHPUnit\Framework\MockObject\MockObject { $uri = $this->createMock(UriInterface::class); - $uri->expects($this->any())->method('getPath')->will($this->returnValue($path)); - $uri->expects($this->any())->method('getQuery')->will($this->returnValue(http_build_query($params))); + $uri->method('getPath')->willReturn($path); + $uri->method('getQuery')->willReturn(http_build_query($params)); return $uri; } @@ -157,13 +142,13 @@ private function mockUri($path = '', array $params = []) * @param array $params The URI query string parameters. * @return ServerRequestInterface */ - private function mockRequest($path = '', array $params = []) + private function mockRequest(string $path = '', array $params = []): \PHPUnit\Framework\MockObject\MockObject { $request = $this->createMock(ServerRequestInterface::class); - $request->expects($this->any())->method('getUri')->will($this->returnValue($this->mockUri($path))); - $request->expects($this->any())->method('getRequestTarget')->will($this->returnValue($path)); - $request->expects($this->any())->method('getQueryParams')->will($this->returnValue($params)); + $request->method('getUri')->willReturn($this->mockUri($path)); + $request->method('getRequestTarget')->willReturn($path); + $request->method('getQueryParams')->willReturn($params); return $request; } @@ -171,47 +156,32 @@ private function mockRequest($path = '', array $params = []) /** * @return ResponseInterface */ - private function mockResponse() + private function mockResponse(): \PHPUnit\Framework\MockObject\MockObject { - $response = $this->createMock(ResponseInterface::class); - - return $response; + return $this->createMock(ResponseInterface::class); } - /** - * @return void - */ - public function testInvoke() + public function testInvoke(): void { $request = $this->mockRequest('/fr/foo/bar'); $response = $this->mockResponse(); - $next = function ($request, $response) { - return $response; - }; + $next = (fn($request, $response) => $response); - $return = call_user_func([ $this->obj, '__invoke' ], $request, $response, $next); + $return = call_user_func($this->obj->__invoke(...), $request, $response, $next); $this->assertEquals($response, $return); } - /** - * @return void - */ - public function testInvokeWithExcludedPath() + public function testInvokeWithExcludedPath(): void { $request = $this->mockRequest('/admin/foo/bar'); $response = $this->mockResponse(); - $next = function ($request, $response) { - return $response; - }; + $next = (fn($request, $response) => $response); - $return = call_user_func([ $this->obj, '__invoke' ], $request, $response, $next); + $return = call_user_func($this->obj->__invoke(...), $request, $response, $next); $this->assertEquals($response, $return); } - /** - * @return void - */ - public function testGetLanguageWithServerRequest() + public function testGetLanguageWithServerRequest(): void { $request = $this->mockRequest('/fr/foo/bar'); $return = $this->callMethod($this->obj, 'getLanguage', [ $request ]); @@ -232,23 +202,17 @@ public function testGetLanguageWithServerRequest() $this->assertEquals('fr', $return); } - /** - * @return void - */ - public function testGetLanguageWithClientRequest() + public function testGetLanguageWithClientRequest(): void { $request = $this->createMock(ClientRequestInterface::class); - $request->expects($this->any())->method('getUri')->will($this->returnValue($this->mockUri('/jp/foo/bar'))); - $request->expects($this->any())->method('getRequestTarget')->will($this->returnValue('/jp/foo/bar')); + $request->method('getUri')->willReturn($this->mockUri('/jp/foo/bar')); + $request->method('getRequestTarget')->willReturn('/jp/foo/bar'); $return = $this->callMethod($this->obj, 'getLanguage', [ $request ]); $this->assertEquals('fr', $return); } - /** - * @return void - */ - public function testGetLanguageUseHost() + public function testGetLanguageUseHost(): void { $this->obj = $this->middlewareFactory([ 'browser_language' => null, @@ -264,28 +228,26 @@ public function testGetLanguageUseHost() ]); $uri = $this->createMock(UriInterface::class); - $uri->expects($this->any())->method('getHost')->will($this->returnValue('fr.example.com')); + + $uri->method('getHost')->willReturn('fr.example.com'); $request = $this->createMock(ServerRequestInterface::class); - $request->expects($this->any())->method('getUri')->will($this->returnValue($uri)); + $request->method('getUri')->willReturn($uri); $return = $this->callMethod($this->obj, 'getLanguage', [ $request ]); $this->assertEquals('fr', $return); $uri = $this->createMock(UriInterface::class); - $uri->expects($this->any())->method('getHost')->will($this->returnValue('jp.example.com')); + $uri->method('getHost')->willReturn('jp.example.com'); $request = $this->createMock(ServerRequestInterface::class); - $request->expects($this->any())->method('getUri')->will($this->returnValue($uri)); + $request->method('getUri')->willReturn($uri); $return = $this->callMethod($this->obj, 'getLanguage', [ $request ]); $this->assertEquals('en', $return); } - /** - * @return void - */ - public function testGetLanguageUseHostWithBadHost() + public function testGetLanguageUseHostWithBadHost(): void { $this->obj = $this->middlewareFactory([ 'browser_language' => null, @@ -301,19 +263,16 @@ public function testGetLanguageUseHostWithBadHost() ]); $uri = $this->createMock(UriInterface::class); - $uri->expects($this->any())->method('getHost')->will($this->returnValue('jp.example.com')); + $uri->method('getHost')->willReturn('jp.example.com'); $request = $this->createMock(ServerRequestInterface::class); - $request->expects($this->any())->method('getUri')->will($this->returnValue($uri)); + $request->method('getUri')->willReturn($uri); $return = $this->callMethod($this->obj, 'getLanguage', [ $request ]); $this->assertEquals('en', $return); } - /** - * @return void - */ - public function testGetLanguageUseDefault() + public function testGetLanguageUseDefault(): void { $this->obj = $this->middlewareFactory([ 'browser_language' => null diff --git a/packages/translator/tests/Charcoal/Translator/Mock/StringClass.php b/packages/translator/tests/Charcoal/Translator/Mock/StringClass.php index 441dd117a..ad17231d0 100644 --- a/packages/translator/tests/Charcoal/Translator/Mock/StringClass.php +++ b/packages/translator/tests/Charcoal/Translator/Mock/StringClass.php @@ -1,29 +1,22 @@ str = $str; } - /** - * @return string - */ - public function __toString() + public function __toString(): string { return $this->str; } diff --git a/packages/translator/tests/Charcoal/Translator/ReflectionsTrait.php b/packages/translator/tests/Charcoal/Translator/ReflectionsTrait.php index 5c59e11dc..1d488c6de 100644 --- a/packages/translator/tests/Charcoal/Translator/ReflectionsTrait.php +++ b/packages/translator/tests/Charcoal/Translator/ReflectionsTrait.php @@ -18,13 +18,10 @@ trait ReflectionsTrait * * @param mixed $class The class name or object that contains the method. * @param string $name The method name to reflect. - * @return ReflectionMethod */ - public function getMethod($class, $name) + public function getMethod($class, $name): \ReflectionMethod { - $reflected = new ReflectionMethod($class, $name); - $reflected->setAccessible(true); - return $reflected; + return new ReflectionMethod($class, $name); } /** @@ -38,7 +35,7 @@ public function getMethod($class, $name) public function callMethod($object, $name, array $args = []) { $method = $this->getMethod($object, $name); - if (empty($args)) { + if ($args === []) { return $method->invoke($object); } else { return $method->invokeArgs($object, $args); @@ -65,13 +62,10 @@ public function callMethodWith($object, $name, ...$args) * * @param mixed $class The class name or object that contains the property. * @param string $name The property name to reflect. - * @return ReflectionProperty */ - public function getProperty($class, $name) + public function getProperty($class, $name): \ReflectionProperty { - $reflected = new ReflectionProperty($class, $name); - $reflected->setAccessible(true); - return $reflected; + return new ReflectionProperty($class, $name); } /** @@ -92,9 +86,8 @@ public function getPropertyValue($object, $name) * @param mixed $object The object to access. * @param string $name The property name to affect. * @param mixed $value The new value. - * @return void */ - public function setPropertyValue($object, $name, $value) + public function setPropertyValue($object, $name, $value): void { $this->getProperty($object, $name)->setValue($object, $value); } diff --git a/packages/translator/tests/Charcoal/Translator/Script/TranslationParserScriptTest.php b/packages/translator/tests/Charcoal/Translator/Script/TranslationParserScriptTest.php index 89ff3c06c..f8e63addb 100644 --- a/packages/translator/tests/Charcoal/Translator/Script/TranslationParserScriptTest.php +++ b/packages/translator/tests/Charcoal/Translator/Script/TranslationParserScriptTest.php @@ -23,10 +23,8 @@ class TranslationParserScriptTest extends AbstractTestCase { /** * Tested Class. - * - * @var TranslationParserScript */ - private $obj; + private \Charcoal\Translator\Script\TranslationParserScript $obj; /** * CLImate Output @@ -37,15 +35,11 @@ class TranslationParserScriptTest extends AbstractTestCase /** * Service Container. - * - * @var Container */ - private $container; + private \Pimple\Container $container; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -61,10 +55,7 @@ protected function setUp(): void ]); } - /** - * @return Container - */ - private function getContainer() + private function getContainer(): \Pimple\Container { $container = new Container(); $provider = new ContainerProvider(); @@ -76,10 +67,7 @@ private function getContainer() return $container; } - /** - * @return void - */ - public function testDefaultArguments() + public function testDefaultArguments(): void { $args = $this->obj->defaultArguments(); $this->assertArrayHasKey('domain', $args); diff --git a/packages/translator/tests/Charcoal/Translator/ServiceProvider/TranslatorServiceProviderTest.php b/packages/translator/tests/Charcoal/Translator/ServiceProvider/TranslatorServiceProviderTest.php index cefdd2bf2..f3b770b30 100644 --- a/packages/translator/tests/Charcoal/Translator/ServiceProvider/TranslatorServiceProviderTest.php +++ b/packages/translator/tests/Charcoal/Translator/ServiceProvider/TranslatorServiceProviderTest.php @@ -20,22 +20,16 @@ class TranslatorServiceProviderTest extends AbstractTestCase { /** * Tested Class. - * - * @var TranslatorServiceProvider */ - private $obj; + private \Charcoal\Translator\ServiceProvider\TranslatorServiceProvider $obj; /** * Service Container. - * - * @var Container */ - private $container; + private \Pimple\Container $container; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -105,81 +99,56 @@ protected function resetDefaultLanguage() $this->container['locales/default-language'] = $raw; } - /** - * @return void - */ - public function testKeys() + public function testKeys(): void { $this->assertFalse(isset($this->container['foofoobarbarbaz'])); $this->assertTrue(isset($this->container['locales/config'])); $this->assertTrue(isset($this->container['locales/available-languages'])); $this->assertTrue(isset($this->container['locales/default-language'])); $this->assertTrue(isset($this->container['locales/browser-language'])); - $this->assertTrue(isset($this->container['translator/message-selector'])); $this->assertTrue(isset($this->container['translator'])); $this->assertTrue(isset($this->container['middlewares/charcoal/translator/middleware/language'])); } - /** - * @return void - */ - public function testAvailableLanguages() + public function testAvailableLanguages(): void { $languages = $this->container['locales/available-languages']; $this->assertContains('en', $languages); } - /** - * @return void - */ - public function testLanguages() + public function testLanguages(): void { $languages = $this->container['locales/languages']; $this->assertArrayHasKey('en', $languages); } - /** - * @return void - */ - public function testDefaultLanguage() + public function testDefaultLanguage(): void { $defaultLanguage = $this->container['locales/default-language']; $this->assertEquals('en', $defaultLanguage); } - /** - * @return void - */ - public function testBrowserLanguageIsNullWithoutHttp() + public function testBrowserLanguageIsNullWithoutHttp(): void { $browserLanguage = $this->container['locales/browser-language']; $this->assertNull($browserLanguage); } - /** - * @return void - */ - public function testBrowserLanguage() + public function testBrowserLanguage(): void { $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'fr'; $browserLanguage = $this->container['locales/browser-language']; $this->assertEquals('fr', $browserLanguage); } - /** - * @return void - */ - public function testBrowserLanguageIsNullIfInvalidHttp() + public function testBrowserLanguageIsNullIfInvalidHttp(): void { $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'baz'; $browserLanguage = $this->container['locales/browser-language']; $this->assertNull($browserLanguage); } - /** - * @return void - */ - public function testDetectedLanguageIsNullWithoutHttp() + public function testDetectedLanguageIsNullWithoutHttp(): void { $this->container['locales/config']->setAutoDetect(true); @@ -191,10 +160,7 @@ public function testDetectedLanguageIsNullWithoutHttp() $this->container['locales/config']->setAutoDetect(false); } - /** - * @return void - */ - public function testDetectedLanguage() + public function testDetectedLanguage(): void { $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'fr'; $this->container['locales/config']->setAutoDetect(true); @@ -207,37 +173,25 @@ public function testDetectedLanguage() $this->container['locales/config']->setAutoDetect(false); } - /** - * @return void - */ - public function testFallbackLanguages() + public function testFallbackLanguages(): void { $fallbackLanguages = $this->container['locales/fallback-languages']; $this->assertEquals([ 'en' ], $fallbackLanguages); } - /** - * @return void - */ - public function testLanguageManager() + public function testLanguageManager(): void { $manager = $this->container['locales/manager']; $this->assertInstanceOf(LocalesManager::class, $manager); } - /** - * @return void - */ - public function testTranslator() + public function testTranslator(): void { $translator = $this->container['translator']; $this->assertInstanceOf(Translator::class, $translator); } - /** - * @return void - */ - public function testMiddleware() + public function testMiddleware(): void { $middleware = $this->container['middlewares/charcoal/translator/middleware/language']; $this->assertInstanceOf(LanguageMiddleware::class, $middleware); diff --git a/packages/translator/tests/Charcoal/Translator/TranslationTest.php b/packages/translator/tests/Charcoal/Translator/TranslationTest.php index b189a175a..fcaaee3fe 100644 --- a/packages/translator/tests/Charcoal/Translator/TranslationTest.php +++ b/packages/translator/tests/Charcoal/Translator/TranslationTest.php @@ -15,17 +15,11 @@ */ class TranslationTest extends AbstractTestCase { - /** - * @var LocalesManager - */ - private $localesManager; + private ?\Charcoal\Translator\LocalesManager $localesManager = null; - /** - * @return LocalesManager - */ - private function localesManager() + private function localesManager(): \Charcoal\Translator\LocalesManager { - if ($this->localesManager === null) { + if (!$this->localesManager instanceof \Charcoal\Translator\LocalesManager) { $this->localesManager = new LocalesManager([ 'locales' => [ 'en' => [ @@ -44,10 +38,7 @@ private function localesManager() return $this->localesManager; } - /** - * @return void - */ - public function testConstructorWithStringParam() + public function testConstructorWithStringParam(): void { $obj = new Translation('Hello!', $this->localesManager()); @@ -58,10 +49,7 @@ public function testConstructorWithStringParam() $this->assertFalse(isset($obj['fr'])); } - /** - * @return void - */ - public function testConstructorWithArrayParam() + public function testConstructorWithArrayParam(): void { $obj = new Translation([ 'en' => 'Hello!', 'fr' => 'Bonjour!' ], $this->localesManager()); @@ -74,10 +62,7 @@ public function testConstructorWithArrayParam() $this->assertFalse(isset($obj['es'])); } - /** - * @return void - */ - public function testConstructorWithObjectParam() + public function testConstructorWithObjectParam(): void { $trans = new Translation([ 'en' => 'Hello!', 'fr' => 'Bonjour!' ], $this->localesManager()); $obj = new Translation($trans, $this->localesManager()); @@ -91,19 +76,13 @@ public function testConstructorWithObjectParam() $this->assertFalse(isset($obj['es'])); } - /** - * @return void - */ - public function testConstructorWithInvalidParam() + public function testConstructorWithInvalidParam(): void { $this->expectException(InvalidArgumentException::class); - $obj = new Translation(false, $this->localesManager()); + new Translation(false, $this->localesManager()); } - /** - * @return void - */ - public function testToString() + public function testToString(): void { $manager = $this->localesManager(); @@ -118,10 +97,7 @@ public function testToString() $this->assertEquals('', (string)$obj); } - /** - * @return void - */ - public function testArraySet() + public function testArraySet(): void { $obj = new Translation('Hello!', $this->localesManager()); $this->assertEquals('Hello!', (string)$obj); @@ -130,19 +106,13 @@ public function testArraySet() $this->assertEquals('Charcoal', (string)$obj); } - /** - * @return void - */ - public function testArrayGet() + public function testArrayGet(): void { $obj = new Translation('Charcoal', $this->localesManager()); $this->assertEquals('Charcoal', $obj['en']); } - /** - * @return void - */ - public function testArrayUnset() + public function testArrayUnset(): void { $obj = new Translation('Hello!', $this->localesManager()); $this->assertTrue(isset($obj['en'])); @@ -151,102 +121,72 @@ public function testArrayUnset() $this->assertFalse(isset($obj['en'])); } - /** - * @return void - */ - public function testOffsetGetThrowsException() + public function testOffsetGetThrowsException(): void { $this->expectException(InvalidArgumentException::class); $obj = new Translation('Hello!', $this->localesManager()); - $ret = $obj[0]; + $obj[0]; } - /** - * @return void - */ - public function testOffsetGetThrowsException2() + public function testOffsetGetThrowsException2(): void { $this->expectException(DomainException::class); $obj = new Translation('Hello!', $this->localesManager()); - $ret = $obj['fr']; + $obj['fr']; } - /** - * @return void - */ - public function testOffsetSetThrowsException() + public function testOffsetSetThrowsException(): void { $this->expectException(InvalidArgumentException::class); $obj = new Translation('Hello!', $this->localesManager()); $obj[0] = 'en'; } - /** - * @return void - */ - public function testOffsetSetThrowsException2() + public function testOffsetSetThrowsException2(): void { $this->expectException(InvalidArgumentException::class); $obj = new Translation('Hello!', $this->localesManager()); $obj['en'] = []; } - /** - * @return void - */ - public function testOffsetExistThrowsException() + public function testOffsetExistThrowsException(): void { $this->expectException(InvalidArgumentException::class); $obj = new Translation('Hello!', $this->localesManager()); - isset($obj[0]); + $obj[0]; } - /** - * @return void - */ - public function testOffsetUnsetThrowsException() + public function testOffsetUnsetThrowsException(): void { $this->expectException(InvalidArgumentException::class); $obj = new Translation('Hello!', $this->localesManager()); unset($obj[0]); } - /** - * @return void - */ - public function testInvalidValueThrowsException() + public function testInvalidValueThrowsException(): void { $this->expectException(InvalidArgumentException::class); - $obj = new Translation([ 'en' ], $this->localesManager()); + new Translation([ 'en' ], $this->localesManager()); } - /** - * @return void - */ - public function testSanitize() + public function testSanitize(): void { $obj = new Translation(' Hello! ', $this->localesManager()); $obj->sanitize('trim'); $this->assertEquals([ 'en' => 'Hello!' ], $obj->data()); } - /** - * @return void - */ - public function testEach() + public function testEach(): void { $obj = new Translation(' Hello! ', $this->localesManager()); - $obj->each(function ($val, $lang) { + $obj->each(function ($val, $lang): string { $this->assertEquals('en', $lang); return trim($val); }); $this->assertEquals([ 'en' => 'Hello!' ], $obj->data()); } - /** - * @return void - */ - public function testJsonSerialize() + public function testJsonSerialize(): void { $obj = new Translation('Hello!', $this->localesManager()); $ret = json_encode($obj); diff --git a/packages/translator/tests/Charcoal/Translator/TranslatorAwareTraitTest.php b/packages/translator/tests/Charcoal/Translator/TranslatorAwareTraitTest.php index 5cb0eb161..72a2378ff 100644 --- a/packages/translator/tests/Charcoal/Translator/TranslatorAwareTraitTest.php +++ b/packages/translator/tests/Charcoal/Translator/TranslatorAwareTraitTest.php @@ -17,34 +17,26 @@ class TranslatorAwareTraitTest extends AbstractTestCase { /** * Tested Class. - * - * @var TranslatorAwareTrait */ private $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { - $this->obj = $this->getMockForTrait(TranslatorAwareTrait::class); + $this->obj = new class () { + use TranslatorAwareTrait; + }; } - /** - * @return void - */ - public function testTranslatorWithoutSettingThrowsException() + public function testTranslatorWithoutSettingThrowsException(): void { $this->expectException(Exception::class); $this->callMethod($this->obj, 'translator'); } - /** - * @return void - */ - public function testSetTranslator() + public function testSetTranslator(): void { $translator = $this->getMockBuilder(Translator::class) ->disableOriginalConstructor() diff --git a/packages/translator/tests/Charcoal/Translator/TranslatorConfigTest.php b/packages/translator/tests/Charcoal/Translator/TranslatorConfigTest.php index 54f95853d..2e3c329bf 100644 --- a/packages/translator/tests/Charcoal/Translator/TranslatorConfigTest.php +++ b/packages/translator/tests/Charcoal/Translator/TranslatorConfigTest.php @@ -15,25 +15,18 @@ class TranslatorConfigTest extends AbstractTestCase { /** * Tested Class. - * - * @var TranslatorConfig */ - private $obj; + private \Charcoal\Translator\TranslatorConfig|array $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { $this->obj = new TranslatorConfig(); } - /** - * @return void - */ - public function testDefaultsArrayAccess() + public function testDefaultsArrayAccess(): void { $this->assertEquals([ 'csv' ], $this->obj['loaders']); $this->assertContains('translations/', $this->obj['paths']); @@ -41,10 +34,7 @@ public function testDefaultsArrayAccess() $this->assertEquals('../cache/translator', $this->obj['cache_dir']); } - /** - * @return void - */ - public function testSetLoaders() + public function testSetLoaders(): void { $this->assertEquals([ 'csv' ], $this->obj->loaders()); @@ -56,46 +46,31 @@ public function testSetLoaders() $this->assertEquals([ 'php' ], $this->obj['loaders']); } - /** - * @return void - */ - public function testSetUnavailableLoaders() + public function testSetUnavailableLoaders(): void { $this->expectException(InvalidArgumentException::class); $this->obj['loaders'] = [ 'foo' ]; } - /** - * @return void - */ - public function testSetInvalidPaths() + public function testSetInvalidPaths(): void { $this->expectException(InvalidArgumentException::class); $this->obj['paths'] = [ false ]; } - /** - * @return void - */ - public function testSetInvalidDomainTranslations() + public function testSetInvalidDomainTranslations(): void { $this->expectException(InvalidArgumentException::class); $this->obj['translations'] = [ false ]; } - /** - * @return void - */ - public function testSetInvalidMessageTranslations() + public function testSetInvalidMessageTranslations(): void { $this->expectException(InvalidArgumentException::class); $this->obj['translations'] = [ [ false ] ]; } - /** - * @return void - */ - public function testSetDebug() + public function testSetDebug(): void { $this->assertFalse($this->obj->debug()); $ret = $this->obj->setDebug(true); @@ -106,10 +81,7 @@ public function testSetDebug() $this->assertFalse($this->obj['debug']); } - /** - * @return void - */ - public function testSetCacheDir() + public function testSetCacheDir(): void { $this->assertEquals('../cache/translator', $this->obj->cacheDir()); $ret = $this->obj->setCacheDir('foo'); @@ -120,10 +92,7 @@ public function testSetCacheDir() $this->assertEquals('bar', $this->obj['cache_dir']); } - /** - * @return void - */ - public function testSetInvalidCacheDir() + public function testSetInvalidCacheDir(): void { $this->expectException(InvalidArgumentException::class); $this->obj['cache_dir'] = false; diff --git a/packages/translator/tests/Charcoal/Translator/TranslatorTest.php b/packages/translator/tests/Charcoal/Translator/TranslatorTest.php index a99352c8d..1db0adbd4 100644 --- a/packages/translator/tests/Charcoal/Translator/TranslatorTest.php +++ b/packages/translator/tests/Charcoal/Translator/TranslatorTest.php @@ -7,7 +7,6 @@ // From 'symfony/translation' use Symfony\Component\Translation\Formatter\MessageFormatter; use Symfony\Component\Translation\Loader\ArrayLoader; -use Symfony\Component\Translation\MessageSelector; // From 'charcoal-translator' use Charcoal\Translator\LocalesManager; @@ -30,43 +29,30 @@ class TranslatorTest extends AbstractTestCase /** * Tested Class. - * - * @var Translator */ - private $obj; + private \Charcoal\Translator\Translator $obj; /** * The language manager. - * - * @var LocalesManager */ - private $localesManager; + private static ?\Charcoal\Translator\LocalesManager $localesManager = null; /** * Set up the test. - * - * @return void */ protected function setUp(): void { - $selector = new MessageSelector(); - $formatter = new MessageFormatter($selector); - $this->obj = new Translator([ 'locale' => 'en', 'cache_dir' => null, 'debug' => false, 'manager' => $this->localesManager(), - 'message_selector' => $selector, - 'message_formatter' => $formatter, + 'message_formatter' => new MessageFormatter(), ]); $this->obj->addLoader('array', new ArrayLoader()); } - /** - * @return void - */ public static function setUpBeforeClass(): void { $path = realpath(__DIR__.'/../../../'.static::SYMFONY_CACHE_PATH); @@ -75,9 +61,6 @@ public static function setUpBeforeClass(): void } } - /** - * @return void - */ public static function tearDownAfterClass(): void { $path = realpath(__DIR__.'/../../../'.static::SYMFONY_CACHE_PATH.'.txt'); @@ -86,13 +69,10 @@ public static function tearDownAfterClass(): void } } - /** - * @return LocalesManager - */ - private function localesManager() + private static function localesManager(): \Charcoal\Translator\LocalesManager { - if ($this->localesManager === null) { - $this->localesManager = new LocalesManager([ + if (!self::$localesManager instanceof \Charcoal\Translator\LocalesManager) { + self::$localesManager = new LocalesManager([ 'locales' => [ 'en' => [ 'locale' => 'en_US.UTF8' @@ -107,46 +87,10 @@ private function localesManager() ]); } - return $this->localesManager; - } - - /** - * @return void - */ - public function testConstructorWithMessageSelector() - { - $selector = new MessageSelector(); - $translator = new Translator([ - 'locale' => 'en', - 'cache_dir' => null, - 'debug' => false, - 'manager' => $this->localesManager(), - 'message_selector' => $selector, - ]); - - $this->assertSame($selector, $this->callMethod($translator, 'selector')); + return self::$localesManager; } - /** - * @return void - */ - public function testConstructorWithoutMessageSelector() - { - $translator = new Translator([ - 'locale' => 'en', - 'cache_dir' => null, - 'debug' => false, - 'manager' => $this->localesManager(), - 'message_selector' => null, - ]); - - $this->assertInstanceOf(MessageSelector::class, $this->callMethod($translator, 'selector')); - } - - /** - * @return void - */ - public function testConstructorWithMessageFormatter() + public function testConstructorWithMessageFormatter(): void { $formatter = new MessageFormatter(); $translator = new Translator([ @@ -160,10 +104,7 @@ public function testConstructorWithMessageFormatter() $this->assertSame($formatter, $this->callMethod($translator, 'formatter')); } - /** - * @return void - */ - public function testConstructorWithoutMessageFormatter() + public function testConstructorWithoutMessageFormatter(): void { $translator = new Translator([ 'locale' => 'en', @@ -176,20 +117,14 @@ public function testConstructorWithoutMessageFormatter() $this->assertInstanceOf(MessageFormatter::class, $this->callMethod($translator, 'formatter')); } - /** - * @return void - */ - public function testAvailableDomains() + public function testAvailableDomains(): void { $domains = $this->obj->availableDomains(); $this->assertIsArray($domains); $this->assertEquals([ 'messages' ], $domains); } - /** - * @return void - */ - public function testTranslation() + public function testTranslation(): void { $ret = $this->obj->translation('Hello!'); $this->assertInstanceOf(Translation::class, $ret); @@ -209,18 +144,16 @@ public function testTranslation() } /** - * @dataProvider invalidTransTests * * @param mixed $value The message ID. - * @return void */ - public function testTranslationInvalidValuesReturnNull($value) + #[\PHPUnit\Framework\Attributes\DataProvider('invalidTransTests')] + public function testTranslationInvalidValuesReturnNull(int|bool|string|array|null $value): void { $this->assertNull($this->obj->translation($value)); } /** - * @dataProvider validTransTests * * @param string $expected The expected translation. * @param string $id The message ID. @@ -228,11 +161,11 @@ public function testTranslationInvalidValuesReturnNull($value) * @param string $parameters An array of parameters for the message. * @param string $locale The locale to use. * @param string $domain The domain for the message. - * @return void */ - public function testTranslate($expected, $id, $translation, $parameters, $locale, $domain) + #[\PHPUnit\Framework\Attributes\DataProvider('validTransTests')] + public function testTranslate(string $expected, string|\Charcoal\Translator\Translation|\Charcoal\Tests\Translator\Mock\StringClass|array $id, string $translation, array $parameters, ?string $locale, string $domain): void { - if (!($id instanceof Translation || is_array($id)) && $locale) { + if (!$id instanceof Translation && !is_array($id) && $locale) { $this->obj->addResource('array', [ (string)$id => $translation ], $locale, $domain); } @@ -240,20 +173,16 @@ public function testTranslate($expected, $id, $translation, $parameters, $locale } /** - * @dataProvider invalidTransTests * * @param mixed $value The message ID. - * @return void */ - public function testTranslateInvalidValuesReturnEmptyString($value) + #[\PHPUnit\Framework\Attributes\DataProvider('invalidTransTests')] + public function testTranslateInvalidValuesReturnEmptyString(int|bool|string|array|null $value): void { $this->assertEquals('', $this->obj->translate($value)); } - /** - * @return void - */ - public function testTranslationChoice() + public function testTranslationChoice(): void { $ret = $this->obj->translationChoice('There is one apple|There is %count% apples', 2); $this->assertInstanceOf(Translation::class, $ret); @@ -273,18 +202,16 @@ public function testTranslationChoice() } /** - * @dataProvider invalidTransTests * * @param mixed $value The message ID. - * @return void */ - public function testTranslationChoiceInvalidValuesReturnNull($value) + #[\PHPUnit\Framework\Attributes\DataProvider('invalidTransTests')] + public function testTranslationChoiceInvalidValuesReturnNull(int|bool|string|array|null $value): void { $this->assertNull($this->obj->translationChoice($value, 1)); } /** - * @dataProvider validTransChoiceTests * * @param string $expected The expected translation. * @param string $id The message ID. @@ -293,11 +220,11 @@ public function testTranslationChoiceInvalidValuesReturnNull($value) * @param string $parameters An array of parameters for the message. * @param string $locale The locale to use. * @param string $domain The domain for the message. - * @return void */ - public function testTranslateChoice($expected, $id, $translation, $number, $parameters, $locale, $domain) + #[\PHPUnit\Framework\Attributes\DataProvider('validTransChoiceTests')] + public function testTranslateChoice(string $expected, string|\Charcoal\Translator\Translation|\Charcoal\Tests\Translator\Mock\StringClass|array $id, string $translation, int $number, array $parameters, ?string $locale, string $domain): void { - if (!($id instanceof Translation || is_array($id)) && $locale) { + if (!$id instanceof Translation && !is_array($id) && $locale) { $this->obj->addResource('array', [ (string)$id => $translation ], $locale, $domain); } @@ -305,59 +232,42 @@ public function testTranslateChoice($expected, $id, $translation, $number, $para } /** - * @dataProvider invalidTransTests * * @param mixed $value The message ID. - * @return void */ - public function testTranslateChoiceInvalidValuesReturnEmptyString($value) + #[\PHPUnit\Framework\Attributes\DataProvider('invalidTransTests')] + public function testTranslateChoiceInvalidValuesReturnEmptyString(int|bool|string|array|null $value): void { $this->assertEquals('', $this->obj->translateChoice($value, 1)); } - /** - * @return void - */ - public function testSetLocaleSetLocalesManagerCurrentLanguage() + public function testSetLocaleSetLocalesManagerCurrentLanguage(): void { $this->obj->setLocale('fr'); $this->assertEquals('fr', $this->localesManager()->currentLocale()); } - /** - * @return void - */ - public function testLocales() + public function testLocales(): void { $this->assertArrayHasKey('en', $this->obj->locales()); $this->assertArrayHasKey('fr', $this->obj->locales()); $this->assertArrayNotHasKey('jp', $this->obj->locales()); } - /** - * @return void - */ - public function testAvailableLocales() + public function testAvailableLocales(): void { $this->assertEquals([ 'en', 'fr' ], $this->obj->availableLocales()); } - /** - * @return void - */ - public function testInvalidArrayTranslation() + public function testInvalidArrayTranslation(): void { $method = $this->getMethod($this->obj, 'isValidTranslation'); - $method->setAccessible(true); $this->assertFalse($method->invokeArgs($this->obj, [ [ 0 => 'Hello!' ] ])); $this->assertFalse($method->invokeArgs($this->obj, [ [ 'hello' => 0 ] ])); } - /** - * @return void - */ - public function testHasTranslation() + public function testHasTranslation(): void { $data = [ 'en' => [ @@ -395,26 +305,21 @@ public function testHasTranslation() /** * @link https://github.com/symfony/translation/blob/v3.2.3/Tests/TranslatorTest.php - * - * @return array */ - public function validTransTests() + public static function validTransTests(): array { // phpcs:disable Generic.Files.LineLength.TooLong return [ [ 'Charcoal est super !', 'Charcoal is great!', 'Charcoal est super !', [], 'fr', '' ], [ 'Charcoal est awesome !', 'Charcoal is %what%!', 'Charcoal est %what% !', [ '%what%' => 'awesome' ], 'fr', '' ], [ 'Charcoal is great!', [ 'en' => 'Charcoal is great!', 'fr' => 'Charcoal est super !'], 'Charcoal est super !', [], null, '' ], - [ 'Charcoal est super !', new Translation([ 'en' => 'Charcoal is great!', 'fr' => 'Charcoal est super !'], $this->localesManager()), 'Charcoal est super !', [], 'fr', '' ], + [ 'Charcoal est super !', new Translation([ 'en' => 'Charcoal is great!', 'fr' => 'Charcoal est super !'], self::localesManager()), 'Charcoal est super !', [], 'fr', '' ], [ 'Charcoal est super !', new StringClass('Charcoal is great!'), 'Charcoal est super !', [], 'fr', '' ], ]; // phpcs:enable } - /** - * @return array - */ - public function invalidTransTests() + public static function invalidTransTests(): array { return [ 'null' => [ null ], @@ -431,10 +336,8 @@ public function invalidTransTests() /** * @link https://github.com/symfony/translation/blob/v3.2.3/Tests/TranslatorTest.php - * - * @return array */ - public function validTransChoiceTests() + public static function validTransChoiceTests(): array { // phpcs:disable Generic.Files.LineLength.TooLong return [ @@ -455,12 +358,12 @@ public function validTransChoiceTests() [ 'Il y a 10 pommes', '{0} There are no apples|one: There is one apple|more: There is %count% apples', '{0} Il n\'y a aucune pomme|one: Il y a %count% pomme|more: Il y a %count% pommes', 10, [], 'fr', '' ], [ 'There are no appless', [ 'en' => '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', 'fr' => '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes' ], '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, [], null, '' ], - [ 'Il y a 0 pomme', new Translation([ 'en' => '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', 'fr' => '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes' ], $this->localesManager()), '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, [], 'fr', '' ], + [ 'Il y a 0 pomme', new Translation([ 'en' => '{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples', 'fr' => '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes' ], self::localesManager()), '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, [], 'fr', '' ], [ 'Il y a 0 pomme', new StringClass('{0} There are no appless|{1} There is one apple|]1,Inf] There is %count% apples'), '[0,1] Il y a %count% pomme|]1,Inf] Il y a %count% pommes', 0, [], 'fr', '' ], // Override %count% with a custom value - [ 'Il y a quelques pommes', 'one: There is one apple|more: There are %count% apples', 'one: Il y a %count% pomme|more: Il y a %count% pommes', 2, [ '%count%' => 'quelques' ], 'fr', '' ], + [ 'Il y a quelques pommes', 'one: There is one apple|more: There are %count% apples', 'one: Il y a %count% pomme|more: Il y a %custom% pommes', 2, [ '%custom%' => 'quelques' ], 'fr', '' ], ]; // phpcs:enable } diff --git a/packages/translator/tests/bootstrap.php b/packages/translator/tests/bootstrap.php new file mode 100644 index 000000000..90929e3b5 --- /dev/null +++ b/packages/translator/tests/bootstrap.php @@ -0,0 +1,14 @@ + - + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/ui/src/Charcoal/Ui/AbstractUiItem.php b/packages/ui/src/Charcoal/Ui/AbstractUiItem.php index 664c1aa00..142537acc 100644 --- a/packages/ui/src/Charcoal/Ui/AbstractUiItem.php +++ b/packages/ui/src/Charcoal/Ui/AbstractUiItem.php @@ -46,7 +46,7 @@ abstract class AbstractUiItem extends AbstractEntity implements * * @param array $data The class depdendencies. */ - public function __construct(array $data = null) + public function __construct(?array $data = null) { if (!isset($data['logger'])) { $data['logger'] = new NullLogger(); diff --git a/packages/ui/src/Charcoal/Ui/ConditionalizableInterface.php b/packages/ui/src/Charcoal/Ui/ConditionalizableInterface.php index a4270cf3d..9f4809adc 100644 --- a/packages/ui/src/Charcoal/Ui/ConditionalizableInterface.php +++ b/packages/ui/src/Charcoal/Ui/ConditionalizableInterface.php @@ -1,5 +1,7 @@ resolvedCondition)) { - if (!isset($this->condition)) { - $this->resolvedCondition = true; - } else { - $this->resolvedCondition = $this->parseConditionalLogic( - $this->condition() - ); - } + $this->resolvedCondition = isset($this->condition) ? $this->parseConditionalLogic( + $this->condition() + ) : true; } return $this->resolvedCondition; @@ -98,7 +94,7 @@ final protected function parseConditionalLogic($condition) $result = $this->resolveConditionalLogic($condition); - return (($not === true) ? !$result : $result); + return (($not) ? !$result : $result); } /** @@ -107,38 +103,37 @@ final protected function parseConditionalLogic($condition) * @todo Simplify logic by moving `form()` method lookup to relevant form widget. * * @param callable|string $condition The callable or renderable condition. - * @return boolean */ - protected function resolveConditionalLogic($condition) + protected function resolveConditionalLogic($condition): bool { if (is_callable([ $this, $condition ])) { - return !!$this->{$condition}(); + return (bool)$this->{$condition}(); } if (is_callable($condition)) { - return !!$condition(); + return (bool)$condition(); } if (is_callable([ $this, 'form' ])) { $form = $this->form(); if (is_callable([ $form, $condition ])) { - return !!$form->{$condition}(); + return (bool)$form->{$condition}(); } if (is_callable([ $form, 'obj' ])) { $obj = $form->obj(); if (is_callable([ $obj, $condition ])) { - return !!$obj->{$condition}(); + return (bool)$obj->{$condition}(); } if (($obj instanceof ViewableInterface) && ($obj->view() instanceof ViewInterface)) { - return !!$obj->renderTemplate($condition); + return (bool)$obj->renderTemplate($condition); } } } - return !!$condition; + return (bool)$condition; } } diff --git a/packages/ui/src/Charcoal/Ui/Dashboard/AbstractDashboard.php b/packages/ui/src/Charcoal/Ui/Dashboard/AbstractDashboard.php index 6ffb025d9..9606fb423 100644 --- a/packages/ui/src/Charcoal/Ui/Dashboard/AbstractDashboard.php +++ b/packages/ui/src/Charcoal/Ui/Dashboard/AbstractDashboard.php @@ -25,7 +25,7 @@ abstract class AbstractDashboard extends AbstractUiItem implements * * @param array|\ArrayAccess $data The class dependencies. */ - public function __construct($data = null) + public function __construct(?array $data = null) { parent::__construct($data); diff --git a/packages/ui/src/Charcoal/Ui/Dashboard/DashboardBuilder.php b/packages/ui/src/Charcoal/Ui/Dashboard/DashboardBuilder.php index 3fe678754..35fc90ac4 100644 --- a/packages/ui/src/Charcoal/Ui/Dashboard/DashboardBuilder.php +++ b/packages/ui/src/Charcoal/Ui/Dashboard/DashboardBuilder.php @@ -18,30 +18,14 @@ class DashboardBuilder */ public const DEFAULT_TYPE = 'charcoal/ui/dashboard/generic'; - /** - * Store the dashboard factory instance. - * - * @var FactoryInterface - */ - protected $factory; - - /** - * Store the dependency-injection container to fulfill the required services. - * - * @var Container $container - */ - protected $container; - /** * Return a new dashboard builder. * * @param FactoryInterface $factory A dashboard factory. * @param Container $container The DI container. */ - public function __construct(FactoryInterface $factory, Container $container) + public function __construct(protected \Charcoal\Factory\FactoryInterface $factory, protected \Pimple\Container $container) { - $this->factory = $factory; - $this->container = $container; } /** @@ -52,7 +36,7 @@ public function __construct(FactoryInterface $factory, Container $container) */ public function build($options) { - $objType = isset($options['type']) ? $options['type'] : self::DEFAULT_TYPE; + $objType = ($options['type'] ?? self::DEFAULT_TYPE); $obj = $this->factory->create($objType); $obj->setData($options); diff --git a/packages/ui/src/Charcoal/Ui/Dashboard/DashboardConfig.php b/packages/ui/src/Charcoal/Ui/Dashboard/DashboardConfig.php index ecd2a8d55..245d4b7d6 100644 --- a/packages/ui/src/Charcoal/Ui/Dashboard/DashboardConfig.php +++ b/packages/ui/src/Charcoal/Ui/Dashboard/DashboardConfig.php @@ -1,5 +1,7 @@ widgets; uasort($widgets, [ $this, 'sortItemsByPriority' ]); - $widgetCallback = isset($widgetCallback) ? $widgetCallback : $this->widgetCallback; + $widgetCallback ??= $this->widgetCallback; foreach ($widgets as $widget) { if (isset($widget['permissions']) && $this instanceof AuthAwareInterface) { $widget->setActive($this->hasPermissions($widget['permissions'])); @@ -185,20 +185,16 @@ public function widgets(callable $widgetCallback = null) /** * Determine if the dashboard has any widgets. - * - * @return boolean */ - public function hasWidgets() + public function hasWidgets(): bool { return ($this->numWidgets() > 0); } /** * Count the number of widgets attached to the dashboard. - * - * @return integer */ - public function numWidgets() + public function numWidgets(): int { return count($this->widgets); } diff --git a/packages/ui/src/Charcoal/Ui/Dashboard/GenericDashboard.php b/packages/ui/src/Charcoal/Ui/Dashboard/GenericDashboard.php index 3f9108db4..de3840f77 100644 --- a/packages/ui/src/Charcoal/Ui/Dashboard/GenericDashboard.php +++ b/packages/ui/src/Charcoal/Ui/Dashboard/GenericDashboard.php @@ -1,5 +1,7 @@ factory = $factory; } /** @@ -51,7 +43,7 @@ public function __construct(FactoryInterface $factory) */ public function build($options) { - $objType = isset($options['type']) ? $options['type'] : self::DEFAULT_TYPE; + $objType = ($options['type'] ?? self::DEFAULT_TYPE); $obj = $this->factory->create($objType); $obj->setData($options); diff --git a/packages/ui/src/Charcoal/Ui/Form/FormConfig.php b/packages/ui/src/Charcoal/Ui/Form/FormConfig.php index ebcd0f419..106d6b090 100644 --- a/packages/ui/src/Charcoal/Ui/Form/FormConfig.php +++ b/packages/ui/src/Charcoal/Ui/Form/FormConfig.php @@ -1,5 +1,7 @@ defaultGroupType(); - } + $type = ($data['type'] ?? $this->defaultGroupType()); $group = $this->formGroupFactory()->create($type); $group->setForm($this->formWidget()); @@ -363,13 +359,12 @@ protected function createFormGroup(array $data = null) * @param FormGroupInterface $group The form group to update. * @param array|null $groupData Optional. The new group data to apply. * @param string|null $groupIdent Optional. The new group identifier. - * @return FormGroupInterface */ protected function updateFormGroup( FormGroupInterface $group, - array $groupData = null, + ?array $groupData = null, $groupIdent = null - ) { + ): FormGroupInterface { $group->setForm($this->formWidget()); if ($groupData !== null) { @@ -385,10 +380,8 @@ protected function updateFormGroup( /** * Retrieve the default form group class name. - * - * @return string */ - public function defaultGroupType() + public function defaultGroupType(): string { return 'charcoal/ui/form-group/generic'; } @@ -399,12 +392,12 @@ public function defaultGroupType() * @param callable $groupCallback Optional callback applied to each form group. * @return FormGroupInterface[]|Generator */ - public function groups(callable $groupCallback = null) + public function groups(?callable $groupCallback = null) { $groups = $this->groups; uasort($groups, [ $this, 'sortItemsByPriority' ]); - $groupCallback = (isset($groupCallback) ? $groupCallback : $this->groupCallback); + $groupCallback ??= $this->groupCallback; $groups = $this->finalizeFormGroups($groups); @@ -432,7 +425,7 @@ public function groups(callable $groupCallback = null) * @param array|FormGroupInterface[] $groups Form groups to finalize. * @return array|FormGroupInterface[] */ - protected function finalizeFormGroups($groups) + protected function finalizeFormGroups($groups): array { $out = []; @@ -441,10 +434,8 @@ protected function finalizeFormGroups($groups) continue; } - if ($group instanceof ConditionalizableInterface) { - if (!$group->resolvedCondition()) { - continue; - } + if ($group instanceof ConditionalizableInterface && !$group->resolvedCondition()) { + continue; } // Test formGroup vs. ACL roles @@ -465,35 +456,33 @@ protected function finalizeFormGroups($groups) } } - if ($group->rawConditionalLogic()) { - if (is_callable([$this, 'obj'])) { - foreach ($group->rawConditionalLogic() as $logic) { - $valid = true; - $value = $this->obj()->get($logic['property']); - - switch ($logic['operator']) { - case '!==': - case '!=': - case '!': - case 'not': - if ($value == $logic['value']) { - $valid = false; - } - break; - default: - case '"==="': - case '"=="': - case '"="': - case '"is"': - if ($value != $logic['value']) { - $valid = false; - } - break; - } - - if (!$valid) { - $group->setConditionalLogicUnmet(true); - } + if ($group->rawConditionalLogic() && is_callable([$this, 'obj'])) { + foreach ($group->rawConditionalLogic() as $logic) { + $valid = true; + $value = $this->obj()->get($logic['property']); + + switch ($logic['operator']) { + case '!==': + case '!=': + case '!': + case 'not': + if ($value == $logic['value']) { + $valid = false; + } + break; + default: + case '"==="': + case '"=="': + case '"="': + case '"is"': + if ($value != $logic['value']) { + $valid = false; + } + break; + } + + if (!$valid) { + $group->setConditionalLogicUnmet(true); } } } @@ -506,10 +495,8 @@ protected function finalizeFormGroups($groups) /** * Determine if the form has any groups. - * - * @return boolean */ - public function hasGroups() + public function hasGroups(): bool { return ($this->numGroups() > 0); } @@ -519,9 +506,8 @@ public function hasGroups() * * @param string $groupIdent The group identifier to look up. * @throws InvalidArgumentException If the group identifier is invalid. - * @return boolean */ - public function hasGroup($groupIdent) + public function hasGroup($groupIdent): bool { if (!is_string($groupIdent)) { throw new InvalidArgumentException( @@ -534,10 +520,8 @@ public function hasGroup($groupIdent) /** * Count the number of form groups. - * - * @return integer */ - public function numGroups() + public function numGroups(): int { return count($this->groups); } @@ -584,10 +568,8 @@ public function groupDisplayMode() /** * Determine if content groups are to be displayed as tabbable panes. - * - * @return boolean */ - public function isTabbable() + public function isTabbable(): bool { return ($this->groupDisplayMode() === 'tab'); } diff --git a/packages/ui/src/Charcoal/Ui/Form/GenericForm.php b/packages/ui/src/Charcoal/Ui/Form/GenericForm.php index 4341ad9d7..3b218cb8d 100644 --- a/packages/ui/src/Charcoal/Ui/Form/GenericForm.php +++ b/packages/ui/src/Charcoal/Ui/Form/GenericForm.php @@ -1,5 +1,7 @@ groups; uasort($groups, [ $this, 'sortItemsByPriority' ]); - $inputCallback = isset($inputCallback) ? $inputCallback : $this->inputCallback; + $inputCallback ??= $this->inputCallback; foreach ($inputs as $input) { if (!$input->l10nMode()) { $input->setL10nMode($this->l10nMode()); @@ -234,20 +234,16 @@ public function inputs(callable $inputCallback = null) /** * Wether this group contains any inputs. - * - * @return boolean */ - public function hasInputs() + public function hasInputs(): bool { return (count($this->inputs) > 0); } /** * Get the number of inputs in this group. - * - * @return integer */ - public function numInputs() + public function numInputs(): int { return count($this->inputs); } diff --git a/packages/ui/src/Charcoal/Ui/FormGroup/GenericFormGroup.php b/packages/ui/src/Charcoal/Ui/FormGroup/GenericFormGroup.php index ab12311bf..3501bc5fe 100644 --- a/packages/ui/src/Charcoal/Ui/FormGroup/GenericFormGroup.php +++ b/packages/ui/src/Charcoal/Ui/FormGroup/GenericFormGroup.php @@ -1,5 +1,7 @@ factory = $factory; - $this->container = $container; } /** @@ -53,7 +37,7 @@ public function __construct(FactoryInterface $factory, Container $container) public function build($options) { $container = $this->container; - $objType = isset($options['type']) ? $options['type'] : self::DEFAULT_TYPE; + $objType = ($options['type'] ?? self::DEFAULT_TYPE); $obj = $this->factory->create($objType, [ 'logger' => $container['logger'], diff --git a/packages/ui/src/Charcoal/Ui/FormInput/FormInputConfig.php b/packages/ui/src/Charcoal/Ui/FormInput/FormInputConfig.php index 8cfbdec53..abd820524 100644 --- a/packages/ui/src/Charcoal/Ui/FormInput/FormInputConfig.php +++ b/packages/ui/src/Charcoal/Ui/FormInput/FormInputConfig.php @@ -1,5 +1,7 @@ factory = $factory; - $this->container = $container; } /** @@ -54,7 +38,7 @@ public function __construct(FactoryInterface $factory, Container $container) public function build($options) { $container = $this->container; - $objType = isset($options['type']) ? $options['type'] : self::DEFAULT_TYPE; + $objType = ($options['type'] ?? self::DEFAULT_TYPE); $obj = $this->factory->create($objType, [ 'logger' => $container['logger'], diff --git a/packages/ui/src/Charcoal/Ui/Layout/LayoutConfig.php b/packages/ui/src/Charcoal/Ui/Layout/LayoutConfig.php index d438062e0..9f860cc8c 100644 --- a/packages/ui/src/Charcoal/Ui/Layout/LayoutConfig.php +++ b/packages/ui/src/Charcoal/Ui/Layout/LayoutConfig.php @@ -1,5 +1,7 @@ structure(); return count($structure); @@ -90,9 +88,8 @@ public function numRows() * Get the row index at a certain position * * @param integer $position Optional. Forced position. - * @return integer|null */ - public function rowIndex($position = null) + public function rowIndex($position = null): ?int { if ($position === null) { $position = $this->position(); @@ -100,7 +97,7 @@ public function rowIndex($position = null) $i = 0; $p = 0; - foreach ($this->structure as $row_ident => $row) { + foreach ($this->structure as $row) { $numCells = count($row['columns']); $p += $numCells; if ($p > $position) { @@ -139,7 +136,7 @@ public function rowData($position = null) * @param integer $position Optional. Forced position. * @return integer|null */ - public function rowNumColumns($position = null) + public function rowNumColumns($position = null): null|float|int { if ($position === null) { $position = $this->position(); @@ -161,7 +158,7 @@ public function rowNumColumns($position = null) * @param integer $position Optional. Forced position. * @return integer */ - public function rowNumCells($position = null) + public function rowNumCells($position = null): ?int { if ($position === null) { $position = $this->position(); @@ -169,8 +166,7 @@ public function rowNumCells($position = null) // Get the data ta position $row = $this->rowData($position); - $numCells = isset($row['columns']) ? count($row['columns']) : null; - return $numCells; + return isset($row['columns']) ? count($row['columns']) : null; } /** @@ -179,7 +175,7 @@ public function rowNumCells($position = null) * @param integer $position Optional. Forced position. * @return integer */ - public function rowFirstCellIndex($position = null) + public function rowFirstCellIndex($position = null): ?int { if ($position === null) { $position = $this->position(); @@ -214,7 +210,7 @@ public function rowFirstCellIndex($position = null) * @param integer $position Optional. Forced position. * @return integer */ - public function cellRowIndex($position = null) + public function cellRowIndex($position = null): int|float { if ($position === null) { $position = $this->position(); @@ -226,10 +222,8 @@ public function cellRowIndex($position = null) /** * Get the total number of cells, in all rows - * - * @return integer */ - public function numCellsTotal() + public function numCellsTotal(): int { $numCells = 0; foreach ($this->structure as $row) { @@ -243,9 +237,8 @@ public function numCellsTotal() * Get the span number (in # of columns) of the current cell * * @param integer $position Optional. Forced position. - * @return integer|null */ - public function cellSpan($position = null) + public function cellSpan($position = null): ?int { $row = $this->rowData($position); $cellIndex = $this->cellRowIndex($position); @@ -260,7 +253,7 @@ public function cellSpan($position = null) * @param integer $position Optional. Forced position. * @return integer */ - public function cellSpanBy12($position = null) + public function cellSpanBy12($position = null): null|float|int { $numColumns = $this->rowNumColumns($position); if (!$numColumns) { @@ -273,9 +266,8 @@ public function cellSpanBy12($position = null) * Get wether or not the current cell starts a row (is the first one on the row) * * @param integer $position Optional. Forced position. - * @return boolean */ - public function cellStartsRow($position = null) + public function cellStartsRow($position = null): bool { if ($position === null) { $position = $this->position(); @@ -288,9 +280,8 @@ public function cellStartsRow($position = null) * Get wether or not the current cell ends a row (is the last one on the row) * * @param integer $position Optional. Forced position. - * @return boolean */ - public function cellEndsRow($position = null) + public function cellEndsRow($position = null): bool { if ($position === null) { $position = $this->position(); @@ -302,18 +293,12 @@ public function cellEndsRow($position = null) return ($cellNum >= ($numCells - 1)); } - /** - * @return string - */ - public function start() + public function start(): string { return ''; } - /** - * @return string - */ - public function end() + public function end(): string { $this->position++; return ''; diff --git a/packages/ui/src/Charcoal/Ui/Menu/AbstractMenu.php b/packages/ui/src/Charcoal/Ui/Menu/AbstractMenu.php index c2cb632dc..d78b589ed 100644 --- a/packages/ui/src/Charcoal/Ui/Menu/AbstractMenu.php +++ b/packages/ui/src/Charcoal/Ui/Menu/AbstractMenu.php @@ -34,17 +34,15 @@ abstract class AbstractMenu extends AbstractUiItem implements /** * Store a menu builder instance. - * - * @var MenuItemBuilder $menuItemBuilder */ - private $menuItemBuilder; + private \Charcoal\Ui\MenuItem\MenuItemBuilder $menuItemBuilder; /** * Return a new menu. * * @param array|\ArrayAccess $data Class dependencies. */ - public function __construct($data) + public function __construct(?array $data) { parent::__construct($data); @@ -126,12 +124,12 @@ public function addItem($item, $ident = null) * @param callable $itemCallback Optional. Item callback. * @return MenuItemInterface[] */ - public function items(callable $itemCallback = null) + public function items(?callable $itemCallback = null) { $items = $this->items; - uasort($items, [ $this, 'sortItemsByPriority' ]); + uasort($items, $this->sortItemsByPriority(...)); - $itemCallback = isset($itemCallback) ? $itemCallback : $this->itemCallback; + $itemCallback ??= $this->itemCallback; foreach ($items as $item) { if ($itemCallback) { $itemCallback($item); diff --git a/packages/ui/src/Charcoal/Ui/Menu/GenericMenu.php b/packages/ui/src/Charcoal/Ui/Menu/GenericMenu.php index d9efbc67e..a31c2dd63 100644 --- a/packages/ui/src/Charcoal/Ui/Menu/GenericMenu.php +++ b/packages/ui/src/Charcoal/Ui/Menu/GenericMenu.php @@ -1,5 +1,7 @@ factory = $factory; - $this->container = $container; } /** @@ -53,8 +37,7 @@ public function __construct(FactoryInterface $factory, Container $container) */ public function build($options) { - $container = $this->container; - $objType = isset($options['type']) ? $options['type'] : self::DEFAULT_TYPE; + $objType = ($options['type'] ?? self::DEFAULT_TYPE); $obj = $this->factory->create($objType); $obj->setData($options); diff --git a/packages/ui/src/Charcoal/Ui/Menu/MenuConfig.php b/packages/ui/src/Charcoal/Ui/Menu/MenuConfig.php index 33ce4a324..63c8c85a7 100644 --- a/packages/ui/src/Charcoal/Ui/Menu/MenuConfig.php +++ b/packages/ui/src/Charcoal/Ui/Menu/MenuConfig.php @@ -1,5 +1,7 @@ url()); + return (bool)$this->url(); } /** @@ -205,12 +205,12 @@ public function addChild($child) * @param callable $childCallback Optional callback. * @return MenuItemInterface[] */ - public function children(callable $childCallback = null) + public function children(?callable $childCallback = null) { $children = $this->children; uasort($children, ['self', 'sortChildrenByPrioriy']); - $childCallback = isset($childCallback) ? $childCallback : $this->childCallback; + $childCallback ??= $this->childCallback; foreach ($children as $child) { if ($childCallback) { $childCallback($child); diff --git a/packages/ui/src/Charcoal/Ui/MenuItem/GenericMenuItem.php b/packages/ui/src/Charcoal/Ui/MenuItem/GenericMenuItem.php index 075073bf8..b0abcca16 100644 --- a/packages/ui/src/Charcoal/Ui/MenuItem/GenericMenuItem.php +++ b/packages/ui/src/Charcoal/Ui/MenuItem/GenericMenuItem.php @@ -1,5 +1,7 @@ factory = $factory; - $this->container = $container; } /** @@ -53,8 +37,7 @@ public function __construct(FactoryInterface $factory, Container $container) */ public function build($options) { - $container = $this->container; - $objType = isset($options['type']) ? $options['type'] : self::DEFAULT_TYPE; + $objType = ($options['type'] ?? self::DEFAULT_TYPE); $obj = $this->factory->create($objType); $obj->setData($options); diff --git a/packages/ui/src/Charcoal/Ui/MenuItem/MenuItemConfig.php b/packages/ui/src/Charcoal/Ui/MenuItem/MenuItemConfig.php index e56673828..d00cb9af9 100644 --- a/packages/ui/src/Charcoal/Ui/MenuItem/MenuItemConfig.php +++ b/packages/ui/src/Charcoal/Ui/MenuItem/MenuItemConfig.php @@ -1,5 +1,7 @@ registerDashboardServices($container); } /** * @param Container $container A Pimple DI container. - * @return void */ - private function registerDashboardServices(Container $container) + private function registerDashboardServices(Container $container): void { /** * @param Container $container A Pimple DI container. * @return LayoutFactory */ - $container['dashboard/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => DashboardInterface::class, - 'default_class' => GenericDashboard::class, - 'arguments' => [ - [ - 'container' => $container, - 'logger' => $container['logger'], - 'view' => $container['view'], - 'widget_builder' => $container['widget/builder'], - 'layout_builder' => $container['layout/builder'], - ], + $container['dashboard/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => DashboardInterface::class, + 'default_class' => GenericDashboard::class, + 'arguments' => [ + [ + 'container' => $container, + 'logger' => $container['logger'], + 'view' => $container['view'], + 'widget_builder' => $container['widget/builder'], + 'layout_builder' => $container['layout/builder'], ], - 'resolver_options' => [ - 'suffix' => 'Dashboard', - ], - ]); - }; + ], + 'resolver_options' => [ + 'suffix' => 'Dashboard', + ], + ])); /** * @param Container $container A Pimple DI container. * @return LayoutBuilder */ - $container['dashboard/builder'] = function (Container $container) { + $container['dashboard/builder'] = function (Container $container): \Charcoal\Ui\Dashboard\DashboardBuilder { $dashboardFactory = $container['dashboard/factory']; - $dashboardBuilder = new DashboardBuilder($dashboardFactory, $container); - return $dashboardBuilder; + return new DashboardBuilder($dashboardFactory, $container); }; } } diff --git a/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php b/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php index 1498d42bf..cf495dda4 100644 --- a/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php +++ b/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php @@ -25,9 +25,8 @@ class FormServiceProvider implements ServiceProviderInterface { /** * @param Container $container A Pimple DI container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { $this->registerFormServices($container); $this->registerFormGroupServices($container); @@ -36,99 +35,88 @@ public function register(Container $container) /** * @param Container $container A Pimple DI container. - * @return void */ - public function registerFormServices(Container $container) + public function registerFormServices(Container $container): void { /** * @param Container $container A Pimple DI container. * @return \Charcoal\Factory\FactoryInterface */ - $container['form/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => FormInterface::class, - 'default_class' => GenericForm::class, - 'arguments' => [ - [ - 'container' => $container, - 'logger' => $container['logger'], - 'view' => $container['view'], - 'layout_builder' => $container['layout/builder'], - 'form_group_factory' => $container['form/group/factory'], - ], + $container['form/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => FormInterface::class, + 'default_class' => GenericForm::class, + 'arguments' => [ + [ + 'container' => $container, + 'logger' => $container['logger'], + 'view' => $container['view'], + 'layout_builder' => $container['layout/builder'], + 'form_group_factory' => $container['form/group/factory'], ], - ]); - }; + ], + ])); /** * @param Container $container A Pimple DI container. * @return FormBuilder */ - $container['form/builder'] = function (Container $container) { + $container['form/builder'] = function (Container $container): \Charcoal\Ui\Form\FormBuilder { $formFactory = $container['form/factory']; - $formBuilder = new FormBuilder($formFactory); - return $formBuilder; + return new FormBuilder($formFactory); }; } /** * @param Container $container A Pimple DI container. - * @return void */ - public function registerFormGroupServices(Container $container) + public function registerFormGroupServices(Container $container): void { /** * @param Container $container A Pimple DI container. * @return \Charcoal\Factory\FactoryInterface */ - $container['form/group/factory'] = function (Container $container) { - return new Factory([ - 'base_class' => FormGroupInterface::class, - 'default_class' => GenericFormGroup::class, - 'arguments' => [ - [ - 'container' => $container, - 'logger' => $container['logger'], - 'view' => $container['view'], - 'layout_builder' => $container['layout/builder'], - 'form_input_builder' => $container['form/input/builder'], - ], - ], - 'resolver_options' => [ - 'suffix' => 'FormGroup', + $container['form/group/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => FormGroupInterface::class, + 'default_class' => GenericFormGroup::class, + 'arguments' => [ + [ + 'container' => $container, + 'logger' => $container['logger'], + 'view' => $container['view'], + 'layout_builder' => $container['layout/builder'], + 'form_input_builder' => $container['form/input/builder'], ], - ]); - }; + ], + 'resolver_options' => [ + 'suffix' => 'FormGroup', + ], + ])); } /** * @param Container $container A Pimple DI container. - * @return void */ - public function registerFormInputServices(Container $container) + public function registerFormInputServices(Container $container): void { /** * @param Container $container A Pimple DI container. * @return \Charcoal\Factory\FactoryInterface */ - $container['form/input/factory'] = function () { - return new Factory([ - 'base_class' => FormInputInterface::class, - 'default_class' => GenericFormInput::class, - 'resolver_options' => [ - 'suffix' => 'FormInput', - ], - ]); - }; + $container['form/input/factory'] = (fn(): \Charcoal\Factory\GenericFactory => new Factory([ + 'base_class' => FormInputInterface::class, + 'default_class' => GenericFormInput::class, + 'resolver_options' => [ + 'suffix' => 'FormInput', + ], + ])); /** * @param Container $container A Pimple DI container. * @return FormInputBuilder */ - $container['form/input/builder'] = function (Container $container) { + $container['form/input/builder'] = function (Container $container): \Charcoal\Ui\FormInput\FormInputBuilder { $formInputFactory = $container['form/input/factory']; - $formInputBuilder = new FormInputBuilder($formInputFactory, $container); - return $formInputBuilder; + return new FormInputBuilder($formInputFactory, $container); }; } } diff --git a/packages/ui/src/Charcoal/Ui/ServiceProvider/LayoutServiceProvider.php b/packages/ui/src/Charcoal/Ui/ServiceProvider/LayoutServiceProvider.php index c01b972bf..df98a5195 100644 --- a/packages/ui/src/Charcoal/Ui/ServiceProvider/LayoutServiceProvider.php +++ b/packages/ui/src/Charcoal/Ui/ServiceProvider/LayoutServiceProvider.php @@ -16,37 +16,30 @@ class LayoutServiceProvider implements ServiceProviderInterface { /** * @param Container $container A Pimple DI container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { $this->registerLayoutServices($container); } /** * @param Container $container A Pimple DI container. - * @return void */ - private function registerLayoutServices(Container $container) + private function registerLayoutServices(Container $container): void { /** * @param Container $container A Pimple DI container. * @return LayoutFactory */ - $container['layout/factory'] = function () { - - $layoutFactory = new LayoutFactory(); - return $layoutFactory; - }; + $container['layout/factory'] = (fn(): \Charcoal\Ui\Layout\LayoutFactory => new LayoutFactory()); /** * @param Container $container A Pimple DI container. * @return LayoutBuilder */ - $container['layout/builder'] = function (Container $container) { + $container['layout/builder'] = function (Container $container): \Charcoal\Ui\Layout\LayoutBuilder { $layoutFactory = $container['layout/factory']; - $layoutBuilder = new LayoutBuilder($layoutFactory, $container); - return $layoutBuilder; + return new LayoutBuilder($layoutFactory, $container); }; } } diff --git a/packages/ui/src/Charcoal/Ui/ServiceProvider/MenuServiceProvider.php b/packages/ui/src/Charcoal/Ui/ServiceProvider/MenuServiceProvider.php index eb2a08c18..0d8f910de 100644 --- a/packages/ui/src/Charcoal/Ui/ServiceProvider/MenuServiceProvider.php +++ b/packages/ui/src/Charcoal/Ui/ServiceProvider/MenuServiceProvider.php @@ -18,9 +18,8 @@ class MenuServiceProvider implements ServiceProviderInterface { /** * @param Container $container A Pimple DI container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { $this->registerMenuServices($container); $this->registerMenuItemServices($container); @@ -28,15 +27,14 @@ public function register(Container $container) /** * @param Container $container A Pimple DI container. - * @return void */ - public function registerMenuServices(Container $container) + public function registerMenuServices(Container $container): void { /** * @param Container $container A Pimple DI container. * @return MenuFactory */ - $container['menu/factory'] = function (Container $container) { + $container['menu/factory'] = function (Container $container): \Charcoal\Ui\Menu\MenuFactory { $menuFactory = new MenuFactory(); $menuFactory->setArguments([ 'container' => $container, @@ -51,10 +49,9 @@ public function registerMenuServices(Container $container) * @param Container $container A Pimple DI container. * @return MenuBuilder */ - $container['menu/builder'] = function (Container $container) { + $container['menu/builder'] = function (Container $container): \Charcoal\Ui\Menu\MenuBuilder { $menuFactory = $container['menu/factory']; - $menuBuilder = new MenuBuilder($menuFactory, $container); - return $menuBuilder; + return new MenuBuilder($menuFactory, $container); }; } @@ -68,14 +65,13 @@ public function registerMenuServices(Container $container) * instantiated at the same time. * * @param Container $container A Pimple DI container. - * @return void */ - public function registerMenuItemServices(Container $container) + public function registerMenuItemServices(Container $container): void { /** * @var callable */ - $delegate = function (Container $container) { + $delegate = function (Container $container): array { $args = [ 'container' => $container, 'logger' => $container['logger'], diff --git a/packages/ui/src/Charcoal/Ui/ServiceProvider/UiServiceProvider.php b/packages/ui/src/Charcoal/Ui/ServiceProvider/UiServiceProvider.php index 2c4e01da7..bb0cf1900 100644 --- a/packages/ui/src/Charcoal/Ui/ServiceProvider/UiServiceProvider.php +++ b/packages/ui/src/Charcoal/Ui/ServiceProvider/UiServiceProvider.php @@ -20,9 +20,8 @@ class UiServiceProvider implements ServiceProviderInterface { /** * @param Container $container A Pimple DI container. - * @return void */ - public function register(Container $container) + public function register(Container $container): void { $container->register(new AuthServiceProvider()); $container->register(new DashboardServiceProvider()); diff --git a/packages/ui/src/Charcoal/Ui/UiGroupingInterface.php b/packages/ui/src/Charcoal/Ui/UiGroupingInterface.php index 77aa467c1..68639f820 100644 --- a/packages/ui/src/Charcoal/Ui/UiGroupingInterface.php +++ b/packages/ui/src/Charcoal/Ui/UiGroupingInterface.php @@ -1,5 +1,7 @@ type = $type; @@ -60,7 +56,7 @@ public function setType($type) * * @return string */ - public function type() + public function type(): ?string { return $this->type; } @@ -74,7 +70,7 @@ public function type() * @throws InvalidArgumentException If the template is not a string. * @return UiItemInterface Chainable */ - public function setTemplate($template) + public function setTemplate($template): static { if (!is_string($template)) { throw new InvalidArgumentException( @@ -92,7 +88,7 @@ public function setTemplate($template) * * @return string If unset, returns the UI item type. */ - public function template() + public function template(): ?string { if ($this->template === null) { return $this->type(); @@ -108,7 +104,7 @@ public function template() * @throws InvalidArgumentException If the controller is not a string. * @return UiItemInterface Chainable */ - public function setController($controller) + public function setController($controller): static { if (!is_string($controller)) { throw new InvalidArgumentException( @@ -126,7 +122,7 @@ public function setController($controller) * * @return string If unset, returns the UI item type. */ - public function controller() + public function controller(): ?string { if ($this->controller === null) { return $this->type(); diff --git a/packages/ui/src/Charcoal/Ui/UiItemInterface.php b/packages/ui/src/Charcoal/Ui/UiItemInterface.php index ef4e58824..01ad3d4ae 100644 --- a/packages/ui/src/Charcoal/Ui/UiItemInterface.php +++ b/packages/ui/src/Charcoal/Ui/UiItemInterface.php @@ -1,5 +1,7 @@ active = !!$active; + $this->active = (bool)$active; return $this; } @@ -159,9 +159,8 @@ public function active() * * @param string|null $type The UI item type. * @throws InvalidArgumentException If the type is not a string (or null). - * @return self */ - public function setType($type) + public function setType($type): static { if (is_string($type) || $type === null) { $this->type = $type; @@ -178,10 +177,8 @@ public function setType($type) * Retrieve the UI item type. * * If it is not explicitely set (or null), then return the object's FQN. - * - * @return string */ - public function type() + public function type(): ?string { if ($this->type === null) { return static::class; @@ -196,9 +193,8 @@ public function type() * * @param string $template A template (identifier). * @throws InvalidArgumentException If the template is not a string. - * @return self */ - public function setTemplate($template) + public function setTemplate($template): static { if (!is_string($template)) { throw new InvalidArgumentException( @@ -216,7 +212,7 @@ public function setTemplate($template) * * @return string If unset, returns the UI item type. */ - public function template() + public function template(): ?string { if ($this->template === null) { return $this->type(); @@ -266,7 +262,7 @@ public function setTabTitle($title) */ public function tabTitle() { - return ($this->tabTitle) ? $this->tabTitle : $this->title(); + return $this->tabTitle ?: $this->title(); } /** @@ -366,7 +362,7 @@ public function setIcon($icon) */ public function setShowTitle($show) { - $this->showTitle = !!$show; + $this->showTitle = (bool)$show; return $this; } @@ -381,7 +377,7 @@ public function showTitle() if ($this->showTitle === false) { return false; } else { - return !!$this->title(); + return (bool)$this->title(); } } @@ -393,7 +389,7 @@ public function showTitle() */ public function setShowSubtitle($show) { - $this->showSubtitle = !!$show; + $this->showSubtitle = (bool)$show; return $this; } @@ -408,7 +404,7 @@ public function showSubtitle() if ($this->showSubtitle === false) { return false; } else { - return !!$this->subtitle(); + return (bool)$this->subtitle(); } } @@ -420,7 +416,7 @@ public function showSubtitle() */ public function setShowDescription($show) { - $this->showDescription = !!$show; + $this->showDescription = (bool)$show; return $this; } @@ -435,7 +431,7 @@ public function showDescription() if ($this->showDescription === false) { return false; } else { - return !!$this->description(); + return (bool)$this->description(); } } @@ -447,7 +443,7 @@ public function showDescription() */ public function setShowNotes($show) { - $this->showNotes = !!$show; + $this->showNotes = (bool)$show; return $this; } @@ -462,7 +458,7 @@ public function showNotes() if ($this->showNotes === false) { return false; } else { - return !!$this->notes(); + return (bool)$this->notes(); } } @@ -474,7 +470,7 @@ public function showNotes() */ public function setShowIcon($show) { - $this->showIcon = !!$show; + $this->showIcon = (bool)$show; return $this; } @@ -489,7 +485,7 @@ public function showIcon() if ($this->showIcon === false) { return false; } else { - return !!$this->icon(); + return (bool)$this->icon(); } } @@ -501,7 +497,7 @@ public function showIcon() */ public function setShowHeader($show) { - $this->showHeader = !!$show; + $this->showHeader = (bool)$show; return $this; } @@ -528,7 +524,7 @@ public function showHeader() */ public function setShowFooter($show) { - $this->showFooter = !!$show; + $this->showFooter = (bool)$show; return $this; } @@ -553,7 +549,7 @@ public function showFooter() */ public function setShowTabTitle($showTabTitle) { - $this->showTabTitle = !!$showTabTitle; + $this->showTabTitle = (bool)$showTabTitle; return $this; } @@ -580,14 +576,10 @@ public function showTabTitle() protected function sortItemsByPriority( PrioritizableInterface $a, PrioritizableInterface $b - ) { + ): int { $priorityA = $a->priority(); $priorityB = $b->priority(); - - if ($priorityA === $priorityB) { - return 0; - } - return ($priorityA < $priorityB) ? (-1) : 1; + return ($priorityA <=> $priorityB); } /** diff --git a/packages/ui/tests/Charcoal/AbstractTestCase.php b/packages/ui/tests/Charcoal/AbstractTestCase.php index 59ba12ea0..80f1772c4 100644 --- a/packages/ui/tests/Charcoal/AbstractTestCase.php +++ b/packages/ui/tests/Charcoal/AbstractTestCase.php @@ -1,5 +1,7 @@ getContainer(); - $this->obj = $this->getMockForAbstractClass(AbstractUiItem::class, [[ + $this->obj = new class ([ 'container' => $container - ]]); + ]) extends AbstractUiItem { + + }; $method = new ReflectionMethod($this->obj, 'setAuthDependencies'); - $method->setAccessible(true); $method->invoke($this->obj, $container); } - /** - * @return void - */ - public function testDefaults() + public function testDefaults(): void { $this->assertTrue($this->obj->active()); $this->assertEquals(0, $this->obj->priority()); @@ -52,40 +47,28 @@ public function testDefaults() $this->assertEquals('', $this->obj->notes()); } - /** - * @return void - */ - public function testSetType() + public function testSetType(): void { $ret = $this->obj->setType('foobar'); $this->assertSame($ret, $this->obj); $this->assertEquals('foobar', $this->obj->type()); } - /** - * @return void - */ - public function testSetAcive() + public function testSetAcive(): void { $ret = $this->obj->setActive(false); $this->assertSame($ret, $this->obj); $this->assertEquals(false, $this->obj->active()); } - /** - * @return void - */ - public function testSetPriority() + public function testSetPriority(): void { $ret = $this->obj->setPriority(42); $this->assertSame($ret, $this->obj); $this->assertEquals(42, $this->obj->priority()); } - /** - * @return void - */ - public function testSetTemplate() + public function testSetTemplate(): void { $ret = $this->obj->setTemplate('foo/bar'); $this->assertSame($ret, $this->obj); @@ -95,60 +78,42 @@ public function testSetTemplate() $this->obj->setTemplate(false); } - /** - * @return void - */ - public function testNoTemplateReturnsType() + public function testNoTemplateReturnsType(): void { $ret = $this->obj->setType('foobar/baz'); $this->assertSame($ret, $this->obj); $this->assertEquals('foobar/baz', $this->obj->template()); } - /** - * @return void - */ - public function testSetTitle() + public function testSetTitle(): void { $ret = $this->obj->setTitle('Hello'); $this->assertSame($ret, $this->obj); $this->assertEquals('Hello', (string)$this->obj->title()); } - /** - * @return void - */ - public function testSetSubtitle() + public function testSetSubtitle(): void { $ret = $this->obj->setSubtitle('Hello'); $this->assertSame($ret, $this->obj); $this->assertEquals('Hello', (string)$this->obj->subtitle()); } - /** - * @return void - */ - public function testSetDescription() + public function testSetDescription(): void { $ret = $this->obj->setDescription('Hello'); $this->assertSame($ret, $this->obj); $this->assertEquals('Hello', (string)$this->obj->description()); } - /** - * @return void - */ - public function testSetNotes() + public function testSetNotes(): void { $ret = $this->obj->setNotes('Hello'); $this->assertSame($ret, $this->obj); $this->assertEquals('Hello', (string)$this->obj->notes()); } - /** - * @return void - */ - public function testShowTitle() + public function testShowTitle(): void { $this->assertFalse($this->obj->showTitle()); $this->obj->setTitle('Foo'); @@ -158,10 +123,7 @@ public function testShowTitle() $this->assertFalse($this->obj->showTitle()); } - /** - * @return void - */ - public function testShowSubtitle() + public function testShowSubtitle(): void { $this->assertFalse($this->obj->showSubtitle()); $this->obj->setSubtitle('Foo'); @@ -171,10 +133,7 @@ public function testShowSubtitle() $this->assertFalse($this->obj->showSubtitle()); } - /** - * @return void - */ - public function testShowDescription() + public function testShowDescription(): void { $this->assertFalse($this->obj->showDescription()); $this->obj->setDescription('Foo'); @@ -184,10 +143,7 @@ public function testShowDescription() $this->assertFalse($this->obj->showDescription()); } - /** - * @return void - */ - public function testShowNotes() + public function testShowNotes(): void { $this->assertFalse($this->obj->showNotes()); $this->obj->setNotes('Foo'); diff --git a/packages/ui/tests/Charcoal/Ui/ContainerIntegrationTrait.php b/packages/ui/tests/Charcoal/Ui/ContainerIntegrationTrait.php index f71d0133c..c7fd41807 100644 --- a/packages/ui/tests/Charcoal/Ui/ContainerIntegrationTrait.php +++ b/packages/ui/tests/Charcoal/Ui/ContainerIntegrationTrait.php @@ -51,9 +51,8 @@ protected function getContainerProvider() /** * @see ContainerProvider - * @return void */ - private function setupContainer() + private function setupContainer(): void { $provider = new ContainerProvider(); $container = new Container(); diff --git a/packages/ui/tests/Charcoal/Ui/ContainerProvider.php b/packages/ui/tests/Charcoal/Ui/ContainerProvider.php index 7e8dc0f08..5ef792d2f 100644 --- a/packages/ui/tests/Charcoal/Ui/ContainerProvider.php +++ b/packages/ui/tests/Charcoal/Ui/ContainerProvider.php @@ -36,9 +36,8 @@ class ContainerProvider * Register the unit tests required services. * * @param Container $container A DI container. - * @return void */ - public function registerBaseServices(Container $container) + public function registerBaseServices(Container $container): void { $this->registerConfig($container); $this->registerSource($container); @@ -50,9 +49,8 @@ public function registerBaseServices(Container $container) * Register the admin services. * * @param Container $container A DI container. - * @return void */ - public function registerConfig(Container $container) + public function registerConfig(Container $container): void { $container['config'] = new AppConfig([ 'base_path' => realpath(__DIR__ . '/../../..'), @@ -71,8 +69,6 @@ public function registerConfig(Container $container) * * Explicitly defined in case of a version mismatch with dependencies. This parameter * is normally defined by {@see \Charcoal\App\ServiceProvider\AppServiceProvider}. - * - * @var array */ $container['module/classes'] = []; } @@ -83,11 +79,10 @@ public function registerConfig(Container $container) * Note: Uses SQLite to create a database in memory. * * @param Container $container A DI container. - * @return void */ - public function registerSource(Container $container) + public function registerSource(Container $container): void { - $container['database'] = function () { + $container['database'] = function (): \PDO { $pdo = new PDO('sqlite::memory:'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; @@ -98,9 +93,8 @@ public function registerSource(Container $container) * Register the admin services. * * @param Container $container A DI container. - * @return void */ - public function registerModelServices(Container $container) + public function registerModelServices(Container $container): void { static $provider = null; @@ -115,9 +109,8 @@ public function registerModelServices(Container $container) * Register the admin services. * * @param Container $container A DI container. - * @return void */ - public function registerAuthServices(Container $container) + public function registerAuthServices(Container $container): void { static $provider = null; @@ -132,9 +125,8 @@ public function registerAuthServices(Container $container) * Setup the application's translator service. * * @param Container $container A DI container. - * @return void */ - public function registerTranslatorServices(Container $container) + public function registerTranslatorServices(Container $container): void { static $provider = null; @@ -149,9 +141,8 @@ public function registerTranslatorServices(Container $container) * Setup the framework's view renderer. * * @param Container $container A DI container. - * @return void */ - public function registerViewServices(Container $container) + public function registerViewServices(Container $container): void { static $provider = null; @@ -166,25 +157,19 @@ public function registerViewServices(Container $container) * Setup the application's logging interface. * * @param Container $container A DI container. - * @return void */ - public function registerLogger(Container $container) + public function registerLogger(Container $container): void { - $container['logger'] = function () { - return new NullLogger(); - }; + $container['logger'] = (fn(): \Psr\Log\NullLogger => new NullLogger()); } /** * Setup the application's caching interface. * * @param Container $container A DI container. - * @return void */ - public function registerCache(Container $container) + public function registerCache(Container $container): void { - $container['cache'] = function () { - return new Pool(); - }; + $container['cache'] = (fn(): \Stash\Pool => new Pool()); } } diff --git a/packages/ui/tests/Charcoal/Ui/Dashboard/AbstractDashboardTest.php b/packages/ui/tests/Charcoal/Ui/Dashboard/AbstractDashboardTest.php index 4851b6527..33d3fdb2e 100644 --- a/packages/ui/tests/Charcoal/Ui/Dashboard/AbstractDashboardTest.php +++ b/packages/ui/tests/Charcoal/Ui/Dashboard/AbstractDashboardTest.php @@ -23,9 +23,6 @@ class AbstractDashboardTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -33,22 +30,18 @@ protected function setUp(): void $container->register(new LayoutServiceProvider()); $container->register(new FormServiceProvider()); - $this->obj = $this->getMockForAbstractClass(AbstractDashboard::class, [ - [ - 'logger' => $container['logger'], - 'view' => $container['view'], - 'layout_builder' => $container['layout/builder'], - 'widget_builder' => $container['form/builder'], - ], - ]); + $this->obj = new class ([ + 'logger' => $container['logger'], + 'view' => $container['view'], + 'layout_builder' => $container['layout/builder'], + 'widget_builder' => $container['form/builder'], + ]) extends AbstractDashboard {}; } /** * Helper method, example layout for tests. - * - * @return array */ - protected function exampleLayout() + protected function exampleLayout(): array { return [ 'structure' => [ @@ -57,15 +50,10 @@ protected function exampleLayout() ]; } - /** - * @return void - */ - public function testSetWidgetCallback() + public function testSetWidgetCallback(): void { $obj = $this->obj; - $cb = function($o) { - return 'foo'; - }; + $cb = (fn($o): string => 'foo'); $ret = $obj->setWidgetCallback($cb); $this->assertSame($ret, $obj); } @@ -77,10 +65,8 @@ public function testSetWidgetCallback() * - calling `setLayout()` with an Layout objects set the layout * - calling `setLayout()` with an array sets the same layout * - `setLayout()` throws an exception if not an array / Layout object - * - * @return void */ - public function testSetLayout() + public function testSetLayout(): void { $container = $this->getContainer(); @@ -101,10 +87,7 @@ public function testSetLayout() $obj->setLayout('foobar'); } - /** - * @return void - */ - public function testSetWidgets() + public function testSetWidgets(): void { $obj = $this->obj; $ret = $obj->setWidgets([ @@ -113,10 +96,7 @@ public function testSetWidgets() $this->assertSame($ret, $obj); } - /** - * @return void - */ - public function testAddWidgetInvalidIdentThrowsException() + public function testAddWidgetInvalidIdentThrowsException(): void { $obj = $this->obj; @@ -124,10 +104,7 @@ public function testAddWidgetInvalidIdentThrowsException() $obj->addWidget([], []); } - /** - * @return void - */ - public function testAddWidgetInvalidWidgetThrowsException() + public function testAddWidgetInvalidWidgetThrowsException(): void { $obj = $this->obj; @@ -135,36 +112,29 @@ public function testAddWidgetInvalidWidgetThrowsException() $obj->addWidget('foo', false); } - /** - * @return void - */ - public function testWidgets() + public function testWidgets(): void { $obj = $this->obj; - $ret = $obj->setWidgets([ + $obj->setWidgets([ 'test' => [] ]); $widgets = $obj->widgets(); - $num = 0; foreach ($widgets as $w) { $this->assertInstanceOf(UiItemInterface::class, $w); } } - /** - * @return void - */ - public function testWidgetsCallback() + public function testWidgetsCallback(): void { $obj = $this->obj; $obj->setWidgets([ 'test' => [] ]); - $cb = function(UiItemInterface $widget) { + $cb = function(UiItemInterface $widget): void { $widget['foo'] = 'bar'; }; @@ -175,30 +145,24 @@ public function testWidgetsCallback() } } - /** - * @return void - */ - public function testHasWidgets() + public function testHasWidgets(): void { $obj = $this->obj; $this->assertFalse($obj->hasWidgets()); - $ret = $obj->setWidgets([ + $obj->setWidgets([ 'test'=>[] ]); $this->assertTrue($obj->hasWidgets()); } - /** - * @return void - */ - public function testNumWidgets() + public function testNumWidgets(): void { $obj = $this->obj; $this->assertEquals(0, $obj->numWidgets()); - $ret = $obj->setWidgets([ + $obj->setWidgets([ 'test'=>[], 'foobar'=>[] ]); diff --git a/packages/ui/tests/Charcoal/Ui/Dashboard/GenericDashboardTest.php b/packages/ui/tests/Charcoal/Ui/Dashboard/GenericDashboardTest.php index eb6bd34cb..73df2edd2 100644 --- a/packages/ui/tests/Charcoal/Ui/Dashboard/GenericDashboardTest.php +++ b/packages/ui/tests/Charcoal/Ui/Dashboard/GenericDashboardTest.php @@ -20,9 +20,6 @@ class GenericDashboardTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -37,10 +34,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('charcoal/ui/dashboard/generic', $this->obj->type()); } diff --git a/packages/ui/tests/Charcoal/Ui/Form/AbstractFormTest.php b/packages/ui/tests/Charcoal/Ui/Form/AbstractFormTest.php index d2cbbf327..f45e873d5 100644 --- a/packages/ui/tests/Charcoal/Ui/Form/AbstractFormTest.php +++ b/packages/ui/tests/Charcoal/Ui/Form/AbstractFormTest.php @@ -20,42 +20,29 @@ class AbstractFormTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); $container->register(new FormServiceProvider()); $container->register(new LayoutServiceProvider()); - $this->obj = $this->getMockForAbstractClass(AbstractForm::class, [ - [ - 'container' => $container, - 'logger' => $container['logger'], - 'view' => $container['view'], - 'layout_builder' => $container['layout/builder'], - 'form_group_factory' => $container['form/group/factory'], - ], - ]); + $this->obj = new class ([ + 'container' => $container, + 'logger' => $container['logger'], + 'view' => $container['view'], + 'layout_builder' => $container['layout/builder'], + 'form_group_factory' => $container['form/group/factory'], + ]) extends AbstractForm {}; } - /** - * @return void - */ - public function testSetGroupCallback() + public function testSetGroupCallback(): void { - $cb = function($o) { - return 'foo'; - }; + $cb = (fn($o): string => 'foo'); $ret = $this->obj->setGroupCallback($cb); $this->assertSame($ret, $this->obj); } - /** - * @return void - */ - public function testSetAction() + public function testSetAction(): void { $this->assertEquals('', $this->obj->action()); $ret = $this->obj->setAction('foo/bar'); @@ -66,10 +53,7 @@ public function testSetAction() $this->obj->setAction(false); } - /** - * @return void - */ - public function testSetMethod() + public function testSetMethod(): void { //$this->assertEquals('post', $obj->method()); $ret = $this->obj->setMethod('get'); @@ -83,20 +67,14 @@ public function testSetMethod() $this->obj->setMethod('foobar'); } - /** - * @return void - */ - public function testSetL10nMode() + public function testSetL10nMode(): void { $ret = $this->obj->setL10nMode('loop'); $this->assertSame($ret, $this->obj); $this->assertEquals('loop', $this->obj->l10nMode()); } - /** - * @return void - */ - public function testSetGroup() + public function testSetGroup(): void { $ret = $this->obj->setGroups([ 'test' => [] @@ -106,37 +84,28 @@ public function testSetGroup() $this->assertEquals(1, $this->obj->numGroups()); } - /** - * @return void - */ - public function testAddGroup() + public function testAddGroup(): void { $ret = $this->obj->addGroup('ident', []); $this->assertSame($ret, $this->obj); } - /** - * @return void - */ - public function testHasGroups() + public function testHasGroups(): void { $this->assertFalse($this->obj->hasGroups()); - $ret = $this->obj->setGroups([ + $this->obj->setGroups([ 'test' => [] ]); $this->assertTrue($this->obj->hasGroups()); } - /** - * @return void - */ - public function testNumGroups() + public function testNumGroups(): void { $this->assertEquals(0, $this->obj->numGroups()); - $ret = $this->obj->setGroups([ + $this->obj->setGroups([ 'test' => [], 'foobar' => [] ]); @@ -144,10 +113,7 @@ public function testNumGroups() $this->assertEquals(2, $this->obj->numGroups()); } - /** - * @return void - */ - public function testSetFormData() + public function testSetFormData(): void { $this->assertEquals([], $this->obj->formData()); $ret = $this->obj->setFormData([ 'foo' => 'bar' ]); @@ -158,10 +124,7 @@ public function testSetFormData() $this->assertEquals([ 'baz' => 42 ], $this->obj->formData()); } - /** - * @return void - */ - public function testAddData() + public function testAddData(): void { $ret = $this->obj->addFormData('foo', 'bar'); $this->assertSame($ret, $this->obj); diff --git a/packages/ui/tests/Charcoal/Ui/Form/GenericFormTest.php b/packages/ui/tests/Charcoal/Ui/Form/GenericFormTest.php index 616c37a63..ebe7dab77 100644 --- a/packages/ui/tests/Charcoal/Ui/Form/GenericFormTest.php +++ b/packages/ui/tests/Charcoal/Ui/Form/GenericFormTest.php @@ -20,9 +20,6 @@ class GenericFormTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -37,10 +34,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('charcoal/ui/form/generic', $this->obj->type()); } diff --git a/packages/ui/tests/Charcoal/Ui/FormGroup/AbstractFormGroupTest.php b/packages/ui/tests/Charcoal/Ui/FormGroup/AbstractFormGroupTest.php index 4483c6321..c935f54bf 100644 --- a/packages/ui/tests/Charcoal/Ui/FormGroup/AbstractFormGroupTest.php +++ b/packages/ui/tests/Charcoal/Ui/FormGroup/AbstractFormGroupTest.php @@ -20,9 +20,6 @@ class AbstractFormGroupTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -33,34 +30,24 @@ protected function setUp(): void 'type' => null ]); - $this->obj = $this->getMockForAbstractClass(AbstractFormGroup::class, [ - [ - 'form' => $form, - 'logger' => $container['logger'], - 'view' => $container['view'], - 'layout_builder' => $container['layout/builder'], - 'form_input_builder' => $container['form/input/builder'], - ], - ]); + $this->obj = new class ([ + 'form' => $form, + 'logger' => $container['logger'], + 'view' => $container['view'], + 'layout_builder' => $container['layout/builder'], + 'form_input_builder' => $container['form/input/builder'], + ]) extends AbstractFormGroup {}; } - /** - * @return void - */ - public function testSetInputCallback() + public function testSetInputCallback(): void { $obj = $this->obj; - $cb = function($o) { - return 'foo'; - }; + $cb = (fn($o): string => 'foo'); $ret = $obj->setInputCallback($cb); $this->assertSame($ret, $obj); } - /** - * @return void - */ - public function testSetInputs() + public function testSetInputs(): void { $obj = $this->obj; $ret = $obj->setInputs([ @@ -69,10 +56,7 @@ public function testSetInputs() $this->assertSame($ret, $obj); } - /** - * @return void - */ - public function testSetPriority() + public function testSetPriority(): void { $this->assertEquals(0, $this->obj->priority()); @@ -86,40 +70,31 @@ public function testSetPriority() $this->obj->setPriority('foobar'); } - /** - * @return void - */ - public function testSetL10nMode() + public function testSetL10nMode(): void { $ret = $this->obj->setL10nMode('loop'); $this->assertSame($ret, $this->obj); $this->assertEquals('loop', $this->obj->l10nMode()); } - /** - * @return void - */ - public function testHasInputs() + public function testHasInputs(): void { $obj = $this->obj; $this->assertFalse($obj->hasInputs()); - $ret = $obj->setInputs([ + $obj->setInputs([ 'test' => [] ]); $this->assertTrue($obj->hasInputs()); } - /** - * @return void - */ - public function testNumInput() + public function testNumInput(): void { $obj = $this->obj; $this->assertEquals(0, $obj->numInputs()); - $ret = $obj->setInputs([ + $obj->setInputs([ 'test' => [], 'foobar' => [] ]); diff --git a/packages/ui/tests/Charcoal/Ui/FormGroup/GenericFormGroupTest.php b/packages/ui/tests/Charcoal/Ui/FormGroup/GenericFormGroupTest.php index 9d8791a0b..9ab9f31c6 100644 --- a/packages/ui/tests/Charcoal/Ui/FormGroup/GenericFormGroupTest.php +++ b/packages/ui/tests/Charcoal/Ui/FormGroup/GenericFormGroupTest.php @@ -21,9 +21,6 @@ class GenericFormGroupTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -46,10 +43,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(GenericFormGroup::class, $this->obj); } diff --git a/packages/ui/tests/Charcoal/Ui/FormInput/GenericFormInputTest.php b/packages/ui/tests/Charcoal/Ui/FormInput/GenericFormInputTest.php index f422ff496..42eacdcef 100644 --- a/packages/ui/tests/Charcoal/Ui/FormInput/GenericFormInputTest.php +++ b/packages/ui/tests/Charcoal/Ui/FormInput/GenericFormInputTest.php @@ -20,9 +20,6 @@ class GenericFormInputTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -38,10 +35,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('charcoal/ui/form-input/generic', $this->obj->type()); } diff --git a/packages/ui/tests/Charcoal/Ui/Layout/AbstractLayoutTest.php b/packages/ui/tests/Charcoal/Ui/Layout/AbstractLayoutTest.php index 0ef2b90e3..0c70d8df7 100644 --- a/packages/ui/tests/Charcoal/Ui/Layout/AbstractLayoutTest.php +++ b/packages/ui/tests/Charcoal/Ui/Layout/AbstractLayoutTest.php @@ -16,12 +16,9 @@ class AbstractLayoutTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { - $this->obj = $this->getMockForAbstractClass(AbstractLayout::class); + $this->obj = new class extends AbstractLayout {}; } /** @@ -30,10 +27,8 @@ protected function setUp(): void * - Is chainable * - Sets the position (retrievable with `position()`) * - Throws an exception when setting non-numeric (integer) values. - * - * @return void */ - public function testSetPosition() + public function testSetPosition(): void { $obj = $this->obj; $this->assertEquals(0, $obj->position()); @@ -46,26 +41,17 @@ public function testSetPosition() $obj->setPosition('foo'); } - /** - * @return void - */ - public function testDefaultPosition() + public function testDefaultPosition(): void { $obj = $this->obj; $this->assertEquals(0, $obj->position()); } - /** - * @return void - */ - public function testSetData() + public function testSetData(): void { $struct = [[ 'columns' => [ 1 ] ]]; - $computed = [ - 'columns' => [ 1 ] - ]; $obj = $this->obj; $ret = $obj->setData([ @@ -75,10 +61,7 @@ public function testSetData() //$this->assertEquals($computed, $obj->structure()); } - /** - * @return void - */ - public function testSetStructure() + public function testSetStructure(): void { $obj = $this->obj; $this->assertEquals([], $obj->structure()); @@ -121,10 +104,7 @@ public function testSetStructure() $this->assertEquals($res, $obj->structure()); } - /** - * @return void - */ - public function testNumRows() + public function testNumRows(): void { $obj = $this->obj; $this->assertEquals(0, $obj->numRows()); @@ -136,10 +116,7 @@ public function testNumRows() $this->assertEquals(3, $obj->numRows()); } - /** - * @return void - */ - public function testRowIndex() + public function testRowIndex(): void { $obj = $this->obj; $this->assertNull($obj->rowIndex()); @@ -156,10 +133,7 @@ public function testRowIndex() $this->assertEquals(0, $obj->rowIndex(5)); } - /** - * @return void - */ - public function testRowData() + public function testRowData(): void { $obj = $this->obj; $this->assertNull($obj->rowData()); @@ -176,10 +150,7 @@ public function testRowData() $this->assertNull($obj->rowData(5)); } - /** - * @return void - */ - public function testRowNumColumns() + public function testRowNumColumns(): void { $obj = $this->obj; $this->assertNull($obj->rowNumColumns()); @@ -196,10 +167,7 @@ public function testRowNumColumns() $this->assertNull($obj->rowNumColumns(5)); } - /** - * @return void - */ - public function testRowNumCells() + public function testRowNumCells(): void { $obj = $this->obj; $this->assertNull($obj->rowNumCells()); @@ -216,10 +184,7 @@ public function testRowNumCells() $this->assertNull($obj->rowNumCells(5)); } - /** - * @return void - */ - public function testRowFirstCellIndex() + public function testRowFirstCellIndex(): void { $obj = $this->obj; $this->assertNull($obj->rowFirstCellIndex()); @@ -236,10 +201,7 @@ public function testRowFirstCellIndex() //$this->assertNull($obj->rowFirstCellIndex(5)); } - /** - * @return void - */ - public function testCellRowIndex() + public function testCellRowIndex(): void { $obj = $this->obj; //$this->assertNull($obj->cellRowIndex()); @@ -256,10 +218,7 @@ public function testCellRowIndex() //$this->assertNull($obj->cellRowIndex(5)); } - /** - * @return void - */ - public function testNumCellsTotal() + public function testNumCellsTotal(): void { $obj = $this->obj; $this->assertEquals(0, $obj->numCellsTotal()); @@ -271,10 +230,7 @@ public function testNumCellsTotal() $this->assertEquals(5, $obj->numCellsTotal()); } - /** - * @return void - */ - public function testNumCellSpan() + public function testNumCellSpan(): void { $obj = $this->obj; $this->assertNull($obj->cellSpan()); @@ -291,10 +247,7 @@ public function testNumCellSpan() $this->assertNull($obj->cellSpan(5)); } - /** - * @return void - */ - public function testNumCellSpanBy12() + public function testNumCellSpanBy12(): void { $obj = $this->obj; $this->assertNull($obj->cellSpanBy12()); @@ -311,10 +264,7 @@ public function testNumCellSpanBy12() $this->assertNull($obj->cellSpanBy12(5)); } - /** - * @return void - */ - public function testCellStartsRow() + public function testCellStartsRow(): void { $obj = $this->obj; //$this->assertNull($obj->cellStartsRow()); @@ -331,10 +281,7 @@ public function testCellStartsRow() //$this->assertNull($obj->cellStartsRow(5)); } - /** - * @return void - */ - public function testCellEndsRow() + public function testCellEndsRow(): void { $obj = $this->obj; //$this->assertNull($obj->cellStartsRow()); @@ -351,19 +298,13 @@ public function testCellEndsRow() //$this->assertNull($obj->cellEndsRow(5)); } - /** - * @return void - */ - public function testStart() + public function testStart(): void { $obj = $this->obj; $this->assertEquals('', $obj->start()); } - /** - * @return void - */ - public function testEnd() + public function testEnd(): void { $obj = $this->obj; $this->assertEquals(0, $obj->position()); diff --git a/packages/ui/tests/Charcoal/Ui/Layout/GenericLayoutTest.php b/packages/ui/tests/Charcoal/Ui/Layout/GenericLayoutTest.php index d5e2443ab..a8dec5e92 100644 --- a/packages/ui/tests/Charcoal/Ui/Layout/GenericLayoutTest.php +++ b/packages/ui/tests/Charcoal/Ui/Layout/GenericLayoutTest.php @@ -19,9 +19,6 @@ class GenericLayoutTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -32,10 +29,7 @@ protected function setUp(): void $this->obj = new GenericLayout(); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('charcoal/ui/layout/generic', $this->obj->type()); } diff --git a/packages/ui/tests/Charcoal/Ui/Menu/AbstractMenuTest.php b/packages/ui/tests/Charcoal/Ui/Menu/AbstractMenuTest.php index 81e3dfbc5..17081f123 100644 --- a/packages/ui/tests/Charcoal/Ui/Menu/AbstractMenuTest.php +++ b/packages/ui/tests/Charcoal/Ui/Menu/AbstractMenuTest.php @@ -20,30 +20,21 @@ class AbstractMenuTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); $container->register(new MenuServiceProvider()); - $this->obj = $this->getMockForAbstractClass(AbstractMenu::class, [ - [ - 'container' => $container, - 'logger' => $container['logger'], - 'view' => $container['view'], - 'menu_item_builder' => $container['menu/item/builder'], - ], - ]); + $this->obj = new class ([ + 'container' => $container, + 'logger' => $container['logger'], + 'view' => $container['view'], + 'menu_item_builder' => $container['menu/item/builder'], + ]) extends AbstractMenu {}; } - /** - * @return void - */ - public function testHasItems() + public function testHasItems(): void { - $obj = $this->obj; $this->assertFalse($this->obj->hasItems()); $this->obj->setItems([ @@ -53,10 +44,7 @@ public function testHasItems() $this->assertTrue($this->obj->hasItems()); } - /** - * @return void - */ - public function testNumItems() + public function testNumItems(): void { $obj = $this->obj; $this->assertEquals(0, $obj->numItems()); @@ -69,10 +57,7 @@ public function testNumItems() $this->assertEquals(2, $obj->numItems()); } - /** - * @return void - */ - public function testItems() + public function testItems(): void { $ret = iterator_to_array($this->obj->items()); $this->assertEmpty($ret); @@ -92,12 +77,9 @@ public function testItems() $this->assertInstanceOf(MenuItemInterface::class, $ret['foobar']); } - /** - * @return void - */ - public function testItemCallback() + public function testItemCallback(): void { - $cb = function($item) { + $cb = function($item): void { $item['property_from_callback'] = 'yes'; }; $ret = $this->obj->setItemCallback($cb); @@ -113,10 +95,7 @@ public function testItemCallback() $this->assertEquals('yes', $ret['foobar']['property_from_callback']); } - /** - * @return void - */ - public function testItemsPriority() + public function testItemsPriority(): void { $ret = iterator_to_array($this->obj->items()); $this->assertEmpty($ret); diff --git a/packages/ui/tests/Charcoal/Ui/Menu/GenericMenuTest.php b/packages/ui/tests/Charcoal/Ui/Menu/GenericMenuTest.php index 7ce03f389..7a853bb0f 100644 --- a/packages/ui/tests/Charcoal/Ui/Menu/GenericMenuTest.php +++ b/packages/ui/tests/Charcoal/Ui/Menu/GenericMenuTest.php @@ -19,9 +19,6 @@ class GenericMenuTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -35,10 +32,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('charcoal/ui/menu/generic', $this->obj->type()); } diff --git a/packages/ui/tests/Charcoal/Ui/MenuItem/AbstractMenuItemTest.php b/packages/ui/tests/Charcoal/Ui/MenuItem/AbstractMenuItemTest.php index 120079305..d30289614 100644 --- a/packages/ui/tests/Charcoal/Ui/MenuItem/AbstractMenuItemTest.php +++ b/packages/ui/tests/Charcoal/Ui/MenuItem/AbstractMenuItemTest.php @@ -19,9 +19,6 @@ class AbstractMenuItemTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -29,40 +26,32 @@ protected function setUp(): void $menu = $container['menu/builder']->build([]); - $this->obj = $this->getMockForAbstractClass(AbstractMenuItem::class, [ - [ - 'menu' => $menu, - 'logger' => $container['logger'], - 'view' => $container['view'], - 'menu_item_builder' => $container['menu/item/builder'], - ], - ]); + $this->obj = new class ([ + 'menu' => $menu, + 'logger' => $container['logger'], + 'view' => $container['view'], + 'menu_item_builder' => $container['menu/item/builder'], + ]) extends AbstractMenuItem {}; } - /** - * @return void - */ - public function testHasChildren() + public function testHasChildren(): void { $obj = $this->obj; $this->assertFalse($obj->hasChildren()); - $ret = $obj->setChildren([ + $obj->setChildren([ 'test' => [] ]); $this->assertTrue($obj->hasChildren()); } - /** - * @return void - */ - public function testNumChildren() + public function testNumChildren(): void { $obj = $this->obj; $this->assertEquals(0, $obj->numChildren()); - $ret = $obj->setChildren([ + $obj->setChildren([ 'test' => [], 'foobar' => [] ]); diff --git a/packages/ui/tests/Charcoal/Ui/MenuItem/GenericMenuItemTest.php b/packages/ui/tests/Charcoal/Ui/MenuItem/GenericMenuItemTest.php index 41afcf827..66a075ad9 100644 --- a/packages/ui/tests/Charcoal/Ui/MenuItem/GenericMenuItemTest.php +++ b/packages/ui/tests/Charcoal/Ui/MenuItem/GenericMenuItemTest.php @@ -19,9 +19,6 @@ class GenericMenuItemTest extends AbstractTestCase */ public $obj; - /** - * @return void - */ protected function setUp(): void { $container = $this->getContainer(); @@ -37,10 +34,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testType() + public function testType(): void { $this->assertEquals('charcoal/ui/menu-item/generic', $this->obj->type()); } diff --git a/packages/ui/tests/Charcoal/Ui/ServiceProvider/DashboardServiceProviderTest.php b/packages/ui/tests/Charcoal/Ui/ServiceProvider/DashboardServiceProviderTest.php index 13da4385c..61bcabf69 100644 --- a/packages/ui/tests/Charcoal/Ui/ServiceProvider/DashboardServiceProviderTest.php +++ b/packages/ui/tests/Charcoal/Ui/ServiceProvider/DashboardServiceProviderTest.php @@ -27,37 +27,24 @@ class DashboardServiceProviderTest extends AbstractTestCase */ public $container; - /** - * @return void - */ protected function setUp(): void { $this->obj = new DashboardServiceProvider(); $this->container = new Container(); - $this->container['logger'] = function () { - return new NullLogger(); - }; + $this->container['logger'] = (fn(): \Psr\Log\NullLogger => new NullLogger()); // Required depdendencies (stub) - $this->container['view'] = function () { - return null; - }; - $this->container['widget/builder'] = function () { - return null; - }; - $this->container['layout/builder'] = function () { - return null; - }; + $this->container['view'] = (fn(): null => null); + $this->container['widget/builder'] = (fn(): null => null); + $this->container['layout/builder'] = (fn(): null => null); } /** * Asserts that the `register()` method * - Registers all services on the container - * - * @return void */ - public function testRegisterRegistersAllProviders() + public function testRegisterRegistersAllProviders(): void { $this->container->register($this->obj); @@ -65,23 +52,17 @@ public function testRegisterRegistersAllProviders() $this->assertTrue(isset($this->container['dashboard/builder'])); } - /** - * @return void - */ - public function testDashboardFactory() + public function testDashboardFactory(): void { $this->container->register($this->obj); $factory = $this->container['dashboard/factory']; - $this->assertInstanceOf('\Charcoal\Factory\GenericFactory', $factory); + $this->assertInstanceOf(\Charcoal\Factory\GenericFactory::class, $factory); } - /** - * @return void - */ - public function testDashboardBuilder() + public function testDashboardBuilder(): void { $this->container->register($this->obj); $factory = $this->container['dashboard/builder']; - $this->assertInstanceOf('\Charcoal\Ui\Dashboard\DashboardBuilder', $factory); + $this->assertInstanceOf(\Charcoal\Ui\Dashboard\DashboardBuilder::class, $factory); } } diff --git a/packages/ui/tests/Charcoal/Ui/ServiceProvider/UiServiceProviderTest.php b/packages/ui/tests/Charcoal/Ui/ServiceProvider/UiServiceProviderTest.php index a4da40ef0..a55f1b665 100644 --- a/packages/ui/tests/Charcoal/Ui/ServiceProvider/UiServiceProviderTest.php +++ b/packages/ui/tests/Charcoal/Ui/ServiceProvider/UiServiceProviderTest.php @@ -24,9 +24,6 @@ class UiServiceProviderTest extends AbstractTestCase */ public $container; - /** - * @return void - */ protected function setUp(): void { $this->obj = new UiServiceProvider(); @@ -36,10 +33,8 @@ protected function setUp(): void /** * Asserts that the `register()` method * - Registers all services on the container - * - * @return void */ - public function testRegisterRegistersAllProviders() + public function testRegisterRegistersAllProviders(): void { $this->container->register($this->obj); diff --git a/packages/ui/tests/bootstrap.php b/packages/ui/tests/bootstrap.php new file mode 100644 index 000000000..90929e3b5 --- /dev/null +++ b/packages/ui/tests/bootstrap.php @@ -0,0 +1,14 @@ + - + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/user/src/Charcoal/User/AbstractAuthToken.php b/packages/user/src/Charcoal/User/AbstractAuthToken.php index 5c9b26503..90743b852 100644 --- a/packages/user/src/Charcoal/User/AbstractAuthToken.php +++ b/packages/user/src/Charcoal/User/AbstractAuthToken.php @@ -38,21 +38,18 @@ abstract class AbstractAuthToken extends AbstractModel implements /** * The related user ID. - * - * @var string */ - private $userId; + private ?string $userId = null; /** * The token's expiration date. - * - * @var DateTimeInterface|null */ - private $expiry; + private ?\DateTimeInterface $expiry = null; /** * @return string */ + #[\Override] public function key() { return 'ident'; @@ -238,7 +235,7 @@ public function getUserIdFromToken($ident, $token) } // Validate encrypted token - if (password_verify($token, $this['token']) !== true) { + if (!password_verify($token, (string)$this['token'])) { $this->panic(); $this->delete(); return null; @@ -250,10 +247,8 @@ public function getUserIdFromToken($ident, $token) /** * Delete all auth tokens from storage for the current user. - * - * @return void */ - public function deleteUserAuthTokens() + public function deleteUserAuthTokens(): void { $userId = $this['userId']; if (isset($userId)) { @@ -292,6 +287,7 @@ protected function panic() * * @return boolean */ + #[\Override] protected function preSave() { $result = parent::preSave(); @@ -310,7 +306,8 @@ protected function preSave() * @param array $properties The properties (ident) set for update. * @return boolean */ - protected function preUpdate(array $properties = null) + #[\Override] + protected function preUpdate(?array $properties = null) { $result = parent::preUpdate($properties); @@ -326,7 +323,7 @@ protected function touchToken() { $token = $this['token']; if (password_needs_rehash($token, PASSWORD_DEFAULT)) { - $this['token'] = password_hash($token, PASSWORD_DEFAULT); + $this['token'] = password_hash((string)$token, PASSWORD_DEFAULT); } } @@ -336,7 +333,8 @@ protected function touchToken() * @param array $data Optional metadata to merge on the object. * @return AuthTokenMetadata */ - protected function createMetadata(array $data = null) + #[\Override] + protected function createMetadata(?array $data = null) { $class = $this->metadataClass(); return new $class($data); @@ -347,6 +345,7 @@ protected function createMetadata(array $data = null) * * @return string */ + #[\Override] protected function metadataClass() { return AuthTokenMetadata::class; diff --git a/packages/user/src/Charcoal/User/AbstractAuthenticator.php b/packages/user/src/Charcoal/User/AbstractAuthenticator.php index 3e4076194..0c4603c2b 100644 --- a/packages/user/src/Charcoal/User/AbstractAuthenticator.php +++ b/packages/user/src/Charcoal/User/AbstractAuthenticator.php @@ -68,31 +68,23 @@ abstract class AbstractAuthenticator implements /** * The user object type. - * - * @var string */ - private $userType; + private string $userType; /** * Store the user model factory instance for the current class. - * - * @var FactoryInterface */ - private $userFactory; + private \Charcoal\Factory\FactoryInterface $userFactory; /** * The auth-token object type. - * - * @var string */ - private $tokenType; + private string $tokenType; /** * Store the auth-token model factory instance for the current class. - * - * @var FactoryInterface */ - private $tokenFactory; + private \Charcoal\Factory\FactoryInterface $tokenFactory; /** * @param array $data Authenticator dependencies. @@ -298,9 +290,8 @@ public function getUserId() * Log a user into the application without sessions or cookies. * * @param AuthenticatableInterface $user The authenticated user. - * @return void */ - public function setUser(AuthenticatableInterface $user) + public function setUser(AuthenticatableInterface $user): void { $this->authenticatedUser = $user; $this->isLoggedOut = false; @@ -312,9 +303,8 @@ public function setUser(AuthenticatableInterface $user) * Log a user into the application without sessions or cookies. * * @param mixed $userId The authenticated user ID. - * @return void */ - public function setUserById($userId) + public function setUserById($userId): void { $user = $this->createUser(); $user->loadFrom($user->getAuthIdKey(), $userId); @@ -376,9 +366,8 @@ public function getAuthenticationToken() * * @param AuthenticatableInterface $user The authenticated user to log in. * @param boolean $remember Whether to "remember" the user or not. - * @return void */ - public function login(AuthenticatableInterface $user, $remember = false) + public function login(AuthenticatableInterface $user, $remember = false): void { if (!$user->getAuthId()) { return; @@ -395,10 +384,8 @@ public function login(AuthenticatableInterface $user, $remember = false) /** * Log the user out of the application. - * - * @return void */ - public function logout() + public function logout(): void { $user = $this->user(); @@ -462,7 +449,7 @@ public function authenticateByPassword($identifier, $password, $remember = false $this->logger->warning(sprintf( '[Authenticator] Invalid login attempt for user "%s" (%s): The table "%s" does not exist.', $identifier, - get_class($user), + $user::class, $user->source()->table() )); return null; @@ -478,7 +465,7 @@ public function authenticateByPassword($identifier, $password, $remember = false // Validate password $hashedPassword = $user->getAuthPassword(); - if (password_verify($password, $hashedPassword)) { + if (password_verify($password, (string)$hashedPassword)) { if (password_needs_rehash($hashedPassword, PASSWORD_DEFAULT)) { $this->rehashUserPassword($user, $password); } @@ -492,7 +479,7 @@ public function authenticateByPassword($identifier, $password, $remember = false $this->logger->warning(sprintf( '[Authenticator] Invalid login attempt for user "%s" (%s): invalid password.', $identifier, - get_class($user) + $user::class )); return null; @@ -510,7 +497,7 @@ protected function authenticateBySession() if (!$user->source()->tableExists()) { $this->logger->warning(sprintf( '[Authenticator] Invalid login attempt by session for a user (%s): The table "%s" does not exist.', - get_class($user), + $user::class, $user->source()->table() )); return null; @@ -573,7 +560,7 @@ protected function authenticateByToken() if (!$user->source()->tableExists()) { $this->logger->warning(sprintf( '[Authenticator] Invalid login attempt by token for a user (%s): The table "%s" does not exist.', - get_class($user), + $user::class, $user->source()->table() )); return null; @@ -601,9 +588,9 @@ protected function authenticateByToken() * @param AuthenticatableInterface|null $user The authenticated user to forget. * @return void */ - protected function deleteUserSession(AuthenticatableInterface $user = null) + protected function deleteUserSession(?AuthenticatableInterface $user = null) { - if ($user === null) { + if (!$user instanceof \Charcoal\User\Access\AuthenticatableInterface) { $user = $this->userFactory()->get($this->userType()); } @@ -619,7 +606,7 @@ protected function deleteUserSession(AuthenticatableInterface $user = null) * @param AuthenticatableInterface|null $user The authenticated user to forget. * @return void */ - protected function deleteUserTokens(AuthenticatableInterface $user = null) + protected function deleteUserTokens(?AuthenticatableInterface $user = null) { $authToken = $this->createToken(); if (!$authToken->isEnabled()) { @@ -628,7 +615,7 @@ protected function deleteUserTokens(AuthenticatableInterface $user = null) $authToken->deleteCookie(); - if ($user === null) { + if (!$user instanceof \Charcoal\User\Access\AuthenticatableInterface) { return; } @@ -732,7 +719,7 @@ public function validateLogin($identifier, $password) */ public function validateAuthIdentifier($identifier) { - return (is_string($identifier) && !empty($identifier)); + return (is_string($identifier) && ($identifier !== '' && $identifier !== '0')); } /** @@ -743,7 +730,7 @@ public function validateAuthIdentifier($identifier) */ public function validateAuthPassword($password) { - return (is_string($password) && !empty($password)); + return (is_string($password) && ($password !== '' && $password !== '0')); } /** @@ -781,7 +768,7 @@ public function rehashUserPassword(AuthenticatableInterface $user, $password, $u $userId = $user->getAuthId(); if ($update && $userId) { - $userClass = get_class($user); + $userClass = $user::class; $this->logger->info(sprintf( '[Authenticator] Rehashing password for user "%s" (%s)', @@ -839,7 +826,7 @@ public function changeUserPassword(AuthenticatableInterface $user, $password, $u $userId = $user->getAuthId(); if ($update && $userId) { - $userClass = get_class($user); + $userClass = $user::class; $this->logger->info(sprintf( '[Authenticator] Changing password for user "%s" (%s)', diff --git a/packages/user/src/Charcoal/User/AbstractAuthorizer.php b/packages/user/src/Charcoal/User/AbstractAuthorizer.php index 6d2361b6d..b9c1da52c 100644 --- a/packages/user/src/Charcoal/User/AbstractAuthorizer.php +++ b/packages/user/src/Charcoal/User/AbstractAuthorizer.php @@ -41,10 +41,8 @@ abstract class AbstractAuthorizer implements /** * The ACL service. - * - * @var Acl */ - private $acl; + private \Laminas\Permissions\Acl\Acl $acl; /** * @param array $data Class dependencies. @@ -334,9 +332,8 @@ protected function getAcl() /** * @param Acl $acl The ACL service. - * @return void */ - private function setAcl(Acl $acl) + private function setAcl(Acl $acl): void { $this->acl = $acl; } diff --git a/packages/user/src/Charcoal/User/AbstractUser.php b/packages/user/src/Charcoal/User/AbstractUser.php index c048b1825..621675d3e 100644 --- a/packages/user/src/Charcoal/User/AbstractUser.php +++ b/packages/user/src/Charcoal/User/AbstractUser.php @@ -29,17 +29,13 @@ abstract class AbstractUser extends Content implements * The email address should be unique and mandatory. * * It is also used as the login name. - * - * @var string */ - private $email; + private ?string $email = null; /** * The password is stored encrypted in the (database) storage. - * - * @var string|null */ - private $password; + private ?string $password = null; /** * The display name serves as a human-readable identifier for the user. @@ -53,42 +49,32 @@ abstract class AbstractUser extends Content implements * * @var string[] */ - private $roles = []; + private array $roles = []; /** * The timestamp of the latest (successful) login. - * - * @var DateTimeInterface|null */ - private $lastLoginDate; + private ?\DateTimeInterface $lastLoginDate = null; /** * The IP address during the latest (successful) login. - * - * @var string|null */ - private $lastLoginIp; + private ?string $lastLoginIp = null; /** * The timestamp of the latest password change. - * - * @var DateTimeInterface|null */ - private $lastPasswordDate; + private ?\DateTimeInterface $lastPasswordDate = null; /** * The IP address during the latest password change. - * - * @var string|null */ - private $lastPasswordIp; + private ?string $lastPasswordIp = null; /** * The token value for the "remember me" session. - * - * @var string|null */ - private $loginToken; + private ?string $loginToken = null; /** * The user preferences. @@ -192,7 +178,7 @@ public function setRoles($roles) ); } - $this->roles = array_filter(array_map('trim', $roles), 'strlen'); + $this->roles = array_filter(array_map(trim(...), $roles), strlen(...)); return $this; } @@ -468,7 +454,8 @@ public function getAuthLoginTokenKey() * @param ValidatorInterface $v Optional. A custom validator object to use for validation. If null, use object's. * @return boolean */ - public function validate(ValidatorInterface &$v = null) + #[\Override] + public function validate(?ValidatorInterface &$v = null) { $result = parent::validate($v); @@ -501,7 +488,7 @@ protected function validateLoginRequired() return false; } - if (strpos($userKey, 'email') !== false && !filter_var($userLogin, FILTER_VALIDATE_EMAIL)) { + if (str_contains($userKey, 'email') && !filter_var($userLogin, FILTER_VALIDATE_EMAIL)) { $this->validator()->error( 'User Credentials: Email format is incorrect.', $userKey @@ -527,7 +514,7 @@ protected function validateLoginUnique() $originalUser = $factory->create($objType)->load($this->getAuthId()); - if (mb_strtolower($originalUser->getAuthIdentifier()) !== mb_strtolower($userLogin)) { + if (mb_strtolower((string)$originalUser->getAuthIdentifier()) !== mb_strtolower((string)$userLogin)) { $existingUser = $factory->create($objType)->loadFrom($userKey, $userLogin); /** Check for existing user with given email. */ if (!empty($existingUser->getAuthId())) { diff --git a/packages/user/src/Charcoal/User/Access/AuthenticatableInterface.php b/packages/user/src/Charcoal/User/Access/AuthenticatableInterface.php index 874ba4c46..e8078d049 100644 --- a/packages/user/src/Charcoal/User/Access/AuthenticatableInterface.php +++ b/packages/user/src/Charcoal/User/Access/AuthenticatableInterface.php @@ -1,5 +1,7 @@ getAuthLoginTokenKey(); $this[$key] = $value; diff --git a/packages/user/src/Charcoal/User/Acl/Manager.php b/packages/user/src/Charcoal/User/Acl/Manager.php index 5f2b8961a..38cf7ab1f 100644 --- a/packages/user/src/Charcoal/User/Acl/Manager.php +++ b/packages/user/src/Charcoal/User/Acl/Manager.php @@ -33,9 +33,8 @@ public function __construct(array $data) * @param Acl $acl The Laminas Acl instant to load permissions to. * @param array $permissions The array of permissions, in [role=>details] array. * @param string $resource The Acl resource (string identifier) to load roles and permissions into. - * @return void */ - public function loadPermissions(Acl &$acl, array $permissions, $resource = '') + public function loadPermissions(Acl &$acl, array $permissions, $resource = ''): void { foreach ($permissions as $role => $rolePermissions) { $this->addRoleAndPermissions($acl, $role, $rolePermissions, $resource); @@ -47,9 +46,8 @@ public function loadPermissions(Acl &$acl, array $permissions, $resource = '') * @param PDO $dbh The PDO database instance. * @param string $table The table where to fetch the roles and permissions. * @param string $resource The Acl resource (string identifier) to load roles and permissions into. - * @return void */ - public function loadDatabasePermissions(Acl &$acl, PDO $dbh, $table, $resource = '') + public function loadDatabasePermissions(Acl &$acl, PDO $dbh, $table, $resource = ''): void { // Quick-and-dirty sanitization $table = preg_replace('/[^A-Za-z0-9_]/', '', $table); @@ -77,13 +75,12 @@ public function loadDatabasePermissions(Acl &$acl, PDO $dbh, $table, $resource = * @param string $role The role (string identifier) to add. * @param array $permissions The permissions details (array) to add. * @param string $resource The Acl resource (string identifier) to add roles and permissions into. - * @return void */ - private function addRoleAndPermissions(Acl &$acl, $role, array $permissions, $resource) + private function addRoleAndPermissions(Acl &$acl, $role, array $permissions, $resource): void { if (!$acl->hasRole($role)) { // Add role - $parentRole = isset($permissions['parent']) ? $permissions['parent'] : null; + $parentRole = ($permissions['parent'] ?? null); $parentRole = $parentRole ?: null; $newRole = new GenericRole($role); $acl->addRole($newRole, $parentRole); @@ -107,11 +104,7 @@ private function addRoleAndPermissions(Acl &$acl, $role, array $permissions, $re } if (isset($permissions['denied'])) { - if (is_string($permissions['denied'])) { - $deniedPermissions = explode(',', $permissions['denied']); - } else { - $deniedPermissions = $permissions['denied']; - } + $deniedPermissions = is_string($permissions['denied']) ? explode(',', $permissions['denied']) : $permissions['denied']; foreach ($deniedPermissions as $denied) { $acl->deny($role, $resource, $denied); } diff --git a/packages/user/src/Charcoal/User/Acl/Permission.php b/packages/user/src/Charcoal/User/Acl/Permission.php index 69e76b8d1..4b2ce3b1a 100644 --- a/packages/user/src/Charcoal/User/Acl/Permission.php +++ b/packages/user/src/Charcoal/User/Acl/Permission.php @@ -21,10 +21,7 @@ class Permission extends AbstractModel implements CategorizableInterface use CategorizableTrait; use TranslatorAwareTrait; - /** - * @var string|null - */ - private $ident; + private ?string $ident = null; /** * @var \Charcoal\Translator\Translation|null @@ -33,9 +30,8 @@ class Permission extends AbstractModel implements CategorizableInterface /** * Permission can be used as a string (ident). - * - * @return string */ + #[\Override] public function __toString(): string { if ($this->ident === null) { @@ -44,10 +40,8 @@ public function __toString(): string return $this->ident; } - /** - * @return string - */ - public function key() + #[\Override] + public function key(): string { return 'ident'; } @@ -55,9 +49,8 @@ public function key() /** * @param string $ident The permission identifier. * @throws InvalidArgumentException If the ident is not a string. - * @return self */ - public function setIdent($ident) + public function setIdent($ident): static { if (!is_string($ident)) { throw new InvalidArgumentException( @@ -68,19 +61,15 @@ public function setIdent($ident) return $this; } - /** - * @return string|null - */ - public function getIdent() + public function getIdent(): ?string { return $this->ident; } /** * @param mixed $name The permission name / label. - * @return self */ - public function setName($name) + public function setName($name): static { $this->name = $this->translator()->translation($name); return $this; @@ -98,6 +87,7 @@ public function getName() * @param Container $container Pimple DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/user/src/Charcoal/User/Acl/PermissionCategory.php b/packages/user/src/Charcoal/User/Acl/PermissionCategory.php index e502fbe93..fc50e719f 100644 --- a/packages/user/src/Charcoal/User/Acl/PermissionCategory.php +++ b/packages/user/src/Charcoal/User/Acl/PermissionCategory.php @@ -1,5 +1,7 @@ name = $this->translator()->translation($name); return $this; @@ -37,10 +38,7 @@ public function getName() return $this->name; } - /** - * @return array - */ - public function loadCategoryItems() + public function loadCategoryItems(): array { return []; } diff --git a/packages/user/src/Charcoal/User/Acl/Role.php b/packages/user/src/Charcoal/User/Acl/Role.php index d564aacd1..b848040ff 100644 --- a/packages/user/src/Charcoal/User/Acl/Role.php +++ b/packages/user/src/Charcoal/User/Acl/Role.php @@ -54,21 +54,14 @@ class Role extends AbstractModel */ public $denied; - /** - * @var boolean - */ - private $superuser = false; + private bool $superuser = false; - /** - * @var integer - */ - private $position; + private ?int $position = null; /** * ACL Role can be used as a string (ident). - * - * @return string */ + #[\Override] public function __toString(): string { if ($this->ident === null) { @@ -77,19 +70,16 @@ public function __toString(): string return $this->ident; } - /** - * @return string - */ - public function key() + #[\Override] + public function key(): string { return 'ident'; } /** * @param string|Role $parent Role's parent. - * @return self */ - public function setParent($parent) + public function setParent($parent): static { if ($parent instanceof self) { $parent = $parent['ident']; @@ -109,9 +99,8 @@ public function getParent() /** * @param mixed $name The user-friendly name of this role. - * @return self */ - public function setName($name) + public function setName($name): static { $this->name = $this->p('name')->parseVal($name); return $this; @@ -127,13 +116,12 @@ public function getName() /** * @param mixed $allowed The allowed permissions for this role. - * @return self */ - public function setAllowed($allowed) + public function setAllowed($allowed): static { $allowed = $this->p('allowed')->parseVal($allowed); if (is_array($allowed)) { - $allowed = array_filter(array_map('trim', $allowed)); + $allowed = array_filter(array_map(trim(...), $allowed)); } $this->allowed = $allowed; @@ -150,13 +138,12 @@ public function getAllowed() /** * @param mixed $denied The denied permissions for this role. - * @return self */ - public function setDenied($denied) + public function setDenied($denied): static { $denied = $this->p('denied')->parseVal($denied); if (is_array($denied)) { - $denied = array_filter(array_map('trim', $denied)); + $denied = array_filter(array_map(trim(...), $denied)); } $this->denied = $denied; @@ -173,27 +160,22 @@ public function getDenied() /** * @param boolean $isSuper The superuser flag. - * @return self */ - public function setSuperuser($isSuper) + public function setSuperuser($isSuper): static { - $this->superuser = !!$isSuper; + $this->superuser = (bool)$isSuper; return $this; } - /** - * @return boolean - */ - public function getSuperuser() + public function getSuperuser(): bool { return $this->superuser; } /** * @param integer|string|null $position The role's ordering position. - * @return self */ - public function setPosition($position) + public function setPosition($position): static { $this->position = (int)$position; return $this; @@ -202,7 +184,7 @@ public function setPosition($position) /** * @return integer */ - public function getPosition() + public function getPosition(): ?int { return $this->position; } @@ -211,6 +193,7 @@ public function getPosition() * @param Container $container Pimple DI container. * @return void */ + #[\Override] protected function setDependencies(Container $container) { parent::setDependencies($container); diff --git a/packages/user/src/Charcoal/User/AclAwareTrait.php b/packages/user/src/Charcoal/User/AclAwareTrait.php index 8b3121dd9..7d84309ff 100644 --- a/packages/user/src/Charcoal/User/AclAwareTrait.php +++ b/packages/user/src/Charcoal/User/AclAwareTrait.php @@ -40,7 +40,7 @@ protected function acl() if (!$this->acl) { throw new RuntimeException(sprintf( 'ACL service is not defined for "%s"', - get_class($this) + $this::class )); } diff --git a/packages/user/src/Charcoal/User/AuthAwareInterface.php b/packages/user/src/Charcoal/User/AuthAwareInterface.php index d913d76aa..0b5e21c64 100644 --- a/packages/user/src/Charcoal/User/AuthAwareInterface.php +++ b/packages/user/src/Charcoal/User/AuthAwareInterface.php @@ -1,5 +1,7 @@ authorizer()->userAllowed($authUser, $permissions); - return $authorized; + return $this->authorizer()->userAllowed($authUser, $permissions); } /** @@ -84,7 +83,7 @@ protected function authenticator() if (!$this->authenticator) { throw new RuntimeException(sprintf( 'Authenticator service is not defined for "%s"', - get_class($this) + $this::class )); } @@ -113,7 +112,7 @@ protected function authorizer() if (!$this->authorizer) { throw new RuntimeException(sprintf( 'Authorizer service is not defined for "%s"', - get_class($this) + $this::class )); } @@ -133,7 +132,7 @@ protected function setRequiredAclPermissions($permissions) } if (is_string($permissions)) { $permissions = explode(',', $permissions); - $permissions = array_map('trim', $permissions); + $permissions = array_map(trim(...), $permissions); } if (!is_array($permissions)) { throw new InvalidArgumentException( diff --git a/packages/user/src/Charcoal/User/AuthToken.php b/packages/user/src/Charcoal/User/AuthToken.php index eb0de07b4..e5aa16655 100644 --- a/packages/user/src/Charcoal/User/AuthToken.php +++ b/packages/user/src/Charcoal/User/AuthToken.php @@ -1,5 +1,7 @@ $expiry, 'path' => $path, 'domain' => '', 'secure' => $secure]); } /** @@ -43,13 +43,13 @@ public function deleteCookie() $path = $metadata['tokenPath']; $secure = $metadata['httpsOnly']; - return setcookie($name, '', $expiry, $path, '', $secure); + return setcookie($name, '', ['expires' => $expiry, 'path' => $path, 'domain' => '', 'secure' => $secure]); } /** * @return array|null `[ 'ident' => '', 'token' => '' ] */ - public function getTokenDataFromCookie() + public function getTokenDataFromCookie(): ?array { if (!$this->isEnabled()) { return null; @@ -63,7 +63,7 @@ public function getTokenDataFromCookie() } $cookie = $_COOKIE[$name]; - $data = array_pad(explode(';', $cookie), 2, null); + $data = array_pad(explode(';', (string)$cookie), 2, null); if (!isset($data[0]) || !isset($data[1])) { return null; } diff --git a/packages/user/src/Charcoal/User/AuthTokenInterface.php b/packages/user/src/Charcoal/User/AuthTokenInterface.php index 2fa04d731..b88813d78 100644 --- a/packages/user/src/Charcoal/User/AuthTokenInterface.php +++ b/packages/user/src/Charcoal/User/AuthTokenInterface.php @@ -1,5 +1,7 @@ true, 'token_name' => 'charcoal_user_login', 'token_duration' => '15 days', 'token_path' => '', 'https_only' => false, ]); - return $defaults; } /** * @param boolean $enabled The enabled flag. - * @return self */ - public function setEnabled($enabled) + public function setEnabled($enabled): static { - $this->enabled = !!$enabled; + $this->enabled = (bool)$enabled; return $this; } /** * @return boolean */ - public function getEnabled() + public function getEnabled(): ?bool { return $this->enabled; } /** * @param boolean $httpsOnly The "HTTPS only" flag. - * @return self */ - public function setHttpsOnly($httpsOnly) + public function setHttpsOnly($httpsOnly): static { - $this->httpsOnly = !!$httpsOnly; + $this->httpsOnly = (bool)$httpsOnly; return $this; } /** * @return boolean */ - public function getHttpsOnly() + public function getHttpsOnly(): ?bool { return $this->httpsOnly; } @@ -89,9 +72,8 @@ public function getHttpsOnly() /** * @param string $name The token name. * @throws InvalidArgumentException If the token name is not a string. - * @return self */ - public function setTokenName($name) + public function setTokenName($name): static { if (!is_string($name)) { throw new InvalidArgumentException( @@ -105,7 +87,7 @@ public function setTokenName($name) /** * @return string */ - public function getTokenName() + public function getTokenName(): ?string { return $this->tokenName; } @@ -113,9 +95,8 @@ public function getTokenName() /** * @param string $duration The token duration, or duration. Ex: "15 days". * @throws InvalidArgumentException If the token name is not a string. - * @return self */ - public function setTokenDuration($duration) + public function setTokenDuration($duration): static { if (!is_string($duration)) { throw new InvalidArgumentException( @@ -129,18 +110,17 @@ public function setTokenDuration($duration) /** * @return string */ - public function getTokenDuration() + public function getTokenDuration(): ?string { return $this->tokenDuration; } /** - * @deprecated In favour of {@see self::setTokenName()}. * * @param string $name The cookie name. - * @return self */ - public function setCookieName($name) + #[\Deprecated(message: 'In favour of {@see self::setTokenName()}.')] + public function setCookieName($name): static { trigger_error( 'Auth token option "cookie_name" is deprecated in favour of "token_name"', @@ -152,11 +132,10 @@ public function setCookieName($name) } /** - * @deprecated In favour of {@see self::getTokenName()}. - * * @return string */ - public function getCookieName() + #[\Deprecated(message: 'In favour of {@see self::getTokenName()}.')] + public function getCookieName(): ?string { trigger_error( 'Auth token option "cookie_duration" is deprecated in favour of "token_duration"', @@ -167,12 +146,11 @@ public function getCookieName() } /** - * @deprecated In favour of {@see self::setTokenDuration()}. * * @param string $duration The cookie duration, or duration. Ex: "15 days". - * @return self */ - public function setCookieDuration($duration) + #[\Deprecated(message: 'In favour of {@see self::setTokenDuration()}.')] + public function setCookieDuration($duration): static { trigger_error( 'Auth token option "cookie_duration" is deprecated in favour of "token_duration"', @@ -184,11 +162,10 @@ public function setCookieDuration($duration) } /** - * @deprecated In favour of {@see self::getTokenDuration()}. - * * @return string */ - public function getCookieDuration() + #[\Deprecated(message: 'In favour of {@see self::getTokenDuration()}.')] + public function getCookieDuration(): ?string { trigger_error( 'Auth token option "cookie_duration" is deprecated in favour of "token_duration"', diff --git a/packages/user/src/Charcoal/User/Authenticator.php b/packages/user/src/Charcoal/User/Authenticator.php index 8e2b643c8..62c804fe0 100644 --- a/packages/user/src/Charcoal/User/Authenticator.php +++ b/packages/user/src/Charcoal/User/Authenticator.php @@ -19,9 +19,9 @@ class Authenticator extends AbstractAuthenticator * * @param AuthenticatableInterface $user The authenticated user to log in. * @param boolean $remember Whether to "remember" the user or not. - * @return void */ - public function login(AuthenticatableInterface $user, $remember = false) + #[\Override] + public function login(AuthenticatableInterface $user, $remember = false): void { parent::login($user, $remember); @@ -36,12 +36,11 @@ public function login(AuthenticatableInterface $user, $remember = false) * @param AuthenticatableInterface $user The user to validate. * @return boolean */ + #[\Override] public function validateAuthentication(AuthenticatableInterface $user) { - if ($user instanceof ContentInterface) { - if (!$user['active']) { - return false; - } + if ($user instanceof ContentInterface && !$user['active']) { + return false; } return parent::validateAuthentication($user); @@ -70,7 +69,7 @@ public function touchUserLogin(AuthenticatableInterface $user, $update = true) $userId = $user->getAuthId(); if ($update && $userId) { - $userClass = get_class($user); + $userClass = $user::class; $this->logger->info(sprintf( 'Updating last login fields for user "%s" (%s)', @@ -80,7 +79,7 @@ public function touchUserLogin(AuthenticatableInterface $user, $update = true) } $user['lastLoginDate'] = 'now'; - $user['lastLoginIp'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null; + $user['lastLoginIp'] = ($_SERVER['REMOTE_ADDR'] ?? null); if ($update && $userId) { $result = $user->update([ @@ -115,6 +114,7 @@ public function touchUserLogin(AuthenticatableInterface $user, $update = true) * @throws InvalidArgumentException If the password is invalid. * @return boolean Returns TRUE if the password was changed, or FALSE otherwise. */ + #[\Override] public function changeUserPassword(AuthenticatableInterface $user, $password, $update = true) { if (!($user instanceof UserInterface)) { @@ -130,7 +130,7 @@ public function changeUserPassword(AuthenticatableInterface $user, $password, $u $userId = $user->getAuthId(); if ($update && $userId) { - $userClass = get_class($user); + $userClass = $user::class; $this->logger->info(sprintf( '[Authenticator] Changing password for user "%s" (%s)', @@ -143,7 +143,7 @@ public function changeUserPassword(AuthenticatableInterface $user, $password, $u $user[$passwordKey] = password_hash($password, PASSWORD_DEFAULT); $user['lastPasswordDate'] = 'now'; - $user['lastPasswordIp'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null; + $user['lastPasswordIp'] = ($_SERVER['REMOTE_ADDR'] ?? null); if ($update && $userId) { $result = $user->update([ diff --git a/packages/user/src/Charcoal/User/AuthenticatorInterface.php b/packages/user/src/Charcoal/User/AuthenticatorInterface.php index 9ead4f012..ee7ef572e 100644 --- a/packages/user/src/Charcoal/User/AuthenticatorInterface.php +++ b/packages/user/src/Charcoal/User/AuthenticatorInterface.php @@ -1,5 +1,7 @@ defaultResource; } @@ -117,9 +114,8 @@ protected function getDefaultResource() /** * @param string|null $resource The ACL resource identifier. * @throws InvalidArgumentException If the resource identifier is not a string. - * @return void */ - private function setDefaultResource($resource) + private function setDefaultResource($resource): void { if (!is_string($resource) && $resource !== null) { throw new InvalidArgumentException( diff --git a/packages/user/src/Charcoal/User/AuthorizerInterface.php b/packages/user/src/Charcoal/User/AuthorizerInterface.php index f4b5a304a..80c9508d4 100644 --- a/packages/user/src/Charcoal/User/AuthorizerInterface.php +++ b/packages/user/src/Charcoal/User/AuthorizerInterface.php @@ -1,5 +1,7 @@ $container['logger'], - 'user_type' => User::class, - 'user_factory' => $container['model/factory'], - 'token_type' => AuthToken::class, - 'token_factory' => $container['model/factory'], - ]); - }; + $container['authenticator'] = (fn(Container $container): \Charcoal\User\Authenticator => new Authenticator([ + 'logger' => $container['logger'], + 'user_type' => User::class, + 'user_factory' => $container['model/factory'], + 'token_type' => AuthToken::class, + 'token_factory' => $container['model/factory'], + ])); } if (!isset($container['authorizer'])) { @@ -45,22 +42,18 @@ public function register(Container $container) * @param Container $container The Pimple DI container. * @return Authorizer */ - $container['authorizer'] = function (Container $container) { - return new Authorizer([ - 'logger' => $container['logger'], - 'acl' => $container['authorizer/acl'], - 'resource' => 'charcoal', - ]); - }; + $container['authorizer'] = (fn(Container $container): \Charcoal\User\Authorizer => new Authorizer([ + 'logger' => $container['logger'], + 'acl' => $container['authorizer/acl'], + 'resource' => 'charcoal', + ])); } if (!isset($container['authorizer/acl'])) { /** * @return Acl */ - $container['authorizer/acl'] = function () { - return new Acl(); - }; + $container['authorizer/acl'] = (fn(): \Laminas\Permissions\Acl\Acl => new Acl()); } } } diff --git a/packages/user/src/Charcoal/User/UserInterface.php b/packages/user/src/Charcoal/User/UserInterface.php index 45e787a18..ef2851d32 100644 --- a/packages/user/src/Charcoal/User/UserInterface.php +++ b/packages/user/src/Charcoal/User/UserInterface.php @@ -1,5 +1,7 @@ setAccessible(true); - return $reflected; + return new ReflectionMethod($class, $name); } /** @@ -38,7 +35,7 @@ public function getMethod($class, $name) public function callMethod($object, $name, array $args = []) { $method = $this->getMethod($object, $name); - if (empty($args)) { + if ($args === []) { return $method->invoke($object); } else { return $method->invokeArgs($object, $args); @@ -65,13 +62,10 @@ public function callMethodWith($object, $name, ...$args) * * @param mixed $class The class name or object that contains the property. * @param string $name The property name to reflect. - * @return ReflectionProperty */ - public function getProperty($class, $name) + public function getProperty($class, $name): \ReflectionProperty { - $reflected = new ReflectionProperty($class, $name); - $reflected->setAccessible(true); - return $reflected; + return new ReflectionProperty($class, $name); } /** @@ -92,9 +86,8 @@ public function getPropertyValue($object, $name) * @param mixed $object The object to access. * @param string $name The property name to affect. * @param mixed $value The new value. - * @return void */ - public function setPropertyValue($object, $name, $value) + public function setPropertyValue($object, $name, $value): void { $this->getProperty($object, $name)->setValue($object, $value); } diff --git a/packages/user/tests/Charcoal/User/AbstractUserTest.php b/packages/user/tests/Charcoal/User/AbstractUserTest.php index 3a91b1d12..f2ba07c69 100644 --- a/packages/user/tests/Charcoal/User/AbstractUserTest.php +++ b/packages/user/tests/Charcoal/User/AbstractUserTest.php @@ -2,6 +2,7 @@ namespace Charcoal\Tests\User; +use Charcoal\User\GenericUser; use DateTime; use InvalidArgumentException; @@ -21,22 +22,16 @@ class AbstractUserTest extends AbstractTestCase { /** * Tested Class. - * - * @var UserInterface */ - private $obj; + private \Charcoal\User\UserInterface $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -46,39 +41,24 @@ protected function setUp(): void $container = $this->container(); - $this->obj = $this->getMockForAbstractClass( - AbstractUser::class, - [ - [ - 'logger' => $container['logger'], - 'translator' => $container['translator'], - ] - ], - '', - true, - true, - true, - [ 'sessionKey' ] - ); - - $this->obj->expects($this->any()) - ->method('sessionKey') - ->will($this->returnValue('charcoal.user')); + $this->obj = new class ([ + 'logger' => $container['logger'], + 'translator' => $container['translator'], + ]) extends AbstractUser { + public static function sessionKey(): string + { + return 'charcoal.user'; + } + }; } - /** - * @return void - */ - public function testKey() + public function testKey(): void { $obj = $this->obj; $this->assertEquals('id', $obj->key()); } - /** - * @return void - */ - public function testDefaultValues() + public function testDefaultValues(): void { $obj = $this->obj; $this->assertTrue($obj['active']); @@ -88,10 +68,8 @@ public function testDefaultValues() * Assert that the `setData` method: * - is chainable * - set the various properties - * - * @return void */ - public function testSetData() + public function testSetData(): void { $obj = $this->obj; $ret = $obj->setData([ @@ -106,10 +84,7 @@ public function testSetData() $this->assertFalse($obj['active']); } - /** - * @return void - */ - public function testSetEmail() + public function testSetEmail(): void { $ret = $this->obj->setEmail('test@example.com'); $this->assertSame($ret, $this->obj); @@ -125,10 +100,7 @@ public function testSetEmail() $this->obj->setEmail(false); } - /** - * @return void - */ - public function testSetRoles() + public function testSetRoles(): void { $ret = $this->obj->setRoles(null); $this->assertSame($ret, $this->obj); @@ -144,10 +116,7 @@ public function testSetRoles() $this->obj->setRoles(42); } - /** - * @return void - */ - public function testSetLastLoginDate() + public function testSetLastLoginDate(): void { $ret = $this->obj->setLastLoginDate('today'); $this->assertSame($ret, $this->obj); @@ -172,10 +141,7 @@ public function testSetLastLoginDate() $this->obj->setLastLoginDate(false); } - /** - * @return void - */ - public function testSetLastLoginIp() + public function testSetLastLoginIp(): void { $ret = $this->obj->setLastLoginIp('8.8.8.8'); $this->assertSame($ret, $this->obj); @@ -197,10 +163,7 @@ public function testSetLastLoginIp() $this->obj->setLastLoginIp(false); } - /** - * @return void - */ - public function testSetLastPasswordDate() + public function testSetLastPasswordDate(): void { $ret = $this->obj->setLastPasswordDate('today'); $this->assertSame($ret, $this->obj); @@ -225,10 +188,7 @@ public function testSetLastPasswordDate() $this->obj->setLastPasswordDate(false); } - /** - * @return void - */ - public function testSetLastPasswordIp() + public function testSetLastPasswordIp(): void { $ret = $this->obj->setLastPasswordIp('8.8.8.8'); $this->assertSame($ret, $this->obj); @@ -253,12 +213,10 @@ public function testSetLastPasswordIp() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/user/tests/Charcoal/User/Acl/ManagerTest.php b/packages/user/tests/Charcoal/User/Acl/ManagerTest.php index 6c9bc2f6d..3c3a925d2 100644 --- a/packages/user/tests/Charcoal/User/Acl/ManagerTest.php +++ b/packages/user/tests/Charcoal/User/Acl/ManagerTest.php @@ -21,22 +21,16 @@ class ManagerTest extends AbstractTestCase { /** * Tested Class. - * - * @var Manager */ - private $obj; + private \Charcoal\User\Acl\Manager $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -47,10 +41,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testLoadPermissions() + public function testLoadPermissions(): void { $acl = new Acl(); $rsc = new Resource('phpunit'); @@ -83,10 +74,7 @@ public function testLoadPermissions() $this->assertFalse($acl->isAllowed('test2', 'phpunit', 'baz')); } - /** - * @return void - */ - public function testLoadPermissionsWithStringPermissions() + public function testLoadPermissionsWithStringPermissions(): void { $acl = new Acl(); $rsc = new Resource('phpunit'); @@ -115,12 +103,10 @@ public function testLoadPermissionsWithStringPermissions() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/user/tests/Charcoal/User/Acl/PermissionCategoryTest.php b/packages/user/tests/Charcoal/User/Acl/PermissionCategoryTest.php index a11906d28..e7d86eff5 100644 --- a/packages/user/tests/Charcoal/User/Acl/PermissionCategoryTest.php +++ b/packages/user/tests/Charcoal/User/Acl/PermissionCategoryTest.php @@ -17,22 +17,16 @@ class PermissionCategoryTest extends AbstractTestCase { /** * Tested Class. - * - * @var PermissionCategory */ - private $obj; + private \Charcoal\User\Acl\PermissionCategory $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -44,10 +38,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testSetName() + public function testSetName(): void { $ret = $this->obj->setName('foobar'); $this->assertSame($ret, $this->obj); @@ -56,12 +47,10 @@ public function testSetName() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/user/tests/Charcoal/User/Acl/PermissionTest.php b/packages/user/tests/Charcoal/User/Acl/PermissionTest.php index f0d74ee35..f53679e78 100644 --- a/packages/user/tests/Charcoal/User/Acl/PermissionTest.php +++ b/packages/user/tests/Charcoal/User/Acl/PermissionTest.php @@ -17,22 +17,16 @@ class PermissionTest extends AbstractTestCase { /** * Tested Class. - * - * @var Permission */ - private $obj; + private \Charcoal\User\Acl\Permission|array $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -44,10 +38,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testToString() + public function testToString(): void { $this->assertEquals('', (string)$this->obj); $this->obj->setIdent('foobar'); @@ -59,18 +50,13 @@ public function testToString() /** * Assert that the object's key is the "ident" property. - * - * @return void */ - public function testKey() + public function testKey(): void { $this->assertEquals('ident', $this->obj->key()); } - /** - * @return void - */ - public function testSetIdent() + public function testSetIdent(): void { $ret = $this->obj->setIdent('foobar'); $this->assertSame($ret, $this->obj); @@ -80,20 +66,14 @@ public function testSetIdent() $this->obj->setIdent(false); } - /** - * @return void - */ - public function testSetName() + public function testSetName(): void { $ret = $this->obj->setName('foobar'); $this->assertSame($ret, $this->obj); $this->assertEquals('foobar', (string)$this->obj['name']); } - /** - * @return void - */ - public function testCastToString() + public function testCastToString(): void { $this->obj->setIdent('foobar'); $this->assertEquals('foobar', (string)$this->obj); @@ -103,12 +83,10 @@ public function testCastToString() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/user/tests/Charcoal/User/Acl/RoleTest.php b/packages/user/tests/Charcoal/User/Acl/RoleTest.php index cf49d59f8..6c1dfe6d3 100644 --- a/packages/user/tests/Charcoal/User/Acl/RoleTest.php +++ b/packages/user/tests/Charcoal/User/Acl/RoleTest.php @@ -17,22 +17,16 @@ class RoleTest extends AbstractTestCase { /** * Tested Class. - * - * @var Role */ - private $obj; + private \Charcoal\User\Acl\Role $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -41,10 +35,7 @@ protected function setUp(): void $this->obj = $container['model/factory']->create(Role::class); } - /** - * @return void - */ - public function testToString() + public function testToString(): void { $this->assertEquals('', (string)$this->obj); $this->obj->ident = 'foobar'; @@ -56,28 +47,20 @@ public function testToString() /** * Assert that the object's key is the "ident" property. - * - * @return void */ - public function testKey() + public function testKey(): void { $this->assertEquals('ident', $this->obj->key()); } - /** - * @return void - */ - public function testSetParent() + public function testSetParent(): void { $ret = $this->obj->setParent('foo'); $this->assertSame($ret, $this->obj); $this->assertEquals('foo', $this->obj['parent']); } - /** - * @return void - */ - public function testSetAllowed() + public function testSetAllowed(): void { $this->assertNull($this->obj['allowed']); $ret = $this->obj->setAllowed('foo'); @@ -88,10 +71,7 @@ public function testSetAllowed() $this->assertSame(['bar', 'baz'], $this->obj['allowed']); } - /** - * @return void - */ - public function testSuperuser() + public function testSuperuser(): void { $this->assertFalse($this->obj['superuser']); $ret = $this->obj->setSuperuser(1); @@ -101,12 +81,10 @@ public function testSuperuser() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/user/tests/Charcoal/User/AuthTokenMetadataTest.php b/packages/user/tests/Charcoal/User/AuthTokenMetadataTest.php index 65b8364f5..c22230df6 100644 --- a/packages/user/tests/Charcoal/User/AuthTokenMetadataTest.php +++ b/packages/user/tests/Charcoal/User/AuthTokenMetadataTest.php @@ -17,25 +17,18 @@ class AuthTokenMetadataTest extends AbstractTestCase { /** * Tested Class. - * - * @var AuthTokenMetadata */ - private $obj; + private \Charcoal\User\AuthTokenMetadata $obj; /** * Set up the test. - * - * @return void */ protected function setUp(): void { $this->obj = new AuthTokenMetadata(); } - /** - * @return void - */ - public function testDefaults() + public function testDefaults(): void { $this->assertTrue($this->obj['enabled']); $this->assertEquals('charcoal_user_login', $this->obj['tokenName']); @@ -43,20 +36,14 @@ public function testDefaults() $this->assertFalse($this->obj['httpsOnly']); } - /** - * @return void - */ - public function testSetEnabled() + public function testSetEnabled(): void { $ret = $this->obj->setEnabled(false); $this->assertSame($ret, $this->obj); $this->assertFalse($this->obj['enabled']); } - /** - * @return void - */ - public function testSetTokenName() + public function testSetTokenName(): void { $ret = $this->obj->setTokenName('foobar'); $this->assertSame($ret, $this->obj); @@ -66,10 +53,7 @@ public function testSetTokenName() $this->obj->setTokenName(false); } - /** - * @return void - */ - public function testSetTokenDuration() + public function testSetTokenDuration(): void { $ret = $this->obj->setTokenDuration('2 month'); $this->assertSame($ret, $this->obj); diff --git a/packages/user/tests/Charcoal/User/AuthTokenTest.php b/packages/user/tests/Charcoal/User/AuthTokenTest.php index 16ddc4ecb..7780e979a 100644 --- a/packages/user/tests/Charcoal/User/AuthTokenTest.php +++ b/packages/user/tests/Charcoal/User/AuthTokenTest.php @@ -19,22 +19,16 @@ class AuthTokenTest extends AbstractTestCase { /** * Tested Class. - * - * @var AuthToken */ - private $obj; + private \Charcoal\User\AuthToken $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -47,38 +41,26 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testSetKeyIsIdent() + public function testSetKeyIsIdent(): void { $this->assertEquals('ident', $this->obj->key()); } - /** - * @return void - */ - public function testSetIdent() + public function testSetIdent(): void { $ret = $this->obj->setIdent('foo'); $this->assertSame($ret, $this->obj); $this->assertEquals('foo', $this->obj['ident']); } - /** - * @return void - */ - public function testSetToken() + public function testSetToken(): void { $ret = $this->obj->setToken('foo'); $this->assertSame($ret, $this->obj); $this->assertEquals('foo', $this->obj['token']); } - /** - * @return void - */ - public function testSetUserId() + public function testSetUserId(): void { $ret = $this->obj->setUserId('foo'); $this->assertSame($ret, $this->obj); @@ -88,10 +70,7 @@ public function testSetUserId() $this->obj->setUserId([]); } - /** - * @return void - */ - public function testSetExpiry() + public function testSetExpiry(): void { $date = new DateTime('tomorrow'); $ret = $this->obj->setExpiry($date); @@ -102,10 +81,7 @@ public function testSetExpiry() $this->obj->setExpiry('fsdjkfsadg'); } - /** - * @return void - */ - public function testSetCreated() + public function testSetCreated(): void { $date = new DateTime('tomorrow'); $ret = $this->obj->setCreated($date); @@ -116,10 +92,7 @@ public function testSetCreated() $this->obj->setCreated('fsdjkfsadg'); } - /** - * @return void - */ - public function testSetLastModified() + public function testSetLastModified(): void { $date = new DateTime('tomorrow'); $ret = $this->obj->setLastModified($date); @@ -132,12 +105,10 @@ public function testSetLastModified() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/user/tests/Charcoal/User/AuthenticatorTest.php b/packages/user/tests/Charcoal/User/AuthenticatorTest.php index b1022640f..ba812d2f0 100644 --- a/packages/user/tests/Charcoal/User/AuthenticatorTest.php +++ b/packages/user/tests/Charcoal/User/AuthenticatorTest.php @@ -19,22 +19,16 @@ class AuthenticatorTest extends AbstractTestCase { /** * Tested Class. - * - * @var Authenticator */ - private $obj; + private \Charcoal\User\Authenticator $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -47,22 +41,18 @@ protected function setUp(): void /** * Create a new Authenticator instance. - * - * @return Authenticator */ - public function createAuthenticator() + public function createAuthenticator(): \Charcoal\User\Authenticator { $container = $this->container(); - $authenticator = new Authenticator([ + return new Authenticator([ 'logger' => $container['logger'], 'user_type' => User::class, 'user_factory' => $container['model/factory'], 'token_type' => AuthToken::class, 'token_factory' => $container['model/factory'], ]); - - return $authenticator; } /** @@ -73,59 +63,41 @@ public function createAuthenticator() */ public function createUser(Authenticator $authenticator) { - $factoryMethod = new ReflectionMethod(Authenticator, 'userFactory'); + $factoryMethod = new ReflectionMethod(\AUTHENTICATOR, 'userFactory'); return $factoryMethod->invoke($authenticator)->create(User::class); } - /** - * @return void - */ - public function testConstructor() + public function testConstructor(): void { $this->assertInstanceOf(Authenticator::class, $this->obj); } - /** - * @return void - */ - public function testAuthenticate() + public function testAuthenticate(): void { $ret = $this->obj->authenticate(); $this->assertNull($ret); } - /** - * @return void - */ - public function testAuthenticateByPasswordInvalidEmail() + public function testAuthenticateByPasswordInvalidEmail(): void { $this->expectException(\InvalidArgumentException::class); $this->obj->authenticateByPassword([], ''); } - /** - * @return void - */ - public function testAuthenticateByPasswordInvalidPassword() + public function testAuthenticateByPasswordInvalidPassword(): void { $this->expectException(\InvalidArgumentException::class); $this->obj->authenticateByPassword('', []); } - /** - * @return void - */ - public function testAuthenticateByPasswordEmpty() + public function testAuthenticateByPasswordEmpty(): void { $this->expectException(\InvalidArgumentException::class); $this->obj->authenticateByPassword('', ''); } - /** - * @return void - */ - public function testAuthenticateByPassword() + public function testAuthenticateByPassword(): void { $this->assertNull($this->obj->authenticateByPassword('test', 'password')); } @@ -137,14 +109,13 @@ public function testAuthenticateByPassword() public function testUpdateSession() { $obj = $this->obj; - + $sessionKey = $obj::sessionKey(); $this->obj['id'] = 'foo'; $this->obj->saveToSession(); $this->assertEquals($_SESSION[$sessionKey], $this->obj['id']); } */ - /** * @return void */ @@ -153,22 +124,19 @@ public function testResetPassword() { $ret = $this->obj->resetPassword('foo'); $this->assertSame($ret, $this->obj); - + $this->obj['id'] = 'bar'; - + $this->expectException(InvalidArgumentException::class); $this->obj->resetPassword(false); } */ - /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/user/tests/Charcoal/User/AuthorizerTest.php b/packages/user/tests/Charcoal/User/AuthorizerTest.php index 8264f90e9..23ef31422 100644 --- a/packages/user/tests/Charcoal/User/AuthorizerTest.php +++ b/packages/user/tests/Charcoal/User/AuthorizerTest.php @@ -29,33 +29,25 @@ class AuthorizerTest extends AbstractTestCase /** * Tested Class. - * - * @var Authorizer */ - private $auth; + private \Charcoal\User\Authorizer $auth; /** * Store the ACL manager. - * - * @var Acl */ - private $acl; + private \Laminas\Permissions\Acl\Acl $acl; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ protected function setUp(): void { - $container = $this->container(); + $this->container(); $this->acl = new Acl(); $this->acl->addResource('area'); @@ -97,9 +89,8 @@ protected function setUpComplexRolesAndPrivileges() * Create an Authorizer instance. * * @param array $data Class dependencies. - * @return Authorizer */ - protected function createAuthorizer(array $data = []) + protected function createAuthorizer(array $data = []): \Charcoal\User\Authorizer { $container = $this->container(); @@ -109,9 +100,7 @@ protected function createAuthorizer(array $data = []) 'resource' => 'area', ]; - $authorizer = new Authorizer($data); - - return $authorizer; + return new Authorizer($data); } /** @@ -130,9 +119,7 @@ protected function mockAuthorizer(array $data = []) 'resource' => 'area', ]; - $stub = $this->getMockForAbstractClass(AbstractAuthorizer::class, [ $data ]); - - return $stub; + return $this->getMockForAbstractClass(AbstractAuthorizer::class, [ $data ]); } /** @@ -144,24 +131,18 @@ protected function createUser() { $container = $this->container(); - $user = $container['model/factory']->create(GenericUser::class); - - return $user; + return $container['model/factory']->create(GenericUser::class); } // Authorizer // ========================================================================= - - /** - * @return void - */ - public function testSetDefaultResourceWithNull() + public function testSetDefaultResourceWithNull(): void { $container = $this->container(); - $authorizer = $this->createAuthorizer([ + $this->createAuthorizer([ 'resource' => null ]); $auth = new Authorizer([ @@ -173,33 +154,24 @@ public function testSetDefaultResourceWithNull() $this->assertNull($this->callMethod($auth, 'getDefaultResource')); } - /** - * @return void - */ - public function testSetDefaultResourceWithBadValue() + public function testSetDefaultResourceWithBadValue(): void { $container = $this->container(); $this->expectException(\InvalidArgumentException::class); - $auth = new Authorizer([ + new Authorizer([ 'logger' => $container['logger'], 'acl' => $this->acl, 'resource' => 35, ]); } - /** - * @return void - */ - public function testRolesAllowedWithoutPermissions() + public function testRolesAllowedWithoutPermissions(): void { $this->assertTrue($this->auth->rolesAllowed([ 'guest' ], [])); } - /** - * @return void - */ - public function testRolesAllowed() + public function testRolesAllowed(): void { $this->assertFalse($this->auth->rolesAllowed([ 'guest' ], [ 'privilege1' ])); @@ -213,10 +185,7 @@ public function testRolesAllowed() $this->assertTrue($this->auth->rolesAllowed([ null ], [ 'privilege1' ])); } - /** - * @return void - */ - public function testUserAllowedWithoutPermissions() + public function testUserAllowedWithoutPermissions(): void { $user = $this->createUser(); $user['roles'] = 'guest'; @@ -224,10 +193,7 @@ public function testUserAllowedWithoutPermissions() $this->assertTrue($this->auth->userAllowed($user, [])); } - /** - * @return void - */ - public function testUserAllowed() + public function testUserAllowed(): void { $user = $this->createUser(); $user['roles'] = 'guest'; @@ -239,10 +205,7 @@ public function testUserAllowed() $this->assertFalse($this->auth->userAllowed($user, [ 'privilege1', 'privilege2' ])); } - /** - * @return void - */ - public function testIsAllowedWithDefaultResource() + public function testIsAllowedWithDefaultResource(): void { $this->acl->allow('guest', 'area', 'privilege1'); $this->assertFalse($this->auth->isAllowed('guest', null, 'privilege1')); @@ -254,11 +217,7 @@ public function testIsAllowedWithDefaultResource() // AbstractAuthorizer // ========================================================================= - - /** - * @return void - */ - public function testIsRoleGrantedCatchesAclExceptions() + public function testIsRoleGrantedCatchesAclExceptions(): void { $this->acl->allow('guest', null, [ 'privilege1', 'privilege2', 'privilege3' ]); $this->acl->deny('guest', null, [ 'privilege4', 'privilege5' ]); @@ -270,10 +229,7 @@ public function testIsRoleGrantedCatchesAclExceptions() $this->assertNull($this->auth->isRoleGrantedAny('guest', 'nonexistent', [ 'privilege4', 'privilege5' ])); } - /** - * @return void - */ - public function testIsRoleGrantedAll() + public function testIsRoleGrantedAll(): void { $this->acl->allow('guest', null, [ 'privilege1', 'privilege2', 'privilege3' ]); $this->acl->deny('guest', null, 'privilege4'); @@ -282,10 +238,7 @@ public function testIsRoleGrantedAll() $this->assertFalse($this->auth->isRoleGrantedAll('guest', null, [ 'privilege1', 'privilege4' ])); } - /** - * @return void - */ - public function testAllRolesGrantedAll() + public function testAllRolesGrantedAll(): void { $this->setUpComplexRolesAndPrivileges(); @@ -293,10 +246,7 @@ public function testAllRolesGrantedAll() $this->assertFalse($this->auth->allRolesGrantedAll([ 'aide', 'staff' ], null, [ 'edit', 'submit' ])); } - /** - * @return void - */ - public function testAnyRolesGrantedAll() + public function testAnyRolesGrantedAll(): void { $this->setUpComplexRolesAndPrivileges(); @@ -304,10 +254,7 @@ public function testAnyRolesGrantedAll() $this->assertFalse($this->auth->anyRolesGrantedAll([ 'aide', 'staff' ], null, [ 'edit', 'publish' ])); } - /** - * @return void - */ - public function testIsRoleGrantedAny() + public function testIsRoleGrantedAny(): void { $this->acl->allow('guest', null, [ 'privilege1', 'privilege2', 'privilege3' ]); $this->acl->deny('guest', null, [ 'privilege4', 'privilege5' ]); @@ -316,10 +263,7 @@ public function testIsRoleGrantedAny() $this->assertFalse($this->auth->isRoleGrantedAny('guest', null, [ 'privilege4', 'privilege5' ])); } - /** - * @return void - */ - public function testAllRolesGrantedAny() + public function testAllRolesGrantedAny(): void { $this->setUpComplexRolesAndPrivileges(); @@ -327,10 +271,7 @@ public function testAllRolesGrantedAny() $this->assertFalse($this->auth->allRolesGrantedAny([ 'aide', 'staff' ], null, [ 'publish', 'other' ])); } - /** - * @return void - */ - public function testAnyRolesGrantedAny() + public function testAnyRolesGrantedAny(): void { $this->setUpComplexRolesAndPrivileges(); @@ -338,10 +279,7 @@ public function testAnyRolesGrantedAny() $this->assertFalse($this->auth->anyRolesGrantedAny([ 'aide', 'staff' ], null, [ 'publish', 'other' ])); } - /** - * @return void - */ - public function testIsUserGrantedWithoutPermissions() + public function testIsUserGrantedWithoutPermissions(): void { $user = $this->createUser(); $user['roles'] = 'guest'; @@ -349,10 +287,7 @@ public function testIsUserGrantedWithoutPermissions() $this->assertFalse($this->auth->isUserGranted($user, null, null)); } - /** - * @return void - */ - public function testIsUserGranted() + public function testIsUserGranted(): void { $this->setUpComplexRolesAndPrivileges(); @@ -367,32 +302,24 @@ public function testIsUserGranted() // ACL // ========================================================================= - /** * Ensures that by default, Laminas ACL denies access to everything by all. - * - * @return void */ - public function testDefaultDeny() + public function testDefaultDeny(): void { $this->assertFalse($this->auth->isAllowed()); } /** * Ensures that by default, Laminas ACL can allow access to everything by all. - * - * @return void */ - public function testDefaultAllow() + public function testDefaultAllow(): void { $this->acl->allow(); $this->assertTrue($this->auth->isAllowed()); } - /** - * @return void - */ - public function testProxyMethods() + public function testProxyMethods(): void { $this->setUpComplexRolesAndPrivileges(); @@ -425,15 +352,12 @@ public function testProxyMethods() // Dependencies // ========================================================================= - /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/user/tests/Charcoal/User/ContainerProvider.php b/packages/user/tests/Charcoal/User/ContainerProvider.php index e2bf4f9c5..a60bb85e1 100644 --- a/packages/user/tests/Charcoal/User/ContainerProvider.php +++ b/packages/user/tests/Charcoal/User/ContainerProvider.php @@ -42,9 +42,8 @@ class ContainerProvider * Register the unit tests required services. * * @param Container $container A DI container. - * @return void */ - public function registerBaseServices(Container $container) + public function registerBaseServices(Container $container): void { $this->registerDatabase($container); $this->registerLogger($container); @@ -58,11 +57,10 @@ public function registerBaseServices(Container $container) * Note: Uses SQLite to create a database in memory. * * @param Container $container A DI container. - * @return void */ - public function registerDatabase(Container $container) + public function registerDatabase(Container $container): void { - $container['database'] = function () { + $container['database'] = function (): \PDO { $pdo = new PDO('sqlite::memory:'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; @@ -73,167 +71,141 @@ public function registerDatabase(Container $container) * Setup the application's logging interface. * * @param Container $container A DI container. - * @return void */ - public function registerLogger(Container $container) + public function registerLogger(Container $container): void { - $container['logger'] = function () { - return new NullLogger(); - }; + $container['logger'] = (fn(): \Psr\Log\NullLogger => new NullLogger()); } /** * Setup the application's caching interface. * * @param Container $container A DI container. - * @return void */ - public function registerCache(Container $container) + public function registerCache(Container $container): void { - $container['cache'] = function () { - return new Pool(); - }; + $container['cache'] = (fn(): \Stash\Pool => new Pool()); } /** * Setup the framework's metadata loader interface. * * @param Container $container A DI container. - * @return void */ - public function registerMetadataLoader(Container $container) + public function registerMetadataLoader(Container $container): void { - $container['metadata/loader'] = function (Container $container) { - return new MetadataLoader([ - 'cache' => $container['cache'], - 'logger' => $container['logger'], - 'base_path' => realpath(__DIR__ . '/../../../'), - 'paths' => [ - 'metadata', - // Standalone repo - 'vendor/charcoal/user/metadata', - // Monorepo - '/../user/metadata', - ] - ]); - }; + $container['metadata/loader'] = (fn(Container $container): \Charcoal\Model\Service\MetadataLoader => new MetadataLoader([ + 'cache' => $container['cache'], + 'logger' => $container['logger'], + 'base_path' => realpath(__DIR__ . '/../../../'), + 'paths' => [ + 'metadata', + // Standalone repo + 'vendor/charcoal/user/metadata', + // Monorepo + '/../user/metadata', + ] + ])); } /** * Setup the framework's data source factory. * * @param Container $container A DI container. - * @return void */ - public function registerSourceFactory(Container $container) + public function registerSourceFactory(Container $container): void { $this->registerLogger($container); $this->registerCache($container); $this->registerDatabase($container); - $container['source/factory'] = function ($container) { - return new Factory([ - 'map' => [ - 'database' => DatabaseSource::class - ], - 'arguments' => [[ - 'logger' => $container['logger'], - 'cache' => $container['cache'], - 'pdo' => $container['database'] - ]] - ]); - }; + $container['source/factory'] = (fn($container): \Charcoal\Factory\GenericFactory => new Factory([ + 'map' => [ + 'database' => DatabaseSource::class + ], + 'arguments' => [[ + 'logger' => $container['logger'], + 'cache' => $container['cache'], + 'pdo' => $container['database'] + ]] + ])); } /** * Setup the framework's model factory. * * @param Container $container A DI container. - * @return void */ - public function registerModelFactory(Container $container) + public function registerModelFactory(Container $container): void { $this->registerSourceFactory($container); $this->registerMetadataLoader($container); $this->registerPropertyFactory($container); - $container['model/factory'] = function ($container) { - return new Factory([ - 'arguments' => [[ - 'container' => $container, - 'logger' => $container['logger'], - 'metadata_loader' => $container['metadata/loader'], - 'source_factory' => $container['source/factory'], - 'property_factory' => $container['property/factory'] - ]] - ]); - }; + $container['model/factory'] = (fn($container): \Charcoal\Factory\GenericFactory => new Factory([ + 'arguments' => [[ + 'container' => $container, + 'logger' => $container['logger'], + 'metadata_loader' => $container['metadata/loader'], + 'source_factory' => $container['source/factory'], + 'property_factory' => $container['property/factory'] + ]] + ])); } /** * Setup the framework's property factory. * * @param Container $container A DI container. - * @return void */ - public function registerPropertyFactory(Container $container) + public function registerPropertyFactory(Container $container): void { $this->registerLogger($container); $this->registerDatabase($container); $this->registerTranslator($container); - $container['property/factory'] = function (Container $container) { - return new Factory([ - 'resolver_options' => [ - 'prefix' => '\\Charcoal\\Property\\', - 'suffix' => 'Property' - ], - 'arguments' => [[ - 'container' => $container, - 'database' => $container['database'], - 'logger' => $container['logger'], - 'translator' => $container['translator'] - ]] - ]); - }; + $container['property/factory'] = (fn(Container $container): \Charcoal\Factory\GenericFactory => new Factory([ + 'resolver_options' => [ + 'prefix' => '\\Charcoal\\Property\\', + 'suffix' => 'Property' + ], + 'arguments' => [[ + 'container' => $container, + 'database' => $container['database'], + 'logger' => $container['logger'], + 'translator' => $container['translator'] + ]] + ])); } /** * Setup the framework's collection loader interface. * * @param Container $container A DI container. - * @return void */ - public function registerModelCollectionLoader(Container $container) + public function registerModelCollectionLoader(Container $container): void { - $container['model/collection/loader'] = function (Container $container) { - return new CollectionLoader([ - 'logger' => $container['logger'], - 'cache' => $container['cache'] - ]); - }; + $container['model/collection/loader'] = (fn(Container $container): \Charcoal\Loader\CollectionLoader => new CollectionLoader([ + 'logger' => $container['logger'], + 'cache' => $container['cache'] + ])); } /** * Setup the framework's Translator. * * @param Container $container A DI container. - * @return void */ - public function registerTranslator(Container $container) + public function registerTranslator(Container $container): void { - $container['locales/manager'] = function () { - return new LocalesManager([ - 'locales' => [ - 'en' => [ 'locale' => 'en-US' ] - ] - ]); - }; - - $container['translator'] = function (Container $container) { - return new Translator([ - 'manager' => $container['locales/manager'] - ]); - }; + $container['locales/manager'] = (fn(): \Charcoal\Translator\LocalesManager => new LocalesManager([ + 'locales' => [ + 'en' => [ 'locale' => 'en-US' ] + ] + ])); + + $container['translator'] = (fn(Container $container): \Charcoal\Translator\Translator => new Translator([ + 'manager' => $container['locales/manager'] + ])); } } diff --git a/packages/user/tests/Charcoal/User/GenericUserTest.php b/packages/user/tests/Charcoal/User/GenericUserTest.php index 16944ce3b..1cb1747a5 100644 --- a/packages/user/tests/Charcoal/User/GenericUserTest.php +++ b/packages/user/tests/Charcoal/User/GenericUserTest.php @@ -20,22 +20,16 @@ class GenericUserTest extends AbstractTestCase { /** * Tested Class. - * - * @var UserInterface */ - private $obj; + private \Charcoal\User\GenericUser $obj; /** * Store the service container. - * - * @var Container */ - private $container; + private ?\Pimple\Container $container = null; /** * Set up the test. - * - * @return void */ protected function setUp(): void { @@ -54,10 +48,7 @@ protected function setUp(): void ]); } - /** - * @return void - */ - public function testSessionKey() + public function testSessionKey(): void { $obj = $this->obj; @@ -67,12 +58,10 @@ public function testSessionKey() /** * Set up the service container. - * - * @return Container */ - private function container() + private function container(): \Pimple\Container { - if ($this->container === null) { + if (!$this->container instanceof \Pimple\Container) { $container = new Container(); $containerProvider = new ContainerProvider(); $containerProvider->registerBaseServices($container); diff --git a/packages/user/tests/bootstrap.php b/packages/user/tests/bootstrap.php new file mode 100644 index 000000000..90929e3b5 --- /dev/null +++ b/packages/user/tests/bootstrap.php @@ -0,0 +1,14 @@ + - + cacheDirectory=".phpunit.cache" + backupStaticProperties="false" + failOnWarning="false" + failOnPhpunitWarning="false" + failOnNotice="false" + failOnDeprecation="false"> ./tests/Charcoal - - + + ./src/Charcoal - - + + + + + + + + - + - - - - diff --git a/packages/view/src/Charcoal/View/AbstractEngine.php b/packages/view/src/Charcoal/View/AbstractEngine.php index fd6af2e7d..6e2a13a92 100644 --- a/packages/view/src/Charcoal/View/AbstractEngine.php +++ b/packages/view/src/Charcoal/View/AbstractEngine.php @@ -16,10 +16,7 @@ */ abstract class AbstractEngine implements EngineInterface { - /** - * @var LoaderInterface - */ - private $loader; + private \Charcoal\View\LoaderInterface $loader; /** * The cache option. @@ -45,9 +42,6 @@ public function __construct(array $data) } } - /** - * @return string - */ abstract public function type(): string; /** @@ -84,7 +78,6 @@ public function loadTemplate(string $templateIdent): string /** * @param string $varName The name of the variable to set this template unto. * @param string|null $templateIdent The "dynamic template" to set. null to clear. - * @return void */ public function setDynamicTemplate(string $varName, ?string $templateIdent): void { @@ -97,7 +90,6 @@ public function setDynamicTemplate(string $varName, ?string $templateIdent): voi * @param mixed $cache A engine cache implementation, * an absolute path to the compiled views, * a boolean to enable/disable cache. - * @return void */ protected function setCache($cache): void { @@ -115,9 +107,6 @@ public function cache() } - /** - * @return LoaderInterface - */ protected function loader(): LoaderInterface { return $this->loader; @@ -127,7 +116,6 @@ protected function loader(): LoaderInterface /** * @param LoaderInterface $loader A loader instance. - * @return void */ private function setLoader(LoaderInterface $loader): void { diff --git a/packages/view/src/Charcoal/View/AbstractLoader.php b/packages/view/src/Charcoal/View/AbstractLoader.php index 4e8152872..8a36d18d5 100644 --- a/packages/view/src/Charcoal/View/AbstractLoader.php +++ b/packages/view/src/Charcoal/View/AbstractLoader.php @@ -41,7 +41,7 @@ public function __construct(?array $data = null) public function load($ident) { // Handle dynamic template - if (substr($ident, 0, 1) === '$') { + if (str_starts_with($ident, '$')) { $ident = $this->dynamicTemplate(substr($ident, 1)); } @@ -63,7 +63,6 @@ public function load($ident) /** * @param string $varName The name of the variable to get template ident from. - * @return string */ public function dynamicTemplate(string $varName): string { @@ -78,7 +77,6 @@ public function dynamicTemplate(string $varName): string * @param string $varName The name of the variable to set this template unto. * @param string|null $templateIdent The "dynamic template" to set or NULL to clear. * or if the template is not a string (and not null). - * @return void */ public function setDynamicTemplate(string $varName, ?string $templateIdent): void { @@ -92,24 +90,17 @@ public function setDynamicTemplate(string $varName, ?string $templateIdent): voi /** * @param string $varName The name of the variable to remove. - * @return void */ public function removeDynamicTemplate(string $varName): void { unset($this->dynamicTemplates[$varName]); } - /** - * @return void - */ public function clearDynamicTemplates(): void { $this->dynamicTemplates = []; } - /** - * @return string - */ protected function basePath(): string { return $this->basePath; @@ -117,9 +108,8 @@ protected function basePath(): string /** * @param string $basePath The base path to set. - * @return self */ - private function setBasePath(string $basePath) + private function setBasePath(string $basePath): static { $basePath = realpath($basePath); $this->basePath = rtrim($basePath, '/\\') . DIRECTORY_SEPARATOR; @@ -136,9 +126,8 @@ protected function paths(): array /** * @param string[] $paths The list of path to add. - * @return self */ - private function setPaths(array $paths) + private function setPaths(array $paths): static { $this->paths = []; @@ -151,9 +140,8 @@ private function setPaths(array $paths) /** * @param string $path The path to add to the load. - * @return self */ - private function addPath(string $path) + private function addPath(string $path): static { $this->paths[] = $this->resolvePath($path); @@ -162,13 +150,12 @@ private function addPath(string $path) /** * @param string $path The path to resolve. - * @return string */ private function resolvePath(string $path): string { $basePath = $this->basePath(); $path = rtrim($path, '/\\') . DIRECTORY_SEPARATOR; - if ($basePath && strpos($path, $basePath) === false) { + if ($basePath && !str_contains($path, $basePath)) { $path = $basePath . DIRECTORY_SEPARATOR . $path; } @@ -187,7 +174,7 @@ private function resolvePath(string $path): string */ protected function isTemplateString(string $ident): bool { - return strpos($ident, PHP_EOL) !== false; + return str_contains($ident, PHP_EOL); } /** @@ -223,7 +210,6 @@ protected function findTemplateFile(string $ident): ?string /** * @param string $ident The template identifier to convert to a filename. - * @return string */ abstract protected function filenameFromIdent(string $ident): string; } diff --git a/packages/view/src/Charcoal/View/AbstractView.php b/packages/view/src/Charcoal/View/AbstractView.php index 19d9bf7b2..0f46b84b7 100644 --- a/packages/view/src/Charcoal/View/AbstractView.php +++ b/packages/view/src/Charcoal/View/AbstractView.php @@ -17,10 +17,7 @@ */ abstract class AbstractView implements ViewInterface { - /** - * @var EngineInterface $engine - */ - private $engine; + private \Charcoal\View\EngineInterface $engine; /** * Build the object with an array of dependencies. @@ -37,11 +34,10 @@ public function __construct(array $data) * Load a template (from identifier). * * @param string $templateIdent The template identifier to load.. - * @return string */ public function loadTemplate(string $templateIdent): string { - if (!$templateIdent) { + if ($templateIdent === '' || $templateIdent === '0') { return ''; } return $this->engine()->loadTemplate($templateIdent); @@ -52,7 +48,6 @@ public function loadTemplate(string $templateIdent): string * * @param string $templateIdent The template identifier, to load and render. * @param mixed $context The view controller (rendering context). - * @return string */ public function render(string $templateIdent, $context = null): string { @@ -64,7 +59,6 @@ public function render(string $templateIdent, $context = null): string * * @param string $templateString The full template string to render. * @param mixed $context The view controller (rendering context). - * @return string */ public function renderTemplate(string $templateString, $context = null): string { @@ -74,7 +68,6 @@ public function renderTemplate(string $templateString, $context = null): string /** * @param string $varName The name of the variable to set this template unto. * @param string|null $templateIdent The "dynamic template" to set. null to clear. - * @return void */ public function setDynamicTemplate(string $varName, ?string $templateIdent): void { @@ -83,8 +76,6 @@ public function setDynamicTemplate(string $varName, ?string $templateIdent): voi /** * Get the view's rendering engine instance. - * - * @return EngineInterface */ protected function engine(): EngineInterface { @@ -95,7 +86,6 @@ protected function engine(): EngineInterface * Set the engine (`EngineInterface`) dependency. * * @param EngineInterface $engine The rendering engine. - * @return void */ private function setEngine(EngineInterface $engine): void { diff --git a/packages/view/src/Charcoal/View/EngineInterface.php b/packages/view/src/Charcoal/View/EngineInterface.php index 6d2f205b5..680ffbd50 100644 --- a/packages/view/src/Charcoal/View/EngineInterface.php +++ b/packages/view/src/Charcoal/View/EngineInterface.php @@ -13,7 +13,6 @@ interface EngineInterface * Load a template (from identifier). * * @param string $templateIdent The template identifier to load. - * @return string */ public function loadTemplate(string $templateIdent): string; @@ -38,7 +37,6 @@ public function renderTemplate(string $templateString, $context): string; /** * @param string $varName The name of the variable to set this template unto. * @param string|null $templateIdent The "dynamic template" to set. null to clear. - * @return void */ public function setDynamicTemplate(string $varName, ?string $templateIdent): void; } diff --git a/packages/view/src/Charcoal/View/LoaderInterface.php b/packages/view/src/Charcoal/View/LoaderInterface.php index 8fe660861..5d2d7898c 100644 --- a/packages/view/src/Charcoal/View/LoaderInterface.php +++ b/packages/view/src/Charcoal/View/LoaderInterface.php @@ -18,13 +18,11 @@ public function load($ident); /** * @param string $varName The name of the variable to set this template unto. * @param string|null $templateIdent The "dynamic template" to set. null to clear. - * @return void */ public function setDynamicTemplate(string $varName, ?string $templateIdent): void; /** * @param string $varName The name of the variable to get template ident from. - * @return string */ public function dynamicTemplate(string $varName): string; } diff --git a/packages/view/src/Charcoal/View/Mustache/AssetsHelpers.php b/packages/view/src/Charcoal/View/Mustache/AssetsHelpers.php index 4862ba681..354fa94bf 100644 --- a/packages/view/src/Charcoal/View/Mustache/AssetsHelpers.php +++ b/packages/view/src/Charcoal/View/Mustache/AssetsHelpers.php @@ -5,7 +5,7 @@ namespace Charcoal\View\Mustache; // From Mustache -use Mustache_LambdaHelper as LambdaHelper; +use Mustache\LambdaHelper as LambdaHelper; /** * Mustache helpers for rendering CSS and JavaScript. @@ -14,10 +14,8 @@ class AssetsHelpers implements HelpersInterface { /** * A string concatenation of inline `