From 0db1a8f99946de72be836f2b006f2938c8b46495 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Tue, 13 Jan 2026 18:39:56 +0100 Subject: [PATCH 1/2] Fix setting default invoice department --- application/inc/Http/Controllers/Payment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/inc/Http/Controllers/Payment.php b/application/inc/Http/Controllers/Payment.php index a70d1b5f..eadc350b 100644 --- a/application/inc/Http/Controllers/Payment.php +++ b/application/inc/Http/Controllers/Payment.php @@ -358,7 +358,7 @@ private function setPaymentStatus(Request $request, Invoice $invoice): void $cardType = EpaymentService::getPaymentName(intval($request->get('paymenttype'))); $internalNote = $this->generateInternalPaymentNote($request); - if (!app(EmailService::class)->valideMail($invoice->getDepartment())) { + if (!$invoice->getDepartment() || !app(EmailService::class)->valideMail($invoice->getDepartment())) { $invoice->setDepartment(ConfigService::getDefaultEmail()); } From 8dba43e0ff162706d81f13f057754c1a71e97b49 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Tue, 13 Jan 2026 19:29:23 +0100 Subject: [PATCH 2/2] Upgrade codebase to support PHP 8.5 compatibility --- .github/workflows/test.yml | 10 +- .gitignore | 2 +- application/composer.json | 5 +- application/composer.lock | 1403 ++++++++++++----- application/inc/Application.php | 9 +- application/inc/Countries.php | 18 +- application/inc/DTO/TableColumn.php | 2 +- application/inc/Exceptions/Handler.php | 3 +- .../Admin/AddressbookController.php | 6 +- .../Admin/CustomSortingController.php | 10 +- .../Controllers/Admin/ExplorerController.php | 8 +- .../Controllers/Admin/ExportController.php | 10 +- .../Controllers/Admin/InvoiceController.php | 14 +- .../Admin/MaintenanceController.php | 10 +- .../Admin/NewsletterController.php | 13 +- .../Http/Controllers/Admin/PageController.php | 6 +- .../Admin/RequirementController.php | 2 +- .../Controllers/Admin/SiteTreeController.php | 8 +- .../Controllers/Admin/TableController.php | 14 +- application/inc/Http/Controllers/Base.php | 2 +- application/inc/Http/Controllers/Feed.php | 2 +- application/inc/Http/Controllers/Payment.php | 61 +- application/inc/Http/Controllers/Search.php | 2 - application/inc/Http/Controllers/Shopping.php | 2 +- application/inc/Http/Middleware/Utf8Url.php | 2 +- application/inc/Http/Request.php | 4 +- application/inc/Models/AbstractEntity.php | 2 +- application/inc/Models/Brand.php | 4 +- application/inc/Models/Category.php | 12 +- application/inc/Models/Contact.php | 31 +- application/inc/Models/CustomPage.php | 6 +- application/inc/Models/CustomSorting.php | 11 +- application/inc/Models/Email.php | 18 +- application/inc/Models/Epayment.php | 6 +- application/inc/Models/File.php | 15 +- application/inc/Models/Invoice.php | 131 +- application/inc/Models/Newsletter.php | 17 +- application/inc/Models/Page.php | 26 +- application/inc/Models/Requirement.php | 4 +- application/inc/Models/Table.php | 62 +- application/inc/Models/User.php | 10 +- application/inc/Services/ConfigService.php | 2 + application/inc/Services/EpaymentService.php | 4 +- .../inc/Services/InvoicePdfService.php | 26 +- application/inc/Services/InvoiceService.php | 80 +- application/inc/Services/OrmService.php | 4 +- application/inc/Services/UploadHandler.php | 7 +- application/inc/TwigExtensions.php | 3 +- application/inc/helpers.php | 67 +- tests/TestResponse.php | 6 +- tests/Unit/Models/EpaymentTest.php | 11 +- tests/Unit/Services/EpaymentServiceTest.php | 27 - 52 files changed, 1440 insertions(+), 780 deletions(-) delete mode 100644 tests/Unit/Services/EpaymentServiceTest.php diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fcab9ee0..8c3bc084 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: [ '8.1', '8.2', '8.3' ] + php: [ '8.1', '8.2', '8.3', '8.4', '8.5' ] steps: - uses: actions/checkout@v4 @@ -35,7 +35,7 @@ jobs: path: | application/vendor ./.php-cs-fixer.cache - key: composer-${{ hashFiles('**/composer.lock') }} + key: composer-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }} restore-keys: composer- - name: Install dependencies @@ -76,9 +76,3 @@ jobs: with: project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} coverage-reports: build/logs/clover.xml - - - name: Upload coverage to Codeclimate - if: matrix.php == '8.1' - uses: paambaati/codeclimate-action@v3.2.0 - env: - CC_TEST_REPORTER_ID: dded30dc4b62f393c80ed752f13c7c7efaf748c3573daee0f4040615457ff9c0 diff --git a/.gitignore b/.gitignore index 99bee583..a994cd48 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,4 @@ /node_modules /tests/application/theme/cache /.phpunit.result.cache -/.php-cs-fixer.cache +.php-cs-fixer.cache diff --git a/application/composer.json b/application/composer.json index 50cb6cd8..936d5602 100644 --- a/application/composer.json +++ b/application/composer.json @@ -31,17 +31,18 @@ "sentry/sentry": "^3.12", "symfony/http-foundation": "^6.1", "symfony/mime": "^6.1", + "symfony/polyfill-mbstring": "^1.33", "tecnickcom/tcpdf": "^6.5", "twig/twig": "^3.4" }, "require-dev": { "ext-pdo_sqlite": "*", "dms/phpunit-arraysubset-asserts": "^0.4.0", - "friendsofphp/php-cs-fixer": "^3.13", + "friendsofphp/php-cs-fixer": "^3.92", "mheap/phpunit-github-actions-printer": "^1.5", "mockery/mockery": "^1.5", "php-coveralls/php-coveralls": "^2.5", - "phpstan/phpstan": "*", + "phpstan/phpstan": "^2.1", "phpstan/phpstan-mockery": "*", "phpstan/phpstan-phpunit": "*", "phpunit/phpunit": "^9.5" diff --git a/application/composer.lock b/application/composer.lock index 1c13f5c3..d325ed19 100644 --- a/application/composer.lock +++ b/application/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "61b46f6b4486dfdaecb11eb0ee9c5743", + "content-hash": "c68c67be068b5554e79988ec73c0ca45", "packages": [ { "name": "ajenbo/image.php", @@ -1774,21 +1774,21 @@ }, { "name": "symfony/options-resolver", - "version": "v6.1.0", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "a3016f5442e28386ded73c43a32a5b68586dd1c4" + "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a3016f5442e28386ded73c43a32a5b68586dd1c4", - "reference": "a3016f5442e28386ded73c43a32a5b68586dd1c4", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", + "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3" + "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", "autoload": { @@ -1821,7 +1821,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.1.0" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.30" }, "funding": [ { @@ -1832,12 +1832,16 @@ "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-02-25T11:15:52+00:00" + "time": "2025-11-12T13:06:53+00:00" }, { "name": "symfony/polyfill-ctype", @@ -2413,30 +2417,102 @@ } ], "packages-dev": [ + { + "name": "clue/ndjson-react", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/clue/reactphp-ndjson.git", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", + "react/event-loop": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Clue\\React\\NDJson\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + } + ], + "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.", + "homepage": "https://github.com/clue/reactphp-ndjson", + "keywords": [ + "NDJSON", + "json", + "jsonlines", + "newline", + "reactphp", + "streaming" + ], + "support": { + "issues": "https://github.com/clue/reactphp-ndjson/issues", + "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0" + }, + "funding": [ + { + "url": "https://clue.engineering/support", + "type": "custom" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2022-12-23T10:58:28+00:00" + }, { "name": "composer/pcre", - "version": "3.1.0", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, "require-dev": { - "phpstan/phpstan": "^1.3", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^5" + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" }, "type": "library", "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, "branch-alias": { "dev-main": "3.x-dev" } @@ -2466,7 +2542,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.0" + "source": "https://github.com/composer/pcre/tree/3.3.2" }, "funding": [ { @@ -2482,28 +2558,28 @@ "type": "tidelift" } ], - "time": "2022-11-17T09:50:14+00:00" + "time": "2024-11-12T16:29:46+00:00" }, { "name": "composer/semver", - "version": "3.3.2", + "version": "3.4.4", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, "type": "library", "extra": { @@ -2545,9 +2621,9 @@ "versioning" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.3.2" + "source": "https://github.com/composer/semver/tree/3.4.4" }, "funding": [ { @@ -2557,26 +2633,22 @@ { "url": "https://github.com/composer", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" } ], - "time": "2022-04-01T19:23:25+00:00" + "time": "2025-08-20T19:15:30+00:00" }, { "name": "composer/xdebug-handler", - "version": "3.0.3", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "ced299686f41dce890debac69273b47ffe98a40c" + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", - "reference": "ced299686f41dce890debac69273b47ffe98a40c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", "shasum": "" }, "require": { @@ -2587,7 +2659,7 @@ "require-dev": { "phpstan/phpstan": "^1.0", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^6.0" + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" }, "type": "library", "autoload": { @@ -2611,9 +2683,9 @@ "performance" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" }, "funding": [ { @@ -2629,7 +2701,7 @@ "type": "tidelift" } ], - "time": "2022-02-25T21:32:43+00:00" + "time": "2024-05-06T16:37:16+00:00" }, { "name": "dms/phpunit-arraysubset-asserts", @@ -2676,79 +2748,6 @@ }, "time": "2022-02-13T15:00:28+00:00" }, - { - "name": "doctrine/annotations", - "version": "1.13.3", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "648b0343343565c4a056bfc8392201385e8d89f0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/648b0343343565c4a056bfc8392201385e8d89f0", - "reference": "648b0343343565c4a056bfc8392201385e8d89f0", - "shasum": "" - }, - "require": { - "doctrine/lexer": "1.*", - "ext-tokenizer": "*", - "php": "^7.1 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" - }, - "require-dev": { - "doctrine/cache": "^1.11 || ^2.0", - "doctrine/coding-standard": "^6.0 || ^8.1", - "phpstan/phpstan": "^1.4.10 || ^1.8.0", - "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", - "symfony/cache": "^4.4 || ^5.2", - "vimeo/psalm": "^4.10" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.13.3" - }, - "time": "2022-07-02T10:48:51+00:00" - }, { "name": "doctrine/instantiator", "version": "1.4.1", @@ -2820,32 +2819,29 @@ "time": "2022-03-03T08:28:38+00:00" }, { - "name": "doctrine/lexer", - "version": "1.2.3", + "name": "evenement/evenement", + "version": "v3.0.2", "source": { "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", - "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": ">=7.0" }, "require-dev": { - "doctrine/coding-standard": "^9.0", - "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.11" + "phpunit/phpunit": "^9 || ^6" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + "Evenement\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2854,95 +2850,136 @@ ], "authors": [ { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" + }, + "time": "2023-08-08T05:53:35+00:00" + }, + { + "name": "fidry/cpu-core-counter", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "webmozarts/strict-phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fidry\\CpuCoreCounter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" } ], - "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "description": "Tiny utility to get the number of CPU cores.", "keywords": [ - "annotations", - "docblock", - "lexer", - "parser", - "php" + "CPU", + "core" ], "support": { - "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.3" + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.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%2Flexer", - "type": "tidelift" + "url": "https://github.com/theofidry", + "type": "github" } ], - "time": "2022-02-28T11:07:21+00:00" + "time": "2025-08-14T07:29:31+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.13.0", + "version": "v3.92.5", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "a6232229a8309e8811dc751c28b91cb34b2943e1" + "reference": "260cc8c4a1d2f6d2f22cd4f9c70aa72e55ebac58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/a6232229a8309e8811dc751c28b91cb34b2943e1", - "reference": "a6232229a8309e8811dc751c28b91cb34b2943e1", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/260cc8c4a1d2f6d2f22cd4f9c70aa72e55ebac58", + "reference": "260cc8c4a1d2f6d2f22cd4f9c70aa72e55ebac58", "shasum": "" }, "require": { - "composer/semver": "^3.2", - "composer/xdebug-handler": "^3.0.3", - "doctrine/annotations": "^1.13", + "clue/ndjson-react": "^1.3", + "composer/semver": "^3.4", + "composer/xdebug-handler": "^3.0.5", + "ext-filter": "*", + "ext-hash": "*", "ext-json": "*", "ext-tokenizer": "*", + "fidry/cpu-core-counter": "^1.3", "php": "^7.4 || ^8.0", - "sebastian/diff": "^4.0", - "symfony/console": "^5.4 || ^6.0", - "symfony/event-dispatcher": "^5.4 || ^6.0", - "symfony/filesystem": "^5.4 || ^6.0", - "symfony/finder": "^5.4 || ^6.0", - "symfony/options-resolver": "^5.4 || ^6.0", - "symfony/polyfill-mbstring": "^1.23", - "symfony/polyfill-php80": "^1.25", - "symfony/polyfill-php81": "^1.25", - "symfony/process": "^5.4 || ^6.0", - "symfony/stopwatch": "^5.4 || ^6.0" + "react/child-process": "^0.6.6", + "react/event-loop": "^1.5", + "react/socket": "^1.16", + "react/stream": "^1.4", + "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", + "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.33", + "symfony/polyfill-php80": "^1.33", + "symfony/polyfill-php81": "^1.33", + "symfony/polyfill-php84": "^1.33", + "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2 || ^8.0", + "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0 || ^8.0" }, "require-dev": { - "justinrainbow/json-schema": "^5.2", - "keradus/cli-executor": "^2.0", - "mikey179/vfsstream": "^1.6.10", - "php-coveralls/php-coveralls": "^2.5.2", - "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", - "phpspec/prophecy": "^1.15", - "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.5", - "phpunitgoodpractices/polyfill": "^1.6", - "phpunitgoodpractices/traits": "^1.9.2", - "symfony/phpunit-bridge": "^6.0", - "symfony/yaml": "^5.4 || ^6.0" + "facile-it/paraunit": "^1.3.1 || ^2.7", + "infection/infection": "^0.31", + "justinrainbow/json-schema": "^6.6", + "keradus/cli-executor": "^2.3", + "mikey179/vfsstream": "^1.6.12", + "php-coveralls/php-coveralls": "^2.9", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", + "phpunit/phpunit": "^9.6.31 || ^10.5.60 || ^11.5.46", + "symfony/polyfill-php85": "^1.33", + "symfony/var-dumper": "^5.4.48 || ^6.4.26 || ^7.4.0 || ^8.0", + "symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -2955,7 +2992,10 @@ "autoload": { "psr-4": { "PhpCsFixer\\": "src/" - } + }, + "exclude-from-classmap": [ + "src/**/Internal/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2972,9 +3012,15 @@ } ], "description": "A tool to automatically fix PHP code style", + "keywords": [ + "Static code analysis", + "fixer", + "standards", + "static analysis" + ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.13.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.92.5" }, "funding": [ { @@ -2982,7 +3028,7 @@ "type": "github" } ], - "time": "2022-10-31T19:28:50+00:00" + "time": "2026-01-08T21:57:37+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -3462,20 +3508,15 @@ }, { "name": "phpstan/phpstan", - "version": "1.9.2", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "d6fdf01c53978b6429f1393ba4afeca39cc68afa" - }, + "version": "2.1.33", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d6fdf01c53978b6429f1393ba4afeca39cc68afa", - "reference": "d6fdf01c53978b6429f1393ba4afeca39cc68afa", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9e800e6bee7d5bd02784d4c6069b48032d16224f", + "reference": "9e800e6bee7d5bd02784d4c6069b48032d16224f", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^7.4|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -3500,8 +3541,11 @@ "static analysis" ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.9.2" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -3511,39 +3555,34 @@ { "url": "https://github.com/phpstan", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" } ], - "time": "2022-11-10T09:56:11+00:00" + "time": "2025-12-05T10:24:31+00:00" }, { "name": "phpstan/phpstan-mockery", - "version": "1.1.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-mockery.git", - "reference": "245b17ccd00f04be3c6b9fc6645f63793b37b2ea" + "reference": "89a949d0ac64298e88b7c7fa00caee565c198394" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-mockery/zipball/245b17ccd00f04be3c6b9fc6645f63793b37b2ea", - "reference": "245b17ccd00f04be3c6b9fc6645f63793b37b2ea", + "url": "https://api.github.com/repos/phpstan/phpstan-mockery/zipball/89a949d0ac64298e88b7c7fa00caee565c198394", + "reference": "89a949d0ac64298e88b7c7fa00caee565c198394", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.5.0" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" }, "require-dev": { - "mockery/mockery": "^1.2.4", - "nikic/php-parser": "^4.13.0", + "mockery/mockery": "^1.6.11", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5" + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6" }, "type": "phpstan-extension", "extra": { @@ -3565,36 +3604,37 @@ "description": "PHPStan Mockery extension", "support": { "issues": "https://github.com/phpstan/phpstan-mockery/issues", - "source": "https://github.com/phpstan/phpstan-mockery/tree/1.1.0" + "source": "https://github.com/phpstan/phpstan-mockery/tree/2.0.0" }, - "time": "2022-05-09T13:12:35+00:00" + "time": "2024-10-14T03:18:12+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "1.2.2", + "version": "2.0.11", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "dea1f87344c6964c607d9076dee42d891f3923f0" + "reference": "5e30669bef866eff70db8b58d72a5c185aa82414" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/dea1f87344c6964c607d9076dee42d891f3923f0", - "reference": "dea1f87344c6964c607d9076dee42d891f3923f0", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/5e30669bef866eff70db8b58d72a5c185aa82414", + "reference": "5e30669bef866eff70db8b58d72a5c185aa82414", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.8.11" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.32" }, "conflict": { "phpunit/phpunit": "<7.0" }, "require-dev": { - "nikic/php-parser": "^4.13.0", + "nikic/php-parser": "^5", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5" + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6" }, "type": "phpstan-extension", "extra": { @@ -3617,9 +3657,9 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.2.2" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.11" }, - "time": "2022-10-28T10:23:07+00:00" + "time": "2025-12-19T09:05:35+00:00" }, { "name": "phpunit/php-code-coverage", @@ -3941,20 +3981,20 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.26", + "version": "9.6.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2" + "reference": "810500e92855eba8a7a5319ae913be2da6f957b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/851867efcbb6a1b992ec515c71cdcf20d895e9d2", - "reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/810500e92855eba8a7a5319ae913be2da6f957b0", + "reference": "810500e92855eba8a7a5319ae913be2da6f957b0", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1", + "doctrine/instantiator": "^1.3.1 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", @@ -3983,8 +4023,8 @@ "sebastian/version": "^3.0.2" }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "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" }, "bin": [ "phpunit" @@ -3992,7 +4032,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "9.6-dev" } }, "autoload": { @@ -4023,7 +4063,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.26" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.11" }, "funding": [ { @@ -4039,56 +4080,7 @@ "type": "tidelift" } ], - "time": "2022-10-28T06:00:21+00:00" - }, - { - "name": "psr/cache", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for caching libraries", - "keywords": [ - "cache", - "psr", - "psr-6" - ], - "support": { - "source": "https://github.com/php-fig/cache/tree/3.0.0" - }, - "time": "2021-02-03T23:26:27+00:00" + "time": "2023-08-19T07:10:56+00:00" }, { "name": "psr/container", @@ -4194,64 +4186,590 @@ "time": "2019-01-08T18:20:26+00:00" }, { - "name": "sebastian/cli-parser", - "version": "1.0.1", + "name": "react/cache", + "version": "v1.2.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "url": "https://github.com/reactphp/cache.git", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=5.3.0", + "react/promise": "^3.0 || ^2.0 || ^1.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "React\\Cache\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" } ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", + "description": "Async, Promise-based cache interface for ReactPHP", + "keywords": [ + "cache", + "caching", + "promise", + "reactphp" + ], "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "issues": "https://github.com/reactphp/cache/issues", + "source": "https://github.com/reactphp/cache/tree/v1.2.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://opencollective.com/reactphp", + "type": "open_collective" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2022-11-30T15:59:55+00:00" }, { - "name": "sebastian/code-unit", - "version": "1.0.8", + "name": "react/child-process", + "version": "v0.6.7", + "source": { + "type": "git", + "url": "https://github.com/reactphp/child-process.git", + "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/970f0e71945556422ee4570ccbabaedc3cf04ad3", + "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/event-loop": "^1.2", + "react/stream": "^1.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/socket": "^1.16", + "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\ChildProcess\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven library for executing child processes with ReactPHP.", + "keywords": [ + "event-driven", + "process", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/child-process/issues", + "source": "https://github.com/reactphp/child-process/tree/v0.6.7" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-12-23T15:25:20+00:00" + }, + { + "name": "react/dns", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3", + "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.7 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3 || ^2", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/dns/issues", + "source": "https://github.com/reactphp/dns/tree/v1.14.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-11-18T19:34:28+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a", + "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "suggest": { + "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.6.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-11-17T20:46:25+00:00" + }, + { + "name": "react/promise", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.12.28 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-08-19T18:57:03+00:00" + }, + { + "name": "react/socket", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08", + "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^1.13", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.6 || ^1.2.1", + "react/stream": "^1.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3.3 || ^2", + "react/promise-stream": "^1.4", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "support": { + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.17.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-11-19T20:47:34+00:00" + }, + { + "name": "react/stream", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.2" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "support": { + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.4.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-11T12:45:25+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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 for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", @@ -4493,16 +5011,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { @@ -4547,7 +5065,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -4555,7 +5073,7 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", @@ -5236,24 +5754,24 @@ }, { "name": "symfony/console", - "version": "v6.1.7", + "version": "v6.4.31", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a1282bd0c096e0bdb8800b104177e2ce404d8815" + "reference": "f9f8a889f54c264f9abac3fc0f7a371ffca51997" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a1282bd0c096e0bdb8800b104177e2ce404d8815", - "reference": "a1282bd0c096e0bdb8800b104177e2ce404d8815", + "url": "https://api.github.com/repos/symfony/console/zipball/f9f8a889f54c264f9abac3fc0f7a371ffca51997", + "reference": "f9f8a889f54c264f9abac3fc0f7a371ffca51997", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/deprecation-contracts": "^2.1|^3", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/string": "^5.4|^6.0" + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { "symfony/dependency-injection": "<5.4", @@ -5267,18 +5785,16 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/lock": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -5307,12 +5823,12 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.1.7" + "source": "https://github.com/symfony/console/tree/v6.4.31" }, "funding": [ { @@ -5323,33 +5839,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": "2022-10-26T21:42:49+00:00" + "time": "2025-12-22T08:30:34+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.1.0", + "version": "v6.4.25", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "a0449a7ad7daa0f7c0acd508259f80544ab5a347" + "reference": "b0cf3162020603587363f0551cd3be43958611ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a0449a7ad7daa0f7c0acd508259f80544ab5a347", - "reference": "a0449a7ad7daa0f7c0acd508259f80544ab5a347", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff", + "reference": "b0cf3162020603587363f0551cd3be43958611ff", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/event-dispatcher-contracts": "^2|^3" + "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<5.4" + "symfony/dependency-injection": "<5.4", + "symfony/service-contracts": "<2.5" }, "provide": { "psr/event-dispatcher-implementation": "1.0", @@ -5357,17 +5878,13 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/error-handler": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/stopwatch": "^5.4|^6.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -5395,7 +5912,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.1.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.25" }, "funding": [ { @@ -5406,42 +5923,43 @@ "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-05T16:51:07+00:00" + "time": "2025-08-13T09:41:44+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.1.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "02ff5eea2f453731cfbc6bc215e456b781480448" + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/02ff5eea2f453731cfbc6bc215e456b781480448", - "reference": "02ff5eea2f453731cfbc6bc215e456b781480448", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", "shasum": "" }, "require": { "php": ">=8.1", "psr/event-dispatcher": "^1" }, - "suggest": { - "symfony/event-dispatcher-implementation": "" - }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.1-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.6-dev" } }, "autoload": { @@ -5474,7 +5992,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.1.1" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" }, "funding": [ { @@ -5490,20 +6008,20 @@ "type": "tidelift" } ], - "time": "2022-02-25T11:15:52+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/filesystem", - "version": "v6.1.5", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "4d216a2beef096edf040a070117c39ca2abce307" + "reference": "441c6b69f7222aadae7cbf5df588496d5ee37789" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/4d216a2beef096edf040a070117c39ca2abce307", - "reference": "4d216a2beef096edf040a070117c39ca2abce307", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/441c6b69f7222aadae7cbf5df588496d5ee37789", + "reference": "441c6b69f7222aadae7cbf5df588496d5ee37789", "shasum": "" }, "require": { @@ -5511,6 +6029,9 @@ "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, + "require-dev": { + "symfony/process": "^5.4|^6.4|^7.0" + }, "type": "library", "autoload": { "psr-4": { @@ -5537,7 +6058,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.1.5" + "source": "https://github.com/symfony/filesystem/tree/v6.4.30" }, "funding": [ { @@ -5548,32 +6069,36 @@ "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-09-21T20:29:40+00:00" + "time": "2025-11-26T14:43:45+00:00" }, { "name": "symfony/finder", - "version": "v6.1.3", + "version": "v6.4.31", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "39696bff2c2970b3779a5cac7bf9f0b88fc2b709" + "reference": "5547f2e1f0ca8e2e7abe490156b62da778cfbe2b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/39696bff2c2970b3779a5cac7bf9f0b88fc2b709", - "reference": "39696bff2c2970b3779a5cac7bf9f0b88fc2b709", + "url": "https://api.github.com/repos/symfony/finder/zipball/5547f2e1f0ca8e2e7abe490156b62da778cfbe2b", + "reference": "5547f2e1f0ca8e2e7abe490156b62da778cfbe2b", "shasum": "" }, "require": { "php": ">=8.1" }, "require-dev": { - "symfony/filesystem": "^6.0" + "symfony/filesystem": "^6.0|^7.0" }, "type": "library", "autoload": { @@ -5601,7 +6126,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.1.3" + "source": "https://github.com/symfony/finder/tree/v6.4.31" }, "funding": [ { @@ -5612,12 +6137,16 @@ "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-07-29T07:42:06+00:00" + "time": "2025-12-11T14:52:17+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -5700,6 +6229,86 @@ ], "time": "2022-11-03T14:55:06+00:00" }, + { + "name": "symfony/polyfill-php84", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php84\\": "" + }, + "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 backporting some PHP 8.4+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.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": "2025-06-24T13:30:11+00:00" + }, { "name": "symfony/process", "version": "v6.4.31", @@ -5852,21 +6461,21 @@ }, { "name": "symfony/stopwatch", - "version": "v6.1.5", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "266636bb8f3fbdccc302491df7b3a1b9a8c238a7" + "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/266636bb8f3fbdccc302491df7b3a1b9a8c238a7", - "reference": "266636bb8f3fbdccc302491df7b3a1b9a8c238a7", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b67e94e06a05d9572c2fa354483b3e13e3cb1898", + "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/service-contracts": "^1|^2|^3" + "symfony/service-contracts": "^2.5|^3" }, "type": "library", "autoload": { @@ -5894,7 +6503,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.1.5" + "source": "https://github.com/symfony/stopwatch/tree/v6.4.24" }, "funding": [ { @@ -5905,12 +6514,16 @@ "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-09-28T16:00:52+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/string", diff --git a/application/inc/Application.php b/application/inc/Application.php index e4878511..8cf94ab2 100644 --- a/application/inc/Application.php +++ b/application/inc/Application.php @@ -131,11 +131,10 @@ public function get(string $id): object $this->services[$id] = new $id(); } - /** @var T */ - $class = $this->services[$id]; - assert(is_object($class)); + $service = $this->services[$id]; + assert($service instanceof $id); - return $class; + return $service; } /** @@ -237,7 +236,7 @@ private function matchRoute(string $method, string $requestUrl): callable $matches[0] = $request; $class = $route->getController(); - /** @var callable(Request, string...) */ + /** @var callable((Request|string)...): Response */ $callable = [new $class(), $route->getAction()]; return $callable(...$matches); diff --git a/application/inc/Countries.php b/application/inc/Countries.php index 1f20b9e6..ebc0ca97 100644 --- a/application/inc/Countries.php +++ b/application/inc/Countries.php @@ -258,14 +258,14 @@ private static function getCountries(): array ]; } -/** - * @return array - */ -public static function getOrdered(): array -{ - $countries = self::getCountries(); - natcasesort($countries); + /** + * @return array + */ + public static function getOrdered(): array + { + $countries = self::getCountries(); + natcasesort($countries); - return $countries; -} + return $countries; + } } diff --git a/application/inc/DTO/TableColumn.php b/application/inc/DTO/TableColumn.php index df28ccbe..c9e07343 100644 --- a/application/inc/DTO/TableColumn.php +++ b/application/inc/DTO/TableColumn.php @@ -7,7 +7,7 @@ class TableColumn { /** - * @param array $options + * @param array $options */ public function __construct( public readonly string $title, diff --git a/application/inc/Exceptions/Handler.php b/application/inc/Exceptions/Handler.php index 4c65227c..9bdb6737 100644 --- a/application/inc/Exceptions/Handler.php +++ b/application/inc/Exceptions/Handler.php @@ -4,6 +4,7 @@ use App\Http\Request; use App\Services\ConfigService; +use Sentry\EventId; use Sentry\State\Scope; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; @@ -11,7 +12,7 @@ class Handler { - private ?string $lastLogId; + private ?EventId $lastLogId; /** @var array */ private array $dontReport = [ diff --git a/application/inc/Http/Controllers/Admin/AddressbookController.php b/application/inc/Http/Controllers/Admin/AddressbookController.php index 9495c6fb..ad8adb34 100644 --- a/application/inc/Http/Controllers/Admin/AddressbookController.php +++ b/application/inc/Http/Controllers/Admin/AddressbookController.php @@ -73,9 +73,9 @@ public function update(Request $request, int $id): JsonResponse throw new InvalidInput(_('Contact not found.'), Response::HTTP_NOT_FOUND); } - $interests = $request->request->all('interests'); - if (!is_array($interests)) { - $interests = []; + $interests = []; + foreach ($request->request->all('interests') as $interest) { + $interests[] = valstring($interest); } $contact->setName($request->getRequestString('name') ?? '') diff --git a/application/inc/Http/Controllers/Admin/CustomSortingController.php b/application/inc/Http/Controllers/Admin/CustomSortingController.php index 2a462dfb..71a64d5c 100644 --- a/application/inc/Http/Controllers/Admin/CustomSortingController.php +++ b/application/inc/Http/Controllers/Admin/CustomSortingController.php @@ -69,10 +69,14 @@ public function create(Request $request): JsonResponse */ public function update(Request $request, int $id): JsonResponse { - $items = $request->get('items'); - if (!is_array($items)) { - $items = []; + $items = []; + $rawItems = $request->get('items'); + if (is_array($rawItems)) { + foreach ($rawItems as $rawItem) { + $items[] = valstring($rawItem); + } } + $title = $request->getRequestString('title'); if (!$title) { throw new InvalidInput(_('You must enter a title.')); diff --git a/application/inc/Http/Controllers/Admin/ExplorerController.php b/application/inc/Http/Controllers/Admin/ExplorerController.php index da4a0f03..d9d96ab9 100644 --- a/application/inc/Http/Controllers/Admin/ExplorerController.php +++ b/application/inc/Http/Controllers/Admin/ExplorerController.php @@ -40,7 +40,7 @@ public function __construct() */ public function index(Request $request): Response { - $currentDir = strval($request->cookies->get('admin_dir', '/images')); + $currentDir = valstring($request->cookies->get('admin_dir', '/images')); $data = [ 'returnType' => $request->get('return', ''), @@ -62,7 +62,7 @@ public function folders(Request $request): JsonResponse $path = ''; } $move = $request->query->getBoolean('move'); - $currentDir = strval($request->cookies->get('admin_dir', '/images')); + $currentDir = valstring($request->cookies->get('admin_dir', '/images')); $html = app(RenderService::class)->render( 'admin/partial-listDirs', @@ -409,7 +409,7 @@ private function updateAltInHtml(array $richTexts, File $file): void */ public function fileMoveDialog(Request $request, int $id): Response { - $currentDir = strval($request->cookies->get('admin_dir', '/images')); + $currentDir = valstring($request->cookies->get('admin_dir', '/images')); $file = app(OrmService::class)->getOne(File::class, $id); if (!$file) { @@ -450,7 +450,7 @@ public function fileUpload(Request $request): Response throw new InvalidInput(_('No file received.')); } - $currentDir = strval($request->cookies->get('admin_dir', '/images')); + $currentDir = valstring($request->cookies->get('admin_dir', '/images')); $targetDir = $request->getRequestString('dir') ?? $currentDir; $destinationType = $request->getRequestString('type') ?? ''; $description = $request->getRequestString('alt') ?? ''; diff --git a/application/inc/Http/Controllers/Admin/ExportController.php b/application/inc/Http/Controllers/Admin/ExportController.php index 660102d5..c168fb24 100644 --- a/application/inc/Http/Controllers/Admin/ExportController.php +++ b/application/inc/Http/Controllers/Admin/ExportController.php @@ -141,7 +141,7 @@ public function index(Request $request): Response continue; } $rowData[] = $column->title; - $rowData[] = strval($row[$i]); + $rowData[] = valstring($row[$i]); $rowData[] = ''; $rowData[] = '0'; @@ -158,10 +158,10 @@ public function index(Request $request): Response $price = $salePrice; } if ($salePrice && $salePrice !== $price) { - $rowData[23] = strval($salePrice); + $rowData[23] = valstring($salePrice); } if ($price) { - $rowData[24] = strval($price); + $rowData[24] = valstring($price); } $variations[] = $rowData; @@ -258,7 +258,7 @@ protected function getPageData(string $type, Page $page): array $salesPrice ?: '', $price ?: '', implode(', ', $paths), - trim($page->getKeywords(), " \n\r\t\v\0,"), + mb_trim($page->getKeywords(), " \n\r\t\v\0,"), '', implode(', ', $this->extractImages($page)), 'n/a', @@ -290,7 +290,7 @@ private function extractImages(InterfaceRichText $richText): array throw new Exception('preg_replace failed'); } - $urls = array_filter($matches[1] ?? []); + $urls = array_filter($matches[1]); $result = []; foreach ($urls as $url) { diff --git a/application/inc/Http/Controllers/Admin/InvoiceController.php b/application/inc/Http/Controllers/Admin/InvoiceController.php index 0e82cf83..ab68c456 100644 --- a/application/inc/Http/Controllers/Admin/InvoiceController.php +++ b/application/inc/Http/Controllers/Admin/InvoiceController.php @@ -27,7 +27,7 @@ class InvoiceController extends AbstractAdminController */ public function index(Request $request): Response { - $momssats = strval($request->get('momssats')); + $momssats = valstring($request->get('momssats')); if (!$momssats) { $momssats = null; } @@ -35,13 +35,13 @@ public function index(Request $request): Response $request->query->getInt('id') ?: null, $request->query->getInt('y'), $request->query->getInt('m'), - strval($request->get('department') ?? ''), - strval($request->get('status', 'activ')), - strval($request->get('name') ?? ''), - strval($request->get('tlf') ?? ''), - strval($request->get('email') ?? ''), + valstring($request->get('department') ?? ''), + valstring($request->get('status', 'activ')), + valstring($request->get('name') ?? ''), + valstring($request->get('tlf') ?? ''), + valstring($request->get('email') ?? ''), $momssats, - strval($request->get('clerk') ?? ''), + valstring($request->get('clerk') ?? ''), ); $user = $request->user(); diff --git a/application/inc/Http/Controllers/Admin/MaintenanceController.php b/application/inc/Http/Controllers/Admin/MaintenanceController.php index ced8f342..b5b65ec6 100644 --- a/application/inc/Http/Controllers/Admin/MaintenanceController.php +++ b/application/inc/Http/Controllers/Admin/MaintenanceController.php @@ -35,7 +35,7 @@ public function index(Request $request): Response $db->addLoadedTable('emails'); $emailStatus = $db->fetchArray("SHOW TABLE STATUS LIKE 'emails'"); - /** @var (string|int)[] */ + /** @var (int|string)[] */ $emailStatus = reset($emailStatus); $page = app(OrmService::class)->getOne(CustomPage::class, 0); @@ -69,7 +69,7 @@ private function byteToHuman(int $size): string $size /= 1024; } - return number_format($size, 1, localeconv()['mon_decimal_point'], '') . $unit; + return number_format($size, 1, valstring(localeconv()['mon_decimal_point']), '') . $unit; } /** @@ -400,7 +400,7 @@ public function mailUsage(): JsonResponse ); foreach ($imap->listMailboxes() as $mailbox) { - $mailboxStatus = $imap->select($mailbox['name'], true); + $mailboxStatus = $imap->select(valstring($mailbox['name']), true); if (!$mailboxStatus['exists']) { continue; } @@ -422,8 +422,8 @@ private function getDbSize(): int $tabels = app(DbService::class)->fetchArray('SHOW TABLE STATUS'); $dbsize = 0; foreach ($tabels as $tabel) { - $dbsize += $tabel['Data_length']; - $dbsize += $tabel['Index_length']; + $dbsize += valint($tabel['Data_length']); + $dbsize += valint($tabel['Index_length']); } return (int)$dbsize; diff --git a/application/inc/Http/Controllers/Admin/NewsletterController.php b/application/inc/Http/Controllers/Admin/NewsletterController.php index 9aca93da..8ace184a 100644 --- a/application/inc/Http/Controllers/Admin/NewsletterController.php +++ b/application/inc/Http/Controllers/Admin/NewsletterController.php @@ -80,9 +80,9 @@ public function update(Request $request, int $id): JsonResponse $html = purifyHTML($request->getRequestString('html') ?? ''); - $interests = $request->request->all('interests'); - if (!is_array($interests)) { - $interests = []; + $interests = []; + foreach ($request->request->all('interests') as $interest) { + $interests[] = valstring($interest); } $newsletter->setFrom($request->getRequestString('from') ?? '') @@ -104,10 +104,11 @@ public function update(Request $request, int $id): JsonResponse public function countRecipients(Request $request): JsonResponse { $newsletter = new Newsletter(); - $interests = $request->query->all('interests'); - if (is_array($interests)) { - $newsletter->setInterests($interests); + $interests = []; + foreach ($request->query->all('interests') as $interest) { + $interests[] = valstring($interest); } + $newsletter->setInterests($interests); return new JsonResponse(['count' => $newsletter->countRecipients()]); } diff --git a/application/inc/Http/Controllers/Admin/PageController.php b/application/inc/Http/Controllers/Admin/PageController.php index 0128e365..36af81a7 100644 --- a/application/inc/Http/Controllers/Admin/PageController.php +++ b/application/inc/Http/Controllers/Admin/PageController.php @@ -26,8 +26,8 @@ class PageController extends AbstractAdminController */ public function index(Request $request, ?int $id = null): Response { - $selectedId = intval($request->cookies->get('activekat', -1)); - $openCategories = explode('<', strval($request->cookies->get('openkat', ''))); + $selectedId = valint($request->cookies->get('activekat', -1)); + $openCategories = explode('<', valstring($request->cookies->get('openkat', ''))); $openCategories = array_map('intval', $openCategories); $orm = app(OrmService::class); @@ -231,7 +231,7 @@ public function removeFromCategory(Request $request, int $id, int $categoryId): */ public function search(Request $request): Response { - $text = strval($request->get('text', '')); + $text = valstring($request->get('text', '')); if (!$text) { throw new InvalidInput(_('You must enter a search word.')); } diff --git a/application/inc/Http/Controllers/Admin/RequirementController.php b/application/inc/Http/Controllers/Admin/RequirementController.php index b667b343..2b30bf9e 100644 --- a/application/inc/Http/Controllers/Admin/RequirementController.php +++ b/application/inc/Http/Controllers/Admin/RequirementController.php @@ -54,7 +54,7 @@ public function editPage(Request $request, ?int $id = null): Response public function update(Request $request, int $id): JsonResponse { $title = $request->getRequestString('title') ?? ''; - $html = strval($request->get('html', '')); + $html = valstring($request->get('html', '')); $html = purifyHTML($html); if ('' === $title || '' === $html) { diff --git a/application/inc/Http/Controllers/Admin/SiteTreeController.php b/application/inc/Http/Controllers/Admin/SiteTreeController.php index efaa3050..cb90fa4b 100644 --- a/application/inc/Http/Controllers/Admin/SiteTreeController.php +++ b/application/inc/Http/Controllers/Admin/SiteTreeController.php @@ -19,7 +19,7 @@ class SiteTreeController extends AbstractAdminController */ public function index(Request $request): Response { - $openCategories = explode('<', strval($request->cookies->get('openkat', ''))); + $openCategories = explode('<', valstring($request->cookies->get('openkat', ''))); $openCategories = array_map('intval', $openCategories); $siteTreeService = new SiteTreeService(); @@ -39,7 +39,7 @@ public function categoryContent(Request $request, int $categoryId): JsonResponse if (!is_string($inputType)) { $inputType = ''; } - $openCategories = explode('<', strval($request->cookies->get('openkat', ''))); + $openCategories = explode('<', valstring($request->cookies->get('openkat', ''))); $openCategories = array_map('intval', $openCategories); $data = [ @@ -76,7 +76,7 @@ public function lable(Request $request, int $id): JsonResponse */ public function pageWidget(Request $request): Response { - $openCategories = explode('<', strval($request->cookies->get('openkat', ''))); + $openCategories = explode('<', valstring($request->cookies->get('openkat', ''))); $openCategories = array_map('intval', $openCategories); $siteTreeService = new SiteTreeService(); @@ -84,7 +84,7 @@ public function pageWidget(Request $request): Response 'siteTree' => $siteTreeService->getSiteTreeData( $openCategories, 'pages', - intval($request->cookies->get('activekat', -1)) + valint($request->cookies->get('activekat', -1)) ), ]; diff --git a/application/inc/Http/Controllers/Admin/TableController.php b/application/inc/Http/Controllers/Admin/TableController.php index 59204633..c0de0f66 100644 --- a/application/inc/Http/Controllers/Admin/TableController.php +++ b/application/inc/Http/Controllers/Admin/TableController.php @@ -49,10 +49,11 @@ public function createDialog(Request $request, int $pageId): Response */ public function addRow(Request $request, int $tableId): JsonResponse { - $cells = $request->request->all('cells'); - if (!is_array($cells)) { - $cells = []; + $cells = []; + foreach ($request->request->all('cells') as $cell) { + $cells[] = valstring($cell); } + $link = $request->getRequestInt('link'); if ($link) { $page = app(OrmService::class)->getOne(Page::class, $link); @@ -73,10 +74,11 @@ public function addRow(Request $request, int $tableId): JsonResponse public function updateRow(Request $request, int $tableId, int $rowId): JsonResponse { - $cells = $request->request->all('cells'); - if (!is_array($cells)) { - $cells = []; + $cells = []; + foreach ($request->request->all('cells') as $cell) { + $cells[] = valstring($cell); } + $link = $request->getRequestInt('link'); if ($link) { $page = app(OrmService::class)->getOne(Page::class, $link); diff --git a/application/inc/Http/Controllers/Base.php b/application/inc/Http/Controllers/Base.php index 0639ad3d..15d04f34 100644 --- a/application/inc/Http/Controllers/Base.php +++ b/application/inc/Http/Controllers/Base.php @@ -44,7 +44,7 @@ public function redirectToSearch(Request $request): RedirectResponse if (null === $query) { throw new Exception('preg_replace failed'); } - $query = trim($query); + $query = mb_trim($query); if ($query) { $redirectUrl = '/search/results/?q=' . rawurlencode($query) . '&sogikke=&minpris=&maxpris=&maerke=0'; } diff --git a/application/inc/Http/Controllers/Feed.php b/application/inc/Http/Controllers/Feed.php index 679df07f..f5de81b1 100644 --- a/application/inc/Http/Controllers/Feed.php +++ b/application/inc/Http/Controllers/Feed.php @@ -134,7 +134,7 @@ public function rss(Request $request): Response $categories = array_unique($categories); $items[] = [ - 'title' => trim($page->getTitle()) ?: ConfigService::getString('site_name'), + 'title' => mb_trim($page->getTitle()) ?: ConfigService::getString('site_name'), 'link' => (string)new Uri(ConfigService::getString('base_url') . $page->getCanonicalLink()), 'description' => $decription, 'pubDate' => gmdate('D, d M Y H:i:s', $page->getTimeStamp()) . ' GMT', diff --git a/application/inc/Http/Controllers/Payment.php b/application/inc/Http/Controllers/Payment.php index eadc350b..671e34d2 100644 --- a/application/inc/Http/Controllers/Payment.php +++ b/application/inc/Http/Controllers/Payment.php @@ -141,26 +141,26 @@ public function addressSave(Request $request, int $id, string $checkId): Respons $data = $this->invoiceService->cleanAddressData($data); $invoice->setStatus(InvoiceStatus::Locked) - ->setName(strval($data['name'])) - ->setAttn(strval($data['attn'])) - ->setAddress(strval($data['address'])) - ->setPostbox(strval($data['postbox'])) - ->setPostcode(strval($data['postcode'])) - ->setCity(strval($data['city'])) - ->setCountry(strval($data['country'])) - ->setEmail(strval($data['email'])) - ->setPhone1(strval($data['phone1'])) - ->setPhone2(strval($data['phone2'])) - ->setHasShippingAddress(intval($data['has_shipping_address']) === 1) - ->setShippingPhone(strval($data['shipping_phone'])) - ->setShippingName(strval($data['shipping_name'])) - ->setShippingAttn(strval($data['shipping_attn'])) - ->setShippingAddress(strval($data['shipping_address'])) - ->setShippingAddress2(strval($data['shipping_address2'])) - ->setShippingPostbox(strval($data['shipping_postbox'])) - ->setShippingPostcode(strval($data['shipping_postcode'])) - ->setShippingCity(strval($data['shipping_city'])) - ->setShippingCountry(strval($data['shipping_country'])) + ->setName(valstring($data['name'])) + ->setAttn(valstring($data['attn'])) + ->setAddress(valstring($data['address'])) + ->setPostbox(valstring($data['postbox'])) + ->setPostcode(valstring($data['postcode'])) + ->setCity(valstring($data['city'])) + ->setCountry(valstring($data['country'])) + ->setEmail(valstring($data['email'])) + ->setPhone1(valstring($data['phone1'])) + ->setPhone2(valstring($data['phone2'])) + ->setHasShippingAddress(valbool($data['has_shipping_address'])) + ->setShippingPhone(valstring($data['shipping_phone'])) + ->setShippingName(valstring($data['shipping_name'])) + ->setShippingAttn(valstring($data['shipping_attn'])) + ->setShippingAddress(valstring($data['shipping_address'])) + ->setShippingAddress2(valstring($data['shipping_address2'])) + ->setShippingPostbox(valstring($data['shipping_postbox'])) + ->setShippingPostcode(valstring($data['shipping_postcode'])) + ->setShippingCity(valstring($data['shipping_city'])) + ->setShippingCountry(valstring($data['shipping_country'])) ->save(); if ($invoice->getInvalid()) { @@ -355,7 +355,7 @@ private function setPaymentStatus(Request $request, Invoice $invoice): void return; } - $cardType = EpaymentService::getPaymentName(intval($request->get('paymenttype'))); + $cardType = EpaymentService::getPaymentName(valint($request->get('paymenttype'))); $internalNote = $this->generateInternalPaymentNote($request); if (!$invoice->getDepartment() || !app(EmailService::class)->valideMail($invoice->getDepartment())) { @@ -363,7 +363,7 @@ private function setPaymentStatus(Request $request, Invoice $invoice): void } $invoice->setCardtype($cardType) - ->setInternalNote(trim($invoice->getInternalNote() . "\n" . $internalNote)) + ->setInternalNote(mb_trim($invoice->getInternalNote() . "\n" . $internalNote)) ->setStatus(InvoiceStatus::PbsOk) ->setTimeStampPay(time()) ->save(); @@ -444,19 +444,22 @@ private function generateInternalPaymentNote(Request $request): string if ($request->get('fraud')) { $internalNote .= _('Possible payment fraud.') . "\n"; } - if ($request->get('cardno')) { - $internalNote .= _('Credit card no.: ') . $request->get('cardno') . "\n"; + $cardno = valstring($request->get('cardno')); + if ($cardno) { + $internalNote .= _('Credit card no.: ') . $cardno . "\n"; } $countries = Countries::getOrdered(); - if ($request->get('issuercountry')) { - $internalNote .= _('Card is from: ') . $countries[$request->get('issuercountry')] . "\n"; + $issuercountry = valstring($request->get('issuercountry')); + if ($issuercountry) { + $internalNote .= _('Card is from: ') . $countries[$issuercountry] . "\n"; } - if ($request->get('payercountry')) { - $internalNote .= _('Payment was made from: ') . $countries[$request->get('payercountry')] . "\n"; + $payercountry = valstring($request->get('payercountry')); + if ($payercountry) { + $internalNote .= _('Payment was made from: ') . $countries[$payercountry] . "\n"; } - return trim($internalNote); + return mb_trim($internalNote); } /** diff --git a/application/inc/Http/Controllers/Search.php b/application/inc/Http/Controllers/Search.php index 891f78b6..fa0af155 100644 --- a/application/inc/Http/Controllers/Search.php +++ b/application/inc/Http/Controllers/Search.php @@ -129,8 +129,6 @@ public function results(Request $request): Response /** * Check if we should performe the search or handle it else where. - * - * @return ?RedirectResponse */ private function checkSearchable(Request $request): ?RedirectResponse { diff --git a/application/inc/Http/Controllers/Shopping.php b/application/inc/Http/Controllers/Shopping.php index f5106647..320c4b99 100644 --- a/application/inc/Http/Controllers/Shopping.php +++ b/application/inc/Http/Controllers/Shopping.php @@ -127,7 +127,7 @@ public function send(Request $request): Response } $note = $this->invoiceService->generateExtraNote($cart); - $note = trim($note . "\n" . $invoice->getNote()); + $note = mb_trim($note . "\n" . $invoice->getNote()); $invoice->setNote($note); $invoice->save(); diff --git a/application/inc/Http/Middleware/Utf8Url.php b/application/inc/Http/Middleware/Utf8Url.php index c5c88515..8df4b825 100644 --- a/application/inc/Http/Middleware/Utf8Url.php +++ b/application/inc/Http/Middleware/Utf8Url.php @@ -25,7 +25,7 @@ public function handle(Request $request, callable $next): Response $encoding = 'windows-1252'; } - $requestUrl = mb_convert_encoding($requestUrl, 'UTF-8', $encoding); + $requestUrl = mb_convert_encoding($requestUrl, 'UTF-8', $encoding) ?: $requestUrl; return redirect($requestUrl, Response::HTTP_MOVED_PERMANENTLY); } diff --git a/application/inc/Http/Request.php b/application/inc/Http/Request.php index 29ecc43c..509308e0 100644 --- a/application/inc/Http/Request.php +++ b/application/inc/Http/Request.php @@ -84,8 +84,6 @@ public function setUser(User $user): void * Get the currently authenticated user. * * @throws Exception - * - * @return ?User */ public function user(): ?User { @@ -97,7 +95,7 @@ public function user(): ?User if (!$this->session instanceof SessionInterface) { throw new Exception('Failed to start session.'); } - $id = $this->session->get('login_id'); + $id = valint($this->session->get('login_id')); $hash = $this->session->get('login_hash'); $this->session->save(); diff --git a/application/inc/Models/AbstractEntity.php b/application/inc/Models/AbstractEntity.php index 41ecfc54..56ef547f 100644 --- a/application/inc/Models/AbstractEntity.php +++ b/application/inc/Models/AbstractEntity.php @@ -8,7 +8,7 @@ abstract class AbstractEntity implements Entity { - /** Table name in database. */ + /** @var string Table name in database. */ public const TABLE_NAME = ''; /** @var ?int The entity ID. */ diff --git a/application/inc/Models/Brand.php b/application/inc/Models/Brand.php index ea42766d..ae3c80aa 100644 --- a/application/inc/Models/Brand.php +++ b/application/inc/Models/Brand.php @@ -20,8 +20,8 @@ class Brand extends AbstractRenderable public function __construct(array $data = []) { $this->iconId = intOrNull($data['icon_id']); - $this->setLink(strval($data['link'])) - ->setTitle(strval($data['title'])) + $this->setLink(valstring($data['link'])) + ->setTitle(valstring($data['title'])) ->setId(intOrNull($data['id'] ?? null)); } diff --git a/application/inc/Models/Category.php b/application/inc/Models/Category.php index 0d33229e..da6bb043 100644 --- a/application/inc/Models/Category.php +++ b/application/inc/Models/Category.php @@ -45,11 +45,11 @@ class Category extends AbstractRenderable */ public function __construct(array $data = []) { - $this->setRenderMode(intval($data['render_mode'])) - ->setEmail(strval($data['email'])) - ->setWeightedChildren(boolval($data['weighted_children'])) - ->setWeight(intval($data['weight'])) - ->setTitle(strval($data['title'])) + $this->setRenderMode(valint($data['render_mode'])) + ->setEmail(valstring($data['email'])) + ->setWeightedChildren(valbool($data['weighted_children'])) + ->setWeight(valint($data['weight'])) + ->setTitle(valstring($data['title'])) ->setId(intOrNull($data['id'] ?? null)); $this->iconId = intOrNull($data['icon_id'] ?? null); @@ -420,7 +420,7 @@ public function getBranch(): array $nodes[] = $category; } while ($category = $category->getParent()); - return array_values(array_reverse($nodes)); + return array_reverse($nodes); } /** diff --git a/application/inc/Models/Contact.php b/application/inc/Models/Contact.php index 2892ccc2..ae2fa58e 100644 --- a/application/inc/Models/Contact.php +++ b/application/inc/Models/Contact.php @@ -49,23 +49,26 @@ class Contact extends AbstractEntity public function __construct(array $data = []) { - $interests = $data['interests'] ?? null; - if (!is_array($interests)) { - $interests = []; + $interests = []; + $rawInterests = $data['interests'] ?? null; + if (is_array($rawInterests)) { + foreach ($rawInterests as $rawInterest) { + $interests[] = valstring($rawInterest); + } } - $this->setTimestamp(intval($data['timestamp'] ?? time())) - ->setName(strval($data['name'])) - ->setEmail(strval($data['email'])) - ->setAddress(strval($data['address'])) - ->setCountry(strval($data['country'])) - ->setPostcode(strval($data['postcode'])) - ->setCity(strval($data['city'])) - ->setPhone1(strval($data['phone1'])) - ->setPhone2(strval($data['phone2'])) - ->setSubscribed(boolval($data['subscribed'])) + $this->setTimestamp(valint($data['timestamp'] ?? time())) + ->setName(valstring($data['name'])) + ->setEmail(valstring($data['email'])) + ->setAddress(valstring($data['address'])) + ->setCountry(valstring($data['country'])) + ->setPostcode(valstring($data['postcode'])) + ->setCity(valstring($data['city'])) + ->setPhone1(valstring($data['phone1'])) + ->setPhone2(valstring($data['phone2'])) + ->setSubscribed(valbool($data['subscribed'])) ->setInterests($interests) - ->setIp(strval($data['ip'])) + ->setIp(valstring($data['ip'])) ->setId(intOrNull($data['id'] ?? null)); } diff --git a/application/inc/Models/CustomPage.php b/application/inc/Models/CustomPage.php index 7dd976bd..966f207f 100644 --- a/application/inc/Models/CustomPage.php +++ b/application/inc/Models/CustomPage.php @@ -22,9 +22,9 @@ class CustomPage extends AbstractEntity implements InterfaceRichText public function __construct(array $data = []) { - $this->setTimeStamp(intval($data['timestamp'])) - ->setTitle(strval($data['title'])) - ->setHtml(strval($data['html'])) + $this->setTimeStamp(valint($data['timestamp'])) + ->setTitle(valstring($data['title'])) + ->setHtml(valstring($data['html'])) ->setId(intOrNull($data['id'] ?? null)); } diff --git a/application/inc/Models/CustomSorting.php b/application/inc/Models/CustomSorting.php index 83d06b23..3df511b9 100644 --- a/application/inc/Models/CustomSorting.php +++ b/application/inc/Models/CustomSorting.php @@ -19,12 +19,15 @@ class CustomSorting extends AbstractEntity public function __construct(array $data = []) { - $items = $data['items'] ?? null; - if (!is_array($items)) { - $items = []; + $items = []; + $rawItems = $data['items'] ?? null; + if (is_array($rawItems)) { + foreach ($rawItems as $rawItem) { + $items[] = valstring($rawItem); + } } - $this->setTitle(strval($data['title'])) + $this->setTitle(valstring($data['title'])) ->setItems($items) ->setId(intOrNull($data['id'] ?? null)); } diff --git a/application/inc/Models/Email.php b/application/inc/Models/Email.php index 763860f8..48837e82 100644 --- a/application/inc/Models/Email.php +++ b/application/inc/Models/Email.php @@ -39,13 +39,13 @@ public function __construct(array $data = []) { $this->emailService = app(EmailService::class); - $this->setTimestamp(intval($data['timestamp'] ?? time())) - ->setSubject(strval($data['subject'])) - ->setBody(strval($data['body'])) - ->setSenderName(strval($data['senderName'])) - ->setSenderAddress(strval($data['senderAddress'])) - ->setRecipientName(strval($data['recipientName'])) - ->setRecipientAddress(strval($data['recipientAddress'])) + $this->setTimestamp(valint($data['timestamp'] ?? time())) + ->setSubject(valstring($data['subject'])) + ->setBody(valstring($data['body'])) + ->setSenderName(valstring($data['senderName'])) + ->setSenderAddress(valstring($data['senderAddress'])) + ->setRecipientName(valstring($data['recipientName'])) + ->setRecipientAddress(valstring($data['recipientAddress'])) ->setId(intOrNull($data['id'] ?? null)); } @@ -200,11 +200,11 @@ public function getRecipientAddress(): string public static function mapFromDB(array $data): array { $from = explode('<', $data['from']); - $senderAddress = trim($from[0]); + $senderAddress = mb_trim($from[0]); $senderName = mb_substr($from[1], 0, -1); $to = explode('<', $data['to']); - $recipientAddress = trim($to[0]); + $recipientAddress = mb_trim($to[0]); $recipientName = mb_substr($to[1], 0, -1); return [ diff --git a/application/inc/Models/Epayment.php b/application/inc/Models/Epayment.php index 4096f601..fe3e74c6 100644 --- a/application/inc/Models/Epayment.php +++ b/application/inc/Models/Epayment.php @@ -34,13 +34,13 @@ public function __construct(EpaymentService $service, stdClass $transactionData) { $this->service = $service; - $this->transactionId = $transactionData->transactionid; - $this->amount = (int)$transactionData->authamount; + $this->transactionId = valint($transactionData->transactionid); + $this->amount = valint($transactionData->authamount); if ('PAYMENT_NEW' === $transactionData->status) { $this->authorized = true; } elseif ('PAYMENT_CAPTURED' === $transactionData->status) { - $this->amountCaptured = (int)$transactionData->capturedamount; + $this->amountCaptured = valint($transactionData->capturedamount); } elseif ('PAYMENT_DELETED' === $transactionData->status) { $this->annulled = true; } diff --git a/application/inc/Models/File.php b/application/inc/Models/File.php index d1dfab87..7bf6819e 100644 --- a/application/inc/Models/File.php +++ b/application/inc/Models/File.php @@ -35,12 +35,12 @@ class File extends AbstractEntity public function __construct(array $data = []) { - $this->setPath(strval($data['path'])) - ->setMime(strval($data['mime'])) - ->setSize(intval($data['size'])) - ->setDescription(strval($data['description'])) - ->setWidth(intval($data['width'])) - ->setHeight(intval($data['height'])) + $this->setPath(valstring($data['path'])) + ->setMime(valstring($data['mime'])) + ->setSize(valint($data['size'])) + ->setDescription(valstring($data['description'])) + ->setWidth(valint($data['width'])) + ->setHeight(valint($data['height'])) ->setId(intOrNull($data['id'] ?? null)); } @@ -299,9 +299,6 @@ public function delete(): bool return parent::delete(); } - /** - * @return ?self - */ public static function getByPath(string $path): ?self { $file = app(OrmService::class)->getOneByQuery( diff --git a/application/inc/Models/Invoice.php b/application/inc/Models/Invoice.php index e460567f..e76dff7e 100644 --- a/application/inc/Models/Invoice.php +++ b/application/inc/Models/Invoice.php @@ -128,43 +128,43 @@ class Invoice extends AbstractEntity public function __construct(array $data = []) { - $this->setItemData(strval($data['item_data'] ?? '[]')) - ->setHasShippingAddress(boolval($data['has_shipping_address'] ?? false)) - ->setTimeStamp(intval($data['timestamp'] ?? time())) - ->setTimeStampPay(intval($data['timestamp_pay'] ?? 0)) - ->setAmount(floatval($data['amount'] ?? 0.00)) - ->setName(strval($data['name'] ?? '')) - ->setAttn(strval($data['attn'] ?? '')) - ->setAddress(strval($data['address'] ?? '')) - ->setPostbox(strval($data['postbox'] ?? '')) - ->setPostcode(strval($data['postcode'] ?? '')) - ->setCity(strval($data['city'] ?? '')) - ->setCountry(strval($data['country'] ?? 'DK')) - ->setEmail(strval($data['email'] ?? '')) - ->setPhone1(strval($data['phone1'] ?? '')) - ->setPhone2(strval($data['phone2'] ?? '')) - ->setShippingPhone(strval($data['shipping_phone'] ?? '')) - ->setShippingName(strval($data['shipping_name'] ?? '')) - ->setShippingAttn(strval($data['shipping_attn'] ?? '')) - ->setShippingAddress(strval($data['shipping_address'] ?? '')) - ->setShippingAddress2(strval($data['shipping_address2'] ?? '')) - ->setShippingPostbox(strval($data['shipping_postbox'] ?? '')) - ->setShippingPostcode(strval($data['shipping_postcode'] ?? '')) - ->setShippingCity(strval($data['shipping_city'] ?? '')) - ->setShippingCountry(strval($data['shipping_country'] ?? 'DK')) - ->setNote(strval($data['note'] ?? '')) - ->setInternalNote(strval($data['internal_note'] ?? '')) - ->setClerk(strval($data['clerk'] ?? '')) - ->setStatus(InvoiceStatus::from(strval($data['status'] ?? 'new'))) - ->setShipping(floatval($data['shipping'] ?? 0.00)) - ->setVat(floatval($data['vat'] ?? 0.25)) - ->setPreVat(boolval($data['pre_vat'] ?? true)) - ->setTransferred(boolval($data['transferred'] ?? false)) - ->setCardtype(strval($data['cardtype'] ?? '')) - ->setIref(strval($data['iref'] ?? '')) - ->setEref(strval($data['eref'] ?? '')) - ->setSent(boolval($data['sent'] ?? false)) - ->setDepartment(strval($data['department'] ?? '')) + $this->setItemData(valstring($data['item_data'] ?? '[]')) + ->setHasShippingAddress(valbool($data['has_shipping_address'] ?? false)) + ->setTimeStamp(valint($data['timestamp'] ?? time())) + ->setTimeStampPay(valint($data['timestamp_pay'] ?? 0)) + ->setAmount(valfloat($data['amount'] ?? 0.00)) + ->setName(valstring($data['name'] ?? '')) + ->setAttn(valstring($data['attn'] ?? '')) + ->setAddress(valstring($data['address'] ?? '')) + ->setPostbox(valstring($data['postbox'] ?? '')) + ->setPostcode(valstring($data['postcode'] ?? '')) + ->setCity(valstring($data['city'] ?? '')) + ->setCountry(valstring($data['country'] ?? 'DK')) + ->setEmail(valstring($data['email'] ?? '')) + ->setPhone1(valstring($data['phone1'] ?? '')) + ->setPhone2(valstring($data['phone2'] ?? '')) + ->setShippingPhone(valstring($data['shipping_phone'] ?? '')) + ->setShippingName(valstring($data['shipping_name'] ?? '')) + ->setShippingAttn(valstring($data['shipping_attn'] ?? '')) + ->setShippingAddress(valstring($data['shipping_address'] ?? '')) + ->setShippingAddress2(valstring($data['shipping_address2'] ?? '')) + ->setShippingPostbox(valstring($data['shipping_postbox'] ?? '')) + ->setShippingPostcode(valstring($data['shipping_postcode'] ?? '')) + ->setShippingCity(valstring($data['shipping_city'] ?? '')) + ->setShippingCountry(valstring($data['shipping_country'] ?? 'DK')) + ->setNote(valstring($data['note'] ?? '')) + ->setInternalNote(valstring($data['internal_note'] ?? '')) + ->setClerk(valstring($data['clerk'] ?? '')) + ->setStatus(InvoiceStatus::from(valstring($data['status'] ?? 'new'))) + ->setShipping(valfloat($data['shipping'] ?? 0.00)) + ->setVat(valfloat($data['vat'] ?? 0.25)) + ->setPreVat(valbool($data['pre_vat'] ?? true)) + ->setTransferred(valbool($data['transferred'] ?? false)) + ->setCardtype(valstring($data['cardtype'] ?? '')) + ->setIref(valstring($data['iref'] ?? '')) + ->setEref(valstring($data['eref'] ?? '')) + ->setSent(valbool($data['sent'] ?? false)) + ->setDepartment(valstring($data['department'] ?? '')) ->setId(intOrNull($data['id'] ?? null)); } @@ -215,8 +215,6 @@ public function setTimeStampPay(int $timeStampPay): self /** * Get time the payment was finalized. - * - * @return ?int */ public function getTimeStampPay(): ?int { @@ -237,8 +235,6 @@ public function setPaymentId(int $paymentId): self /** * Get payment id. - * - * @return ?int */ public function getPaymentId(): ?int { @@ -272,7 +268,7 @@ public function getAmount(): float */ public function setName(string $name): self { - $this->name = trim($name); + $this->name = mb_trim($name); return $this; } @@ -292,7 +288,7 @@ public function getName(): string */ public function setAttn(string $attn): self { - $this->attn = trim($attn); + $this->attn = mb_trim($attn); return $this; } @@ -312,7 +308,7 @@ public function getAttn(): string */ public function setAddress(string $address): self { - $this->address = trim($address); + $this->address = mb_trim($address); return $this; } @@ -332,7 +328,7 @@ public function getAddress(): string */ public function setPostbox(string $postbox): self { - $this->postbox = trim($postbox); + $this->postbox = mb_trim($postbox); return $this; } @@ -352,7 +348,7 @@ public function getPostbox(): string */ public function setPostcode(string $postcode): self { - $this->postcode = trim($postcode); + $this->postcode = mb_trim($postcode); return $this; } @@ -372,7 +368,7 @@ public function getPostcode(): string */ public function setCity(string $city): self { - $this->city = trim($city); + $this->city = mb_trim($city); return $this; } @@ -392,7 +388,7 @@ public function getCity(): string */ public function setCountry(string $country): self { - $this->country = trim($country); + $this->country = mb_trim($country); return $this; } @@ -412,7 +408,7 @@ public function getCountry(): string */ public function setEmail(string $email): self { - $this->email = trim($email); + $this->email = mb_trim($email); return $this; } @@ -432,7 +428,7 @@ public function getEmail(): string */ public function setPhone1(string $phone1): self { - $this->phone1 = trim($phone1); + $this->phone1 = mb_trim($phone1); return $this; } @@ -452,7 +448,7 @@ public function getPhone1(): string */ public function setPhone2(string $phone2): self { - $this->phone2 = trim($phone2); + $this->phone2 = mb_trim($phone2); return $this; } @@ -492,7 +488,7 @@ public function hasShippingAddress(): bool */ public function setShippingPhone(string $shippingPhone): self { - $this->shippingPhone = trim($shippingPhone); + $this->shippingPhone = mb_trim($shippingPhone); return $this; } @@ -512,7 +508,7 @@ public function getShippingPhone(): string */ public function setShippingName(string $shippingName): self { - $this->shippingName = trim($shippingName); + $this->shippingName = mb_trim($shippingName); return $this; } @@ -532,7 +528,7 @@ public function getShippingName(): string */ public function setShippingAttn(string $shippingAttn): self { - $this->shippingAttn = trim($shippingAttn); + $this->shippingAttn = mb_trim($shippingAttn); return $this; } @@ -552,7 +548,7 @@ public function getShippingAttn(): string */ public function setShippingAddress(string $shippingAddress): self { - $this->shippingAddress = trim($shippingAddress); + $this->shippingAddress = mb_trim($shippingAddress); return $this; } @@ -572,7 +568,7 @@ public function getShippingAddress(): string */ public function setShippingAddress2(string $shippingAddress2): self { - $this->shippingAddress2 = trim($shippingAddress2); + $this->shippingAddress2 = mb_trim($shippingAddress2); return $this; } @@ -592,7 +588,7 @@ public function getShippingAddress2(): string */ public function setShippingPostbox(string $shippingPostbox): self { - $this->shippingPostbox = trim($shippingPostbox); + $this->shippingPostbox = mb_trim($shippingPostbox); return $this; } @@ -612,7 +608,7 @@ public function getShippingPostbox(): string */ public function setShippingPostcode(string $shippingPostcode): self { - $this->shippingPostcode = trim($shippingPostcode); + $this->shippingPostcode = mb_trim($shippingPostcode); return $this; } @@ -632,7 +628,7 @@ public function getShippingPostcode(): string */ public function setShippingCity(string $shippingCity): self { - $this->shippingCity = trim($shippingCity); + $this->shippingCity = mb_trim($shippingCity); return $this; } @@ -652,7 +648,7 @@ public function getShippingCity(): string */ public function setShippingCountry(string $shippingCountry): self { - $this->shippingCountry = trim($shippingCountry); + $this->shippingCountry = mb_trim($shippingCountry); return $this; } @@ -672,7 +668,7 @@ public function getShippingCountry(): string */ public function setNote(string $note): self { - $this->note = trim($note); + $this->note = mb_trim($note); return $this; } @@ -692,7 +688,7 @@ public function getNote(): string */ public function setClerk(string $clerk): self { - $this->clerk = trim($clerk); + $this->clerk = mb_trim($clerk); return $this; } @@ -837,7 +833,7 @@ public function isTransferred(): bool */ public function setCardtype(string $cardtype): self { - $this->cardtype = trim($cardtype) ?: _('Unknown'); + $this->cardtype = mb_trim($cardtype) ?: _('Unknown'); return $this; } @@ -857,7 +853,7 @@ public function getCardtype(): string */ public function setIref(string $iref): self { - $this->iref = trim($iref); + $this->iref = mb_trim($iref); return $this; } @@ -877,7 +873,7 @@ public function getIref(): string */ public function setEref(string $eref): self { - $this->eref = trim($eref); + $this->eref = mb_trim($eref); return $this; } @@ -917,7 +913,7 @@ public function isSent(): bool */ public function setDepartment(string $department): self { - $this->department = trim($department); + $this->department = mb_trim($department); return $this; } @@ -937,7 +933,7 @@ public function getDepartment(): string */ public function setInternalNote(string $internalNote): self { - $this->internalNote = trim($internalNote); + $this->internalNote = mb_trim($internalNote); return $this; } @@ -1027,6 +1023,7 @@ public function setItemData(string $itemData): self $items = json_decode($itemData, true); if (is_array($items)) { foreach ($items as $item) { + assert(is_array($item)); $quantity = $item['quantity'] ?? null; if (!is_int($quantity)) { $quantity = 0; diff --git a/application/inc/Models/Newsletter.php b/application/inc/Models/Newsletter.php index fe1d1bc1..a3f9db78 100644 --- a/application/inc/Models/Newsletter.php +++ b/application/inc/Models/Newsletter.php @@ -35,16 +35,19 @@ class Newsletter extends AbstractEntity implements InterfaceRichText public function __construct(array $data = []) { - $interests = $data['interests'] ?? null; - if (!is_array($interests)) { - $interests = []; + $interests = []; + $rawInterests = $data['interests'] ?? null; + if (is_array($rawInterests)) { + foreach ($rawInterests as $rawInterest) { + $interests[] = valstring($rawInterest); + } } - $this->setFrom(strval($data['from'] ?? '')) - ->setSubject(strval($data['subject'] ?? '')) + $this->setFrom(valstring($data['from'] ?? '')) + ->setSubject(valstring($data['subject'] ?? '')) ->setInterests($interests) - ->setHtml(strval($data['html'] ?? '')) - ->setSent(boolval($data['sent'] ?? false)) + ->setHtml(valstring($data['html'] ?? '')) + ->setSent(valbool($data['sent'] ?? false)) ->setId(intOrNull($data['id'] ?? null)); } diff --git a/application/inc/Models/Page.php b/application/inc/Models/Page.php index 19333caf..4d69b140 100644 --- a/application/inc/Models/Page.php +++ b/application/inc/Models/Page.php @@ -51,18 +51,18 @@ class Page extends AbstractRenderable implements InterfaceRichText public function __construct(array $data = []) { $this->iconId = intOrNull($data['icon_id'] ?? null); - $this->setSku(strval($data['sku'])) - ->setTimeStamp(intval($data['timestamp'] ?? 0)) - ->setKeywords(strval($data['keywords'])) - ->setExcerpt(strval($data['excerpt'])) + $this->setSku(valstring($data['sku'])) + ->setTimeStamp(valint($data['timestamp'] ?? 0)) + ->setKeywords(valstring($data['keywords'])) + ->setExcerpt(valstring($data['excerpt'])) ->setRequirementId(intOrNull($data['requirement_id'])) ->setBrandId(intOrNull($data['brand_id'])) - ->setPrice(intval($data['price'])) - ->setOldPrice(intval($data['old_price'])) - ->setPriceType(intval($data['price_type'])) - ->setOldPriceType(intval($data['old_price_type'])) - ->setHtml(strval($data['html'])) - ->setTitle(strval($data['title'])) + ->setPrice(valint($data['price'])) + ->setOldPrice(valint($data['old_price'])) + ->setPriceType(valint($data['price_type'])) + ->setOldPriceType(valint($data['old_price_type'])) + ->setHtml(valstring($data['html'])) + ->setTitle(valstring($data['title'])) ->setId(intOrNull($data['id'] ?? null)); } @@ -377,8 +377,6 @@ public function isInCategory(Category $category): bool /** * Get the primery category for this page. - * - * @return ?Category */ public function getPrimaryCategory(): ?Category { @@ -519,8 +517,6 @@ public function hasProductTable(): bool /** * Get product brand. - * - * @return ?Brand */ public function getBrand(): ?Brand { @@ -534,8 +530,6 @@ public function getBrand(): ?Brand /** * Get product requirement. - * - * @return ?Requirement */ public function getRequirement(): ?Requirement { diff --git a/application/inc/Models/Requirement.php b/application/inc/Models/Requirement.php index 6610a1c7..ea5541ef 100644 --- a/application/inc/Models/Requirement.php +++ b/application/inc/Models/Requirement.php @@ -16,8 +16,8 @@ class Requirement extends AbstractRenderable implements InterfaceRichText public function __construct(array $data = []) { - $this->setHtml(strval($data['html'])) - ->setTitle(strval($data['title'])) + $this->setHtml(valstring($data['html'])) + ->setTitle(valstring($data['title'])) ->setId(intOrNull($data['id'] ?? null)); } diff --git a/application/inc/Models/Table.php b/application/inc/Models/Table.php index fb970c0d..c43dfe4a 100644 --- a/application/inc/Models/Table.php +++ b/application/inc/Models/Table.php @@ -37,11 +37,11 @@ class Table extends AbstractEntity public function __construct(array $data = []) { - $this->setPageId(intval($data['page_id'])) - ->setTitle(strval($data['title'])) - ->setColumnData(strval($data['column_data'])) - ->setOrderBy(intval($data['order_by'])) - ->setHasLinks(boolval($data['has_links'])) + $this->setPageId(valint($data['page_id'])) + ->setTitle(valstring($data['title'])) + ->setColumnData(valstring($data['column_data'])) + ->setOrderBy(valint($data['order_by'])) + ->setHasLinks(valbool($data['has_links'])) ->setId(intOrNull($data['id'] ?? null)); } @@ -139,21 +139,33 @@ public function setColumnData(string $columnData): self { $columns = json_decode($columnData, true); - if (is_array($columns)) { - foreach ($columns as $columnData) { - $column = new TableColumn( - $columnData['title'], - ColumnType::from($columnData['type']), - $columnData['sorting'], - $columnData['options'], - ); - - if (in_array($column->type, [ColumnType::Price, ColumnType::SalesPrice], true)) { - $this->hasPrices = true; - } - - $this->columns[] = $column; + if (!is_array($columns)) { + return $this; + } + foreach ($columns as $columnData) { + if (!is_array($columnData)) { + continue; + } + $rawOptions = $columnData['options'] ?? []; + if (!is_array($rawOptions)) { + continue; + } + $options = []; + foreach ($rawOptions as $key => $rawOption) { + $options[$key] = is_string($rawOption) ? $rawOption : ''; } + $column = new TableColumn( + valstring($columnData['title']), + ColumnType::from(valint($columnData['type'])), + valint($columnData['sorting']), + $options, + ); + + if (in_array($column->type, [ColumnType::Price, ColumnType::SalesPrice], true)) { + $this->hasPrices = true; + } + + $this->columns[] = $column; } return $this; @@ -323,9 +335,11 @@ public function removeRow(int $rowId): void /** * Sort a 2D array based on a custome sort order. * - * @param array> $rows + * @template T of array * - * @return array> + * @param array $rows + * + * @return list */ private function orderRows(array $rows, ?int $orderBy = null): array { @@ -342,7 +356,11 @@ private function orderRows(array $rows, ?int $orderBy = null): array $tempArray = []; foreach ($rows as $rowKey => $row) { - $tempArray[$rowKey] = $options[$row[$orderBy]] ?? -1; + $optionKey = $row[$orderBy]; + if (!is_string($optionKey) && !is_int($optionKey)) { + throw new Exception('Invalid order key: ' . gettype($optionKey)); + } + $tempArray[$rowKey] = $options[$optionKey] ?? -1; } asort($tempArray); diff --git a/application/inc/Models/User.php b/application/inc/Models/User.php index 4658ce5f..f903e926 100644 --- a/application/inc/Models/User.php +++ b/application/inc/Models/User.php @@ -43,11 +43,11 @@ class User extends AbstractEntity public function __construct(array $data = []) { - $this->setFullName(strval($data['full_name'])) - ->setNickname(strval($data['nickname'])) - ->setPasswordHash(strval($data['password_hash'])) - ->setAccessLevel(intval($data['access_level'])) - ->setLastLogin(intval($data['last_login'])) + $this->setFullName(valstring($data['full_name'])) + ->setNickname(valstring($data['nickname'])) + ->setPasswordHash(valstring($data['password_hash'])) + ->setAccessLevel(valint($data['access_level'])) + ->setLastLogin(valint($data['last_login'])) ->setId(intOrNull($data['id'] ?? null)); } diff --git a/application/inc/Services/ConfigService.php b/application/inc/Services/ConfigService.php index a57db239..ad5689d8 100644 --- a/application/inc/Services/ConfigService.php +++ b/application/inc/Services/ConfigService.php @@ -17,8 +17,10 @@ class ConfigService */ public static function load(string $basePath): void { + /** @var array|false */ $config = @include $basePath . '/inc/config.php'; if ($config === false) { + /** @var array */ $config = include $basePath . '/inc/config_sample.php'; } self::$config = $config; diff --git a/application/inc/Services/EpaymentService.php b/application/inc/Services/EpaymentService.php index 09b9de0d..53fcd703 100644 --- a/application/inc/Services/EpaymentService.php +++ b/application/inc/Services/EpaymentService.php @@ -159,7 +159,7 @@ public function annul(Epayment $epayment): bool ] ); - return $response->deleteResult; + return (bool)$response->deleteResult; } /** @@ -179,6 +179,6 @@ public function confirm(Epayment $epayment, int $amount): bool 'pbsResponse' => true, ]); - return $response->captureResult; + return (bool)$response->captureResult; } } diff --git a/application/inc/Services/InvoicePdfService.php b/application/inc/Services/InvoicePdfService.php index c87384f6..da09a5ba 100644 --- a/application/inc/Services/InvoicePdfService.php +++ b/application/inc/Services/InvoicePdfService.php @@ -220,7 +220,7 @@ private function getBillingAddress(array $countries): string $address .= "\n" . $countries[$this->invoice->getCountry()]; } - return trim($address); + return mb_trim($address); } /** @@ -256,7 +256,7 @@ private function getShippingAddress(array $countries): string $address .= "\n" . $countries[$this->invoice->getShippingCountry()]; } - return trim($address); + return mb_trim($address); } /** @@ -292,11 +292,12 @@ private function insertProductLine(InvoiceItem $item): int { $value = $item->value * (1 + $this->invoice->getVat()); $lineTotal = $value * $item->quantity; + $decimalSeparator = valstring(localeconv()['mon_decimal_point'] ?? '.'); $this->pdf->Cell(self::CELL_WIDTH_QUANTITY, 6, (string)$item->quantity, 'RL', 0, 'R'); $lines = $this->pdf->MultiCell(self::CELL_WIDTH_TITLE, 6, $item->title, 'RL', 'L', false, 0); - $this->pdf->Cell(self::CELL_WIDTH_PRICE, 6, number_format($value, 2, localeconv()['mon_decimal_point'], ''), 'RL', 0, 'R'); - $this->pdf->Cell(self::CELL_WIDTH_TOTAL, 6, number_format($lineTotal, 2, localeconv()['mon_decimal_point'], ''), 'RL', 1, 'R'); + $this->pdf->Cell(self::CELL_WIDTH_PRICE, 6, number_format($value, 2, $decimalSeparator, ''), 'RL', 0, 'R'); + $this->pdf->Cell(self::CELL_WIDTH_TOTAL, 6, number_format($lineTotal, 2, $decimalSeparator, ''), 'RL', 1, 'R'); if ($lines > 1) { $this->insertTableSpacing($lines - 1); @@ -321,9 +322,11 @@ private function insertTableSpacing(int $lines): void */ private function insertTableFooter(): void { + $decimalSeparator = valstring(localeconv()['mon_decimal_point'] ?? '.'); + $vatText = ($this->invoice->getVat() * 100) . _('% VAT is: ') - . number_format($this->invoice->getNetAmount() * $this->invoice->getVat(), 2, localeconv()['mon_decimal_point'], ''); - $shippingPrice = number_format($this->invoice->getShipping(), 2, localeconv()['mon_decimal_point'], ''); + . number_format($this->invoice->getNetAmount() * $this->invoice->getVat(), 2, $decimalSeparator, ''); + $shippingPrice = number_format($this->invoice->getShipping(), 2, $decimalSeparator, ''); $finePrint = '' . _('Payment Terms:') . ' ' . _('Initial net amount.') . '
' . _('In case of payment later than the stated deadline, 2% interest will be added per month.') @@ -340,7 +343,14 @@ private function insertTableFooter(): void $this->pdf->SetFont('times', 'B', 11); $this->pdf->Cell(self::CELL_WIDTH_PRICE, 9, _('Total (USD)'), 1, 0, 'C'); $this->pdf->SetFont('times', '', 11); - $this->pdf->Cell(self::CELL_WIDTH_TOTAL, 9, number_format($this->invoice->getAmount(), 2, localeconv()['mon_decimal_point'], ''), 1, 1, 'R'); + $this->pdf->Cell( + self::CELL_WIDTH_TOTAL, + 9, + number_format($this->invoice->getAmount(), 2, $decimalSeparator, ''), + 1, + 1, + 'R' + ); } /** @@ -351,7 +361,7 @@ private function generateFooter(): void //Note $note = $this->getPaymentNote(); $note .= $this->invoice->getNote(); - $note = trim($note); + $note = mb_trim($note); if ($note) { $this->pdf->SetFont('times', 'B', 10); diff --git a/application/inc/Services/InvoiceService.php b/application/inc/Services/InvoiceService.php index 6817cf71..7369abff 100644 --- a/application/inc/Services/InvoiceService.php +++ b/application/inc/Services/InvoiceService.php @@ -21,7 +21,7 @@ class InvoiceService /** * Create an invoice from the client cart array. * - * @param array $cart + * @param array $cart */ public function createFromCart(array $cart): Invoice { @@ -44,7 +44,7 @@ public function createFromCart(array $cart): Invoice $pageId = null; if ('line' === $item['type']) { // Find item based on price table row $db->addLoadedTable('list_rows'); - $listRow = $db->fetchOne('SELECT * FROM `list_rows` WHERE id = ' . $item['id']); + $listRow = $db->fetchOne('SELECT * FROM `list_rows` WHERE id = ' . valint($item['id'])); $table = $listRow ? $orm->getOne(Table::class, (int)$listRow['list_id']) : null; if ($table) { $pageId = $table->getPage()->getId(); @@ -56,12 +56,12 @@ public function createFromCart(array $cart): Invoice $cells = array_map('html_entity_decode', $cells); foreach ($table->getColumns() as $i => $column) { - if (empty($cells[$i]) || !trim($cells[$i])) { + if (empty($cells[$i]) || !mb_trim($cells[$i])) { continue; } if (in_array($column->type, [ColumnType::String, ColumnType::Int], true)) { - $title .= ' ' . trim($cells[$i]); + $title .= ' ' . mb_trim($cells[$i]); } elseif (in_array( $column->type, [ColumnType::Price, ColumnType::SalesPrice], @@ -70,10 +70,10 @@ public function createFromCart(array $cart): Invoice $value = (int)$cells[$i]; } } - $title = trim($title); + $title = mb_trim($title); } } elseif ('page' === $item['type']) { - $pageId = $item['id'] ?? null; + $pageId = intOrNull($item['id'] ?? null); } $page = $pageId ? $orm->getOne(Page::class, $pageId) : null; @@ -96,7 +96,7 @@ public function createFromCart(array $cart): Invoice } $items[] = [ - 'title' => trim($title), + 'title' => mb_trim($title), 'quantity' => $quantity, 'value' => $value, ]; @@ -119,7 +119,7 @@ public function createFromCart(array $cart): Invoice /** * Clean up address data. * - * @param array $data + * @param array $data * * @return array */ @@ -181,12 +181,12 @@ public function cleanAddressData(array $data): array /** * Generate additional order comments based on cart options. * - * @param array $cart + * @param array $cart */ public function generateExtraNote(array $cart): string { $notes = []; - switch ($cart['payMethod'] ?? '') { + switch (valstring($cart['payMethod'] ?? '')) { case 'creditcard': $notes[] = _('I would like to pay via credit card.'); break; @@ -197,7 +197,7 @@ public function generateExtraNote(array $cart): string $notes[] = _('I would like to pay via cash.'); break; } - switch ($cart['deleveryMethod'] ?? '') { + switch (valstring($cart['deleveryMethod'] ?? '')) { case 'pickup': $notes[] = _('I will pick up the goods in your shop.'); break; @@ -255,7 +255,7 @@ public function addToAddressBook(Invoice $invoice, ?string $clientIp): void /** * Update invoice and mange it's state. * - * @param array $updates + * @param array $updates */ public function invoiceBasicUpdate(Invoice $invoice, User $user, InvoiceAction $action, array $updates): void { @@ -265,34 +265,34 @@ public function invoiceBasicUpdate(Invoice $invoice, User $user, InvoiceAction $ if (InvoiceAction::Lock === $action) { $status = InvoiceStatus::Locked; } - $invoice->setTimeStamp(strtotime(strval($updates['date'])) ?: time()); - $invoice->setShipping(floatval($updates['shipping'])); - $invoice->setAmount(floatval($updates['amount'])); - $invoice->setVat(floatval($updates['vat'])); - $invoice->setPreVat(boolval($updates['preVat'])); - $invoice->setIref(strval($updates['iref'])); - $invoice->setEref(strval($updates['eref'])); - $invoice->setName(strval($updates['name'])); - $invoice->setAttn(strval($updates['attn'])); - $invoice->setAddress(strval($updates['address'])); - $invoice->setPostbox(strval($updates['postbox'])); - $invoice->setPostcode(strval($updates['postcode'])); - $invoice->setCity(strval($updates['city'])); - $invoice->setCountry(strval($updates['country'])); - $invoice->setEmail(strval($updates['email'])); - $invoice->setPhone1(strval($updates['phone1'])); - $invoice->setPhone2(strval($updates['phone2'])); - $invoice->setHasShippingAddress(boolval($updates['hasShippingAddress'])); + $invoice->setTimeStamp(strtotime(valstring($updates['date'])) ?: time()); + $invoice->setShipping(valfloat($updates['shipping'])); + $invoice->setAmount(valfloat($updates['amount'])); + $invoice->setVat(valfloat($updates['vat'])); + $invoice->setPreVat(valbool($updates['preVat'])); + $invoice->setIref(valstring($updates['iref'])); + $invoice->setEref(valstring($updates['eref'])); + $invoice->setName(valstring($updates['name'])); + $invoice->setAttn(valstring($updates['attn'])); + $invoice->setAddress(valstring($updates['address'])); + $invoice->setPostbox(valstring($updates['postbox'])); + $invoice->setPostcode(valstring($updates['postcode'])); + $invoice->setCity(valstring($updates['city'])); + $invoice->setCountry(valstring($updates['country'])); + $invoice->setEmail(valstring($updates['email'])); + $invoice->setPhone1(valstring($updates['phone1'])); + $invoice->setPhone2(valstring($updates['phone2'])); + $invoice->setHasShippingAddress(valbool($updates['hasShippingAddress'])); if ($updates['hasShippingAddress']) { - $invoice->setShippingPhone(strval($updates['shippingPhone'])); - $invoice->setShippingName(strval($updates['shippingName'])); - $invoice->setShippingAttn(strval($updates['shippingAttn'])); - $invoice->setShippingAddress(strval($updates['shippingAddress'])); - $invoice->setShippingAddress2(strval($updates['shippingAddress2'])); - $invoice->setShippingPostbox(strval($updates['shippingPostbox'])); - $invoice->setShippingPostcode(strval($updates['shippingPostcode'])); - $invoice->setShippingCity(strval($updates['shippingCity'])); - $invoice->setShippingCountry(strval($updates['shippingCountry'])); + $invoice->setShippingPhone(valstring($updates['shippingPhone'])); + $invoice->setShippingName(valstring($updates['shippingName'])); + $invoice->setShippingAttn(valstring($updates['shippingAttn'])); + $invoice->setShippingAddress(valstring($updates['shippingAddress'])); + $invoice->setShippingAddress2(valstring($updates['shippingAddress2'])); + $invoice->setShippingPostbox(valstring($updates['shippingPostbox'])); + $invoice->setShippingPostcode(valstring($updates['shippingPostcode'])); + $invoice->setShippingCity(valstring($updates['shippingCity'])); + $invoice->setShippingCountry(valstring($updates['shippingCountry'])); } $invoice->setItemData(json_encode($updates['lines'], JSON_THROW_ON_ERROR) ?: '[]'); } @@ -300,7 +300,7 @@ public function invoiceBasicUpdate(Invoice $invoice, User $user, InvoiceAction $ if (isset($updates['note']) && is_string($updates['note'])) { $note = $updates['note']; if (InvoiceStatus::New !== $invoice->getStatus()) { - $note = trim($invoice->getNote() . "\n" . $note); + $note = mb_trim($invoice->getNote() . "\n" . $note); } $invoice->setNote($note); } diff --git a/application/inc/Services/OrmService.php b/application/inc/Services/OrmService.php index 3f44cb9e..198d8499 100644 --- a/application/inc/Services/OrmService.php +++ b/application/inc/Services/OrmService.php @@ -53,7 +53,7 @@ public function getOneByQuery(string $class, string $query): ?AbstractEntity if (null === $query) { throw new Exception('preg_replace failed'); } - $query = trim($query); + $query = mb_trim($query); if (!isset($this->oneBySql[$class]) || !array_key_exists($query, $this->oneBySql[$class])) { $this->oneBySql[$class][$query] = null; @@ -89,7 +89,7 @@ public function getByQuery(string $class, string $query): array if (null === $query) { throw new Exception('preg_replace failed'); } - $query = trim($query); + $query = mb_trim($query); if (!isset($this->bySql[$class][$query])) { $this->bySql[$class][$query] = []; $db = app(DbService::class); diff --git a/application/inc/Services/UploadHandler.php b/application/inc/Services/UploadHandler.php index 3a820e30..54e5cda7 100644 --- a/application/inc/Services/UploadHandler.php +++ b/application/inc/Services/UploadHandler.php @@ -99,8 +99,11 @@ private function processFile(string $destinationType, string $description): File } elseif ($this->isVideoFile()) { $getID3 = new getID3(); $fileInfo = $getID3->analyze($filePath); - $width = $fileInfo['video']['resolution_x']; - $height = $fileInfo['video']['resolution_y']; + $format = $fileInfo['video'] ?? []; + $width = is_array($format) ? $format['resolution_x'] ?? 0 : 0; + $width = is_int($width) ? $width : 0; + $height = is_array($format) ? $format['resolution_y'] ?? 0 : 0; + $height = is_int($height) ? $height : 0; } return $this->insertFile($description, $width, $height); diff --git a/application/inc/TwigExtensions.php b/application/inc/TwigExtensions.php index 155f67c0..8f2bc6cb 100644 --- a/application/inc/TwigExtensions.php +++ b/application/inc/TwigExtensions.php @@ -17,8 +17,9 @@ public function getFilters(): array new TwigFilter('money', function (float $amount, bool $thousan = true, int $decimals = 2): string { $conv = localeconv(); $decimal_point = $conv['mon_decimal_point']; + $decimal_point = is_string($decimal_point) ? $decimal_point : ''; $thousands_sep = ''; - if ($thousan) { + if ($thousan && is_string($conv['mon_thousands_sep'])) { $thousands_sep = $conv['mon_thousands_sep']; } diff --git a/application/inc/helpers.php b/application/inc/helpers.php index 928083f4..09b983ad 100644 --- a/application/inc/helpers.php +++ b/application/inc/helpers.php @@ -55,11 +55,11 @@ function first(array $array): mixed function intOrNull(mixed $value): ?int { - if ($value === null) { + if ($value === null || !is_scalar($value)) { return null; } - return intval($value); + return valint($value); } /** @@ -85,11 +85,13 @@ function cleanFileName(string $name): string /** * Natsort an array. * - * @param array> $rows Array to sort - * @param int|string $orderBy Key to sort by - * @param string $direction desc for revers sorting + * @template T of array + * + * @param array $rows Array to sort + * @param int|string $orderBy Key to sort by + * @param string $direction desc for revers sorting * - * @return array> + * @return list */ function arrayNatsort(array $rows, int|string $orderBy, string $direction = 'asc'): array { @@ -125,7 +127,7 @@ function stringLimit(string $string, int $length = 50, string $ellipsis = '…') $length -= mb_strlen($ellipsis); $string = mb_substr($string, 0, $length); - $string = trim($string); + $string = mb_trim($string); if (mb_strlen($string) >= $length) { $string = preg_replace('/\s+\S+$/u', '', $string); if (null === $string) { @@ -188,7 +190,7 @@ function purifyHTML(string $html): string throw new Exception('preg_replace failed'); } - return trim($html); + return mb_trim($html); } /** @@ -218,3 +220,52 @@ function htmlUrlDecode(string $html): string // Decode all html entities return html_entity_decode($html, ENT_QUOTES, 'UTF-8'); } + +function valbool(mixed $value): bool +{ + if ($value instanceof Stringable || is_scalar($value)) { + filter_var((string)$value, FILTER_VALIDATE_BOOLEAN); + } + + return (bool)$value; +} + +function valstring(mixed $value): string +{ + if ($value === null) { + return ''; + } + if (!$value instanceof Stringable && !is_scalar($value)) { + throw new Exception('Not string: ' . gettype($value)); + } + + return (string)$value; +} + +function valfloat(mixed $value): float +{ + if (is_float($value)) { + return $value; + } + + $value = valstring($value); + if (!is_numeric($value)) { + throw new Exception('Not numeric: ' . $value); + } + + return (float)$value; +} + +function valint(mixed $value): int +{ + if (is_int($value)) { + return $value; + } + + $value = valstring($value); + if (!ctype_digit($value)) { + throw new Exception('Not int: ' . $value); + } + + return (int)$value; +} diff --git a/tests/TestResponse.php b/tests/TestResponse.php index ed77d777..bcf86aba 100644 --- a/tests/TestResponse.php +++ b/tests/TestResponse.php @@ -85,7 +85,7 @@ public function assertNotSee(string $value): self /** * Assert that the response is a superset of the given JSON. * - * @param array $data + * @param array $data * * @return $this */ @@ -99,8 +99,8 @@ public function assertJson(array $data, bool $strict = false): self /** * Assert that the response has a given JSON structure. * - * @param null|array $structure - * @param null|array> $responseData + * @param null|array $structure + * @param null|array $responseData * * @return $this */ diff --git a/tests/Unit/Models/EpaymentTest.php b/tests/Unit/Models/EpaymentTest.php index c07566af..5002c350 100644 --- a/tests/Unit/Models/EpaymentTest.php +++ b/tests/Unit/Models/EpaymentTest.php @@ -36,7 +36,7 @@ protected function tearDown(): void */ private function getPayment(string $status = 'PAYMENT_NEW', int $amount = 100, int $captured = 0): Epayment { - $data = new StdClass(); + $data = new stdClass(); $data->transactionid = 1; $data->status = $status; $data->authamount = $amount; @@ -45,15 +45,6 @@ private function getPayment(string $status = 'PAYMENT_NEW', int $amount = 100, i return new Epayment($this->epaymentService, $data); } - /** - * @covers \App\Models\Epayment::__construct - */ - public function testCanInstanciate(): void - { - $epayment = $this->getPayment(); - static::assertInstanceOf(Epayment::class, $epayment); - } - /** * @covers \App\Models\Epayment::isAuthorized */ diff --git a/tests/Unit/Services/EpaymentServiceTest.php b/tests/Unit/Services/EpaymentServiceTest.php deleted file mode 100644 index 7613b2d3..00000000 --- a/tests/Unit/Services/EpaymentServiceTest.php +++ /dev/null @@ -1,27 +0,0 @@ -epaymentService = new EpaymentService('', ''); - } - - /** - * @covers \App\Services\EpaymentService::__construct - */ - public function testCanInstanciate(): void - { - static::assertInstanceOf(EpaymentService::class, $this->epaymentService); - } -}