diff --git a/app/composer.json b/app/composer.json index 879b2b491..af45c91e2 100644 --- a/app/composer.json +++ b/app/composer.json @@ -76,6 +76,10 @@ }, "prefer-stable": true, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "cakephp/plugin-installer": true + } } } diff --git a/app/composer.lock b/app/composer.lock index 13ddabd4b..b9b0a2c32 100644 --- a/app/composer.lock +++ b/app/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "cakephp/cakephp", - "version": "4.3.8", + "version": "4.4.8", "source": { "type": "git", "url": "https://github.com/cakephp/cakephp.git", - "reference": "34aae68e91e6834aa6711c3e435a3f220bf56c0b" + "reference": "ad188775dde89ad758dad9923ff558900914d59c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/cakephp/zipball/34aae68e91e6834aa6711c3e435a3f220bf56c0b", - "reference": "34aae68e91e6834aa6711c3e435a3f220bf56c0b", + "url": "https://api.github.com/repos/cakephp/cakephp/zipball/ad188775dde89ad758dad9923ff558900914d59c", + "reference": "ad188775dde89ad758dad9923ff558900914d59c", "shasum": "" }, "require": { @@ -27,9 +27,9 @@ "ext-json": "*", "ext-mbstring": "*", "laminas/laminas-diactoros": "^2.2.2", - "laminas/laminas-httphandlerrunner": "^1.1", + "laminas/laminas-httphandlerrunner": "^1.1 || ^2.0", "league/container": "^4.2.0", - "php": ">=7.2.0", + "php": ">=7.4.0", "psr/container": "^1.1 || ^2.0", "psr/http-client": "^1.0", "psr/http-server-handler": "^1.0", @@ -108,20 +108,20 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/cakephp" }, - "time": "2022-04-23T01:23:23+00:00" + "time": "2022-12-02T02:29:42+00:00" }, { "name": "cakephp/chronos", - "version": "2.3.0", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/cakephp/chronos.git", - "reference": "3ecd6e7ae191c676570cd1bed51fd561de4606dd" + "reference": "a21b7b633f483c4cf525d200219d200f551ee38b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/chronos/zipball/3ecd6e7ae191c676570cd1bed51fd561de4606dd", - "reference": "3ecd6e7ae191c676570cd1bed51fd561de4606dd", + "url": "https://api.github.com/repos/cakephp/chronos/zipball/a21b7b633f483c4cf525d200219d200f551ee38b", + "reference": "a21b7b633f483c4cf525d200219d200f551ee38b", "shasum": "" }, "require": { @@ -152,41 +152,40 @@ }, { "name": "The CakePHP Team", - "homepage": "http://cakephp.org" + "homepage": "https://cakephp.org" } ], "description": "A simple API extension for DateTime.", - "homepage": "http://cakephp.org", + "homepage": "https://cakephp.org", "keywords": [ "date", "datetime", "time" ], "support": { - "irc": "irc://irc.freenode.org/cakephp", "issues": "https://github.com/cakephp/chronos/issues", "source": "https://github.com/cakephp/chronos" }, - "time": "2021-10-17T02:44:05+00:00" + "time": "2022-11-08T02:17:04+00:00" }, { "name": "cakephp/migrations", - "version": "3.5.1", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/cakephp/migrations.git", - "reference": "6b03a44bef94b99a24ab7d4c44cb292bb6f275c2" + "reference": "e1a0a768d6ff572ef5a9aa9024243882f29c96c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/migrations/zipball/6b03a44bef94b99a24ab7d4c44cb292bb6f275c2", - "reference": "6b03a44bef94b99a24ab7d4c44cb292bb6f275c2", + "url": "https://api.github.com/repos/cakephp/migrations/zipball/e1a0a768d6ff572ef5a9aa9024243882f29c96c9", + "reference": "e1a0a768d6ff572ef5a9aa9024243882f29c96c9", "shasum": "" }, "require": { "cakephp/cache": "^4.3.0", "cakephp/orm": "^4.3.0", - "php": ">=7.2.0", + "php": ">=7.4.0", "robmorgan/phinx": "^0.12" }, "require-dev": { @@ -227,7 +226,7 @@ "issues": "https://github.com/cakephp/migrations/issues", "source": "https://github.com/cakephp/migrations" }, - "time": "2022-03-14T14:26:38+00:00" + "time": "2022-10-14T05:38:58+00:00" }, { "name": "cakephp/plugin-installer", @@ -329,16 +328,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.3.1", + "version": "1.3.4", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "4c679186f2aca4ab6a0f1b0b9cf9252decb44d0b" + "reference": "69098eca243998b53eed7a48d82dedd28b447cd5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/4c679186f2aca4ab6a0f1b0b9cf9252decb44d0b", - "reference": "4c679186f2aca4ab6a0f1b0b9cf9252decb44d0b", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/69098eca243998b53eed7a48d82dedd28b447cd5", + "reference": "69098eca243998b53eed7a48d82dedd28b447cd5", "shasum": "" }, "require": { @@ -385,7 +384,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.3.1" + "source": "https://github.com/composer/ca-bundle/tree/1.3.4" }, "funding": [ { @@ -401,20 +400,20 @@ "type": "tidelift" } ], - "time": "2021-10-28T20:44:15+00:00" + "time": "2022-10-12T12:08:29+00:00" }, { "name": "doctrine/cache", - "version": "2.1.1", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce" + "reference": "1ca8f21980e770095a31456042471a57bc4c68fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/331b4d5dbaeab3827976273e9356b3b453c300ce", - "reference": "331b4d5dbaeab3827976273e9356b3b453c300ce", + "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb", + "reference": "1ca8f21980e770095a31456042471a57bc4c68fb", "shasum": "" }, "require": { @@ -424,18 +423,12 @@ "doctrine/common": ">2.2,<2.4" }, "require-dev": { - "alcaeus/mongo-php-adapter": "^1.1", "cache/integration-tests": "dev-master", - "doctrine/coding-standard": "^8.0", - "mongodb/mongodb": "^1.1", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", - "predis/predis": "~1.0", + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "psr/cache": "^1.0 || ^2.0 || ^3.0", - "symfony/cache": "^4.4 || ^5.2 || ^6.0@dev", - "symfony/var-exporter": "^4.4 || ^5.2 || ^6.0@dev" - }, - "suggest": { - "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" + "symfony/cache": "^4.4 || ^5.4 || ^6", + "symfony/var-exporter": "^4.4 || ^5.4 || ^6" }, "type": "library", "autoload": { @@ -484,7 +477,7 @@ ], "support": { "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/2.1.1" + "source": "https://github.com/doctrine/cache/tree/2.2.0" }, "funding": [ { @@ -500,7 +493,7 @@ "type": "tidelift" } ], - "time": "2021-07-17T14:49:29+00:00" + "time": "2022-05-20T20:07:39+00:00" }, { "name": "doctrine/dbal", @@ -615,25 +608,25 @@ }, { "name": "doctrine/deprecations", - "version": "v0.5.3", + "version": "v1.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "9504165960a1f83cc1480e2be1dd0a0478561314" + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/9504165960a1f83cc1480e2be1dd0a0478561314", - "reference": "9504165960a1f83cc1480e2be1dd0a0478561314", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", "shasum": "" }, "require": { "php": "^7.1|^8.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0|^7.0|^8.0", - "phpunit/phpunit": "^7.0|^8.0|^9.0", - "psr/log": "^1.0" + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" @@ -652,43 +645,41 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v0.5.3" + "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" }, - "time": "2021-03-21T12:59:47+00:00" + "time": "2022-05-02T15:47:09+00:00" }, { "name": "doctrine/event-manager", - "version": "1.1.1", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f" + "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/41370af6a30faa9dc0368c4a6814d596e81aba7f", - "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/95aa4cb529f1e96576f3fda9f5705ada4056a520", + "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520", "shasum": "" }, "require": { + "doctrine/deprecations": "^0.5.3 || ^1", "php": "^7.1 || ^8.0" }, "conflict": { - "doctrine/common": "<2.9@dev" + "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpunit/phpunit": "^7.0" + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "~1.4.10 || ^1.8.8", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.24" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { "psr-4": { - "Doctrine\\Common\\": "lib/Doctrine/Common" + "Doctrine\\Common\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -732,7 +723,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/1.1.x" + "source": "https://github.com/doctrine/event-manager/tree/1.2.0" }, "funding": [ { @@ -748,29 +739,28 @@ "type": "tidelift" } ], - "time": "2020-05-29T18:28:51+00:00" + "time": "2022-10-12T20:51:15+00:00" }, { "name": "laminas/laminas-diactoros", - "version": "2.9.2", + "version": "2.22.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-diactoros.git", - "reference": "07475df6b4bf6277ae8b9cbbc94d0ac6fee5e726" + "reference": "df8c7f9e11d854269f4aa7c06ffa38caa42e4405" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/07475df6b4bf6277ae8b9cbbc94d0ac6fee5e726", - "reference": "07475df6b4bf6277ae8b9cbbc94d0ac6fee5e726", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/df8c7f9e11d854269f4aa7c06ffa38caa42e4405", + "reference": "df8c7f9e11d854269f4aa7c06ffa38caa42e4405", "shasum": "" }, "require": { - "php": "^7.3 || ~8.0.0 || ~8.1.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0", "psr/http-factory": "^1.0", "psr/http-message": "^1.0" }, "conflict": { - "phpspec/prophecy": "<1.9.0", "zendframework/zend-diactoros": "*" }, "provide": { @@ -782,13 +772,12 @@ "ext-dom": "*", "ext-gd": "*", "ext-libxml": "*", - "http-interop/http-factory-tests": "^0.8.0", - "laminas/laminas-coding-standard": "~1.0.0", - "php-http/psr7-integration-tests": "^1.1", - "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.1", - "psalm/plugin-phpunit": "^0.14.0", - "vimeo/psalm": "^4.3" + "http-interop/http-factory-tests": "^0.9.0", + "laminas/laminas-coding-standard": "^2.4.0", + "php-http/psr7-integration-tests": "^1.1.1", + "phpunit/phpunit": "^9.5.26", + "psalm/plugin-phpunit": "^0.18.0", + "vimeo/psalm": "^4.29.0" }, "type": "library", "extra": { @@ -847,38 +836,34 @@ "type": "community_bridge" } ], - "time": "2022-04-06T17:37:15+00:00" + "time": "2022-11-22T05:54:54+00:00" }, { "name": "laminas/laminas-httphandlerrunner", - "version": "1.5.0", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-httphandlerrunner.git", - "reference": "5f94e55d93f756e8ad07b9049aeb3d6d84582d0e" + "reference": "d15af53895fd581b5a448a09fd9a4baebc4ae6e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/5f94e55d93f756e8ad07b9049aeb3d6d84582d0e", - "reference": "5f94e55d93f756e8ad07b9049aeb3d6d84582d0e", + "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/d15af53895fd581b5a448a09fd9a4baebc4ae6e5", + "reference": "d15af53895fd581b5a448a09fd9a4baebc4ae6e5", "shasum": "" }, "require": { - "laminas/laminas-zendframework-bridge": "^1.0", - "php": "^7.3 || ~8.0.0 || ~8.1.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0", "psr/http-message": "^1.0", "psr/http-message-implementation": "^1.0", "psr/http-server-handler": "^1.0" }, - "replace": { - "zendframework/zend-httphandlerrunner": "^1.1.0" - }, "require-dev": { - "laminas/laminas-coding-standard": "~1.0.0", - "laminas/laminas-diactoros": "^2.8.0", - "phpunit/phpunit": "^9.5.9", - "psalm/plugin-phpunit": "^0.16.1", - "vimeo/psalm": "^4.10.0" + "laminas/laminas-coding-standard": "~2.4.0", + "laminas/laminas-diactoros": "^2.18", + "phpunit/phpunit": "^9.5.25", + "psalm/plugin-phpunit": "^0.17.0", + "vimeo/psalm": "^4.28" }, "type": "library", "extra": { @@ -918,69 +903,7 @@ "type": "community_bridge" } ], - "time": "2021-09-22T09:17:54+00:00" - }, - { - "name": "laminas/laminas-zendframework-bridge", - "version": "1.5.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-zendframework-bridge.git", - "reference": "7f049390b756d34ba5940a8fb47634fbb51f79ab" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/7f049390b756d34ba5940a8fb47634fbb51f79ab", - "reference": "7f049390b756d34ba5940a8fb47634fbb51f79ab", - "shasum": "" - }, - "require": { - "php": ">=7.4, <8.2" - }, - "require-dev": { - "phpunit/phpunit": "^9.5.14", - "psalm/plugin-phpunit": "^0.15.2", - "squizlabs/php_codesniffer": "^3.6.2", - "vimeo/psalm": "^4.21.0" - }, - "type": "library", - "extra": { - "laminas": { - "module": "Laminas\\ZendFrameworkBridge" - } - }, - "autoload": { - "files": [ - "src/autoload.php" - ], - "psr-4": { - "Laminas\\ZendFrameworkBridge\\": "src//" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Alias legacy ZF class names to Laminas Project equivalents.", - "keywords": [ - "ZendFramework", - "autoloading", - "laminas", - "zf" - ], - "support": { - "forum": "https://discourse.laminas.dev/", - "issues": "https://github.com/laminas/laminas-zendframework-bridge/issues", - "rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom", - "source": "https://github.com/laminas/laminas-zendframework-bridge" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2022-02-22T22:17:01+00:00" + "time": "2022-10-25T13:41:39+00:00" }, { "name": "league/container", @@ -1066,16 +989,16 @@ }, { "name": "mobiledetect/mobiledetectlib", - "version": "2.8.39", + "version": "2.8.41", "source": { "type": "git", "url": "https://github.com/serbanghita/Mobile-Detect.git", - "reference": "0fd6753003fc870f6e229bae869cc1337c99bc45" + "reference": "fc9cccd4d3706d5a7537b562b59cc18f9e4c0cb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/0fd6753003fc870f6e229bae869cc1337c99bc45", - "reference": "0fd6753003fc870f6e229bae869cc1337c99bc45", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/fc9cccd4d3706d5a7537b562b59cc18f9e4c0cb1", + "reference": "fc9cccd4d3706d5a7537b562b59cc18f9e4c0cb1", "shasum": "" }, "require": { @@ -1116,26 +1039,26 @@ ], "support": { "issues": "https://github.com/serbanghita/Mobile-Detect/issues", - "source": "https://github.com/serbanghita/Mobile-Detect/tree/2.8.39" + "source": "https://github.com/serbanghita/Mobile-Detect/tree/2.8.41" }, - "time": "2022-02-17T19:24:25+00:00" + "time": "2022-11-08T18:31:26+00:00" }, { "name": "psr/cache", - "version": "1.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/cache.git", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { @@ -1155,7 +1078,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for caching libraries", @@ -1165,9 +1088,9 @@ "psr-6" ], "support": { - "source": "https://github.com/php-fig/cache/tree/master" + "source": "https://github.com/php-fig/cache/tree/3.0.0" }, - "time": "2016-08-06T20:24:11+00:00" + "time": "2021-02-03T23:26:27+00:00" }, { "name": "psr/container", @@ -1498,30 +1421,30 @@ }, { "name": "psr/log", - "version": "1.1.4", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "url": "https://api.github.com/repos/php-fig/log/zipball/ef29f6d262798707a9edd554e2b82517ef3a9376", + "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1542,31 +1465,31 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" + "source": "https://github.com/php-fig/log/tree/2.0.0" }, - "time": "2021-05-03T11:20:27+00:00" + "time": "2021-07-14T16:41:46+00:00" }, { "name": "psr/simple-cache", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/simple-cache.git", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + "reference": "8707bf3cea6f710bf6ef05491234e3ab06f6432a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/8707bf3cea6f710bf6ef05491234e3ab06f6432a", + "reference": "8707bf3cea6f710bf6ef05491234e3ab06f6432a", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -1581,7 +1504,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interfaces for simple caching", @@ -1593,22 +1516,22 @@ "simple-cache" ], "support": { - "source": "https://github.com/php-fig/simple-cache/tree/master" + "source": "https://github.com/php-fig/simple-cache/tree/2.0.0" }, - "time": "2017-10-23T01:57:42+00:00" + "time": "2021-10-29T13:22:09+00:00" }, { "name": "robmorgan/phinx", - "version": "0.12.10", + "version": "0.12.13", "source": { "type": "git", "url": "https://github.com/cakephp/phinx.git", - "reference": "ad056cff354fc67fedf9bf96c441c2b428afad0c" + "reference": "6eb0f295e140ed2804d93396755f0ce9ada4ec07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/phinx/zipball/ad056cff354fc67fedf9bf96c441c2b428afad0c", - "reference": "ad056cff354fc67fedf9bf96c441c2b428afad0c", + "url": "https://api.github.com/repos/cakephp/phinx/zipball/6eb0f295e140ed2804d93396755f0ce9ada4ec07", + "reference": "6eb0f295e140ed2804d93396755f0ce9ada4ec07", "shasum": "" }, "require": { @@ -1679,41 +1602,40 @@ ], "support": { "issues": "https://github.com/cakephp/phinx/issues", - "source": "https://github.com/cakephp/phinx/tree/0.12.10" + "source": "https://github.com/cakephp/phinx/tree/0.12.13" }, - "time": "2022-01-21T19:53:14+00:00" + "time": "2022-10-03T04:57:40+00:00" }, { "name": "symfony/config", - "version": "v5.4.7", + "version": "v6.0.11", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "05624c386afa1b4ccc1357463d830fade8d9d404" + "reference": "956d4ec5df274dda91a4cedfccc2bfd063f6f649" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/05624c386afa1b4ccc1357463d830fade8d9d404", - "reference": "05624c386afa1b4ccc1357463d830fade8d9d404", + "url": "https://api.github.com/repos/symfony/config/zipball/956d4ec5df274dda91a4cedfccc2bfd063f6f649", + "reference": "956d4ec5df274dda91a4cedfccc2bfd063f6f649", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "symfony/deprecation-contracts": "^2.1|^3", - "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^5.4|^6.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.16", "symfony/polyfill-php81": "^1.22" }, "conflict": { "symfony/finder": "<4.4" }, "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/messenger": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/messenger": "^5.4|^6.0", "symfony/service-contracts": "^1.1|^2|^3", - "symfony/yaml": "^4.4|^5.0|^6.0" + "symfony/yaml": "^5.4|^6.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -1744,7 +1666,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.7" + "source": "https://github.com/symfony/config/tree/v6.0.11" }, "funding": [ { @@ -1760,50 +1682,46 @@ "type": "tidelift" } ], - "time": "2022-03-21T13:42:03+00:00" + "time": "2022-06-27T17:10:44+00:00" }, { "name": "symfony/console", - "version": "v5.4.7", + "version": "v6.0.16", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "900275254f0a1a2afff1ab0e11abd5587a10e1d6" + "reference": "be294423f337dda97c810733138c0caec1bb0575" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/900275254f0a1a2afff1ab0e11abd5587a10e1d6", - "reference": "900275254f0a1a2afff1ab0e11abd5587a10e1d6", + "url": "https://api.github.com/repos/symfony/console/zipball/be294423f337dda97c810733138c0caec1bb0575", + "reference": "be294423f337dda97c810733138c0caec1bb0575", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.0.2", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1|^2|^3", - "symfony/string": "^5.1|^6.0" + "symfony/string": "^5.4|^6.0" }, "conflict": { - "psr/log": ">=3", - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" }, "provide": { - "psr/log-implementation": "1.0|2.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { - "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/lock": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0" + "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", @@ -1843,7 +1761,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.7" + "source": "https://github.com/symfony/console/tree/v6.0.16" }, "funding": [ { @@ -1859,29 +1777,29 @@ "type": "tidelift" } ], - "time": "2022-03-31T17:09:19+00:00" + "time": "2022-11-25T18:58:46+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.1", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", + "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.0.2" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", @@ -1910,7 +1828,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.2" }, "funding": [ { @@ -1926,27 +1844,26 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-01-02T09:55:41+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.7", + "version": "v6.0.13", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f" + "reference": "3adca49133bd055ebe6011ed1e012be3c908af79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3a4442138d80c9f7b600fb297534ac718b61d37f", - "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3adca49133bd055ebe6011ed1e012be3c908af79", + "reference": "3adca49133bd055ebe6011ed1e012be3c908af79", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", - "symfony/polyfill-php80": "^1.16" + "symfony/polyfill-mbstring": "~1.8" }, "type": "library", "autoload": { @@ -1974,7 +1891,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.7" + "source": "https://github.com/symfony/filesystem/tree/v6.0.13" }, "funding": [ { @@ -1990,20 +1907,20 @@ "type": "tidelift" } ], - "time": "2022-04-01T12:33:59+00:00" + "time": "2022-09-21T20:25:27+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.25.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "shasum": "" }, "require": { @@ -2018,7 +1935,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2056,7 +1973,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" }, "funding": [ { @@ -2072,20 +1989,20 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.25.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + "reference": "511a08c03c1960e08a883f4cffcacd219b758354" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", + "reference": "511a08c03c1960e08a883f4cffcacd219b758354", "shasum": "" }, "require": { @@ -2097,7 +2014,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2137,7 +2054,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" }, "funding": [ { @@ -2153,20 +2070,20 @@ "type": "tidelift" } ], - "time": "2021-11-23T21:10:46+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.25.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", "shasum": "" }, "require": { @@ -2178,7 +2095,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2221,7 +2138,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" }, "funding": [ { @@ -2237,20 +2154,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.25.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "shasum": "" }, "require": { @@ -2265,7 +2182,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2304,169 +2221,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-11-30T18:21:41+00:00" - }, - { - "name": "symfony/polyfill-php73", - "version": "v1.25.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "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 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-06-05T21:20:04+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.25.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" }, "funding": [ { @@ -2482,20 +2237,20 @@ "type": "tidelift" } ], - "time": "2022-03-04T08:16:47+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.25.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f" + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", - "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", "shasum": "" }, "require": { @@ -2504,7 +2259,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2545,7 +2300,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" }, "funding": [ { @@ -2561,24 +2316,24 @@ "type": "tidelift" } ], - "time": "2021-09-13T13:58:11+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.1.1", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239" + "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/925e713fe8fcacf6bc05e936edd8dd5441a21239", - "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d78d39c1599bd1188b8e26bb341da52c3c6d8a66", + "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.0.2", "psr/container": "^2.0" }, "conflict": { @@ -2590,7 +2345,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", @@ -2600,10 +2355,7 @@ "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2630,7 +2382,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.1.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.0.2" }, "funding": [ { @@ -2646,38 +2398,37 @@ "type": "tidelift" } ], - "time": "2022-05-30T19:18:58+00:00" + "time": "2022-05-30T19:17:58+00:00" }, { "name": "symfony/string", - "version": "v5.4.3", + "version": "v6.0.15", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10" + "reference": "51ac0fa0ccf132a00519b87c97e8f775fa14e771" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/92043b7d8383e48104e411bc9434b260dbeb5a10", - "reference": "92043b7d8383e48104e411bc9434b260dbeb5a10", + "url": "https://api.github.com/repos/symfony/string/zipball/51ac0fa0ccf132a00519b87c97e8f775fa14e771", + "reference": "51ac0fa0ccf132a00519b87c97e8f775fa14e771", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": ">=3.0" + "symfony/translation-contracts": "<2.0" }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0|^6.0" + "symfony/error-handler": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/translation-contracts": "^2.0|^3.0", + "symfony/var-exporter": "^5.4|^6.0" }, "type": "library", "autoload": { @@ -2716,7 +2467,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.3" + "source": "https://github.com/symfony/string/tree/v6.0.15" }, "funding": [ { @@ -2732,20 +2483,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-10-10T09:34:08+00:00" }, { "name": "twbs/bootstrap", - "version": "v5.1.3", + "version": "v5.2.3", "source": { "type": "git", "url": "https://github.com/twbs/bootstrap.git", - "reference": "1a6fdfae6be09b09eaced8f0e442ca6f7680a61e" + "reference": "cb021439c683d9805e2864c58095b92d405e9b11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twbs/bootstrap/zipball/1a6fdfae6be09b09eaced8f0e442ca6f7680a61e", - "reference": "1a6fdfae6be09b09eaced8f0e442ca6f7680a61e", + "url": "https://api.github.com/repos/twbs/bootstrap/zipball/cb021439c683d9805e2864c58095b92d405e9b11", + "reference": "cb021439c683d9805e2864c58095b92d405e9b11", "shasum": "" }, "replace": { @@ -2780,24 +2531,24 @@ ], "support": { "issues": "https://github.com/twbs/bootstrap/issues", - "source": "https://github.com/twbs/bootstrap/tree/v5.1.3" + "source": "https://github.com/twbs/bootstrap/tree/v5.2.3" }, - "time": "2021-10-09T06:43:19+00:00" + "time": "2022-11-21T18:19:01+00:00" } ], "packages-dev": [ { "name": "brick/varexporter", - "version": "0.3.5", + "version": "0.3.7", "source": { "type": "git", "url": "https://github.com/brick/varexporter.git", - "reference": "05241f28dfcba2b51b11e2d750e296316ebbe518" + "reference": "3e263cd718d242594c52963760fee2059fd5833c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/varexporter/zipball/05241f28dfcba2b51b11e2d750e296316ebbe518", - "reference": "05241f28dfcba2b51b11e2d750e296316ebbe518", + "url": "https://api.github.com/repos/brick/varexporter/zipball/3e263cd718d242594c52963760fee2059fd5833c", + "reference": "3e263cd718d242594c52963760fee2059fd5833c", "shasum": "" }, "require": { @@ -2807,7 +2558,7 @@ "require-dev": { "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^8.5 || ^9.0", - "vimeo/psalm": "4.4.1" + "vimeo/psalm": "4.23.0" }, "type": "library", "autoload": { @@ -2825,28 +2576,35 @@ ], "support": { "issues": "https://github.com/brick/varexporter/issues", - "source": "https://github.com/brick/varexporter/tree/0.3.5" + "source": "https://github.com/brick/varexporter/tree/0.3.7" }, - "time": "2021-02-10T13:53:07+00:00" + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + } + ], + "time": "2022-06-29T23:37:57+00:00" }, { "name": "cakephp/bake", - "version": "2.7.0", + "version": "2.8.2", "source": { "type": "git", "url": "https://github.com/cakephp/bake.git", - "reference": "3933caa0941b2f75f3e53c5456efdbf588917584" + "reference": "ef021497ab517c33ecd97d2184200d8990ffc0ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/bake/zipball/3933caa0941b2f75f3e53c5456efdbf588917584", - "reference": "3933caa0941b2f75f3e53c5456efdbf588917584", + "url": "https://api.github.com/repos/cakephp/bake/zipball/ef021497ab517c33ecd97d2184200d8990ffc0ab", + "reference": "ef021497ab517c33ecd97d2184200d8990ffc0ab", "shasum": "" }, "require": { "brick/varexporter": "^0.3.5", "cakephp/cakephp": "^4.3.0", "cakephp/twig-view": "^1.0.2", + "nikic/php-parser": "^4.13.2", "php": ">=7.2" }, "require-dev": { @@ -2883,25 +2641,25 @@ "issues": "https://github.com/cakephp/bake/issues", "source": "https://github.com/cakephp/bake" }, - "time": "2022-04-14T08:50:07+00:00" + "time": "2022-10-05T18:45:20+00:00" }, { "name": "cakephp/cakephp-codesniffer", - "version": "4.5.1", + "version": "4.6.0", "source": { "type": "git", "url": "https://github.com/cakephp/cakephp-codesniffer.git", - "reference": "6b17905db024b8d7e64a15296688545c61ab6694" + "reference": "5a64e6e6434128f6a1549318de86c564737d5cda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/cakephp-codesniffer/zipball/6b17905db024b8d7e64a15296688545c61ab6694", - "reference": "6b17905db024b8d7e64a15296688545c61ab6694", + "url": "https://api.github.com/repos/cakephp/cakephp-codesniffer/zipball/5a64e6e6434128f6a1549318de86c564737d5cda", + "reference": "5a64e6e6434128f6a1549318de86c564737d5cda", "shasum": "" }, "require": { "php": ">=7.2.0", - "slevomat/coding-standard": "^6.3.6 || ^7.0", + "slevomat/coding-standard": "^6.3.6 || ^7.0 || ^8.0", "squizlabs/php_codesniffer": "^3.6" }, "require-dev": { @@ -2935,28 +2693,28 @@ "issues": "https://github.com/cakephp/cakephp-codesniffer/issues", "source": "https://github.com/cakephp/cakephp-codesniffer" }, - "time": "2021-07-11T04:47:47+00:00" + "time": "2022-07-04T03:29:58+00:00" }, { "name": "cakephp/debug_kit", - "version": "4.7.1", + "version": "4.9.2", "source": { "type": "git", "url": "https://github.com/cakephp/debug_kit.git", - "reference": "ce564bacca4ebf471c34a886741672b54328b382" + "reference": "c6590fca606783bce5b0564a2997cd76042cf652" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/debug_kit/zipball/ce564bacca4ebf471c34a886741672b54328b382", - "reference": "ce564bacca4ebf471c34a886741672b54328b382", + "url": "https://api.github.com/repos/cakephp/debug_kit/zipball/c6590fca606783bce5b0564a2997cd76042cf652", + "reference": "c6590fca606783bce5b0564a2997cd76042cf652", "shasum": "" }, "require": { - "cakephp/cakephp": "^4.3.0", + "cakephp/cakephp": "^4.4.0", "cakephp/chronos": "^2.0", "composer/composer": "^1.3 | ^2.0", "jdorn/sql-formatter": "^1.2", - "php": ">=7.2" + "php": ">=7.4" }, "require-dev": { "cakephp/authorization": "^2.0", @@ -3001,7 +2759,7 @@ "issues": "https://github.com/cakephp/debug_kit/issues", "source": "https://github.com/cakephp/debug_kit" }, - "time": "2022-01-20T02:44:41+00:00" + "time": "2022-11-26T08:47:15+00:00" }, { "name": "cakephp/repl", @@ -3124,34 +2882,109 @@ "time": "2021-09-17T14:07:52+00:00" }, { - "name": "composer/composer", - "version": "2.3.5", + "name": "composer/class-map-generator", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/composer/composer.git", - "reference": "50c47b1f907cfcdb8f072b88164d22b527557ae1" + "url": "https://github.com/composer/class-map-generator.git", + "reference": "1e1cb2b791facb2dfe32932a7718cf2571187513" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/50c47b1f907cfcdb8f072b88164d22b527557ae1", - "reference": "50c47b1f907cfcdb8f072b88164d22b527557ae1", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/1e1cb2b791facb2dfe32932a7718cf2571187513", + "reference": "1e1cb2b791facb2dfe32932a7718cf2571187513", "shasum": "" }, "require": { - "composer/ca-bundle": "^1.0", - "composer/metadata-minifier": "^1.0", "composer/pcre": "^2 || ^3", - "composer/semver": "^3.0", - "composer/spdx-licenses": "^1.2", - "composer/xdebug-handler": "^2.0.2 || ^3.0.3", - "justinrainbow/json-schema": "^5.2.11", - "php": "^7.2.5 || ^8.0", - "psr/log": "^1.0 || ^2.0 || ^3.0", - "react/promise": "^2.8", - "seld/jsonlint": "^1.4", - "seld/phar-utils": "^1.2", - "symfony/console": "^5.4.1 || ^6.0", - "symfony/filesystem": "^5.4 || ^6.0", + "php": "^7.2 || ^8.0", + "symfony/finder": "^4.4 || ^5.3 || ^6" + }, + "require-dev": { + "phpstan/phpstan": "^1.6", + "phpstan/phpstan-deprecation-rules": "^1", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/filesystem": "^5.4 || ^6", + "symfony/phpunit-bridge": "^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\ClassMapGenerator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Utilities to scan PHP code and generate class maps.", + "keywords": [ + "classmap" + ], + "support": { + "issues": "https://github.com/composer/class-map-generator/issues", + "source": "https://github.com/composer/class-map-generator/tree/1.0.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-06-19T11:31:27+00:00" + }, + { + "name": "composer/composer", + "version": "2.4.4", + "source": { + "type": "git", + "url": "https://github.com/composer/composer.git", + "reference": "e8d9087229bcdbc5867594d3098091412f1130cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/composer/zipball/e8d9087229bcdbc5867594d3098091412f1130cf", + "reference": "e8d9087229bcdbc5867594d3098091412f1130cf", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0", + "composer/class-map-generator": "^1.0", + "composer/metadata-minifier": "^1.0", + "composer/pcre": "^2 || ^3", + "composer/semver": "^3.0", + "composer/spdx-licenses": "^1.5.7", + "composer/xdebug-handler": "^2.0.2 || ^3.0.3", + "justinrainbow/json-schema": "^5.2.11", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "react/promise": "^2.8", + "seld/jsonlint": "^1.4", + "seld/phar-utils": "^1.2", + "seld/signal-handler": "^2.0", + "symfony/console": "^5.4.11 || ^6.0.11", + "symfony/filesystem": "^5.4 || ^6.0", "symfony/finder": "^5.4 || ^6.0", "symfony/polyfill-php73": "^1.24", "symfony/polyfill-php80": "^1.24", @@ -3162,7 +2995,7 @@ "phpstan/phpstan-deprecation-rules": "^1", "phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-strict-rules": "^1", - "phpstan/phpstan-symfony": "^1.1", + "phpstan/phpstan-symfony": "^1.2.10", "symfony/phpunit-bridge": "^6.0" }, "suggest": { @@ -3176,7 +3009,12 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.3-dev" + "dev-main": "2.4-dev" + }, + "phpstan": { + "includes": [ + "phpstan/rules.neon" + ] } }, "autoload": { @@ -3210,7 +3048,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/2.3.5" + "source": "https://github.com/composer/composer/tree/2.4.4" }, "funding": [ { @@ -3226,7 +3064,7 @@ "type": "tidelift" } ], - "time": "2022-04-13T14:43:00+00:00" + "time": "2022-10-27T12:39:29+00:00" }, { "name": "composer/metadata-minifier", @@ -3299,16 +3137,16 @@ }, { "name": "composer/pcre", - "version": "3.0.0", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "e300eb6c535192decd27a85bc72a9290f0d6b3bd" + "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/e300eb6c535192decd27a85bc72a9290f0d6b3bd", - "reference": "e300eb6c535192decd27a85bc72a9290f0d6b3bd", + "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", + "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", "shasum": "" }, "require": { @@ -3350,7 +3188,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.0.0" + "source": "https://github.com/composer/pcre/tree/3.1.0" }, "funding": [ { @@ -3366,7 +3204,7 @@ "type": "tidelift" } ], - "time": "2022-02-25T20:21:48+00:00" + "time": "2022-11-17T09:50:14+00:00" }, { "name": "composer/semver", @@ -3451,16 +3289,16 @@ }, { "name": "composer/spdx-licenses", - "version": "1.5.6", + "version": "1.5.7", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "a30d487169d799745ca7280bc90fdfa693536901" + "reference": "c848241796da2abf65837d51dce1fae55a960149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/a30d487169d799745ca7280bc90fdfa693536901", - "reference": "a30d487169d799745ca7280bc90fdfa693536901", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/c848241796da2abf65837d51dce1fae55a960149", + "reference": "c848241796da2abf65837d51dce1fae55a960149", "shasum": "" }, "require": { @@ -3511,7 +3349,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/spdx-licenses/issues", - "source": "https://github.com/composer/spdx-licenses/tree/1.5.6" + "source": "https://github.com/composer/spdx-licenses/tree/1.5.7" }, "funding": [ { @@ -3527,7 +3365,7 @@ "type": "tidelift" } ], - "time": "2021-11-18T10:14:14+00:00" + "time": "2022-05-23T07:37:50+00:00" }, { "name": "composer/xdebug-handler", @@ -4108,16 +3946,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.2", + "version": "v4.15.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", + "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", "shasum": "" }, "require": { @@ -4158,9 +3996,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2" }, - "time": "2021-11-30T19:35:32+00:00" + "time": "2022-11-12T15:38:23+00:00" }, { "name": "phar-io/manifest", @@ -4273,245 +4111,18 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" - }, - "time": "2021-10-19T17:43:47+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.6.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "77a32518733312af16a44300404e945338981de3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3", - "reference": "77a32518733312af16a44300404e945338981de3", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "*", - "psalm/phar": "^4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1" - }, - "time": "2022-03-15T21:29:03+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "v1.15.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", - "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.2", - "phpdocumentor/reflection-docblock": "^5.2", - "sebastian/comparator": "^3.0 || ^4.0", - "sebastian/recursion-context": "^3.0 || ^4.0" - }, - "require-dev": { - "phpspec/phpspec": "^6.0 || ^7.0", - "phpunit/phpunit": "^8.0 || ^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "support": { - "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" - }, - "time": "2021-12-08T12:19:24+00:00" - }, { "name": "phpstan/phpdoc-parser", - "version": "1.4.5", + "version": "1.13.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "129a63b3bc7caeb593c224c41f420675e63cfefc" + "reference": "aac44118344d197e6d5f7c6cee91885f0a89acdd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/129a63b3bc7caeb593c224c41f420675e63cfefc", - "reference": "129a63b3bc7caeb593c224c41f420675e63cfefc", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/aac44118344d197e6d5f7c6cee91885f0a89acdd", + "reference": "aac44118344d197e6d5f7c6cee91885f0a89acdd", "shasum": "" }, "require": { @@ -4521,6 +4132,7 @@ "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5", "symfony/process": "^5.2" @@ -4540,22 +4152,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.4.5" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.13.1" }, - "time": "2022-04-22T11:11:01+00:00" + "time": "2022-11-20T08:52:26+00:00" }, { "name": "phpstan/phpstan", - "version": "0.12.99", + "version": "0.12.100", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "b4d40f1d759942f523be267a1bab6884f46ca3f7" + "reference": "48236ddf823547081b2b153d1cd2994b784328c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b4d40f1d759942f523be267a1bab6884f46ca3f7", - "reference": "b4d40f1d759942f523be267a1bab6884f46ca3f7", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/48236ddf823547081b2b153d1cd2994b784328c3", + "reference": "48236ddf823547081b2b153d1cd2994b784328c3", "shasum": "" }, "require": { @@ -4586,7 +4198,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/0.12.99" + "source": "https://github.com/phpstan/phpstan/tree/0.12.100" }, "funding": [ { @@ -4597,36 +4209,32 @@ "url": "https://github.com/phpstan", "type": "github" }, - { - "url": "https://www.patreon.com/phpstan", - "type": "patreon" - }, { "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", "type": "tidelift" } ], - "time": "2021-09-12T20:09:55+00:00" + "time": "2022-11-01T09:52:08+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.15", + "version": "9.2.19", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f" + "reference": "c77b56b63e3d2031bd8997fcec43c1925ae46559" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2e9da11878c4202f97915c1cb4bb1ca318a63f5f", - "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c77b56b63e3d2031bd8997fcec43c1925ae46559", + "reference": "c77b56b63e3d2031bd8997fcec43c1925ae46559", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.13.0", + "nikic/php-parser": "^4.14", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -4675,7 +4283,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.15" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.19" }, "funding": [ { @@ -4683,7 +4291,7 @@ "type": "github" } ], - "time": "2022-03-07T09:28:20+00:00" + "time": "2022-11-18T07:47:47+00:00" }, { "name": "phpunit/php-file-iterator", @@ -4928,16 +4536,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.20", + "version": "9.5.26", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba" + "reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/12bc8879fb65aef2138b26fc633cb1e3620cffba", - "reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/851867efcbb6a1b992ec515c71cdcf20d895e9d2", + "reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2", "shasum": "" }, "require": { @@ -4952,7 +4560,6 @@ "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", - "phpspec/prophecy": "^1.12.1", "phpunit/php-code-coverage": "^9.2.13", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", @@ -4960,20 +4567,16 @@ "phpunit/php-timer": "^5.0.2", "sebastian/cli-parser": "^1.0.1", "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.5", + "sebastian/comparator": "^4.0.8", "sebastian/diff": "^4.0.3", "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.3", + "sebastian/exporter": "^4.0.5", "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.0", + "sebastian/type": "^3.2", "sebastian/version": "^3.0.2" }, - "require-dev": { - "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0.1" - }, "suggest": { "ext-soap": "*", "ext-xdebug": "*" @@ -5015,7 +4618,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.20" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.26" }, "funding": [ { @@ -5025,22 +4628,26 @@ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" } ], - "time": "2022-04-01T12:37:26+00:00" + "time": "2022-10-28T06:00:21+00:00" }, { "name": "psy/psysh", - "version": "v0.11.2", + "version": "v0.11.9", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "7f7da640d68b9c9fec819caae7c744a213df6514" + "reference": "1acec99d6684a54ff92f8b548a4e41b566963778" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/7f7da640d68b9c9fec819caae7c744a213df6514", - "reference": "7f7da640d68b9c9fec819caae7c744a213df6514", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/1acec99d6684a54ff92f8b548a4e41b566963778", + "reference": "1acec99d6684a54ff92f8b548a4e41b566963778", "shasum": "" }, "require": { @@ -5055,15 +4662,13 @@ "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.2", - "hoa/console": "3.17.05.02" + "bamarni/composer-bin-plugin": "^1.2" }, "suggest": { "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", "ext-pdo-sqlite": "The doc command requires SQLite to work.", "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", - "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.", - "hoa/console": "A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit." + "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history." }, "bin": [ "bin/psysh" @@ -5103,9 +4708,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.11.2" + "source": "https://github.com/bobthecow/psysh/tree/v0.11.9" }, - "time": "2022-02-28T15:28:54+00:00" + "time": "2022-11-06T15:29:46+00:00" }, { "name": "react/promise", @@ -5352,16 +4957,16 @@ }, { "name": "sebastian/comparator", - "version": "4.0.6", + "version": "4.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382" + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", "shasum": "" }, "require": { @@ -5414,7 +5019,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" }, "funding": [ { @@ -5422,7 +5027,7 @@ "type": "github" } ], - "time": "2020-10-26T15:49:45+00:00" + "time": "2022-09-14T12:41:17+00:00" }, { "name": "sebastian/complexity", @@ -5612,16 +5217,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", "shasum": "" }, "require": { @@ -5677,7 +5282,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" }, "funding": [ { @@ -5685,7 +5290,7 @@ "type": "github" } ], - "time": "2021-11-11T14:18:36+00:00" + "time": "2022-09-14T06:03:37+00:00" }, { "name": "sebastian/global-state", @@ -6040,16 +5645,16 @@ }, { "name": "sebastian/type", - "version": "3.0.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad" + "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", - "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", + "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", "shasum": "" }, "require": { @@ -6061,7 +5666,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -6084,7 +5689,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.0.0" + "source": "https://github.com/sebastianbergmann/type/tree/3.2.0" }, "funding": [ { @@ -6092,7 +5697,7 @@ "type": "github" } ], - "time": "2022-03-15T09:54:48+00:00" + "time": "2022-09-12T14:47:03+00:00" }, { "name": "sebastian/version", @@ -6213,16 +5818,16 @@ }, { "name": "seld/phar-utils", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/Seldaek/phar-utils.git", - "reference": "9f3452c93ff423469c0d56450431562ca423dcee" + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/9f3452c93ff423469c0d56450431562ca423dcee", - "reference": "9f3452c93ff423469c0d56450431562ca423dcee", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", "shasum": "" }, "require": { @@ -6255,43 +5860,104 @@ ], "support": { "issues": "https://github.com/Seldaek/phar-utils/issues", - "source": "https://github.com/Seldaek/phar-utils/tree/1.2.0" + "source": "https://github.com/Seldaek/phar-utils/tree/1.2.1" + }, + "time": "2022-08-31T10:31:18+00:00" + }, + { + "name": "seld/signal-handler", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/signal-handler.git", + "reference": "f69d119511dc0360440cdbdaa71829c149b7be75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/signal-handler/zipball/f69d119511dc0360440cdbdaa71829c149b7be75", + "reference": "f69d119511dc0360440cdbdaa71829c149b7be75", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "require-dev": { + "phpstan/phpstan": "^1", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^7.5.20 || ^8.5.23", + "psr/log": "^1 || ^2 || ^3" }, - "time": "2021-12-10T11:20:11+00:00" + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\Signal\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Simple unix signal handler that silently fails where signals are not supported for easy cross-platform development", + "keywords": [ + "posix", + "sigint", + "signal", + "sigterm", + "unix" + ], + "support": { + "issues": "https://github.com/Seldaek/signal-handler/issues", + "source": "https://github.com/Seldaek/signal-handler/tree/2.0.1" + }, + "time": "2022-07-20T18:31:45+00:00" }, { "name": "slevomat/coding-standard", - "version": "7.1", + "version": "8.6.4", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "b521bd358b5f7a7d69e9637fd139e036d8adeb6f" + "reference": "8a02c83e59c3230a2a4367b29956a2f2b56e3a24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b521bd358b5f7a7d69e9637fd139e036d8adeb6f", - "reference": "b521bd358b5f7a7d69e9637fd139e036d8adeb6f", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/8a02c83e59c3230a2a4367b29956a2f2b56e3a24", + "reference": "8a02c83e59c3230a2a4367b29956a2f2b56e3a24", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", "php": "^7.2 || ^8.0", - "phpstan/phpdoc-parser": "^1.4.1", - "squizlabs/php_codesniffer": "^3.6.2" + "phpstan/phpdoc-parser": ">=1.11.0 <1.14.0", + "squizlabs/php_codesniffer": "^3.7.1" }, "require-dev": { - "phing/phing": "2.17.2", + "phing/phing": "2.17.4", "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpstan/phpstan": "1.4.10|1.5.2", + "phpstan/phpstan": "1.4.10|1.9.2", "phpstan/phpstan-deprecation-rules": "1.0.0", - "phpstan/phpstan-phpunit": "1.0.0|1.1.0", - "phpstan/phpstan-strict-rules": "1.1.0", - "phpunit/phpunit": "7.5.20|8.5.21|9.5.19" + "phpstan/phpstan-phpunit": "1.0.0|1.2.2", + "phpstan/phpstan-strict-rules": "1.4.4", + "phpunit/phpunit": "7.5.20|8.5.21|9.5.26" }, "type": "phpcodesniffer-standard", "extra": { "branch-alias": { - "dev-master": "7.x-dev" + "dev-master": "8.x-dev" } }, "autoload": { @@ -6304,9 +5970,13 @@ "MIT" ], "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/7.1" + "source": "https://github.com/slevomat/coding-standard/tree/8.6.4" }, "funding": [ { @@ -6318,20 +5988,20 @@ "type": "tidelift" } ], - "time": "2022-03-29T12:44:16+00:00" + "time": "2022-11-14T09:26:24+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.6.2", + "version": "3.7.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a" + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", "shasum": "" }, "require": { @@ -6374,26 +6044,24 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2021-12-12T21:44:58+00:00" + "time": "2022-06-18T07:21:10+00:00" }, { "name": "symfony/finder", - "version": "v5.4.3", + "version": "v6.0.11", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d" + "reference": "09cb683ba5720385ea6966e5e06be2a34f2568b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/231313534dded84c7ecaa79d14bc5da4ccb69b7d", - "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d", + "url": "https://api.github.com/repos/symfony/finder/zipball/09cb683ba5720385ea6966e5e06be2a34f2568b1", + "reference": "09cb683ba5720385ea6966e5e06be2a34f2568b1", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.0.2" }, "type": "library", "autoload": { @@ -6421,7 +6089,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.3" + "source": "https://github.com/symfony/finder/tree/v6.0.11" }, "funding": [ { @@ -6437,25 +6105,186 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:34:36+00:00" + "time": "2022-07-29T07:39:48+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "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 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/process", - "version": "v5.4.7", + "version": "v6.0.11", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "38a44b2517b470a436e1c944bf9b9ba3961137fb" + "reference": "44270a08ccb664143dede554ff1c00aaa2247a43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/38a44b2517b470a436e1c944bf9b9ba3961137fb", - "reference": "38a44b2517b470a436e1c944bf9b9ba3961137fb", + "url": "https://api.github.com/repos/symfony/process/zipball/44270a08ccb664143dede554ff1c00aaa2247a43", + "reference": "44270a08ccb664143dede554ff1c00aaa2247a43", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.0.2" }, "type": "library", "autoload": { @@ -6483,7 +6312,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.7" + "source": "https://github.com/symfony/process/tree/v6.0.11" }, "funding": [ { @@ -6499,36 +6328,35 @@ "type": "tidelift" } ], - "time": "2022-03-18T16:18:52+00:00" + "time": "2022-06-27T17:10:44+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.4.6", + "version": "v6.0.14", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "294e9da6e2e0dd404e983daa5aa74253d92c05d0" + "reference": "72af925ddd41ca0372d166d004bc38a00c4608cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/294e9da6e2e0dd404e983daa5aa74253d92c05d0", - "reference": "294e9da6e2e0dd404e983daa5aa74253d92c05d0", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/72af925ddd41ca0372d166d004bc38a00c4608cc", + "reference": "72af925ddd41ca0372d166d004bc38a00c4608cc", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.0.2", + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { "phpunit/phpunit": "<5.4.3", - "symfony/console": "<4.4" + "symfony/console": "<5.4" }, "require-dev": { "ext-iconv": "*", - "symfony/console": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/uid": "^5.1|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/uid": "^5.4|^6.0", "twig/twig": "^2.13|^3.0.4" }, "suggest": { @@ -6572,7 +6400,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.6" + "source": "https://github.com/symfony/var-dumper/tree/v6.0.14" }, "funding": [ { @@ -6588,7 +6416,7 @@ "type": "tidelift" } ], - "time": "2022-03-02T12:42:23+00:00" + "time": "2022-10-07T08:02:12+00:00" }, { "name": "theseer/tokenizer", @@ -6642,7 +6470,7 @@ }, { "name": "twig/markdown-extra", - "version": "v3.3.8", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/twigphp/markdown-extra.git", @@ -6699,7 +6527,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/markdown-extra/tree/v3.3.8" + "source": "https://github.com/twigphp/markdown-extra/tree/v3.4.0" }, "funding": [ { @@ -6715,16 +6543,16 @@ }, { "name": "twig/twig", - "version": "v3.3.10", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "8442df056c51b706793adf80a9fd363406dd3674" + "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/8442df056c51b706793adf80a9fd363406dd3674", - "reference": "8442df056c51b706793adf80a9fd363406dd3674", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/c38fd6b0b7f370c198db91ffd02e23b517426b58", + "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58", "shasum": "" }, "require": { @@ -6739,7 +6567,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -6775,7 +6603,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.3.10" + "source": "https://github.com/twigphp/Twig/tree/v3.4.3" }, "funding": [ { @@ -6787,65 +6615,7 @@ "type": "tidelift" } ], - "time": "2022-04-06T06:47:41+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" - }, - "time": "2021-03-09T10:59:23+00:00" + "time": "2022-09-28T08:42:51+00:00" } ], "aliases": [], @@ -6857,5 +6627,5 @@ "php": ">=7.3" }, "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.2.0" } diff --git a/app/vendor/bin/composer b/app/vendor/bin/composer deleted file mode 120000 index f43551575..000000000 --- a/app/vendor/bin/composer +++ /dev/null @@ -1 +0,0 @@ -../composer/composer/bin/composer \ No newline at end of file diff --git a/app/vendor/bin/composer b/app/vendor/bin/composer new file mode 100755 index 000000000..b48a11b33 --- /dev/null +++ b/app/vendor/bin/composer @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/composer/composer/bin/composer'); + exit(0); + } +} + +include __DIR__ . '/..'.'/composer/composer/bin/composer'; diff --git a/app/vendor/bin/doctrine-dbal b/app/vendor/bin/doctrine-dbal deleted file mode 120000 index 58a8a89c2..000000000 --- a/app/vendor/bin/doctrine-dbal +++ /dev/null @@ -1 +0,0 @@ -../doctrine/dbal/bin/doctrine-dbal \ No newline at end of file diff --git a/app/vendor/bin/doctrine-dbal b/app/vendor/bin/doctrine-dbal new file mode 100755 index 000000000..374a92a09 --- /dev/null +++ b/app/vendor/bin/doctrine-dbal @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/doctrine/dbal/bin/doctrine-dbal'); + exit(0); + } +} + +include __DIR__ . '/..'.'/doctrine/dbal/bin/doctrine-dbal'; diff --git a/app/vendor/bin/jsonlint b/app/vendor/bin/jsonlint deleted file mode 120000 index 4282f1737..000000000 --- a/app/vendor/bin/jsonlint +++ /dev/null @@ -1 +0,0 @@ -../seld/jsonlint/bin/jsonlint \ No newline at end of file diff --git a/app/vendor/bin/jsonlint b/app/vendor/bin/jsonlint new file mode 100755 index 000000000..513f1c973 --- /dev/null +++ b/app/vendor/bin/jsonlint @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/seld/jsonlint/bin/jsonlint'); + exit(0); + } +} + +include __DIR__ . '/..'.'/seld/jsonlint/bin/jsonlint'; diff --git a/app/vendor/bin/phinx b/app/vendor/bin/phinx deleted file mode 120000 index 8b2b0f455..000000000 --- a/app/vendor/bin/phinx +++ /dev/null @@ -1 +0,0 @@ -../robmorgan/phinx/bin/phinx \ No newline at end of file diff --git a/app/vendor/bin/phinx b/app/vendor/bin/phinx new file mode 100755 index 000000000..6734d67f2 --- /dev/null +++ b/app/vendor/bin/phinx @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/robmorgan/phinx/bin/phinx'); + exit(0); + } +} + +include __DIR__ . '/..'.'/robmorgan/phinx/bin/phinx'; diff --git a/app/vendor/bin/php-parse b/app/vendor/bin/php-parse deleted file mode 120000 index 062d66a3e..000000000 --- a/app/vendor/bin/php-parse +++ /dev/null @@ -1 +0,0 @@ -../nikic/php-parser/bin/php-parse \ No newline at end of file diff --git a/app/vendor/bin/php-parse b/app/vendor/bin/php-parse new file mode 100755 index 000000000..80f0e486d --- /dev/null +++ b/app/vendor/bin/php-parse @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse'); + exit(0); + } +} + +include __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse'; diff --git a/app/vendor/bin/phpcbf b/app/vendor/bin/phpcbf deleted file mode 120000 index bdf04fbca..000000000 --- a/app/vendor/bin/phpcbf +++ /dev/null @@ -1 +0,0 @@ -../squizlabs/php_codesniffer/bin/phpcbf \ No newline at end of file diff --git a/app/vendor/bin/phpcbf b/app/vendor/bin/phpcbf new file mode 100755 index 000000000..dd5f763df --- /dev/null +++ b/app/vendor/bin/phpcbf @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/squizlabs/php_codesniffer/bin/phpcbf'); + exit(0); + } +} + +include __DIR__ . '/..'.'/squizlabs/php_codesniffer/bin/phpcbf'; diff --git a/app/vendor/bin/phpcs b/app/vendor/bin/phpcs deleted file mode 120000 index 9481d68a4..000000000 --- a/app/vendor/bin/phpcs +++ /dev/null @@ -1 +0,0 @@ -../squizlabs/php_codesniffer/bin/phpcs \ No newline at end of file diff --git a/app/vendor/bin/phpcs b/app/vendor/bin/phpcs new file mode 100755 index 000000000..5123b7d63 --- /dev/null +++ b/app/vendor/bin/phpcs @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/squizlabs/php_codesniffer/bin/phpcs'); + exit(0); + } +} + +include __DIR__ . '/..'.'/squizlabs/php_codesniffer/bin/phpcs'; diff --git a/app/vendor/bin/phpstan b/app/vendor/bin/phpstan deleted file mode 120000 index 959384f7f..000000000 --- a/app/vendor/bin/phpstan +++ /dev/null @@ -1 +0,0 @@ -../phpstan/phpstan/phpstan \ No newline at end of file diff --git a/app/vendor/bin/phpstan b/app/vendor/bin/phpstan new file mode 100755 index 000000000..8a0d5a7e3 --- /dev/null +++ b/app/vendor/bin/phpstan @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/phpstan/phpstan/phpstan'); + exit(0); + } +} + +include __DIR__ . '/..'.'/phpstan/phpstan/phpstan'; diff --git a/app/vendor/bin/phpstan.phar b/app/vendor/bin/phpstan.phar deleted file mode 120000 index 502769bef..000000000 --- a/app/vendor/bin/phpstan.phar +++ /dev/null @@ -1 +0,0 @@ -../phpstan/phpstan/phpstan.phar \ No newline at end of file diff --git a/app/vendor/bin/phpstan.phar b/app/vendor/bin/phpstan.phar new file mode 100755 index 000000000..9694c2fae --- /dev/null +++ b/app/vendor/bin/phpstan.phar @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/phpstan/phpstan/phpstan.phar'); + exit(0); + } +} + +include __DIR__ . '/..'.'/phpstan/phpstan/phpstan.phar'; diff --git a/app/vendor/bin/phpunit b/app/vendor/bin/phpunit deleted file mode 120000 index 2c4893031..000000000 --- a/app/vendor/bin/phpunit +++ /dev/null @@ -1 +0,0 @@ -../phpunit/phpunit/phpunit \ No newline at end of file diff --git a/app/vendor/bin/phpunit b/app/vendor/bin/phpunit new file mode 100755 index 000000000..c52ed8c3b --- /dev/null +++ b/app/vendor/bin/phpunit @@ -0,0 +1,120 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = 'phpvfscomposer://'.$this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + $data = str_replace('__DIR__', var_export(dirname($this->realpath), true), $data); + $data = str_replace('__FILE__', var_export($this->realpath, true), $data); + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/phpunit/phpunit/phpunit'); + exit(0); + } +} + +include __DIR__ . '/..'.'/phpunit/phpunit/phpunit'; diff --git a/app/vendor/bin/psysh b/app/vendor/bin/psysh deleted file mode 120000 index 3c06b1ae9..000000000 --- a/app/vendor/bin/psysh +++ /dev/null @@ -1 +0,0 @@ -../psy/psysh/bin/psysh \ No newline at end of file diff --git a/app/vendor/bin/psysh b/app/vendor/bin/psysh new file mode 100755 index 000000000..c10304ba4 --- /dev/null +++ b/app/vendor/bin/psysh @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/psy/psysh/bin/psysh'); + exit(0); + } +} + +include __DIR__ . '/..'.'/psy/psysh/bin/psysh'; diff --git a/app/vendor/bin/validate-json b/app/vendor/bin/validate-json deleted file mode 120000 index 141e25102..000000000 --- a/app/vendor/bin/validate-json +++ /dev/null @@ -1 +0,0 @@ -../justinrainbow/json-schema/bin/validate-json \ No newline at end of file diff --git a/app/vendor/bin/validate-json b/app/vendor/bin/validate-json new file mode 100755 index 000000000..5910c8159 --- /dev/null +++ b/app/vendor/bin/validate-json @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/justinrainbow/json-schema/bin/validate-json'); + exit(0); + } +} + +include __DIR__ . '/..'.'/justinrainbow/json-schema/bin/validate-json'; diff --git a/app/vendor/bin/var-dump-server b/app/vendor/bin/var-dump-server deleted file mode 120000 index 6bd4e93db..000000000 --- a/app/vendor/bin/var-dump-server +++ /dev/null @@ -1 +0,0 @@ -../symfony/var-dumper/Resources/bin/var-dump-server \ No newline at end of file diff --git a/app/vendor/bin/var-dump-server b/app/vendor/bin/var-dump-server new file mode 100755 index 000000000..527f3ed42 --- /dev/null +++ b/app/vendor/bin/var-dump-server @@ -0,0 +1,117 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server'); + exit(0); + } +} + +include __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server'; diff --git a/app/vendor/brick/varexporter/composer.json b/app/vendor/brick/varexporter/composer.json index f627551c0..916985d8c 100644 --- a/app/vendor/brick/varexporter/composer.json +++ b/app/vendor/brick/varexporter/composer.json @@ -13,7 +13,7 @@ "require-dev": { "phpunit/phpunit": "^8.5 || ^9.0", "php-coveralls/php-coveralls": "^2.2", - "vimeo/psalm": "4.4.1" + "vimeo/psalm": "4.23.0" }, "autoload": { "psr-4": { diff --git a/app/vendor/brick/varexporter/src/Internal/GenericExporter.php b/app/vendor/brick/varexporter/src/Internal/GenericExporter.php index e665fd280..6b520a231 100644 --- a/app/vendor/brick/varexporter/src/Internal/GenericExporter.php +++ b/app/vendor/brick/varexporter/src/Internal/GenericExporter.php @@ -51,7 +51,14 @@ final class GenericExporter * * @var bool */ - public $inlineNumericScalarArray; + public $inlineArray; + + /** + * @psalm-readonly + * + * @var bool + */ + public $inlineScalarList; /** * @psalm-readonly @@ -74,10 +81,6 @@ final class GenericExporter */ public $indentLevel; - /** - * @param int $options - * @param int Indentation level - */ public function __construct(int $options, int $indentLevel = 0) { $this->objectExporters[] = new ObjectExporter\StdClassExporter($this); @@ -96,13 +99,18 @@ public function __construct(int $options, int $indentLevel = 0) $this->objectExporters[] = new ObjectExporter\SerializeExporter($this); } + if (! ($options & VarExporter::NO_ENUMS)) { + $this->objectExporters[] = new ObjectExporter\EnumExporter($this); + } + if (! ($options & VarExporter::NOT_ANY_OBJECT)) { $this->objectExporters[] = new ObjectExporter\AnyObjectExporter($this); } $this->addTypeHints = (bool) ($options & VarExporter::ADD_TYPE_HINTS); $this->skipDynamicProperties = (bool) ($options & VarExporter::SKIP_DYNAMIC_PROPERTIES); - $this->inlineNumericScalarArray = (bool) ($options & VarExporter::INLINE_NUMERIC_SCALAR_ARRAY); + $this->inlineArray = (bool) ($options & VarExporter::INLINE_ARRAY); + $this->inlineScalarList = (bool) ($options & VarExporter::INLINE_SCALAR_LIST); $this->closureSnapshotUses = (bool) ($options & VarExporter::CLOSURE_SNAPSHOT_USES); $this->trailingCommaInArray = (bool) ($options & VarExporter::TRAILING_COMMA_IN_ARRAY); @@ -165,11 +173,11 @@ public function exportArray(array $array, array $path, array $parentIds) : array $result = []; $count = count($array); - $isNumeric = array_keys($array) === range(0, $count - 1); + $isList = array_keys($array) === range(0, $count - 1); $current = 0; - $inline = ($this->inlineNumericScalarArray && $isNumeric && $this->isScalarArray($array)); + $inline = $this->inlineArray || ($this->inlineScalarList && $isList && $this->isScalarList($array)); foreach ($array as $key => $value) { $isLast = (++$current === $count); @@ -180,12 +188,16 @@ public function exportArray(array $array, array $path, array $parentIds) : array $exported = $this->export($value, $newPath, $parentIds); if ($inline) { - $result[] = $exported[0]; + if ($isList) { + $result[] = $exported[0]; + } else { + $result[] = var_export($key, true) . ' => ' . $exported[0]; + } } else { $prepend = ''; $append = ''; - if (! $isNumeric) { + if (! $isList) { $prepend = var_export($key, true) . ' => '; } @@ -220,7 +232,7 @@ public function exportArray(array $array, array $path, array $parentIds) : array * * @return bool */ - private function isScalarArray(array $array) : bool + private function isScalarList(array $array) : bool { foreach ($array as $value) { if ($value !== null && ! is_scalar($value)) { diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/AnyObjectExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/AnyObjectExporter.php index 5449e71ab..090393e4f 100644 --- a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/AnyObjectExporter.php +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/AnyObjectExporter.php @@ -29,7 +29,7 @@ public function supports(\ReflectionObject $reflectionObject) : bool * * @psalm-suppress MixedAssignment */ - public function export($object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array + public function export(object $object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array { $lines = $this->getCreateObjectCode($reflectionObject); diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/ClosureExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/ClosureExporter.php index 6cfb9f57f..ea98891cc 100644 --- a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/ClosureExporter.php +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/ClosureExporter.php @@ -39,7 +39,7 @@ public function supports(\ReflectionObject $reflectionObject) : bool /** * {@inheritDoc} */ - public function export($object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array + public function export(object $object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array { assert($object instanceof Closure); diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/InternalClassExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/InternalClassExporter.php index 1deb23e61..e0adbd111 100644 --- a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/InternalClassExporter.php +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/InternalClassExporter.php @@ -25,7 +25,7 @@ public function supports(\ReflectionObject $reflectionObject) : bool /** * {@inheritDoc} */ - public function export($object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array + public function export(object $object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array { $className = $reflectionObject->getName(); diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SerializeExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SerializeExporter.php index 7c826c3ac..604a104ea 100644 --- a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SerializeExporter.php +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SerializeExporter.php @@ -25,7 +25,7 @@ public function supports(\ReflectionObject $reflectionObject) : bool /** * {@inheritDoc} */ - public function export($object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array + public function export(object $object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array { $lines = $this->getCreateObjectCode($reflectionObject); diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SetStateExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SetStateExporter.php index 4963dd260..a464b992a 100644 --- a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SetStateExporter.php +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/SetStateExporter.php @@ -31,7 +31,7 @@ public function supports(\ReflectionObject $reflectionObject) : bool /** * {@inheritDoc} */ - public function export($object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array + public function export(object $object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array { $className = $reflectionObject->getName(); diff --git a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/StdClassExporter.php b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/StdClassExporter.php index 52fc0a97c..ac958f18f 100644 --- a/app/vendor/brick/varexporter/src/Internal/ObjectExporter/StdClassExporter.php +++ b/app/vendor/brick/varexporter/src/Internal/ObjectExporter/StdClassExporter.php @@ -24,7 +24,7 @@ public function supports(\ReflectionObject $reflectionObject) : bool /** * {@inheritDoc} */ - public function export($object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array + public function export(object $object, \ReflectionObject $reflectionObject, array $path, array $parentIds) : array { $exported = $this->exporter->exportArray((array) $object, $path, $parentIds); diff --git a/app/vendor/brick/varexporter/src/VarExporter.php b/app/vendor/brick/varexporter/src/VarExporter.php index c2717683f..21d6e4fcd 100644 --- a/app/vendor/brick/varexporter/src/VarExporter.php +++ b/app/vendor/brick/varexporter/src/VarExporter.php @@ -48,10 +48,16 @@ final class VarExporter public const NO_CLOSURES = 1 << 6; /** - * Formats numeric arrays containing only scalar values on a single line. + * Formats lists (0-based numeric arrays) containing only scalar values on a single line. * Types considered scalar here are int, bool, float, string and null. + * This option is a subset of INLINE_ARRAY, and has no effect when INLINE_ARRAY is used. */ - public const INLINE_NUMERIC_SCALAR_ARRAY = 1 << 7; + public const INLINE_SCALAR_LIST = 1 << 7; + + /** + * @deprecated Please use INLINE_SCALAR_LIST instead. + */ + public const INLINE_NUMERIC_SCALAR_ARRAY = self::INLINE_SCALAR_LIST; /** * Export static vars defined via `use` as variables. @@ -63,6 +69,16 @@ final class VarExporter */ public const TRAILING_COMMA_IN_ARRAY = 1 << 9; + /** + * Disallows exporting enums. + */ + public const NO_ENUMS = 1 << 10; + + /** + * Formats all arrays on a single line. + */ + public const INLINE_ARRAY = 1 << 11; + /** * @param mixed $var The variable to export. * @param int $options A bitmask of options. Possible values are `VarExporter::*` constants. diff --git a/app/vendor/cakephp/bake/composer.json b/app/vendor/cakephp/bake/composer.json index 96daca727..58ad76d07 100644 --- a/app/vendor/cakephp/bake/composer.json +++ b/app/vendor/cakephp/bake/composer.json @@ -21,7 +21,8 @@ "php": ">=7.2", "cakephp/cakephp": "^4.3.0", "cakephp/twig-view": "^1.0.2", - "brick/varexporter": "^0.3.5" + "brick/varexporter": "^0.3.5", + "nikic/php-parser": "^4.13.2" }, "require-dev": { "cakephp/cakephp-codesniffer": "^4.0", @@ -52,7 +53,7 @@ "cs-check": "phpcs --parallel=16 -p src/ tests/", "cs-fix": "phpcbf --parallel=16 -p src/ tests/", "stan": "phpstan analyse src/ && psalm.phar", - "stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:^1.5 psalm/phar:~4.22.0 && mv composer.backup composer.json", + "stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:^1.7 psalm/phar:~4.27.0 && mv composer.backup composer.json", "test": "phpunit", "test-coverage": "phpunit --coverage-clover=clover.xml" }, diff --git a/app/vendor/cakephp/bake/src/Command/BakeCommand.php b/app/vendor/cakephp/bake/src/Command/BakeCommand.php index 6ca98b700..903192c0e 100644 --- a/app/vendor/cakephp/bake/src/Command/BakeCommand.php +++ b/app/vendor/cakephp/bake/src/Command/BakeCommand.php @@ -16,12 +16,17 @@ */ namespace Bake\Command; +use Bake\CodeGen\CodeParser; +use Bake\CodeGen\ParsedFile; use Bake\Utility\CommonOptionsTrait; +use Bake\Utility\TemplateRenderer; use Cake\Command\Command; use Cake\Console\Arguments; use Cake\Console\ConsoleIo; use Cake\Core\Configure; use Cake\Core\ConventionsTrait; +use Cake\Event\Event; +use Cake\Event\EventManager; use InvalidArgumentException; /** @@ -150,6 +155,19 @@ public function getTemplatePath(Arguments $args, ?string $container = null): str return str_replace('/', DIRECTORY_SEPARATOR, $path); } + /** + * Creates a new instance of TemplateRenderer with theme set. + * + * @return \Bake\Utility\TemplateRenderer + */ + public function createTemplateRenderer(): TemplateRenderer + { + $renderer = new TemplateRenderer($this->theme); + EventManager::instance()->dispatch(new Event('Bake.renderer', $renderer)); + + return $renderer; + } + /** * Delete empty file in a given path * @@ -179,4 +197,47 @@ protected function isValidColumnName(string $name): bool { return (bool)preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $name); } + + /** + * Parses a file if it exists. + * + * @param string $path File path + * @return \Bake\CodeGen\ParsedFile|null + */ + protected function parseFile(string $path): ?ParsedFile + { + if (file_exists($path)) { + return (new CodeParser())->parseFile(file_get_contents($path)); + } + + return null; + } + + /** + * Write file contents out to path and prompt user with options with file exists. + * + * @param \Cake\Console\ConsoleIo $io Console io + * @param string $path The path to create the file at + * @param string $contents The contents to put into the file + * @param bool $forceOverwrite Whether the file should be overwritten without prompting the user + * @param bool $skipIfUnchnged Skip writing output if the contents match existing file + * @return bool True if successful, false otherwise + * @throws \Cake\Console\Exception\StopException When `q` is given as an answer + * to whether a file should be overwritten. + */ + protected function writeFile( + ConsoleIo $io, + string $path, + string $contents, + bool $forceOverwrite = false, + bool $skipIfUnchnged = true + ): bool { + if ($skipIfUnchnged && file_exists($path) && file_get_contents($path) === $contents) { + $io->info("Skipping update to `{$path}`. It already exists and would not change."); + + return true; + } + + return $io->createFile($path, $contents, $forceOverwrite); + } } diff --git a/app/vendor/cakephp/bake/src/Command/CellCommand.php b/app/vendor/cakephp/bake/src/Command/CellCommand.php index 962f6dbd4..989a7ddb7 100644 --- a/app/vendor/cakephp/bake/src/Command/CellCommand.php +++ b/app/vendor/cakephp/bake/src/Command/CellCommand.php @@ -107,7 +107,7 @@ protected function bakeTemplate(string $name, Arguments $args, ConsoleIo $io): v $path = $this->getTemplatePath($args, 'cell'); $path .= implode(DS, [$name, 'display.php']); - $io->createFile($path, '', $args->getOption('force')); + $io->createFile($path, '', $this->force); } /** diff --git a/app/vendor/cakephp/bake/src/Command/ControllerCommand.php b/app/vendor/cakephp/bake/src/Command/ControllerCommand.php index d83e43969..954fd3a73 100644 --- a/app/vendor/cakephp/bake/src/Command/ControllerCommand.php +++ b/app/vendor/cakephp/bake/src/Command/ControllerCommand.php @@ -17,7 +17,6 @@ namespace Bake\Command; use Bake\Utility\TableScanner; -use Bake\Utility\TemplateRenderer; use Cake\Console\Arguments; use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; @@ -177,14 +176,13 @@ public function bakeController(string $controllerName, array $data, Arguments $a 'pluginPath' => null, ]; - $renderer = new TemplateRenderer($this->theme); - $renderer->set($data); - - $contents = $renderer->generate('Bake.Controller/controller'); + $contents = $this->createTemplateRenderer() + ->set($data) + ->generate('Bake.Controller/controller'); $path = $this->getPath($args); $filename = $path . $controllerName . 'Controller.php'; - $io->createFile($filename, $contents, $args->getOption('force')); + $io->createFile($filename, $contents, $this->force); } /** diff --git a/app/vendor/cakephp/bake/src/Command/FixtureCommand.php b/app/vendor/cakephp/bake/src/Command/FixtureCommand.php index 69855d217..5353e0c52 100644 --- a/app/vendor/cakephp/bake/src/Command/FixtureCommand.php +++ b/app/vendor/cakephp/bake/src/Command/FixtureCommand.php @@ -17,13 +17,12 @@ namespace Bake\Command; use Bake\Utility\TableScanner; -use Bake\Utility\TemplateRenderer; use Brick\VarExporter\VarExporter; use Cake\Console\Arguments; use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Core\Configure; -use Cake\Database\Exception; +use Cake\Database\Exception\DatabaseException; use Cake\Database\Schema\TableSchemaInterface; use Cake\Datasource\ConnectionManager; use Cake\Utility\Inflector; @@ -160,7 +159,7 @@ protected function bake(string $model, string $useTable, Arguments $args, Consol try { $data = $this->readSchema($model, $useTable); - } catch (Exception $e) { + } catch (DatabaseException $e) { $this->getTableLocator()->remove($model); $useTable = Inflector::underscore($model); $table = $useTable; @@ -261,13 +260,13 @@ public function generateFixtureFile(Arguments $args, ConsoleIo $io, string $mode $path = $this->getPath($args); $filename = $vars['name'] . 'Fixture.php'; - $renderer = new TemplateRenderer($args->getOption('theme')); - $renderer->set('model', $model); - $renderer->set($vars); - $content = $renderer->generate('Bake.tests/fixture'); + $contents = $this->createTemplateRenderer() + ->set('model', $model) + ->set($vars) + ->generate('Bake.tests/fixture'); $io->out("\n" . sprintf('Baking test fixture for %s...', $model), 1, ConsoleIo::NORMAL); - $io->createFile($path . $filename, $content, $args->getOption('force')); + $io->createFile($path . $filename, $contents, $this->force); $emptyFile = $path . '.gitkeep'; $this->deleteEmptyFile($emptyFile, $io); } diff --git a/app/vendor/cakephp/bake/src/Command/ModelCommand.php b/app/vendor/cakephp/bake/src/Command/ModelCommand.php index d6a19b7d0..0e7c38603 100644 --- a/app/vendor/cakephp/bake/src/Command/ModelCommand.php +++ b/app/vendor/cakephp/bake/src/Command/ModelCommand.php @@ -16,15 +16,15 @@ */ namespace Bake\Command; +use Bake\CodeGen\FileBuilder; use Bake\Utility\TableScanner; -use Bake\Utility\TemplateRenderer; use Cake\Console\Arguments; use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Core\Configure; use Cake\Database\Connection; use Cake\Database\Driver\Sqlserver; -use Cake\Database\Exception; +use Cake\Database\Exception\DatabaseException; use Cake\Database\Schema\CachedCollection; use Cake\Database\Schema\TableSchema; use Cake\Database\Schema\TableSchemaInterface; @@ -227,6 +227,7 @@ public function getAssociations(Table $table, Arguments $args, ConsoleIo $io): a $associations = [ 'belongsTo' => [], + 'hasOne' => [], 'hasMany' => [], 'belongsToMany' => [], ]; @@ -242,6 +243,7 @@ public function getAssociations(Table $table, Arguments $args, ConsoleIo $io): a return $associations; } + $associations = $this->findHasOne($table, $associations); $associations = $this->findHasMany($table, $associations); $associations = $this->findBelongsToMany($table, $associations); @@ -346,11 +348,25 @@ public function findBelongsTo(Table $model, array $associations): array ]; } else { $tmpModelName = $this->_modelNameFromKey($fieldName); - if (!in_array(Inflector::tableize($tmpModelName), $this->_tables, true)) { + if (!$this->getTableLocator()->exists($tmpModelName)) { + $this->getTableLocator()->get( + $tmpModelName, + ['connection' => ConnectionManager::get($this->connection)] + ); + } + $associationTable = $this->getTableLocator()->get($tmpModelName); + $this->getTableLocator()->remove($tmpModelName); + $tables = $this->listAll(); + // Check if association model could not be instantiated as a subclass but a generic Table instance instead + if ( + get_class($associationTable) === Table::class && + !in_array(Inflector::tableize($tmpModelName), $tables, true) + ) { $found = $this->findTableReferencedBy($schema, $fieldName); - if ($found) { - $tmpModelName = Inflector::camelize($found); + if (!$found) { + continue; } + $tmpModelName = Inflector::camelize($found); } $assoc = [ 'alias' => $tmpModelName, @@ -406,13 +422,65 @@ public function findTableReferencedBy(TableSchemaInterface $schema, string $keyF } /** - * Find the hasMany relations and add them to associations list + * Checks whether the given source and target table names are sides + * of a possible many-to-many relation. + * + * @param string $sourceTable The source table name. + * @param string $targetTable The target table name. + * @return bool + */ + public function isPossibleBelongsToManyRelation(string $sourceTable, string $targetTable): bool + { + $tables = $this->listAll(); + + $pregTableName = preg_quote($sourceTable, '/'); + $pregPattern = "/^{$pregTableName}_|_{$pregTableName}$/"; + + if (preg_match($pregPattern, $targetTable) === 1) { + $possibleBTMTargetTable = preg_replace($pregPattern, '', $targetTable); + if (in_array($possibleBTMTargetTable, $tables, true)) { + return true; + } + } + + return false; + } + + /** + * Checks whether the given table schema has a unique constraint for + * the given field. + * + * The check is only going to be satisfied if the constraint has + * only this one specific field. Multi-column constraints will not + * match, as they cannot guarantee uniqueness on the given field. + * + * @param \Cake\Database\Schema\TableSchemaInterface $schema The schema to check for the constraint. + * @param string $keyField The field of the constraint. + * @return bool + */ + public function hasUniqueConstraintFor(TableSchemaInterface $schema, string $keyField): bool + { + foreach ($schema->constraints() as $constraint) { + $constraintInfo = $schema->getConstraint($constraint); + if ( + $constraintInfo['type'] === TableSchema::CONSTRAINT_UNIQUE && + $constraintInfo['columns'] === [$keyField] + ) { + return true; + } + } + + return false; + } + + /** + * Find the hasOne relations and add them to associations list * * @param \Cake\ORM\Table $model Model instance being generated * @param array $associations Array of in progress associations - * @return array Associations with hasMany added in. + * @return array Associations with hasOne added in. */ - public function findHasMany(Table $model, array $associations): array + public function findHasOne(Table $model, array $associations): array { $schema = $model->getSchema(); $primaryKey = $schema->getPrimaryKey(); @@ -421,21 +489,67 @@ public function findHasMany(Table $model, array $associations): array $tables = $this->listAll(); foreach ($tables as $otherTableName) { + if ($this->isPossibleBelongsToManyRelation($tableName, $otherTableName)) { + continue; + } + $otherModel = $this->getTableObject($this->_camelize($otherTableName), $otherTableName); $otherSchema = $otherModel->getSchema(); - $pregTableName = preg_quote($tableName, '/'); - $pregPattern = "/^{$pregTableName}_|_{$pregTableName}$/"; - if (preg_match($pregPattern, $otherTableName) === 1) { - $possibleHABTMTargetTable = preg_replace($pregPattern, '', $otherTableName); - if (in_array($possibleHABTMTargetTable, $tables)) { + foreach ($otherSchema->columns() as $fieldName) { + if (!$this->hasUniqueConstraintFor($otherSchema, $fieldName)) { continue; } + + $assoc = false; + if (!in_array($fieldName, $primaryKey) && $fieldName === $foreignKey) { + $assoc = [ + 'alias' => $otherModel->getAlias(), + 'foreignKey' => $fieldName, + ]; + } + if ($assoc && $this->plugin) { + $assoc['className'] = $this->plugin . '.' . $assoc['alias']; + } + if ($assoc) { + $associations['hasOne'][] = $assoc; + } + } + } + + return $associations; + } + + /** + * Find the hasMany relations and add them to associations list + * + * @param \Cake\ORM\Table $model Model instance being generated + * @param array $associations Array of in progress associations + * @return array Associations with hasMany added in. + */ + public function findHasMany(Table $model, array $associations): array + { + $schema = $model->getSchema(); + $primaryKey = $schema->getPrimaryKey(); + $tableName = $schema->name(); + $foreignKey = $this->_modelKey($tableName); + + $tables = $this->listAll(); + foreach ($tables as $otherTableName) { + if ($this->isPossibleBelongsToManyRelation($tableName, $otherTableName)) { + continue; } + $otherModel = $this->getTableObject($this->_camelize($otherTableName), $otherTableName); + $otherSchema = $otherModel->getSchema(); + foreach ($otherSchema->columns() as $fieldName) { $assoc = false; - if (!in_array($fieldName, $primaryKey) && $fieldName === $foreignKey) { + if ( + !in_array($fieldName, $primaryKey) && + $fieldName === $foreignKey && + !$this->hasUniqueConstraintFor($otherSchema, $fieldName) + ) { $assoc = [ 'alias' => $otherModel->getAlias(), 'foreignKey' => $fieldName, @@ -683,12 +797,19 @@ public function getValidation(Table $model, array $associations, Arguments $args $validate = []; $primaryKey = $schema->getPrimaryKey(); + $foreignKeys = []; + if (isset($associations['belongsTo'])) { + foreach ($associations['belongsTo'] as $assoc) { + $foreignKeys[] = $assoc['foreignKey']; + } + } foreach ($fields as $fieldName) { // Skip primary key if (in_array($fieldName, $primaryKey, true)) { continue; } $field = $schema->getColumn($fieldName); + $field['isForeignKey'] = in_array($fieldName, $foreignKeys, true); $validation = $this->fieldValidation($schema, $fieldName, $field, $primaryKey); if ($validation) { $validate[$fieldName] = $validation; @@ -776,7 +897,8 @@ public function fieldValidation( 'args' => [], ]; } else { - if ($metaData['default'] === null || $metaData['default'] === false) { + // FKs shouldn't be required on create to allow e.g. save calls with hasMany associations to create entities + if (($metaData['default'] === null || $metaData['default'] === false) && !$metaData['isForeignKey']) { $validation['requirePresence'] = [ 'rule' => 'requirePresence', 'args' => ['create'], @@ -956,7 +1078,7 @@ public function getCounterCache(Table $model): array try { $otherSchema = $otherModel->getSchema(); - } catch (Exception $e) { + } catch (DatabaseException $e) { continue; } @@ -985,7 +1107,9 @@ public function bakeEntity(Table $model, array $data, Arguments $args, ConsoleIo if ($args->getOption('no-entity')) { return; } + $name = $this->_entityName($model->getAlias()); + $io->out("\n" . sprintf('Baking entity class for %s...', $name), 1, ConsoleIo::NORMAL); $namespace = Configure::read('App.namespace'); $pluginPath = ''; @@ -994,22 +1118,28 @@ public function bakeEntity(Table $model, array $data, Arguments $args, ConsoleIo $pluginPath = $this->plugin . '.'; } + $path = $this->getPath($args); + $filename = $path . 'Entity' . DS . $name . '.php'; + + $parsedFile = null; + if ($args->getOption('update')) { + $parsedFile = $this->parseFile($filename); + } + $data += [ 'name' => $name, 'namespace' => $namespace, 'plugin' => $this->plugin, 'pluginPath' => $pluginPath, 'primaryKey' => [], + 'fileBuilder' => new FileBuilder($io, "{$namespace}\Model\Entity", $parsedFile), ]; - $renderer = new TemplateRenderer($this->theme); - $renderer->set($data); - $out = $renderer->generate('Bake.Model/entity'); + $contents = $this->createTemplateRenderer() + ->set($data) + ->generate('Bake.Model/entity'); - $path = $this->getPath($args); - $filename = $path . 'Entity' . DS . $name . '.php'; - $io->out("\n" . sprintf('Baking entity class for %s...', $name), 1, ConsoleIo::NORMAL); - $io->createFile($filename, $out, $args->getOption('force')); + $this->writeFile($io, $filename, $contents, $this->force); $emptyFile = $path . 'Entity' . DS . '.gitkeep'; $this->deleteEmptyFile($emptyFile, $io); @@ -1030,13 +1160,23 @@ public function bakeTable(Table $model, array $data, Arguments $args, ConsoleIo return; } + $name = $model->getAlias(); + $io->out("\n" . sprintf('Baking table class for %s...', $name), 1, ConsoleIo::NORMAL); + $namespace = Configure::read('App.namespace'); $pluginPath = ''; if ($this->plugin) { $namespace = $this->_pluginNamespace($this->plugin); } - $name = $model->getAlias(); + $path = $this->getPath($args); + $filename = $path . 'Table' . DS . $name . 'Table.php'; + + $parsedFile = null; + if ($args->getOption('update')) { + $parsedFile = $this->parseFile($filename); + } + $entity = $this->_entityName($model->getAlias()); $data += [ 'plugin' => $this->plugin, @@ -1052,16 +1192,14 @@ public function bakeTable(Table $model, array $data, Arguments $args, ConsoleIo 'rulesChecker' => [], 'behaviors' => [], 'connection' => $this->connection, + 'fileBuilder' => new FileBuilder($io, "{$namespace}\Model\Table", $parsedFile), ]; - $renderer = new TemplateRenderer($this->theme); - $renderer->set($data); - $out = $renderer->generate('Bake.Model/table'); + $contents = $this->createTemplateRenderer() + ->set($data) + ->generate('Bake.Model/table'); - $path = $this->getPath($args); - $filename = $path . 'Table' . DS . $name . 'Table.php'; - $io->out("\n" . sprintf('Baking table class for %s...', $name), 1, ConsoleIo::NORMAL); - $io->createFile($filename, $out, $args->getOption('force')); + $this->writefile($io, $filename, $contents, $this->force); // Work around composer caching that classes/files do not exist. // Check for the file as it might not exist in tests. @@ -1140,6 +1278,9 @@ public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionPar )->addArgument('name', [ 'help' => 'Name of the model to bake (without the Table suffix). ' . 'You can use Plugin.name to bake plugin models.', + ])->addOption('update', [ + 'boolean' => true, + 'help' => 'Update generated methods in existing files. If the file doesn\'t exist it will be created.', ])->addOption('table', [ 'help' => 'The table name to use if you have non-conventional table names.', ])->addOption('no-entity', [ diff --git a/app/vendor/cakephp/bake/src/Command/PluginCommand.php b/app/vendor/cakephp/bake/src/Command/PluginCommand.php index 2479e1068..aa9f8103e 100644 --- a/app/vendor/cakephp/bake/src/Command/PluginCommand.php +++ b/app/vendor/cakephp/bake/src/Command/PluginCommand.php @@ -174,17 +174,18 @@ protected function _generateFiles( true ); - $renderer = new TemplateRenderer($args->getOption('theme')); - $renderer->set([ - 'package' => $package, - 'namespace' => $namespace, - 'baseNamespace' => $baseNamespace, - 'plugin' => $pluginName, - 'routePath' => Inflector::dasherize($pluginName), - 'path' => $path, - 'root' => ROOT, - 'cakeVersion' => $composerConfig['require']['cakephp/cakephp'], - ]); + $renderer = $this->createTemplateRenderer() + ->set([ + 'name' => $name, + 'package' => $package, + 'namespace' => $namespace, + 'baseNamespace' => $baseNamespace, + 'plugin' => $pluginName, + 'routePath' => Inflector::dasherize($pluginName), + 'path' => $path, + 'root' => ROOT, + 'cakeVersion' => $composerConfig['require']['cakephp/cakephp'], + ]); $root = $path . $pluginName . DS; @@ -202,7 +203,7 @@ protected function _generateFiles( $templatesPath = array_shift($paths) . BakeView::BAKE_TEMPLATE_FOLDER . '/Plugin'; if (is_dir($templatesPath)) { $templates = array_keys(iterator_to_array( - $fs->findRecursive($templatesPath, '/.*\.(twig|php)/') + $fs->findRecursive($templatesPath, '/\.twig$/') )); } } while (!$templates); @@ -211,7 +212,11 @@ protected function _generateFiles( foreach ($templates as $template) { $template = substr($template, strrpos($template, 'Plugin' . DIRECTORY_SEPARATOR) + 7, -4); $template = rtrim($template, '.'); - $this->_generateFile($renderer, $template, $root, $io); + $filename = $template; + if ($filename === 'src/Plugin.php') { + $filename = 'src/' . $name . 'Plugin.php'; + } + $this->_generateFile($renderer, $template, $root, $filename, $io); } } @@ -221,6 +226,7 @@ protected function _generateFiles( * @param \Bake\Utility\TemplateRenderer $renderer The renderer to use. * @param string $template The template to render * @param string $root The path to the plugin's root + * @param string $filename Filename to generate. * @param \Cake\Console\ConsoleIo $io The io instance. * @return void */ @@ -228,11 +234,12 @@ protected function _generateFile( TemplateRenderer $renderer, string $template, string $root, + string $filename, ConsoleIo $io ): void { $io->out(sprintf('Generating %s file...', $template)); $out = $renderer->generate('Bake.Plugin/' . $template); - $io->createFile($root . $template, $out); + $io->createFile($root . $filename, $out); } /** @@ -270,7 +277,7 @@ protected function _modifyAutoloader( $io->out('Modifying composer autoloader'); $out = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n"; - $io->createFile($file, $out, (bool)$args->getOption('force')); + $io->createFile($file, $out, $this->force); $composer = $this->findComposer($args, $io); diff --git a/app/vendor/cakephp/bake/src/Command/SimpleBakeCommand.php b/app/vendor/cakephp/bake/src/Command/SimpleBakeCommand.php index b48aa4a3a..8e114c149 100644 --- a/app/vendor/cakephp/bake/src/Command/SimpleBakeCommand.php +++ b/app/vendor/cakephp/bake/src/Command/SimpleBakeCommand.php @@ -16,7 +16,6 @@ */ namespace Bake\Command; -use Bake\Utility\TemplateRenderer; use Cake\Console\Arguments; use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; @@ -100,13 +99,13 @@ public function execute(Arguments $args, ConsoleIo $io): ?int */ protected function bake(string $name, Arguments $args, ConsoleIo $io): void { - $renderer = new TemplateRenderer($args->getOption('theme')); - $renderer->set('name', $name); - $renderer->set($this->templateData($args)); - $contents = $renderer->generate($this->template()); + $contents = $this->createTemplateRenderer() + ->set('name', $name) + ->set($this->templateData($args)) + ->generate($this->template()); $filename = $this->getPath($args) . $this->fileName($name); - $io->createFile($filename, $contents, (bool)$args->getOption('force')); + $io->createFile($filename, $contents, $this->force); $emptyFile = $this->getPath($args) . '.gitkeep'; $this->deleteEmptyFile($emptyFile, $io); diff --git a/app/vendor/cakephp/bake/src/Command/TemplateCommand.php b/app/vendor/cakephp/bake/src/Command/TemplateCommand.php index 4b8ea3629..8a4e3de0c 100644 --- a/app/vendor/cakephp/bake/src/Command/TemplateCommand.php +++ b/app/vendor/cakephp/bake/src/Command/TemplateCommand.php @@ -18,7 +18,6 @@ use Bake\Utility\Model\AssociationFilter; use Bake\Utility\TableScanner; -use Bake\Utility\TemplateRenderer; use Cake\Console\Arguments; use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; @@ -85,6 +84,13 @@ class TemplateCommand extends BakeCommand */ public $path; + /** + * Output extension + * + * @var string + */ + public $ext = 'php'; + /** * Override initialize * @@ -351,15 +357,16 @@ public function bake( $content = $this->getContent($args, $io, $template); } if (empty($content)) { - $io->err("No generated content for '{$template}.php', not generating template."); + // phpcs:ignore Generic.Files.LineLength + $io->err("No generated content for '{$template}.{$this->ext}', not generating template."); return; } $path = $this->getTemplatePath($args); - $filename = $path . Inflector::underscore($outputFile) . '.php'; + $filename = $path . Inflector::underscore($outputFile) . '.' . $this->ext; $io->out("\n" . sprintf('Baking `%s` view template file...', $outputFile), 1, ConsoleIo::NORMAL); - $io->createFile($filename, $content, $args->getOption('force')); + $io->createFile($filename, $content, $this->force); } /** @@ -386,10 +393,10 @@ public function getContent(Arguments $args, ConsoleIo $io, string $action, ?arra $vars['fields'] = array_diff($vars['fields'], $vars['hidden']); } - $renderer = new TemplateRenderer($args->getOption('theme')); - $renderer->set('action', $action); - $renderer->set('plugin', $this->plugin); - $renderer->set($vars); + $renderer = $this->createTemplateRenderer() + ->set('action', $action) + ->set('plugin', $this->plugin) + ->set($vars); $indexColumns = 0; if ($action === 'index' && $args->getOption('index-columns') !== null) { diff --git a/app/vendor/cakephp/bake/src/Command/TestCommand.php b/app/vendor/cakephp/bake/src/Command/TestCommand.php index 6158ec9b7..7df61a610 100644 --- a/app/vendor/cakephp/bake/src/Command/TestCommand.php +++ b/app/vendor/cakephp/bake/src/Command/TestCommand.php @@ -16,14 +16,13 @@ */ namespace Bake\Command; -use Bake\Utility\TemplateRenderer; use Cake\Console\Arguments; use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Console\Shell; use Cake\Controller\Controller; use Cake\Core\Configure; -use Cake\Core\Exception\Exception; +use Cake\Core\Exception\CakeException; use Cake\Core\Plugin; use Cake\Filesystem\Filesystem; use Cake\Http\Response; @@ -279,32 +278,32 @@ public function bake(string $type, string $className, Arguments $args, ConsoleIo $io->out("\n" . sprintf('Baking test case for %s ...', $fullClassName), 1, Shell::QUIET); - $renderer = new TemplateRenderer($this->theme); - $renderer->set('fixtures', $this->_fixtures); - $renderer->set('plugin', $this->plugin); - $renderer->set(compact( - 'subject', - 'className', - 'properties', - 'methods', - 'type', - 'fullClassName', - 'mock', - 'preConstruct', - 'postConstruct', - 'construction', - 'uses', - 'baseNamespace', - 'subNamespace', - 'namespace' - )); - $out = $renderer->generate('Bake.tests/test_case'); + $contents = $this->createTemplateRenderer() + ->set('fixtures', $this->_fixtures) + ->set('plugin', $this->plugin) + ->set(compact( + 'subject', + 'className', + 'properties', + 'methods', + 'type', + 'fullClassName', + 'mock', + 'preConstruct', + 'postConstruct', + 'construction', + 'uses', + 'baseNamespace', + 'subNamespace', + 'namespace' + )) + ->generate('Bake.tests/test_case'); $filename = $this->testCaseFileName($type, $fullClassName); $emptyFile = dirname($filename) . DS . '.gitkeep'; $this->deleteEmptyFile($emptyFile, $io); - if ($io->createFile($filename, $out, $args->getOption('force'))) { - return $out; + if ($io->createFile($filename, $contents, $this->force)) { + return $contents; } return false; @@ -399,12 +398,12 @@ public function getSubspacePath(string $type): string * * @param string $type The type of thing having a test generated. * @return string - * @throws \Cake\Core\Exception\Exception When invalid object types are requested. + * @throws \Cake\Core\Exception\CakeException When invalid object types are requested. */ public function mapType(string $type): string { if (empty($this->classTypes[$type])) { - throw new Exception('Invalid object type: ' . $type); + throw new CakeException('Invalid object type: ' . $type); } return $this->classTypes[$type]; diff --git a/app/vendor/cakephp/bake/src/Utility/CommonOptionsTrait.php b/app/vendor/cakephp/bake/src/Utility/CommonOptionsTrait.php index 2ec2d448d..4d4b080ad 100644 --- a/app/vendor/cakephp/bake/src/Utility/CommonOptionsTrait.php +++ b/app/vendor/cakephp/bake/src/Utility/CommonOptionsTrait.php @@ -31,7 +31,7 @@ trait CommonOptionsTrait { /** - * @var string|null + * @var string */ public $plugin; @@ -45,6 +45,11 @@ trait CommonOptionsTrait */ public $connection; + /** + * @var bool + */ + public $force = false; + /** * Pull common/frequently used arguments & options into properties * so that method signatures can be simpler. @@ -70,6 +75,7 @@ protected function extractCommonProperties(Arguments $args): void $this->theme = $args->getOption('theme'); $this->connection = $args->getOption('connection'); + $this->force = $args->getOption('force'); } /** @@ -105,6 +111,7 @@ protected function _setCommonOptions(ConsoleOptionParser $parser): ConsoleOption ])->addOption('force', [ 'short' => 'f', 'boolean' => true, + 'default' => 'false', 'help' => 'Force overwriting existing files without prompting.', ])->addOption('connection', [ 'short' => 'c', diff --git a/app/vendor/cakephp/bake/src/Utility/TemplateRenderer.php b/app/vendor/cakephp/bake/src/Utility/TemplateRenderer.php index bffec7ae2..10abc01ef 100644 --- a/app/vendor/cakephp/bake/src/Utility/TemplateRenderer.php +++ b/app/vendor/cakephp/bake/src/Utility/TemplateRenderer.php @@ -42,7 +42,7 @@ class TemplateRenderer /** * Template theme * - * @var string + * @var string|null */ protected $theme; @@ -51,9 +51,9 @@ class TemplateRenderer * * @param ?string $theme The template theme/plugin to use. */ - public function __construct(?string $theme = '') + public function __construct(?string $theme = null) { - $this->theme = $theme ?? ''; + $this->theme = $theme; } /** diff --git a/app/vendor/cakephp/bake/src/View/BakeView.php b/app/vendor/cakephp/bake/src/View/BakeView.php index b359c5e14..2700cb679 100644 --- a/app/vendor/cakephp/bake/src/View/BakeView.php +++ b/app/vendor/cakephp/bake/src/View/BakeView.php @@ -45,8 +45,9 @@ class BakeView extends TwigView public function initialize(): void { $this->setConfig('environment', [ - 'cache' => false, - 'strict_variables' => Configure::read('Bake.twigStrictVariables', false), + 'autoescape' => false, + 'cache' => false, + 'strict_variables' => Configure::read('Bake.twigStrictVariables', false), ]); parent::initialize(); @@ -69,7 +70,7 @@ public function initialize(): void * * @param string|null $template Name of view file to use, or a template string to render * @param string|false|null $layout Layout to use. Not used, for consistency with other views only - * @throws \Cake\Core\Exception\Exception If there is an error in the view. + * @throws \Cake\Core\Exception\CakeException If there is an error in the view. * @return string Rendered content. */ public function render(?string $template = null, $layout = null): string diff --git a/app/vendor/cakephp/bake/src/View/Helper/BakeHelper.php b/app/vendor/cakephp/bake/src/View/Helper/BakeHelper.php index 07ab0965a..8dc0d899f 100644 --- a/app/vendor/cakephp/bake/src/View/Helper/BakeHelper.php +++ b/app/vendor/cakephp/bake/src/View/Helper/BakeHelper.php @@ -3,6 +3,7 @@ namespace Bake\View\Helper; +use Bake\CodeGen\ImportHelper; use Bake\Utility\Model\AssociationFilter; use Brick\VarExporter\VarExporter; use Cake\Core\Configure; @@ -456,6 +457,115 @@ public function escapeArguments(array $args): array }, $args); } + /** + * Generates block of use statements from imports. + * + * @param array $imports Class imports + * @return string + */ + public function getClassUses(array $imports): string + { + $uses = []; + + $imports = ImportHelper::normalize($imports); + asort($imports, SORT_STRING | SORT_FLAG_CASE); + foreach ($imports as $alias => $type) { + $uses[] = 'use ' . $this->getUseType($alias, $type) . ';'; + } + + return implode("\n", $uses); + } + + /** + * Generates block of suse statements from function imports. + * + * @param array $imports Function imports + * @return string + */ + public function getFunctionUses(array $imports): string + { + $uses = []; + + $imports = ImportHelper::normalize($imports); + asort($imports, SORT_STRING | SORT_FLAG_CASE); + foreach ($imports as $alias => $type) { + $uses[] = 'use function ' . $this->getUseType($alias, $type) . ';'; + } + + return implode("\n", $uses); + } + + /** + * Generates block of use statements from const imports. + * + * @param array $imports constImports + * @return string + */ + public function getConstUses(array $imports): string + { + $uses = []; + + $imports = ImportHelper::normalize($imports); + asort($imports, SORT_STRING | SORT_FLAG_CASE); + foreach ($imports as $alias => $type) { + $uses[] = 'use const ' . $this->getUseType($alias, $type) . ';'; + } + + return implode("\n", $uses); + } + + /** + * Gets use type string from name and alias. + * + * @param string $alias Import alias + * @param string $name Import name + * @return string + */ + protected function getUseType(string $alias, string $name): string + { + if ($name == $alias || substr($name, -strlen("\\{$alias}")) === "\\{$alias}") { + return $name; + } + + return "{$name} as {$alias}"; + } + + /** + * Concats strings together. + * + * @param string $delimiter Delimiter to separate strings + * @param array|string> $strings Strings to concatenate + * @param string $prefix Code to prepend if final output is not empty + * @param string $suffix Code to append if final output is not empty + * @return string + */ + public function concat( + string $delimiter, + array $strings, + string $prefix = '', + string $suffix = '' + ): string { + $output = implode( + $delimiter, + array_map(function ($string) use ($delimiter) { + if (is_string($string)) { + return $string; + } + + return implode($delimiter, array_filter($string)); + }, array_filter($strings)) + ); + + if ($prefix && !empty($output)) { + $output = $prefix . $output; + } + if ($suffix && !empty($output)) { + $output .= $suffix; + } + + return $output; + } + /** * To be mocked elsewhere... * diff --git a/app/vendor/cakephp/bake/templates/bake/Command/command.twig b/app/vendor/cakephp/bake/templates/bake/Command/command.twig index e1c7c91e5..9eeafa29e 100644 --- a/app/vendor/cakephp/bake/templates/bake/Command/command.twig +++ b/app/vendor/cakephp/bake/templates/bake/Command/command.twig @@ -13,15 +13,15 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} - - + diff --git a/app/vendor/cakephp/bake/templates/bake/Plugin/src/Controller/AppController.php.twig b/app/vendor/cakephp/bake/templates/bake/Plugin/src/Controller/AppController.php.twig index dcdc78cde..c03c62bb0 100644 --- a/app/vendor/cakephp/bake/templates/bake/Plugin/src/Controller/AppController.php.twig +++ b/app/vendor/cakephp/bake/templates/bake/Plugin/src/Controller/AppController.php.twig @@ -13,12 +13,12 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} -loadSqlFiles('tests/schema.sql', 'test'); diff --git a/app/vendor/cakephp/bake/templates/bake/Shell/helper.twig b/app/vendor/cakephp/bake/templates/bake/Shell/helper.twig index 171b4cfa8..d52832442 100644 --- a/app/vendor/cakephp/bake/templates/bake/Shell/helper.twig +++ b/app/vendor/cakephp/bake/templates/bake/Shell/helper.twig @@ -13,12 +13,12 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} - ${{ pluralVar }} */ ?>
diff --git a/app/vendor/cakephp/bake/templates/bake/View/cell.twig b/app/vendor/cakephp/bake/templates/bake/View/cell.twig index 6ba66be8c..8f0a8acd4 100644 --- a/app/vendor/cakephp/bake/templates/bake/View/cell.twig +++ b/app/vendor/cakephp/bake/templates/bake/View/cell.twig @@ -13,12 +13,12 @@ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ #} - ['primary' => ['type' => 'primary', 'columns' => ['id']]], ], + [ + 'table' => 'todo_reminders', + 'columns' => [ + 'id' => ['type' => 'integer', 'null' => false], + 'todo_item_id' => ['type' => 'integer', 'null' => false], + 'triggered_at' => ['type' => 'datetime'], + ], + 'constraints' => [ + 'primary' => ['type' => 'primary', 'columns' => ['id']], + 'unique_todo_item' => ['type' => 'unique', 'columns' => ['todo_item_id']], + ], + ], [ 'table' => 'todo_labels', 'columns' => [ @@ -511,4 +523,15 @@ ], ], ], + [ + 'table' => 'self_referencing_unique_keys', + 'columns' => [ + 'id' => ['type' => 'integer'], + 'parent_id' => ['type' => 'integer'], + ], + 'constraints' => [ + 'primary' => ['type' => 'primary', 'columns' => ['id']], + 'unique_self_referencing_parent' => ['type' => 'unique', 'columns' => ['parent_id']], + ], + ], ]; diff --git a/app/vendor/cakephp/cakephp-codesniffer/.github/workflows/ci.yml b/app/vendor/cakephp/cakephp-codesniffer/.github/workflows/ci.yml index f3149de54..a9c5b62b7 100644 --- a/app/vendor/cakephp/cakephp-codesniffer/.github/workflows/ci.yml +++ b/app/vendor/cakephp/cakephp-codesniffer/.github/workflows/ci.yml @@ -54,9 +54,9 @@ jobs: composer install fi - - name: Configure PHPUnit matcher + - name: Setup problem matchers for PHPUnit if: matrix.php-version == '7.4' - uses: mheap/phpunit-matcher-action@master + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - name: Run PHPUnit run: | diff --git a/app/vendor/cakephp/cakephp-codesniffer/CakePHP/ruleset.xml b/app/vendor/cakephp/cakephp-codesniffer/CakePHP/ruleset.xml index b85444eba..543481aa8 100644 --- a/app/vendor/cakephp/cakephp-codesniffer/CakePHP/ruleset.xml +++ b/app/vendor/cakephp/cakephp-codesniffer/CakePHP/ruleset.xml @@ -23,6 +23,7 @@ */config/Migrations/* + */config/Seeds/* */config/* diff --git a/app/vendor/cakephp/cakephp-codesniffer/composer.json b/app/vendor/cakephp/cakephp-codesniffer/composer.json index 2fd121bee..bb1e9380f 100644 --- a/app/vendor/cakephp/cakephp-codesniffer/composer.json +++ b/app/vendor/cakephp/cakephp-codesniffer/composer.json @@ -19,7 +19,7 @@ }, "require": { "php": ">=7.2.0", - "slevomat/coding-standard": "^6.3.6 || ^7.0", + "slevomat/coding-standard": "^6.3.6 || ^7.0 || ^8.0", "squizlabs/php_codesniffer": "^3.6" }, "require-dev": { @@ -30,6 +30,11 @@ "CakePHP\\": "CakePHP/" } }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + }, "scripts": { "add-standard" : "phpcs --config-set installed_paths $(pwd)", "test": [ diff --git a/app/vendor/cakephp/cakephp/VERSION.txt b/app/vendor/cakephp/cakephp/VERSION.txt index 181b6fa38..5a8d53355 100644 --- a/app/vendor/cakephp/cakephp/VERSION.txt +++ b/app/vendor/cakephp/cakephp/VERSION.txt @@ -16,4 +16,4 @@ // @license https://opensource.org/licenses/mit-license.php MIT License // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -4.3.8 +4.4.8 diff --git a/app/vendor/cakephp/cakephp/composer.json b/app/vendor/cakephp/cakephp/composer.json index 9e5e15436..be3c472cc 100644 --- a/app/vendor/cakephp/cakephp/composer.json +++ b/app/vendor/cakephp/cakephp/composer.json @@ -22,14 +22,14 @@ } ], "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", "cakephp/chronos": "^2.2", "composer/ca-bundle": "^1.2", "laminas/laminas-diactoros": "^2.2.2", - "laminas/laminas-httphandlerrunner": "^1.1", + "laminas/laminas-httphandlerrunner": "^1.1 || ^2.0", "league/container": "^4.2.0", "psr/container": "^1.1 || ^2.0", "psr/http-client": "^1.0", @@ -97,7 +97,7 @@ "TestPluginTwo\\": "tests/test_app/Plugin/TestPluginTwo/src/", "Company\\TestPluginThree\\": "tests/test_app/Plugin/Company/TestPluginThree/src/", "Company\\TestPluginThree\\Test\\": "tests/test_app/Plugin/Company/TestPluginThree/tests/", - "ParentPlugin\\": "tests/test_app/Plugin/ParentPlugin/src/" + "Named\\": "tests/test_app/Plugin/Named/src/" } }, "scripts": { @@ -115,7 +115,7 @@ ], "stan-tests": "phpstan.phar analyze -c tests/phpstan.neon", "stan-baseline": "phpstan.phar --generate-baseline", - "stan-setup": "cp composer.json composer.backup && composer require --dev symfony/polyfill-php81 phpstan/phpstan:~1.5.0 psalm/phar:~4.22.0 && mv composer.backup composer.json", + "stan-setup": "cp composer.json composer.backup && composer require --dev symfony/polyfill-php81 phpstan/phpstan:~1.9.0 psalm/phar:~4.30.0 && mv composer.backup composer.json", "lowest": "validate-prefer-lowest", "lowest-setup": "composer update --prefer-lowest --prefer-stable --prefer-dist --no-interaction && cp composer.json composer.backup && composer require --dev dereuromark/composer-prefer-lowest && mv composer.backup composer.json", "test": "phpunit", diff --git a/app/vendor/cakephp/cakephp/config/bootstrap.php b/app/vendor/cakephp/cakephp/config/bootstrap.php index 47b2d402d..da48e6bff 100644 --- a/app/vendor/cakephp/cakephp/config/bootstrap.php +++ b/app/vendor/cakephp/cakephp/config/bootstrap.php @@ -18,7 +18,7 @@ /** * @var float */ -define('TIME_START', (float)microtime(true)); +define('TIME_START', microtime(true)); require CAKE . 'basics.php'; diff --git a/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php b/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php index ed01098e3..da5bcc719 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/CacheEngine.php @@ -18,6 +18,7 @@ use Cake\Core\InstanceConfigTrait; use DateInterval; +use DateTime; use Psr\SimpleCache\CacheInterface; /** @@ -383,7 +384,9 @@ protected function duration($ttl): int return $ttl; } if ($ttl instanceof DateInterval) { - return (int)$ttl->format('%s'); + return (int)DateTime::createFromFormat('U', '0') + ->add($ttl) + ->format('U'); } throw new InvalidArgumentException('TTL values must be one of null, int, \DateInterval'); diff --git a/app/vendor/cakephp/cakephp/src/Cache/Engine/ArrayEngine.php b/app/vendor/cakephp/cakephp/src/Cache/Engine/ArrayEngine.php index 9050537eb..4693c0242 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Engine/ArrayEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Engine/ArrayEngine.php @@ -35,7 +35,7 @@ class ArrayEngine extends CacheEngine * * Structured as [key => [exp => expiration, val => value]] * - * @var array + * @var array */ protected $data = []; diff --git a/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php b/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php index 46a7f187a..35252b98e 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php @@ -17,7 +17,6 @@ namespace Cake\Cache\Engine; use Cake\Cache\CacheEngine; -use Cake\Cache\InvalidArgumentException; use CallbackFilterIterator; use Exception; use FilesystemIterator; @@ -173,6 +172,7 @@ public function get($key, $default = null) /** @psalm-suppress PossiblyNullReference */ $this->_File->rewind(); $time = time(); + /** @psalm-suppress RiskyCast */ $cachetime = (int)$this->_File->current(); if ($cachetime < $time) { @@ -441,14 +441,7 @@ protected function _key($key): string { $key = parent::_key($key); - if (preg_match('/[\/\\<>?:|*"]/', $key)) { - throw new InvalidArgumentException( - "Cache key `{$key}` contains invalid characters. " . - 'You cannot use /, \\, <, >, ?, :, |, *, or " in cache keys.' - ); - } - - return $key; + return rawurlencode($key); } /** diff --git a/app/vendor/cakephp/cakephp/src/Cache/Engine/RedisEngine.php b/app/vendor/cakephp/cakephp/src/Cache/Engine/RedisEngine.php index b7f0fec4b..dc90ef72f 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Engine/RedisEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Engine/RedisEngine.php @@ -47,6 +47,7 @@ class RedisEngine extends CacheEngine * - `port` port number to the Redis server. * - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace * with either another cache config or another application. + * - `scanCount` Number of keys to ask for each scan (default: 10) * - `server` URL or IP to the Redis server host. * - `timeout` timeout in seconds (float). * - `unix_socket` Path to the unix socket file (default: false) @@ -65,6 +66,7 @@ class RedisEngine extends CacheEngine 'server' => '127.0.0.1', 'timeout' => 0, 'unix_socket' => false, + 'scanCount' => 10, ]; /** @@ -227,6 +229,21 @@ public function delete($key): bool return $this->_Redis->del($key) > 0; } + /** + * Delete a key from the cache asynchronously + * + * Just unlink a key from the cache. The actual removal will happen later asynchronously. + * + * @param string $key Identifier for the data + * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed + */ + public function deleteAsync(string $key): bool + { + $key = $this->_key($key); + + return $this->_Redis->unlink($key) > 0; + } + /** * Delete all keys from the cache * @@ -241,7 +258,7 @@ public function clear(): bool $pattern = $this->_config['prefix'] . '*'; while (true) { - $keys = $this->_Redis->scan($iterator, $pattern); + $keys = $this->_Redis->scan($iterator, $pattern, (int)$this->_config['scanCount']); if ($keys === false) { break; @@ -256,6 +273,37 @@ public function clear(): bool return $isAllDeleted; } + /** + * Delete all keys from the cache by a blocking operation + * + * Faster than clear() using unlink method. + * + * @return bool True if the cache was successfully cleared, false otherwise + */ + public function clearBlocking(): bool + { + $this->_Redis->setOption(Redis::OPT_SCAN, (string)Redis::SCAN_RETRY); + + $isAllDeleted = true; + $iterator = null; + $pattern = $this->_config['prefix'] . '*'; + + while (true) { + $keys = $this->_Redis->scan($iterator, $pattern, (int)$this->_config['scanCount']); + + if ($keys === false) { + break; + } + + foreach ($keys as $key) { + $isDeleted = ($this->_Redis->unlink($key) > 0); + $isAllDeleted = $isAllDeleted && $isDeleted; + } + } + + return $isAllDeleted; + } + /** * Write data for key into cache if it doesn't exist already. * If it already exists, it fails and returns false. diff --git a/app/vendor/cakephp/cakephp/src/Cache/composer.json b/app/vendor/cakephp/cakephp/src/Cache/composer.json index 001a8a9dc..96aec1982 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/composer.json +++ b/app/vendor/cakephp/cakephp/src/Cache/composer.json @@ -22,7 +22,7 @@ "source": "https://github.com/cakephp/cache" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0", "psr/simple-cache": "^1.0 || ^2.0" }, diff --git a/app/vendor/cakephp/cakephp/src/Collection/Collection.php b/app/vendor/cakephp/cakephp/src/Collection/Collection.php index d3af8c0f0..147d41302 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/Collection.php +++ b/app/vendor/cakephp/cakephp/src/Collection/Collection.php @@ -17,6 +17,7 @@ namespace Cake\Collection; use ArrayIterator; +use Exception; use IteratorIterator; use Serializable; @@ -120,8 +121,14 @@ public function countKeys(): int */ public function __debugInfo(): array { + try { + $count = $this->count(); + } catch (Exception $e) { + $count = 'An exception occurred while getting count'; + } + return [ - 'count' => $this->count(), + 'count' => $count, ]; } } diff --git a/app/vendor/cakephp/cakephp/src/Collection/composer.json b/app/vendor/cakephp/cakephp/src/Collection/composer.json index 87c05665e..16ec80218 100644 --- a/app/vendor/cakephp/cakephp/src/Collection/composer.json +++ b/app/vendor/cakephp/cakephp/src/Collection/composer.json @@ -23,7 +23,7 @@ "source": "https://github.com/cakephp/collection" }, "require": { - "php": ">=7.2.0" + "php": ">=7.4.0" }, "autoload": { "psr-4": { diff --git a/app/vendor/cakephp/cakephp/src/Command/Command.php b/app/vendor/cakephp/cakephp/src/Command/Command.php index 5c6afc026..1ab0c3c49 100644 --- a/app/vendor/cakephp/cakephp/src/Command/Command.php +++ b/app/vendor/cakephp/cakephp/src/Command/Command.php @@ -30,6 +30,7 @@ * Includes traits that integrate logging * and ORM models to console commands. */ +#[\AllowDynamicProperties] class Command extends BaseCommand { use LocatorAwareTrait; @@ -67,3 +68,10 @@ public function execute(Arguments $args, ConsoleIo $io) { } } + +// phpcs:disable +class_alias( + 'Cake\Command\Command', + 'Cake\Console\Command' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php b/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php index 891f6d8e8..f02b1a70e 100644 --- a/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php +++ b/app/vendor/cakephp/cakephp/src/Command/I18nExtractCommand.php @@ -147,8 +147,6 @@ protected function _getPaths(ConsoleIo $io): void if (strtoupper($response) === 'Q') { $io->err('Extract Aborted'); $this->abort(); - - return; } if (strtoupper($response) === 'D' && count($this->_paths)) { $io->out(); diff --git a/app/vendor/cakephp/cakephp/src/Command/RoutesCheckCommand.php b/app/vendor/cakephp/cakephp/src/Command/RoutesCheckCommand.php index b660e4d68..86245a5c7 100644 --- a/app/vendor/cakephp/cakephp/src/Command/RoutesCheckCommand.php +++ b/app/vendor/cakephp/cakephp/src/Command/RoutesCheckCommand.php @@ -58,7 +58,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int } } - unset($route['_matchedRoute']); + unset($route['_route'], $route['_matchedRoute']); ksort($route); $output = [ diff --git a/app/vendor/cakephp/cakephp/src/Command/RoutesCommand.php b/app/vendor/cakephp/cakephp/src/Command/RoutesCommand.php index e3a20b9f1..fd567611a 100644 --- a/app/vendor/cakephp/cakephp/src/Command/RoutesCommand.php +++ b/app/vendor/cakephp/cakephp/src/Command/RoutesCommand.php @@ -40,9 +40,10 @@ public function execute(Arguments $args, ConsoleIo $io): ?int $header[] = 'Defaults'; } - $output = []; + $availableRoutes = Router::routes(); + $output = $duplicateRoutesCounter = []; - foreach (Router::routes() as $route) { + foreach ($availableRoutes as $route) { $methods = $route->defaults['_method'] ?? ''; $item = [ @@ -52,7 +53,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int $route->defaults['prefix'] ?? '', $route->defaults['controller'] ?? '', $route->defaults['action'] ?? '', - is_string($methods) ? $methods : implode(', ', $route->defaults['_method']), + is_string($methods) ? $methods : implode(', ', $methods), ]; if ($args->getOption('verbose')) { @@ -61,6 +62,11 @@ public function execute(Arguments $args, ConsoleIo $io): ?int } $output[] = $item; + + if (!isset($duplicateRoutesCounter[$route->template])) { + $duplicateRoutesCounter[$route->template] = 0; + } + $duplicateRoutesCounter[$route->template]++; } if ($args->getOption('sort')) { @@ -74,6 +80,31 @@ public function execute(Arguments $args, ConsoleIo $io): ?int $io->helper('table')->output($output); $io->out(); + $duplicateRoutes = []; + + foreach ($availableRoutes as $route) { + if ($duplicateRoutesCounter[$route->template] > 1) { + $methods = $route->defaults['_method'] ?? ''; + + $duplicateRoutes[] = [ + $route->options['_name'] ?? $route->getName(), + $route->template, + $route->defaults['plugin'] ?? '', + $route->defaults['prefix'] ?? '', + $route->defaults['controller'] ?? '', + $route->defaults['action'] ?? '', + is_string($methods) ? $methods : implode(', ', $methods), + ]; + } + } + + if ($duplicateRoutes) { + array_unshift($duplicateRoutes, $header); + $io->warning('The following possible route collisions were detected.'); + $io->helper('table')->output($duplicateRoutes); + $io->out(); + } + return static::CODE_SUCCESS; } diff --git a/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php b/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php index ad4866bfe..c927ccf80 100644 --- a/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php +++ b/app/vendor/cakephp/cakephp/src/Console/BaseCommand.php @@ -65,6 +65,16 @@ public function getName(): string return $this->name; } + /** + * Get the command description. + * + * @return string + */ + public static function getDescription(): string + { + return ''; + } + /** * Get the root command name. * @@ -91,9 +101,8 @@ public static function defaultName(): string $pos = strrpos(static::class, '\\'); /** @psalm-suppress PossiblyFalseOperand */ $name = substr(static::class, $pos + 1, -7); - $name = Inflector::underscore($name); - return $name; + return Inflector::underscore($name); } /** @@ -109,6 +118,7 @@ public function getOptionParser(): ConsoleOptionParser [$root, $name] = explode(' ', $this->name, 2); $parser = new ConsoleOptionParser($name); $parser->setRootName($root); + $parser->setDescription(static::getDescription()); $parser = $this->buildOptionParser($parser); if ($parser->subcommands()) { @@ -153,7 +163,7 @@ public function run(array $argv, ConsoleIo $io): ?int $parser = $this->getOptionParser(); try { - [$options, $arguments] = $parser->parse($argv); + [$options, $arguments] = $parser->parse($argv, $io); $args = new Arguments( $arguments, $options, @@ -233,6 +243,7 @@ abstract public function execute(Arguments $args, ConsoleIo $io); * @param int $code The exit code to use. * @throws \Cake\Console\Exception\StopException * @return void + * @psalm-return never-return */ public function abort(int $code = self::CODE_ERROR): void { diff --git a/app/vendor/cakephp/cakephp/src/Console/Command.php b/app/vendor/cakephp/cakephp/src/Console/Command.php index f593ff9bc..9494b024a 100644 --- a/app/vendor/cakephp/cakephp/src/Console/Command.php +++ b/app/vendor/cakephp/cakephp/src/Console/Command.php @@ -4,8 +4,4 @@ /** * @deprecated 4.0.0 Use {@link \Cake\Command\Command} instead. */ - -class_alias( - 'Cake\Command\Command', - 'Cake\Console\Command' -); +class_exists('Cake\Command\Command'); diff --git a/app/vendor/cakephp/cakephp/src/Console/Command/HelpCommand.php b/app/vendor/cakephp/cakephp/src/Console/Command/HelpCommand.php index 9999518f7..8f96f1a86 100644 --- a/app/vendor/cakephp/cakephp/src/Console/Command/HelpCommand.php +++ b/app/vendor/cakephp/cakephp/src/Console/Command/HelpCommand.php @@ -112,7 +112,10 @@ protected function asText(ConsoleIo $io, iterable $commands): void [, $shortestName] = explode('.', $shortestName, 2); } - $grouped[$prefix][] = $shortestName; + $grouped[$prefix][] = [ + 'name' => $shortestName, + 'description' => is_subclass_of($class, BaseCommand::class) ? $class::getDescription() : '', + ]; } ksort($grouped); @@ -122,8 +125,11 @@ protected function asText(ConsoleIo $io, iterable $commands): void foreach ($grouped as $prefix => $names) { $io->out("{$prefix}:"); sort($names); - foreach ($names as $name) { - $io->out(' - ' . $name); + foreach ($names as $data) { + $io->out(' - ' . $data['name']); + if ($data['description']) { + $io->info(str_pad(" \u{2514}", 13, "\u{2500}") . ' ' . $data['description']); + } } $io->out(''); } diff --git a/app/vendor/cakephp/cakephp/src/Console/CommandCollection.php b/app/vendor/cakephp/cakephp/src/Console/CommandCollection.php index a3ac801c5..47aa17db2 100644 --- a/app/vendor/cakephp/cakephp/src/Console/CommandCollection.php +++ b/app/vendor/cakephp/cakephp/src/Console/CommandCollection.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Console; diff --git a/app/vendor/cakephp/cakephp/src/Console/CommandCollectionAwareInterface.php b/app/vendor/cakephp/cakephp/src/Console/CommandCollectionAwareInterface.php index 7892bc677..5c2e457c4 100644 --- a/app/vendor/cakephp/cakephp/src/Console/CommandCollectionAwareInterface.php +++ b/app/vendor/cakephp/cakephp/src/Console/CommandCollectionAwareInterface.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Console; diff --git a/app/vendor/cakephp/cakephp/src/Console/CommandFactory.php b/app/vendor/cakephp/cakephp/src/Console/CommandFactory.php index 20c8367a2..364bb4b16 100644 --- a/app/vendor/cakephp/cakephp/src/Console/CommandFactory.php +++ b/app/vendor/cakephp/cakephp/src/Console/CommandFactory.php @@ -2,15 +2,15 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Console; diff --git a/app/vendor/cakephp/cakephp/src/Console/CommandFactoryInterface.php b/app/vendor/cakephp/cakephp/src/Console/CommandFactoryInterface.php index 7be77a84f..67284a416 100644 --- a/app/vendor/cakephp/cakephp/src/Console/CommandFactoryInterface.php +++ b/app/vendor/cakephp/cakephp/src/Console/CommandFactoryInterface.php @@ -2,15 +2,15 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Console; diff --git a/app/vendor/cakephp/cakephp/src/Console/CommandRunner.php b/app/vendor/cakephp/cakephp/src/Console/CommandRunner.php index 4d6fdfd43..8e84e7ea0 100644 --- a/app/vendor/cakephp/cakephp/src/Console/CommandRunner.php +++ b/app/vendor/cakephp/cakephp/src/Console/CommandRunner.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Console; diff --git a/app/vendor/cakephp/cakephp/src/Console/CommandScanner.php b/app/vendor/cakephp/cakephp/src/Console/CommandScanner.php index a704e4112..d086679af 100644 --- a/app/vendor/cakephp/cakephp/src/Console/CommandScanner.php +++ b/app/vendor/cakephp/cakephp/src/Console/CommandScanner.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Console; diff --git a/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php b/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php index 977aa7071..cac0d22f5 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php +++ b/app/vendor/cakephp/cakephp/src/Console/ConsoleErrorHandler.php @@ -1,10 +1,7 @@ usage() === $argument->usage(); + return $this->name() === $argument->name() && + $this->usage() === $argument->usage(); } /** diff --git a/app/vendor/cakephp/cakephp/src/Console/ConsoleInputOption.php b/app/vendor/cakephp/cakephp/src/Console/ConsoleInputOption.php index 21a253dd8..b6853726c 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ConsoleInputOption.php +++ b/app/vendor/cakephp/cakephp/src/Console/ConsoleInputOption.php @@ -76,6 +76,13 @@ class ConsoleInputOption */ protected $_choices; + /** + * The prompt string + * + * @var string|null + */ + protected $prompt; + /** * Is the option required. * @@ -94,6 +101,7 @@ class ConsoleInputOption * @param array $choices Valid choices for this option. * @param bool $multiple Whether this option can accept multiple value definition. * @param bool $required Whether this option is required or not. + * @param string|null $prompt The prompt string. * @throws \Cake\Console\Exception\ConsoleException */ public function __construct( @@ -104,7 +112,8 @@ public function __construct( $default = null, array $choices = [], bool $multiple = false, - bool $required = false + bool $required = false, + ?string $prompt = null ) { $this->_name = $name; $this->_short = $short; @@ -113,6 +122,7 @@ public function __construct( $this->_choices = $choices; $this->_multiple = $multiple; $this->required = $required; + $this->prompt = $prompt; if ($isBoolean) { $this->_default = (bool)$default; @@ -125,6 +135,12 @@ public function __construct( sprintf('Short option "%s" is invalid, short options must be one letter.', $this->_short) ); } + if (isset($this->_default) && $this->prompt) { + throw new ConsoleException( + 'You cannot set both `prompt` and `default` options. ' . + 'Use either a static `default` or interactive `prompt`' + ); + } } /** @@ -266,6 +282,26 @@ public function validChoice($value): bool return true; } + /** + * Get the list of choices this option has. + * + * @return array + */ + public function choices(): array + { + return $this->_choices; + } + + /** + * Get the prompt string + * + * @return string + */ + public function prompt(): string + { + return (string)$this->prompt; + } + /** * Append the option's XML into the parent. * diff --git a/app/vendor/cakephp/cakephp/src/Console/ConsoleIo.php b/app/vendor/cakephp/cakephp/src/Console/ConsoleIo.php index 704f7951a..583873800 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ConsoleIo.php +++ b/app/vendor/cakephp/cakephp/src/Console/ConsoleIo.php @@ -298,6 +298,7 @@ public function success($message, int $newlines = 1, int $level = self::NORMAL): * @param string $message Error message. * @param int $code Error code. * @return void + * @psalm-return never-return * @throws \Cake\Console\Exception\StopException */ public function abort($message, $code = CommandInterface::CODE_ERROR): void diff --git a/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php b/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php index 77044ffce..b20775a1d 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php +++ b/app/vendor/cakephp/cakephp/src/Console/ConsoleOptionParser.php @@ -245,7 +245,7 @@ public static function buildFromArray(array $spec, bool $defaultOptions = true) */ public function toArray(): array { - $result = [ + return [ 'command' => $this->_command, 'arguments' => $this->_args, 'options' => $this->_options, @@ -253,8 +253,6 @@ public function toArray(): array 'description' => $this->_description, 'epilog' => $this->_epilog, ]; - - return $result; } /** @@ -426,6 +424,7 @@ public function addOption($name, array $options = []) 'multiple' => false, 'choices' => [], 'required' => false, + 'prompt' => null, ]; $options += $defaults; $option = new ConsoleInputOption( @@ -436,7 +435,8 @@ public function addOption($name, array $options = []) $options['default'], $options['choices'], $options['multiple'], - $options['required'] + $options['required'], + $options['prompt'] ); } $this->_options[$name] = $option; @@ -677,10 +677,11 @@ public function subcommands() * to parse the $argv * * @param array $argv Array of args (argv) to parse. + * @param \Cake\Console\ConsoleIo|null $io A ConsoleIo instance or null. If null prompt options will error. * @return array [$params, $args] * @throws \Cake\Console\Exception\ConsoleException When an invalid parameter is encountered. */ - public function parse(array $argv): array + public function parse(array $argv, ?ConsoleIo $io = null): array { $command = isset($argv[0]) ? Inflector::underscore($argv[0]) : null; if (isset($this->_subcommands[$command])) { @@ -688,7 +689,7 @@ public function parse(array $argv): array } if (isset($this->_subcommands[$command]) && $this->_subcommands[$command]->parser()) { /** @psalm-suppress PossiblyNullReference */ - return $this->_subcommands[$command]->parser()->parse($argv); + return $this->_subcommands[$command]->parser()->parse($argv, $io); } $params = $args = []; $this->_tokens = $argv; @@ -722,12 +723,29 @@ public function parse(array $argv): array $isBoolean = $option->isBoolean(); $default = $option->defaultValue(); - if ($default !== null && !isset($params[$name]) && !$isBoolean) { + $useDefault = !isset($params[$name]); + if ($default !== null && $useDefault && !$isBoolean) { $params[$name] = $default; } - if ($isBoolean && !isset($params[$name])) { + if ($isBoolean && $useDefault) { $params[$name] = false; } + $prompt = $option->prompt(); + if (!isset($params[$name]) && $prompt) { + if (!$io) { + throw new ConsoleException( + 'Cannot use interactive option prompts without a ConsoleIo instance. ' . + 'Please provide a `$io` parameter to `parse()`.' + ); + } + $choices = $option->choices(); + if ($choices) { + $value = $io->askChoice($prompt, $choices); + } else { + $value = $io->ask($prompt); + } + $params[$name] = $value; + } if ($option->isRequired() && !isset($params[$name])) { throw new ConsoleException( sprintf('Missing required option. The `%s` option is required and has no default value.', $name) diff --git a/app/vendor/cakephp/cakephp/src/Console/Shell.php b/app/vendor/cakephp/cakephp/src/Console/Shell.php index 0fae3a508..636216766 100644 --- a/app/vendor/cakephp/cakephp/src/Console/Shell.php +++ b/app/vendor/cakephp/cakephp/src/Console/Shell.php @@ -40,6 +40,7 @@ * @deprecated 3.6.0 ShellDispatcher and Shell will be removed in 5.0 * @method int|bool|null|void main(...$args) Main entry method for the shell. */ +#[\AllowDynamicProperties] class Shell { use LocatorAwareTrait; @@ -136,7 +137,7 @@ class Shell * Contains tasks to load and instantiate * * @var array|bool - * @link https://book.cakephp.org/4/en/console-and-shells.html#Shell::$tasks + * @link https://book.cakephp.org/4/en/console-commands/shells.html#shell-tasks */ public $tasks = []; @@ -180,7 +181,7 @@ class Shell * * @param \Cake\Console\ConsoleIo|null $io An io instance. * @param \Cake\ORM\Locator\LocatorInterface|null $locator Table locator instance. - * @link https://book.cakephp.org/4/en/console-and-shells.html#Shell + * @link https://book.cakephp.org/4/en/console-commands/shells.html */ public function __construct(?ConsoleIo $io = null, ?LocatorInterface $locator = null) { @@ -468,7 +469,7 @@ public function runCommand(array $argv, bool $autoMethod = false, array $extra = $command = isset($argv[0]) ? Inflector::underscore($argv[0]) : null; $this->OptionParser = $this->getOptionParser(); try { - [$this->params, $this->args] = $this->OptionParser->parse($argv); + [$this->params, $this->args] = $this->OptionParser->parse($argv, $this->_io); } catch (ConsoleException $e) { $this->err('Error: ' . $e->getMessage()); diff --git a/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php b/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php index 79f4fcedf..2075784b0 100644 --- a/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php +++ b/app/vendor/cakephp/cakephp/src/Console/ShellDispatcher.php @@ -179,9 +179,7 @@ public function dispatch(array $extra = []): int try { $result = $this->_dispatch($extra); } catch (StopException $e) { - $code = $e->getCode(); - - return $code; + return $e->getCode(); } if ($result === null || $result === true) { /** @psalm-suppress DeprecatedClass */ diff --git a/app/vendor/cakephp/cakephp/src/Console/composer.json b/app/vendor/cakephp/cakephp/src/Console/composer.json index 971d9a610..d7d392b50 100644 --- a/app/vendor/cakephp/cakephp/src/Console/composer.json +++ b/app/vendor/cakephp/cakephp/src/Console/composer.json @@ -23,7 +23,7 @@ "source": "https://github.com/cakephp/console" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0", "cakephp/event": "^4.0", "cakephp/filesystem": "^4.0", diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component.php b/app/vendor/cakephp/cakephp/src/Controller/Component.php index 52540c039..1ebafbd59 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component.php @@ -58,6 +58,7 @@ * @link https://book.cakephp.org/4/en/controllers/components.html * @see \Cake\Controller\Controller::$components */ +#[\AllowDynamicProperties] class Component implements EventListenerInterface { use InstanceConfigTrait; diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php b/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php index 715ed486a..85e27729a 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component/PaginatorComponent.php @@ -18,8 +18,8 @@ use Cake\Controller\Component; use Cake\Controller\ComponentRegistry; -use Cake\Datasource\Exception\PageOutOfBoundsException; -use Cake\Datasource\Paginator; +use Cake\Datasource\Paging\Exception\PageOutOfBoundsException; +use Cake\Datasource\Paging\NumericPaginator; use Cake\Datasource\ResultSetInterface; use Cake\Http\Exception\NotFoundException; use InvalidArgumentException; @@ -34,14 +34,15 @@ * You configure pagination when calling paginate(). See that method for more details. * * @link https://book.cakephp.org/4/en/controllers/components/pagination.html - * @mixin \Cake\Datasource\Paginator + * @mixin \Cake\Datasource\Paging\NumericPaginator + * @deprecated 4.4.0 Use Cake\Datasource\Paging\Paginator directly. */ class PaginatorComponent extends Component { /** * Datasource paginator instance. * - * @var \Cake\Datasource\Paginator + * @var \Cake\Datasource\Paging\NumericPaginator */ protected $_paginator; @@ -50,18 +51,30 @@ class PaginatorComponent extends Component */ public function __construct(ComponentRegistry $registry, array $config = []) { + deprecationWarning( + 'PaginatorComponent is deprecated, use a Cake\Datasource\Pagination\NumericPaginator instance directly.' + ); + if (!empty($this->_defaultConfig)) { throw new UnexpectedValueException('Default configuration must be set using a custom Paginator class.'); } if (isset($config['paginator'])) { - if (!$config['paginator'] instanceof Paginator) { - throw new InvalidArgumentException('Paginator must be an instance of ' . Paginator::class); + $config['className'] = $config['paginator']; + deprecationWarning( + '`paginator` option is deprecated,' + . ' use `className` instead a specify a paginator name/FQCN.' + ); + } + + if (isset($config['className'])) { + if (!$config['className'] instanceof NumericPaginator) { + throw new InvalidArgumentException('Paginator must be an instance of ' . NumericPaginator::class); } - $this->_paginator = $config['paginator']; - unset($config['paginator']); + $this->_paginator = $config['className']; + unset($config['className']); } else { - $this->_paginator = new Paginator(); + $this->_paginator = new NumericPaginator(); } parent::__construct($registry, $config); @@ -86,7 +99,7 @@ public function implementedEvents(): array * These settings are used to build the queries made and control other pagination settings. * * If your settings contain a key with the current table's alias. The data inside that key will be used. - * Otherwise the top level configuration will be used. + * Otherwise, the top level configuration will be used. * * ``` * $settings = [ @@ -225,10 +238,10 @@ public function mergeOptions(string $alias, array $settings): array /** * Set paginator instance. * - * @param \Cake\Datasource\Paginator $paginator Paginator instance. + * @param \Cake\Datasource\Paging\NumericPaginator $paginator Paginator instance. * @return $this */ - public function setPaginator(Paginator $paginator) + public function setPaginator(NumericPaginator $paginator) { $this->_paginator = $paginator; @@ -238,9 +251,9 @@ public function setPaginator(Paginator $paginator) /** * Get paginator instance. * - * @return \Cake\Datasource\Paginator + * @return \Cake\Datasource\Paging\NumericPaginator */ - public function getPaginator(): Paginator + public function getPaginator(): NumericPaginator { return $this->_paginator; } diff --git a/app/vendor/cakephp/cakephp/src/Controller/Component/RequestHandlerComponent.php b/app/vendor/cakephp/cakephp/src/Controller/Component/RequestHandlerComponent.php index f18c3cc64..84c5a26ab 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Component/RequestHandlerComponent.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Component/RequestHandlerComponent.php @@ -22,6 +22,7 @@ use Cake\Core\App; use Cake\Core\Configure; use Cake\Event\EventInterface; +use Cake\Http\ContentTypeNegotiation; use Cake\Http\Exception\NotFoundException; use Cake\Http\Response; use Cake\Http\ServerRequest; @@ -38,6 +39,8 @@ * etc. and return a response accordingly. * * @link https://book.cakephp.org/4/en/controllers/components/request-handling.html + * @deprecated 4.4.0 See the 4.4 migration guide for how to upgrade. + * https://book.cakephp.org/4/en/appendices/4-4-migration-guide.html#requesthandlercomponent */ class RequestHandlerComponent extends Component { @@ -121,7 +124,9 @@ public function implementedEvents(): array */ protected function _setExtension(ServerRequest $request, Response $response): void { - $accept = $request->parseAccept(); + $content = new ContentTypeNegotiation(); + $accept = $content->parseAccept($request); + if (empty($accept) || current($accept)[0] === 'text/html') { return; } @@ -214,14 +219,10 @@ public function beforeRender(EventInterface $event): void $response = $response->withCharset(Configure::read('App.encoding')); } - if ( - $this->_config['checkHttpCache'] && - $response->checkNotModified($controller->getRequest()) - ) { - $controller->setResponse($response); + $request = $controller->getRequest(); + if ($this->_config['checkHttpCache'] && $response->isNotModified($request)) { + $response = $response->withNotModified(); $event->stopPropagation(); - - return; } $controller->setResponse($response); @@ -252,6 +253,7 @@ public function beforeRender(EventInterface $event): void * types the client accepts. If a string is passed, returns true * if the client accepts it. If an array is passed, returns true * if the client accepts one or more elements in the array. + * @deprecated 4.4.0 Use ContentTypeNegotiation::prefersChoice() or Controller::getViewClasses() instead. */ public function accepts($type = null) { @@ -339,12 +341,15 @@ public function requestedWith($type = null) * a boolean will be returned if that type is preferred. * If an array of types are provided then the first preferred type is returned. * If no type is provided the first preferred type is returned. + * @deprecated 4.4.0 Use Controller::getViewClasses() instead. */ public function prefers($type = null) { $controller = $this->getController(); + $request = $controller->getRequest(); + $content = new ContentTypeNegotiation(); - $acceptRaw = $controller->getRequest()->parseAccept(); + $acceptRaw = $content->parseAccept($request); if (empty($acceptRaw)) { return $type ? $type === $this->ext : $this->ext; } @@ -470,12 +475,7 @@ public function respondAs($type, array $options = []): bool } if (is_array($cType)) { $cType = $cType[$options['index']] ?? $cType; - - if ($this->prefers($cType)) { - $cType = $this->prefers($cType); - } else { - $cType = $cType[0]; - } + $cType = $this->prefers($cType) ?: $cType[0]; } if (!$cType) { diff --git a/app/vendor/cakephp/cakephp/src/Controller/Controller.php b/app/vendor/cakephp/cakephp/src/Controller/Controller.php index a3300fbde..623214fd6 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/Controller.php +++ b/app/vendor/cakephp/cakephp/src/Controller/Controller.php @@ -19,18 +19,25 @@ use Cake\Controller\Exception\MissingActionException; use Cake\Core\App; use Cake\Datasource\ModelAwareTrait; +use Cake\Datasource\Paging\Exception\PageOutOfBoundsException; +use Cake\Datasource\Paging\NumericPaginator; +use Cake\Datasource\Paging\PaginatorInterface; use Cake\Event\EventDispatcherInterface; use Cake\Event\EventDispatcherTrait; use Cake\Event\EventInterface; use Cake\Event\EventListenerInterface; use Cake\Event\EventManagerInterface; +use Cake\Http\ContentTypeNegotiation; +use Cake\Http\Exception\NotFoundException; use Cake\Http\Response; use Cake\Http\ServerRequest; use Cake\Log\LogTrait; use Cake\ORM\Locator\LocatorAwareTrait; use Cake\Routing\Router; +use Cake\View\View; use Cake\View\ViewVarsTrait; use Closure; +use InvalidArgumentException; use Psr\Http\Message\ResponseInterface; use ReflectionClass; use ReflectionException; @@ -86,6 +93,7 @@ * @property \Cake\Controller\Component\AuthComponent $Auth * @link https://book.cakephp.org/4/en/controllers.html */ +#[\AllowDynamicProperties] class Controller implements EventListenerInterface, EventDispatcherInterface { use EventDispatcherTrait; @@ -128,7 +136,7 @@ class Controller implements EventListenerInterface, EventDispatcherInterface * tables your controller will be paginating. * * @var array - * @see \Cake\Controller\Component\PaginatorComponent + * @see \Cake\Datasource\Paging\NumericPaginator */ public $paginate = []; @@ -759,12 +767,78 @@ public function render(?string $template = null, ?string $layout = null): Respon if ($builder->getTemplate() === null) { $builder->setTemplate($this->request->getParam('action')); } + $viewClass = $this->chooseViewClass(); + $view = $this->createView($viewClass); - $view = $this->createView(); $contents = $view->render(); - $this->setResponse($view->getResponse()->withStringBody($contents)); + $response = $view->getResponse()->withStringBody($contents); - return $this->response; + return $this->setResponse($response)->response; + } + + /** + * Get the View classes this controller can perform content negotiation with. + * + * Each view class must implement the `getContentType()` hook method + * to participate in negotiation. + * + * @see Cake\Http\ContentTypeNegotiation + * @return array + */ + public function viewClasses(): array + { + return []; + } + + /** + * Use the view classes defined on this controller to view + * selection based on content-type negotiation. + * + * @return string|null The chosen view class or null for no decision. + */ + protected function chooseViewClass(): ?string + { + $possibleViewClasses = $this->viewClasses(); + if (empty($possibleViewClasses)) { + return null; + } + // Controller or component has already made a view class decision. + // That decision should overwrite the framework behavior. + if ($this->viewBuilder()->getClassName() !== null) { + return null; + } + + $typeMap = []; + foreach ($possibleViewClasses as $class) { + $viewContentType = $class::contentType(); + if ($viewContentType && !isset($typeMap[$viewContentType])) { + $typeMap[$viewContentType] = $class; + } + } + $request = $this->getRequest(); + + // Prefer the _ext route parameter if it is defined. + $ext = $request->getParam('_ext'); + if ($ext) { + $extTypes = (array)($this->response->getMimeType($ext) ?: []); + foreach ($extTypes as $extType) { + if (isset($typeMap[$extType])) { + return $typeMap[$extType]; + } + } + + throw new NotFoundException(); + } + + // Use accept header based negotiation. + $contentType = new ContentTypeNegotiation(); + $preferredType = $contentType->preferredType($request, array_keys($typeMap)); + if ($preferredType) { + return $typeMap[$preferredType]; + } + + // Use the match-all view if available or null for no decision. + return $typeMap[View::TYPE_MATCH_ALL] ?? null; } /** @@ -818,7 +892,7 @@ public function referer($default = '/', bool $local = true): string /** * Handles pagination of records in Table objects. * - * Will load the referenced Table object, and have the PaginatorComponent + * Will load the referenced Table object, and have the paginator * paginate the query using the request date and settings defined in `$this->paginate`. * * This method will also make the PaginatorHelper available in the view. @@ -847,13 +921,57 @@ public function paginate($object = null, array $settings = []) } } - $this->loadComponent('Paginator'); if (empty($table)) { throw new RuntimeException('Unable to locate an object compatible with paginate.'); } + $settings += $this->paginate; - return $this->Paginator->paginate($table, $settings); + if (isset($this->Paginator)) { + return $this->Paginator->paginate($table, $settings); + } + + if (isset($settings['paginator'])) { + $settings['className'] = $settings['paginator']; + deprecationWarning( + '`paginator` option is deprecated,' + . ' use `className` instead a specify a paginator name/FQCN.' + ); + } + + $paginator = $settings['className'] ?? NumericPaginator::class; + unset($settings['className']); + if (is_string($paginator)) { + $className = App::className($paginator, 'Datasource/Paging', 'Paginator'); + if ($className === null) { + throw new InvalidArgumentException('Invalid paginator: ' . $paginator); + } + $paginator = new $className(); + } + if (!$paginator instanceof PaginatorInterface) { + throw new InvalidArgumentException('Paginator must be an instance of ' . PaginatorInterface::class); + } + + $results = null; + try { + $results = $paginator->paginate( + $table, + $this->request->getQueryParams(), + $settings + ); + } catch (PageOutOfBoundsException $e) { + // Exception thrown below + } finally { + $paging = $paginator->getPagingParams() + (array)$this->request->getAttribute('paging', []); + $this->request = $this->request->withAttribute('paging', $paging); + } + + if (isset($e)) { + throw new NotFoundException(null, null, $e); + } + + /** @psalm-suppress NullableReturnStatement */ + return $results; } /** diff --git a/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php b/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php index 65a09ca99..835a056c9 100644 --- a/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php +++ b/app/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php @@ -79,10 +79,9 @@ public function create(ServerRequestInterface $request): Controller throw $this->missingController($request); } - // If the controller has a container definition - // add the request as a service. + // Get the controller from the container if defined. + // The request is in the container by default. if ($this->container->has($className)) { - $this->container->add(ServerRequest::class, $request); $controller = $this->container->get($className); } else { $controller = $reflection->newInstance($request); @@ -269,7 +268,7 @@ protected function coerceStringToType(string $argument, ReflectionNamedType $typ case 'float': return is_numeric($argument) ? (float)$argument : null; case 'int': - return ctype_digit($argument) ? (int)$argument : null; + return filter_var($argument, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE); case 'bool': return $argument === '0' ? false : ($argument === '1' ? true : null); case 'array': diff --git a/app/vendor/cakephp/cakephp/src/Core/Configure.php b/app/vendor/cakephp/cakephp/src/Core/Configure.php index e4e8f10d8..a6f8dc442 100644 --- a/app/vendor/cakephp/cakephp/src/Core/Configure.php +++ b/app/vendor/cakephp/cakephp/src/Core/Configure.php @@ -37,7 +37,7 @@ class Configure /** * Array of values currently stored in Configure. * - * @var array + * @var array */ protected static $_values = [ 'debug' => false, diff --git a/app/vendor/cakephp/cakephp/src/Core/Container.php b/app/vendor/cakephp/cakephp/src/Core/Container.php index 27ccafbb5..b5b56f2b0 100644 --- a/app/vendor/cakephp/cakephp/src/Core/Container.php +++ b/app/vendor/cakephp/cakephp/src/Core/Container.php @@ -22,9 +22,6 @@ * Dependency Injection container * * Based on the container out of League\Container - * - * @experimental This class' interface is not stable and may change - * in future minor releases. */ class Container extends LeagueContainer implements ContainerInterface { diff --git a/app/vendor/cakephp/cakephp/src/Core/ContainerApplicationInterface.php b/app/vendor/cakephp/cakephp/src/Core/ContainerApplicationInterface.php index 3caff77cb..bd5f31dc6 100644 --- a/app/vendor/cakephp/cakephp/src/Core/ContainerApplicationInterface.php +++ b/app/vendor/cakephp/cakephp/src/Core/ContainerApplicationInterface.php @@ -18,9 +18,6 @@ /** * Interface for applications that configure and use a dependency injection container. - * - * @experimental This interface is not final and can have additional - * methods and parameters added in future minor releases. */ interface ContainerApplicationInterface { diff --git a/app/vendor/cakephp/cakephp/src/Core/ContainerInterface.php b/app/vendor/cakephp/cakephp/src/Core/ContainerInterface.php index 244e45f7e..d8d39e1bc 100644 --- a/app/vendor/cakephp/cakephp/src/Core/ContainerInterface.php +++ b/app/vendor/cakephp/cakephp/src/Core/ContainerInterface.php @@ -26,9 +26,6 @@ * * The methods defined in this interface use the conventions provided * by league/container as that is the library that CakePHP uses. - * - * @experimental This interface is not final and can have additional - * methods and parameters added in future minor releases. */ interface ContainerInterface extends DefinitionContainerInterface { diff --git a/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php b/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php index 4c85e326c..1862d6e43 100644 --- a/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php +++ b/app/vendor/cakephp/cakephp/src/Core/PluginCollection.php @@ -238,15 +238,28 @@ public function create(string $name, array $config = []): PluginInterface } $config += ['name' => $name]; - /** @var class-string<\Cake\Core\PluginInterface> $className */ - $className = str_replace('/', '\\', $name) . '\\' . 'Plugin'; + $namespace = str_replace('/', '\\', $name); + + $className = $namespace . '\\' . 'Plugin'; + // Check for [Vendor/]Foo/Plugin class if (!class_exists($className)) { - $className = BasePlugin::class; - if (empty($config['path'])) { - $config['path'] = $this->findPath($name); + $pos = strpos($name, '/'); + if ($pos === false) { + $className = $namespace . '\\' . $name . 'Plugin'; + } else { + $className = $namespace . '\\' . substr($name, $pos + 1) . 'Plugin'; + } + + // Check for [Vendor/]Foo/FooPlugin + if (!class_exists($className)) { + $className = BasePlugin::class; + if (empty($config['path'])) { + $config['path'] = $this->findPath($name); + } } } + /** @var class-string<\Cake\Core\PluginInterface> $className */ return new $className($config); } diff --git a/app/vendor/cakephp/cakephp/src/Core/ServiceProvider.php b/app/vendor/cakephp/cakephp/src/Core/ServiceProvider.php index b2ed8add9..8ff9b9cae 100644 --- a/app/vendor/cakephp/cakephp/src/Core/ServiceProvider.php +++ b/app/vendor/cakephp/cakephp/src/Core/ServiceProvider.php @@ -28,9 +28,6 @@ * to organize your application's dependencies. They also help * improve performance of applications with many services by * allowing service registration to be deferred until services are needed. - * - * @experimental This class' interface is not stable and may change - * in future minor releases. */ abstract class ServiceProvider extends AbstractServiceProvider implements BootableServiceProviderInterface { diff --git a/app/vendor/cakephp/cakephp/src/Core/composer.json b/app/vendor/cakephp/cakephp/src/Core/composer.json index ffd17ba7a..2a62b03ec 100644 --- a/app/vendor/cakephp/cakephp/src/Core/composer.json +++ b/app/vendor/cakephp/cakephp/src/Core/composer.json @@ -22,7 +22,7 @@ "source": "https://github.com/cakephp/core" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/utility": "^4.0" }, "suggest": { diff --git a/app/vendor/cakephp/cakephp/src/Core/functions.php b/app/vendor/cakephp/cakephp/src/Core/functions.php index 2ca8619e8..e74ac1736 100644 --- a/app/vendor/cakephp/cakephp/src/Core/functions.php +++ b/app/vendor/cakephp/cakephp/src/Core/functions.php @@ -30,7 +30,7 @@ * * @param mixed $text Text to wrap through htmlspecialchars. Also works with arrays, and objects. * Arrays will be mapped and have all their elements escaped. Objects will be string cast if they - * implement a `__toString` method. Otherwise the class name will be used. + * implement a `__toString` method. Otherwise, the class name will be used. * Other scalar types will be returned unchanged. * @param bool $double Encode existing html entities. * @param string|null $charset Character set to use when escaping. @@ -206,8 +206,10 @@ function env(string $key, $default = null) $key = 'SCRIPT_URL'; } + /** @var string|null $val */ $val = $_SERVER[$key] ?? $_ENV[$key] ?? null; if ($val == null && getenv($key) !== false) { + /** @var string|false $val */ $val = getenv($key); } diff --git a/app/vendor/cakephp/cakephp/src/Database/Connection.php b/app/vendor/cakephp/cakephp/src/Database/Connection.php index 5153d0e81..92a54ae8d 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Connection.php +++ b/app/vendor/cakephp/cakephp/src/Database/Connection.php @@ -31,6 +31,7 @@ use Cake\Database\Schema\Collection as SchemaCollection; use Cake\Database\Schema\CollectionInterface as SchemaCollectionInterface; use Cake\Datasource\ConnectionInterface; +use Cake\Log\Engine\BaseLog; use Cake\Log\Log; use Psr\Log\LoggerInterface; use Psr\SimpleCache\CacheInterface; @@ -135,11 +136,14 @@ public function __construct(array $config) { $this->_config = $config; - $driver = ''; - if (!empty($config['driver'])) { - $driver = $config['driver']; - } - $this->setDriver($driver, $config); + $driverConfig = array_diff_key($config, array_flip([ + 'name', + 'driver', + 'log', + 'cacheMetaData', + 'cacheKeyPrefix', + ])); + $this->_driver = $this->createDriver($config['driver'] ?? '', $driverConfig); if (!empty($config['log'])) { $this->enableQueryLogging((bool)$config['log']); @@ -183,24 +187,43 @@ public function configName(): string * @throws \Cake\Database\Exception\MissingDriverException When a driver class is missing. * @throws \Cake\Database\Exception\MissingExtensionException When a driver's PHP extension is missing. * @return $this + * @deprecated 4.4.0 Setting the driver is deprecated. Use the connection config instead. */ public function setDriver($driver, $config = []) { + deprecationWarning('Setting the driver is deprecated. Use the connection config instead.'); + + $this->_driver = $this->createDriver($driver, $config); + + return $this; + } + + /** + * Creates driver from name, class name or instance. + * + * @param \Cake\Database\DriverInterface|string $name Driver name, class name or instance. + * @param array $config Driver config if $name is not an instance. + * @return \Cake\Database\DriverInterface + * @throws \Cake\Database\Exception\MissingDriverException When a driver class is missing. + * @throws \Cake\Database\Exception\MissingExtensionException When a driver's PHP extension is missing. + */ + protected function createDriver($name, array $config): DriverInterface + { + $driver = $name; if (is_string($driver)) { /** @psalm-var class-string<\Cake\Database\DriverInterface>|null $className */ $className = App::className($driver, 'Database/Driver'); if ($className === null) { - throw new MissingDriverException(['driver' => $driver]); + throw new MissingDriverException(['driver' => $driver, 'connection' => $this->configName()]); } $driver = new $className($config); } + if (!$driver->enabled()) { - throw new MissingExtensionException(['driver' => get_class($driver), 'name' => $config['name']]); + throw new MissingExtensionException(['driver' => get_class($driver), 'name' => $this->configName()]); } - $this->_driver = $driver; - - return $this; + return $driver; } /** @@ -406,7 +429,7 @@ public function getSchemaCollection(): SchemaCollectionInterface * * @param string $table the table to insert values in * @param array $values values to be inserted - * @param array $types list of associative array containing the types to be used for casting + * @param array $types Array containing the types to be used for casting * @return \Cake\Database\StatementInterface */ public function insert(string $table, array $values, array $types = []): StatementInterface @@ -427,7 +450,7 @@ public function insert(string $table, array $values, array $types = []): Stateme * @param string $table the table to update rows from * @param array $values values to be updated * @param array $conditions conditions to be set for update statement - * @param array $types list of associative array containing the types to be used for casting + * @param array $types list of associative array containing the types to be used for casting * @return \Cake\Database\StatementInterface */ public function update(string $table, array $values, array $conditions = [], array $types = []): StatementInterface @@ -445,7 +468,7 @@ public function update(string $table, array $values, array $conditions = [], arr * * @param string $table the table to delete rows from * @param array $conditions conditions to be set for delete statement - * @param array $types list of associative array containing the types to be used for casting + * @param array $types list of associative array containing the types to be used for casting * @return \Cake\Database\StatementInterface */ public function delete(string $table, array $conditions = [], array $types = []): StatementInterface @@ -897,7 +920,7 @@ public function getLogger(): LoggerInterface return $this->_logger; } - if (!class_exists(QueryLogger::class)) { + if (!class_exists(BaseLog::class)) { throw new RuntimeException( 'For logging you must either set a logger using Connection::setLogger()' . ' or require the cakephp/log package in your composer config.' diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php b/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php index 0b2cdb0c5..6ca955856 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php +++ b/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlite.php @@ -29,6 +29,7 @@ use Cake\Database\StatementInterface; use InvalidArgumentException; use PDO; +use RuntimeException; /** * Class Sqlite @@ -52,6 +53,8 @@ class Sqlite extends Driver 'database' => ':memory:', 'encoding' => 'utf8', 'mask' => 0644, + 'cache' => null, + 'mode' => null, 'flags' => [], 'init' => [], ]; @@ -132,12 +135,30 @@ public function connect(): bool ); } - $databaseExists = file_exists($config['database']); + $chmodFile = false; + if ($config['database'] !== ':memory:' && $config['mode'] !== 'memory') { + $chmodFile = !file_exists($config['database']); + } - $dsn = "sqlite:{$config['database']}"; - $this->_connect($dsn, $config); + $params = []; + if ($config['cache']) { + $params[] = 'cache=' . $config['cache']; + } + if ($config['mode']) { + $params[] = 'mode=' . $config['mode']; + } - if (!$databaseExists && $config['database'] !== ':memory:') { + if ($params) { + if (PHP_VERSION_ID < 80100) { + throw new RuntimeException('SQLite URI support requires PHP 8.1.'); + } + $dsn = 'sqlite:file:' . $config['database'] . '?' . implode('&', $params); + } else { + $dsn = 'sqlite:' . $config['database']; + } + + $this->_connect($dsn, $config); + if ($chmodFile) { // phpcs:disable @chmod($config['database'], $config['mask']); // phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlserver.php b/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlserver.php index 23e23dd2e..a0dc2ec58 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlserver.php +++ b/app/vendor/cakephp/cakephp/src/Database/Driver/Sqlserver.php @@ -75,6 +75,8 @@ class Sqlserver extends Driver 'failoverPartner' => null, 'loginTimeout' => null, 'multiSubnetFailover' => null, + 'encrypt' => null, + 'trustServerCertificate' => null, ]; /** @@ -151,6 +153,12 @@ public function connect(): bool if ($config['multiSubnetFailover'] !== null) { $dsn .= ";MultiSubnetFailover={$config['multiSubnetFailover']}"; } + if ($config['encrypt'] !== null) { + $dsn .= ";Encrypt={$config['encrypt']}"; + } + if ($config['trustServerCertificate'] !== null) { + $dsn .= ";TrustServerCertificate={$config['trustServerCertificate']}"; + } $this->_connect($dsn, $config); $connection = $this->getConnection(); diff --git a/app/vendor/cakephp/cakephp/src/Database/Exception/MissingDriverException.php b/app/vendor/cakephp/cakephp/src/Database/Exception/MissingDriverException.php index d9f142264..77532a16c 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Exception/MissingDriverException.php +++ b/app/vendor/cakephp/cakephp/src/Database/Exception/MissingDriverException.php @@ -26,5 +26,5 @@ class MissingDriverException extends CakeException /** * @inheritDoc */ - protected $_messageTemplate = 'Database driver %s could not be found.'; + protected $_messageTemplate = 'Could not find driver `%s` for connection `%s`.'; } diff --git a/app/vendor/cakephp/cakephp/src/Database/Expression/CaseExpressionTrait.php b/app/vendor/cakephp/cakephp/src/Database/Expression/CaseExpressionTrait.php index e486a193f..8d1728b9e 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Expression/CaseExpressionTrait.php +++ b/app/vendor/cakephp/cakephp/src/Database/Expression/CaseExpressionTrait.php @@ -20,6 +20,7 @@ use Cake\Chronos\MutableDate; use Cake\Database\ExpressionInterface; use Cake\Database\Query; +use Cake\Database\TypedResultInterface; use Cake\Database\ValueBinder; use DateTimeInterface; @@ -67,6 +68,8 @@ protected function inferType($value): ?string $value instanceof IdentifierExpression ) { $type = $this->_typeMap->type($value->getIdentifier()); + } elseif ($value instanceof TypedResultInterface) { + $type = $value->getReturnType(); } return $type; diff --git a/app/vendor/cakephp/cakephp/src/Database/Expression/QueryExpression.php b/app/vendor/cakephp/cakephp/src/Database/Expression/QueryExpression.php index 2ab13d219..edb67399e 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Expression/QueryExpression.php +++ b/app/vendor/cakephp/cakephp/src/Database/Expression/QueryExpression.php @@ -51,7 +51,7 @@ class QueryExpression implements ExpressionInterface, Countable /** * Constructor. A new expression object can be created without any params and - * be built dynamically. Otherwise it is possible to pass an array of conditions + * be built dynamically. Otherwise, it is possible to pass an array of conditions * containing either a tree-like array structure to be parsed and/or other * expression objects. Optionally, you can set the conjunction keyword to be used * for joining each part of this level of the expression tree. @@ -111,7 +111,7 @@ public function getConjunction(): string * be added. When using an array and the key is 'OR' or 'AND' a new expression * object will be created with that conjunction and internal array value passed * as conditions. - * @param array $types Associative array of fields pointing to the type of the + * @param array $types Associative array of fields pointing to the type of the * values that are being passed. Used for correctly binding values to statements. * @see \Cake\Database\Query::where() for examples on conditions * @return $this @@ -702,7 +702,7 @@ public function hasNestedExpression(): bool * representation is wrapped around an adequate instance or of this class. * * @param array $conditions list of conditions to be stored in this object - * @param array $types list of types associated on fields referenced in $conditions + * @param array $types list of types associated on fields referenced in $conditions * @return void */ protected function _addConditions(array $conditions, array $types): void diff --git a/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php b/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php index bf51eaf19..e4bbc0878 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php +++ b/app/vendor/cakephp/cakephp/src/Database/Expression/WhenThenExpression.php @@ -134,7 +134,7 @@ public function when($when, $type = null) 'The `$when` argument must be either a non-empty array, a scalar value, an object, ' . 'or an instance of `\%s`, `%s` given.', ExpressionInterface::class, - is_array($when) ? '[]' : getTypeName($when) + is_array($when) ? '[]' : getTypeName($when) // @phpstan-ignore-line )); } diff --git a/app/vendor/cakephp/cakephp/src/Database/Expression/WindowExpression.php b/app/vendor/cakephp/cakephp/src/Database/Expression/WindowExpression.php index 3604be4b0..383e652cf 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Expression/WindowExpression.php +++ b/app/vendor/cakephp/cakephp/src/Database/Expression/WindowExpression.php @@ -310,13 +310,11 @@ protected function buildOffsetSql(ValueBinder $binder, $offset, string $directio $offset = $offset->sql($binder); } - $sql = sprintf( + return sprintf( '%s %s', $offset ?? 'UNBOUNDED', $direction ); - - return $sql; } /** diff --git a/app/vendor/cakephp/cakephp/src/Database/FieldTypeConverter.php b/app/vendor/cakephp/cakephp/src/Database/FieldTypeConverter.php index ff7f39f67..3448aa1ef 100644 --- a/app/vendor/cakephp/cakephp/src/Database/FieldTypeConverter.php +++ b/app/vendor/cakephp/cakephp/src/Database/FieldTypeConverter.php @@ -118,7 +118,7 @@ public function __construct(TypeMap $typeMap, DriverInterface $driver) * using the corresponding Type class. * * @param array $row The array with the fields to be casted - * @return array + * @return array */ public function __invoke(array $row): array { diff --git a/app/vendor/cakephp/cakephp/src/Database/IdentifierQuoter.php b/app/vendor/cakephp/cakephp/src/Database/IdentifierQuoter.php index 6b21a5ad6..b3a93e262 100644 --- a/app/vendor/cakephp/cakephp/src/Database/IdentifierQuoter.php +++ b/app/vendor/cakephp/cakephp/src/Database/IdentifierQuoter.php @@ -128,8 +128,8 @@ protected function _quoteParts(Query $query): void /** * A generic identifier quoting function used for various parts of the query * - * @param array $part the part of the query to quote - * @return array + * @param array $part the part of the query to quote + * @return array */ protected function _basicQuoter(array $part): array { @@ -148,7 +148,7 @@ protected function _basicQuoter(array $part): array * object * * @param array $joins The joins to quote. - * @return array + * @return array */ protected function _quoteJoins(array $joins): array { diff --git a/app/vendor/cakephp/cakephp/src/Database/Query.php b/app/vendor/cakephp/cakephp/src/Database/Query.php index 3df66cd51..98f7bbc1e 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Query.php +++ b/app/vendor/cakephp/cakephp/src/Database/Query.php @@ -101,6 +101,7 @@ class Query implements ExpressionInterface, IteratorAggregate * The list of query clauses to traverse for generating a SELECT statement * * @var array + * @deprecated 4.4.3 This property is unused. */ protected $_selectParts = [ 'with', 'select', 'from', 'join', 'where', 'group', 'having', 'order', 'limit', @@ -111,6 +112,7 @@ class Query implements ExpressionInterface, IteratorAggregate * The list of query clauses to traverse for generating an UPDATE statement * * @var array + * @deprecated 4.4.3 This property is unused. */ protected $_updateParts = ['with', 'update', 'set', 'where', 'epilog']; @@ -118,6 +120,7 @@ class Query implements ExpressionInterface, IteratorAggregate * The list of query clauses to traverse for generating a DELETE statement * * @var array + * @deprecated 4.4.3 This property is unused. */ protected $_deleteParts = ['with', 'delete', 'modifier', 'from', 'where', 'epilog']; @@ -125,6 +128,7 @@ class Query implements ExpressionInterface, IteratorAggregate * The list of query clauses to traverse for generating an INSERT statement * * @var array + * @deprecated 4.4.3 This property is unused. */ protected $_insertParts = ['with', 'insert', 'values', 'epilog']; @@ -1642,7 +1646,7 @@ public function unionAll($query, $overwrite = false) * with Query::values(). * * @param array $columns The columns to insert into. - * @param array $types A map between columns & their datatypes. + * @param array $types A map between columns & their datatypes. * @return $this * @throws \RuntimeException When there are 0 columns. */ @@ -1886,14 +1890,36 @@ public function type(): string * any format accepted by \Cake\Database\Expression\QueryExpression: * * ``` - * $expression = $query->newExpr(); // Returns an empty expression object - * $expression = $query->newExpr('Table.column = Table2.column'); // Return a raw SQL expression + * $expression = $query->expr(); // Returns an empty expression object + * $expression = $query->expr('Table.column = Table2.column'); // Return a raw SQL expression * ``` * * @param \Cake\Database\ExpressionInterface|array|string|null $rawExpression A string, array or anything you want wrapped in an expression object * @return \Cake\Database\Expression\QueryExpression */ public function newExpr($rawExpression = null): QueryExpression + { + return $this->expr($rawExpression); + } + + /** + * Returns a new QueryExpression object. This is a handy function when + * building complex queries using a fluent interface. You can also override + * this function in subclasses to use a more specialized QueryExpression class + * if required. + * + * You can optionally pass a single raw SQL string or an array or expressions in + * any format accepted by \Cake\Database\Expression\QueryExpression: + * + * ``` + * $expression = $query->expr(); // Returns an empty expression object + * $expression = $query->expr('Table.column = Table2.column'); // Return a raw SQL expression + * ``` + * + * @param \Cake\Database\ExpressionInterface|array|string|null $rawExpression A string, array or anything you want wrapped in an expression object + * @return \Cake\Database\Expression\QueryExpression + */ + public function expr($rawExpression = null): QueryExpression { $expression = new QueryExpression([], $this->getTypeMap()); diff --git a/app/vendor/cakephp/cakephp/src/Database/README.md b/app/vendor/cakephp/cakephp/src/Database/README.md index 877c7b68d..d7bbe8eb1 100644 --- a/app/vendor/cakephp/cakephp/src/Database/README.md +++ b/app/vendor/cakephp/cakephp/src/Database/README.md @@ -35,35 +35,29 @@ to use: ```php use Cake\Database\Connection; use Cake\Database\Driver\Mysql; +use Cake\Database\Driver\Sqlite; -$driver = new Mysql([ +$connection = new Connection([ + 'driver' => Mysql::class, 'database' => 'test', 'username' => 'root', - 'password' => 'secret' -]); -$connection = new Connection([ - 'driver' => $driver + 'password' => 'secret', ]); -``` - -Drivers are classes responsible for actually executing the commands to the database and -correctly building the SQL according to the database specific dialect. Drivers can also -be specified by passing a class name. In that case, include all the connection details -directly in the options array: -```php -use Cake\Database\Connection; - -$connection = new Connection([ - 'driver' => Cake\Database\Driver\Sqlite::class, +$connection2 = new Connection([ + 'driver' => Sqlite::class, 'database' => '/path/to/file.db' ]); ``` +Drivers are classes responsible for actually executing the commands to the database and +correctly building the SQL according to the database specific dialect. + ### Connection options This is a list of possible options that can be passed when creating a connection: +* `driver`: Driver class name * `persistent`: Creates a persistent connection * `host`: The server host * `database`: The database name diff --git a/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php b/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php index 2cdd0980e..7d76cc01e 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php +++ b/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php @@ -110,7 +110,9 @@ protected function reconnect(): bool try { $this->connection->connect(); - $this->connection->log('[RECONNECT]'); + if ($this->connection->isQueryLoggingEnabled()) { + $this->connection->log('[RECONNECT]'); + } return true; } catch (Exception $e) { diff --git a/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchemaDialect.php b/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchemaDialect.php index d8dddef82..6142eb800 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchemaDialect.php +++ b/app/vendor/cakephp/cakephp/src/Database/Schema/MysqlSchemaDialect.php @@ -238,7 +238,9 @@ public function convertIndexDescription(TableSchema $schema, array $row): void $name = $type = TableSchema::CONSTRAINT_PRIMARY; } - $columns[] = $row['Column_name']; + if (!empty($row['Column_name'])) { + $columns[] = $row['Column_name']; + } if ($row['Index_type'] === 'FULLTEXT') { $type = TableSchema::INDEX_FULLTEXT; diff --git a/app/vendor/cakephp/cakephp/src/Database/Schema/SqlGeneratorInterface.php b/app/vendor/cakephp/cakephp/src/Database/Schema/SqlGeneratorInterface.php index 3acaf27b9..9fbd5919f 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Schema/SqlGeneratorInterface.php +++ b/app/vendor/cakephp/cakephp/src/Database/Schema/SqlGeneratorInterface.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Database\Schema; diff --git a/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchema.php b/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchema.php index f9ad3dcb0..3dac32330 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchema.php +++ b/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchema.php @@ -71,7 +71,7 @@ class TableSchema implements TableSchemaInterface, SqlGeneratorInterface /** * Options for the table. * - * @var array + * @var array */ protected $_options = []; diff --git a/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchemaAwareInterface.php b/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchemaAwareInterface.php index f08e363ba..d4045f9d2 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchemaAwareInterface.php +++ b/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchemaAwareInterface.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Database\Schema; diff --git a/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchemaInterface.php b/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchemaInterface.php index 19e942de6..c3ec9d183 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchemaInterface.php +++ b/app/vendor/cakephp/cakephp/src/Database/Schema/TableSchemaInterface.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Database\Schema; diff --git a/app/vendor/cakephp/cakephp/src/Database/Type/BatchCastingInterface.php b/app/vendor/cakephp/cakephp/src/Database/Type/BatchCastingInterface.php index 35f046bcb..8761f1c88 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Type/BatchCastingInterface.php +++ b/app/vendor/cakephp/cakephp/src/Database/Type/BatchCastingInterface.php @@ -31,7 +31,7 @@ interface BatchCastingInterface * @param array $values The original array of values containing the fields to be casted * @param array $fields The field keys to cast * @param \Cake\Database\DriverInterface $driver Object from which database preferences and configuration will be extracted. - * @return array + * @return array */ public function manyToPHP(array $values, array $fields, DriverInterface $driver): array; } diff --git a/app/vendor/cakephp/cakephp/src/Database/Type/BoolType.php b/app/vendor/cakephp/cakephp/src/Database/Type/BoolType.php index eeb1c8854..7bfa769bf 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Type/BoolType.php +++ b/app/vendor/cakephp/cakephp/src/Database/Type/BoolType.php @@ -59,7 +59,7 @@ public function toDatabase($value, DriverInterface $driver): ?bool */ public function toPHP($value, DriverInterface $driver): ?bool { - if ($value === null || $value === true || $value === false) { + if ($value === null || is_bool($value)) { return $value; } @@ -76,21 +76,11 @@ public function toPHP($value, DriverInterface $driver): ?bool public function manyToPHP(array $values, array $fields, DriverInterface $driver): array { foreach ($fields as $field) { - if (!isset($values[$field]) || $values[$field] === true || $values[$field] === false) { + $value = $values[$field] ?? null; + if ($value === null || is_bool($value)) { continue; } - if ($values[$field] === '1') { - $values[$field] = true; - continue; - } - - if ($values[$field] === '0') { - $values[$field] = false; - continue; - } - - $value = $values[$field]; if (!is_numeric($value)) { $values[$field] = strtolower($value) === 'true'; continue; diff --git a/app/vendor/cakephp/cakephp/src/Database/Type/DateTimeType.php b/app/vendor/cakephp/cakephp/src/Database/Type/DateTimeType.php index e87fdeaf8..655c78f3c 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Type/DateTimeType.php +++ b/app/vendor/cakephp/cakephp/src/Database/Type/DateTimeType.php @@ -328,7 +328,7 @@ public function marshal($value): ?DateTimeInterface return $value->setTimezone($this->defaultTimezone); } - /** @var class-string<\DatetimeInterface> $class */ + /** @var class-string<\DateTimeInterface> $class */ $class = $this->_className; try { if ($value === '' || $value === null || is_bool($value)) { @@ -336,7 +336,7 @@ public function marshal($value): ?DateTimeInterface } if (is_int($value) || (is_string($value) && ctype_digit($value))) { - /** @var \Datetime|\DateTimeImmutable $dateTime */ + /** @var \DateTime|\DateTimeImmutable $dateTime */ $dateTime = new $class('@' . $value); return $dateTime->setTimezone($this->defaultTimezone); @@ -349,7 +349,7 @@ public function marshal($value): ?DateTimeInterface $dateTime = $this->_parseValue($value); } - /** @var \Datetime|\DateTimeImmutable $dateTime */ + /** @var \DateTime|\DateTimeImmutable $dateTime */ if ($dateTime !== null) { $dateTime = $dateTime->setTimezone($this->defaultTimezone); } @@ -392,7 +392,7 @@ public function marshal($value): ?DateTimeInterface $value['microsecond'] ); - /** @var \Datetime|\DateTimeImmutable $dateTime */ + /** @var \DateTime|\DateTimeImmutable $dateTime */ $dateTime = new $class($format, $value['timezone'] ?? $this->userTimezone); return $dateTime->setTimezone($this->defaultTimezone); diff --git a/app/vendor/cakephp/cakephp/src/Database/TypeMap.php b/app/vendor/cakephp/cakephp/src/Database/TypeMap.php index ad3482cb8..ac3f8eb8b 100644 --- a/app/vendor/cakephp/cakephp/src/Database/TypeMap.php +++ b/app/vendor/cakephp/cakephp/src/Database/TypeMap.php @@ -22,29 +22,29 @@ class TypeMap { /** - * Associative array with the default fields and the related types this query might contain. + * Array with the default fields and the related types this query might contain. * * Used to avoid repetition when calling multiple functions inside this class that * may require a custom type for a specific field. * - * @var array + * @var array */ protected $_defaults = []; /** - * Associative array with the fields and the related types that override defaults this query might contain + * Array with the fields and the related types that override defaults this query might contain * * Used to avoid repetition when calling multiple functions inside this class that * may require a custom type for a specific field. * - * @var array + * @var array */ protected $_types = []; /** * Creates an instance with the given defaults * - * @param array $defaults The defaults to use. + * @param array $defaults The defaults to use. */ public function __construct(array $defaults = []) { @@ -69,7 +69,7 @@ public function __construct(array $defaults = []) * This method will replace all the existing default mappings with the ones provided. * To add into the mappings use `addDefaults()`. * - * @param array $defaults Associative array where keys are field names and values + * @param array $defaults Array where keys are field names / positions and values * are the correspondent type. * @return $this */ @@ -83,7 +83,7 @@ public function setDefaults(array $defaults) /** * Returns the currently configured types. * - * @return array + * @return array */ public function getDefaults(): array { @@ -95,7 +95,7 @@ public function getDefaults(): array * * If a key already exists it will not be overwritten. * - * @param array $types The additional types to add. + * @param array $types The additional types to add. * @return void */ public function addDefaults(array $types): void @@ -114,7 +114,7 @@ public function addDefaults(array $types): void * * This method will replace all the existing type maps with the ones provided. * - * @param array $types Associative array where keys are field names and values + * @param array $types Array where keys are field names / positions and values * are the correspondent type. * @return $this */ @@ -128,7 +128,7 @@ public function setTypes(array $types) /** * Gets a map of fields and their associated types for single-use. * - * @return array + * @return array */ public function getTypes(): array { @@ -151,7 +151,7 @@ public function type($column): ?string /** * Returns an array of all types mapped types * - * @return array + * @return array */ public function toArray(): array { diff --git a/app/vendor/cakephp/cakephp/src/Database/TypeMapTrait.php b/app/vendor/cakephp/cakephp/src/Database/TypeMapTrait.php index d33070937..402a9b5fe 100644 --- a/app/vendor/cakephp/cakephp/src/Database/TypeMapTrait.php +++ b/app/vendor/cakephp/cakephp/src/Database/TypeMapTrait.php @@ -66,7 +66,7 @@ public function getTypeMap(): TypeMap * To add a default without overwriting existing ones * use `getTypeMap()->addDefaults()` * - * @param array $types The array of types to set. + * @param array $types The array of types to set. * @return $this * @see \Cake\Database\TypeMap::setDefaults() */ @@ -80,7 +80,7 @@ public function setDefaultTypes(array $types) /** * Gets default types of current type map. * - * @return array + * @return array */ public function getDefaultTypes(): array { diff --git a/app/vendor/cakephp/cakephp/src/Database/composer.json b/app/vendor/cakephp/cakephp/src/Database/composer.json index 93251172c..64c22e80b 100644 --- a/app/vendor/cakephp/cakephp/src/Database/composer.json +++ b/app/vendor/cakephp/cakephp/src/Database/composer.json @@ -24,12 +24,13 @@ "source": "https://github.com/cakephp/database" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0", "cakephp/datasource": "^4.0" }, "suggest": { - "cakephp/i18n": "If you are using locale-aware datetime formats or Chronos types." + "cakephp/i18n": "If you are using locale-aware datetime formats or Chronos types.", + "cakephp/log": "If you want to use query logging without providing a logger yourself." }, "autoload": { "psr-4": { diff --git a/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php index fcf96b65d..01a7d5330 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/ConnectionInterface.php @@ -74,7 +74,7 @@ public function configName(): string; /** * Get the configuration data used to create the connection. * - * @return array + * @return array */ public function config(): array; @@ -82,7 +82,7 @@ public function config(): array; * Executes a callable function inside a transaction, if any exception occurs * while executing the passed callable, the transaction will be rolled back * If the result of the callable function is `false`, the transaction will - * also be rolled back. Otherwise the transaction is committed after executing + * also be rolled back. Otherwise, the transaction is committed after executing * the callback. * * The callback will receive the connection instance as its first argument. diff --git a/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php index 2f7b27337..c0991064b 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/EntityInterface.php @@ -216,7 +216,7 @@ public function getOriginalValues(): array; /** * Returns whether this entity contains a field named $field - * regardless of if it is empty. + * and is not set to null. * * @param array|string $field The field to check. * @return bool diff --git a/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php b/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php index a18b4cdea..b8ef4a9dd 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/EntityTrait.php @@ -107,7 +107,7 @@ trait EntityTrait * not defined in the map will take its value. For example, `'*' => true` * means that any field not defined in the map will be accessible by default * - * @var array + * @var array */ protected $_accessible = ['*' => true]; @@ -279,12 +279,12 @@ public function &get(string $field) } $value = null; - $method = static::_accessor($field, 'get'); if (isset($this->_fields[$field])) { $value = &$this->_fields[$field]; } + $method = static::_accessor($field, 'get'); if ($method) { $result = $this->{$method}($value); @@ -1071,7 +1071,7 @@ protected function _readError($object, $path = null): array /** * Get a list of invalid fields and their data for errors upon validation/patching * - * @return array + * @return array */ public function getInvalid(): array { @@ -1096,7 +1096,7 @@ public function getInvalidField(string $field) * This value could not be patched into the entity and is simply copied into the _invalid property for debugging * purposes or to be able to log it away. * - * @param array $fields The values to set. + * @param array $fields The values to set. * @param bool $overwrite Whether to overwrite pre-existing values for $field. * @return $this */ diff --git a/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php b/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php index 787365b14..be75b2d76 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/Exception/PageOutOfBoundsException.php @@ -1,28 +1,7 @@ $fields The values to set. * @param bool $overwrite Whether to overwrite pre-existing values for $field. * @return $this */ diff --git a/app/vendor/cakephp/cakephp/src/Datasource/Locator/AbstractLocator.php b/app/vendor/cakephp/cakephp/src/Datasource/Locator/AbstractLocator.php index 4bf00a814..1d925c09d 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/Locator/AbstractLocator.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/Locator/AbstractLocator.php @@ -53,7 +53,7 @@ public function get(string $alias, array $options = []) unset($storeOptions['allowFallbackClass']); if (isset($this->instances[$alias])) { - if (!empty($storeOptions) && $this->options[$alias] !== $storeOptions) { + if (!empty($storeOptions) && isset($this->options[$alias]) && $this->options[$alias] !== $storeOptions) { throw new RuntimeException(sprintf( 'You cannot configure "%s", it already exists in the registry.', $alias diff --git a/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php b/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php index d842cd90a..a87c8ea62 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/Paginator.php @@ -1,679 +1,7 @@ - */ - protected $_defaultConfig = [ - 'page' => 1, - 'limit' => 20, - 'maxLimit' => 100, - 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], - ]; - - /** - * Paging params after pagination operation is done. - * - * @var array - */ - protected $_pagingParams = []; - - /** - * Handles automatic pagination of model records. - * - * ### Configuring pagination - * - * When calling `paginate()` you can use the $settings parameter to pass in - * pagination settings. These settings are used to build the queries made - * and control other pagination settings. - * - * If your settings contain a key with the current table's alias. The data - * inside that key will be used. Otherwise the top level configuration will - * be used. - * - * ``` - * $settings = [ - * 'limit' => 20, - * 'maxLimit' => 100 - * ]; - * $results = $paginator->paginate($table, $settings); - * ``` - * - * The above settings will be used to paginate any repository. You can configure - * repository specific settings by keying the settings with the repository alias. - * - * ``` - * $settings = [ - * 'Articles' => [ - * 'limit' => 20, - * 'maxLimit' => 100 - * ], - * 'Comments' => [ ... ] - * ]; - * $results = $paginator->paginate($table, $settings); - * ``` - * - * This would allow you to have different pagination settings for - * `Articles` and `Comments` repositories. - * - * ### Controlling sort fields - * - * By default CakePHP will automatically allow sorting on any column on the - * repository object being paginated. Often times you will want to allow - * sorting on either associated columns or calculated fields. In these cases - * you will need to define an allowed list of all the columns you wish to allow - * sorting on. You can define the allowed sort fields in the `$settings` parameter: - * - * ``` - * $settings = [ - * 'Articles' => [ - * 'finder' => 'custom', - * 'sortableFields' => ['title', 'author_id', 'comment_count'], - * ] - * ]; - * ``` - * - * Passing an empty array as sortableFields disallows sorting altogether. - * - * ### Paginating with custom finders - * - * You can paginate with any find type defined on your table using the - * `finder` option. - * - * ``` - * $settings = [ - * 'Articles' => [ - * 'finder' => 'popular' - * ] - * ]; - * $results = $paginator->paginate($table, $settings); - * ``` - * - * Would paginate using the `find('popular')` method. - * - * You can also pass an already created instance of a query to this method: - * - * ``` - * $query = $this->Articles->find('popular')->matching('Tags', function ($q) { - * return $q->where(['name' => 'CakePHP']) - * }); - * $results = $paginator->paginate($query); - * ``` - * - * ### Scoping Request parameters - * - * By using request parameter scopes you can paginate multiple queries in - * the same controller action: - * - * ``` - * $articles = $paginator->paginate($articlesQuery, ['scope' => 'articles']); - * $tags = $paginator->paginate($tagsQuery, ['scope' => 'tags']); - * ``` - * - * Each of the above queries will use different query string parameter sets - * for pagination data. An example URL paginating both results would be: - * - * ``` - * /dashboard?articles[page]=1&tags[page]=2 - * ``` - * - * @param \Cake\Datasource\RepositoryInterface|\Cake\Datasource\QueryInterface $object The repository or query - * to paginate. - * @param array $params Request params - * @param array $settings The settings/configuration used for pagination. - * @return \Cake\Datasource\ResultSetInterface Query results - * @throws \Cake\Datasource\Exception\PageOutOfBoundsException - */ - public function paginate(object $object, array $params = [], array $settings = []): ResultSetInterface - { - $query = null; - if ($object instanceof QueryInterface) { - $query = $object; - $object = $query->getRepository(); - if ($object === null) { - throw new CakeException('No repository set for query.'); - } - } - - $data = $this->extractData($object, $params, $settings); - $query = $this->getQuery($object, $query, $data); - - $cleanQuery = clone $query; - $results = $query->all(); - $data['numResults'] = count($results); - $data['count'] = $this->getCount($cleanQuery, $data); - - $pagingParams = $this->buildParams($data); - $alias = $object->getAlias(); - $this->_pagingParams = [$alias => $pagingParams]; - if ($pagingParams['requestedPage'] > $pagingParams['page']) { - throw new PageOutOfBoundsException([ - 'requestedPage' => $pagingParams['requestedPage'], - 'pagingParams' => $this->_pagingParams, - ]); - } - - return $results; - } - - /** - * Get query for fetching paginated results. - * - * @param \Cake\Datasource\RepositoryInterface $object Repository instance. - * @param \Cake\Datasource\QueryInterface|null $query Query Instance. - * @param array $data Pagination data. - * @return \Cake\Datasource\QueryInterface - */ - protected function getQuery(RepositoryInterface $object, ?QueryInterface $query, array $data): QueryInterface - { - if ($query === null) { - $query = $object->find($data['finder'], $data['options']); - } else { - $query->applyOptions($data['options']); - } - - return $query; - } - - /** - * Get total count of records. - * - * @param \Cake\Datasource\QueryInterface $query Query instance. - * @param array $data Pagination data. - * @return int|null - */ - protected function getCount(QueryInterface $query, array $data): ?int - { - return $query->count(); - } - - /** - * Extract pagination data needed - * - * @param \Cake\Datasource\RepositoryInterface $object The repository object. - * @param array $params Request params - * @param array $settings The settings/configuration used for pagination. - * @return array Array with keys 'defaults', 'options' and 'finder' - */ - protected function extractData(RepositoryInterface $object, array $params, array $settings): array - { - $alias = $object->getAlias(); - $defaults = $this->getDefaults($alias, $settings); - $options = $this->mergeOptions($params, $defaults); - $options = $this->validateSort($object, $options); - $options = $this->checkLimit($options); - - $options += ['page' => 1, 'scope' => null]; - $options['page'] = (int)$options['page'] < 1 ? 1 : (int)$options['page']; - [$finder, $options] = $this->_extractFinder($options); - - return compact('defaults', 'options', 'finder'); - } - - /** - * Build pagination params. - * - * @param array $data Paginator data containing keys 'options', - * 'count', 'defaults', 'finder', 'numResults'. - * @return array Paging params. - */ - protected function buildParams(array $data): array - { - $limit = $data['options']['limit']; - - $paging = [ - 'count' => $data['count'], - 'current' => $data['numResults'], - 'perPage' => $limit, - 'page' => $data['options']['page'], - 'requestedPage' => $data['options']['page'], - ]; - - $paging = $this->addPageCountParams($paging, $data); - $paging = $this->addStartEndParams($paging, $data); - $paging = $this->addPrevNextParams($paging, $data); - $paging = $this->addSortingParams($paging, $data); - - $paging += [ - 'limit' => $data['defaults']['limit'] != $limit ? $limit : null, - 'scope' => $data['options']['scope'], - 'finder' => $data['finder'], - ]; - - return $paging; - } - - /** - * Add "page" and "pageCount" params. - * - * @param array $params Paging params. - * @param array $data Paginator data. - * @return array Updated params. - */ - protected function addPageCountParams(array $params, array $data): array - { - $page = $params['page']; - $pageCount = 0; - - if ($params['count'] !== null) { - $pageCount = max((int)ceil($params['count'] / $params['perPage']), 1); - $page = min($page, $pageCount); - } elseif ($params['current'] === 0 && $params['requestedPage'] > 1) { - $page = 1; - } - - $params['page'] = $page; - $params['pageCount'] = $pageCount; - - return $params; - } - - /** - * Add "start" and "end" params. - * - * @param array $params Paging params. - * @param array $data Paginator data. - * @return array Updated params. - */ - protected function addStartEndParams(array $params, array $data): array - { - $start = $end = 0; - - if ($params['current'] > 0) { - $start = (($params['page'] - 1) * $params['perPage']) + 1; - $end = $start + $params['current'] - 1; - } - - $params['start'] = $start; - $params['end'] = $end; - - return $params; - } - - /** - * Add "prevPage" and "nextPage" params. - * - * @param array $params Paginator params. - * @param array $data Paging data. - * @return array Updated params. - */ - protected function addPrevNextParams(array $params, array $data): array - { - $params['prevPage'] = $params['page'] > 1; - if ($params['count'] === null) { - $params['nextPage'] = true; - } else { - $params['nextPage'] = $params['count'] > $params['page'] * $params['perPage']; - } - - return $params; - } - - /** - * Add sorting / ordering params. - * - * @param array $params Paginator params. - * @param array $data Paging data. - * @return array Updated params. - */ - protected function addSortingParams(array $params, array $data): array - { - $defaults = $data['defaults']; - $order = (array)$data['options']['order']; - $sortDefault = $directionDefault = false; - - if (!empty($defaults['order']) && count($defaults['order']) === 1) { - $sortDefault = key($defaults['order']); - $directionDefault = current($defaults['order']); - } - - $params += [ - 'sort' => $data['options']['sort'], - 'direction' => isset($data['options']['sort']) && count($order) ? current($order) : null, - 'sortDefault' => $sortDefault, - 'directionDefault' => $directionDefault, - 'completeSort' => $order, - ]; - - return $params; - } - - /** - * Extracts the finder name and options out of the provided pagination options. - * - * @param array $options the pagination options. - * @return array An array containing in the first position the finder name - * and in the second the options to be passed to it. - */ - protected function _extractFinder(array $options): array - { - $type = !empty($options['finder']) ? $options['finder'] : 'all'; - unset($options['finder'], $options['maxLimit']); - - if (is_array($type)) { - $options = (array)current($type) + $options; - $type = key($type); - } - - return [$type, $options]; - } - - /** - * Get paging params after pagination operation. - * - * @return array - */ - public function getPagingParams(): array - { - return $this->_pagingParams; - } - - /** - * Shim method for reading the deprecated whitelist or allowedParameters options - * - * @return array - */ - protected function getAllowedParameters(): array - { - $allowed = $this->getConfig('allowedParameters'); - if (!$allowed) { - $allowed = []; - } - $whitelist = $this->getConfig('whitelist'); - if ($whitelist) { - deprecationWarning('The `whitelist` option is deprecated. Use the `allowedParameters` option instead.'); - - return array_merge($allowed, $whitelist); - } - - return $allowed; - } - - /** - * Shim method for reading the deprecated sortWhitelist or sortableFields options. - * - * @param array $config The configuration data to coalesce and emit warnings on. - * @return array|null - */ - protected function getSortableFields(array $config): ?array - { - $allowed = $config['sortableFields'] ?? null; - if ($allowed !== null) { - return $allowed; - } - $deprecated = $config['sortWhitelist'] ?? null; - if ($deprecated !== null) { - deprecationWarning('The `sortWhitelist` option is deprecated. Use `sortableFields` instead.'); - } - - return $deprecated; - } - - /** - * Merges the various options that Paginator uses. - * Pulls settings together from the following places: - * - * - General pagination settings - * - Model specific settings. - * - Request parameters - * - * The result of this method is the aggregate of all the option sets - * combined together. You can change config value `allowedParameters` to modify - * which options/values can be set using request parameters. - * - * @param array $params Request params. - * @param array $settings The settings to merge with the request data. - * @return array Array of merged options. - */ - public function mergeOptions(array $params, array $settings): array - { - if (!empty($settings['scope'])) { - $scope = $settings['scope']; - $params = !empty($params[$scope]) ? (array)$params[$scope] : []; - } - - $allowed = $this->getAllowedParameters(); - $params = array_intersect_key($params, array_flip($allowed)); - - return array_merge($settings, $params); - } - - /** - * Get the settings for a $model. If there are no settings for a specific - * repository, the general settings will be used. - * - * @param string $alias Model name to get settings for. - * @param array $settings The settings which is used for combining. - * @return array An array of pagination settings for a model, - * or the general settings. - */ - public function getDefaults(string $alias, array $settings): array - { - if (isset($settings[$alias])) { - $settings = $settings[$alias]; - } - - $defaults = $this->getConfig(); - $defaults['whitelist'] = $defaults['allowedParameters'] = $this->getAllowedParameters(); - - $maxLimit = $settings['maxLimit'] ?? $defaults['maxLimit']; - $limit = $settings['limit'] ?? $defaults['limit']; - - if ($limit > $maxLimit) { - $limit = $maxLimit; - } - - $settings['maxLimit'] = $maxLimit; - $settings['limit'] = $limit; - - return $settings + $defaults; - } - - /** - * Validate that the desired sorting can be performed on the $object. - * - * Only fields or virtualFields can be sorted on. The direction param will - * also be sanitized. Lastly sort + direction keys will be converted into - * the model friendly order key. - * - * You can use the allowedParameters option to control which columns/fields are - * available for sorting via URL parameters. This helps prevent users from ordering large - * result sets on un-indexed values. - * - * If you need to sort on associated columns or synthetic properties you - * will need to use the `sortableFields` option. - * - * Any columns listed in the allowed sort fields will be implicitly trusted. - * You can use this to sort on synthetic columns, or columns added in custom - * find operations that may not exist in the schema. - * - * The default order options provided to paginate() will be merged with the user's - * requested sorting field/direction. - * - * @param \Cake\Datasource\RepositoryInterface $object Repository object. - * @param array $options The pagination options being used for this request. - * @return array An array of options with sort + direction removed and - * replaced with order if possible. - */ - public function validateSort(RepositoryInterface $object, array $options): array - { - if (isset($options['sort'])) { - $direction = null; - if (isset($options['direction'])) { - $direction = strtolower($options['direction']); - } - if (!in_array($direction, ['asc', 'desc'], true)) { - $direction = 'asc'; - } - - $order = isset($options['order']) && is_array($options['order']) ? $options['order'] : []; - if ($order && $options['sort'] && strpos($options['sort'], '.') === false) { - $order = $this->_removeAliases($order, $object->getAlias()); - } - - $options['order'] = [$options['sort'] => $direction] + $order; - } else { - $options['sort'] = null; - } - unset($options['direction']); - - if (empty($options['order'])) { - $options['order'] = []; - } - if (!is_array($options['order'])) { - return $options; - } - - $sortAllowed = false; - $allowed = $this->getSortableFields($options); - if ($allowed !== null) { - $options['sortableFields'] = $options['sortWhitelist'] = $allowed; - - $field = key($options['order']); - $sortAllowed = in_array($field, $allowed, true); - if (!$sortAllowed) { - $options['order'] = []; - $options['sort'] = null; - - return $options; - } - } - - if ( - $options['sort'] === null - && count($options['order']) === 1 - && !is_numeric(key($options['order'])) - ) { - $options['sort'] = key($options['order']); - } - - $options['order'] = $this->_prefix($object, $options['order'], $sortAllowed); - - return $options; - } - - /** - * Remove alias if needed. - * - * @param array $fields Current fields - * @param string $model Current model alias - * @return array $fields Unaliased fields where applicable - */ - protected function _removeAliases(array $fields, string $model): array - { - $result = []; - foreach ($fields as $field => $sort) { - if (strpos($field, '.') === false) { - $result[$field] = $sort; - continue; - } - - [$alias, $currentField] = explode('.', $field); - - if ($alias === $model) { - $result[$currentField] = $sort; - continue; - } - - $result[$field] = $sort; - } - - return $result; - } - - /** - * Prefixes the field with the table alias if possible. - * - * @param \Cake\Datasource\RepositoryInterface $object Repository object. - * @param array $order Order array. - * @param bool $allowed Whether the field was allowed. - * @return array Final order array. - */ - protected function _prefix(RepositoryInterface $object, array $order, bool $allowed = false): array - { - $tableAlias = $object->getAlias(); - $tableOrder = []; - foreach ($order as $key => $value) { - if (is_numeric($key)) { - $tableOrder[] = $value; - continue; - } - $field = $key; - $alias = $tableAlias; - - if (strpos($key, '.') !== false) { - [$alias, $field] = explode('.', $key); - } - $correctAlias = ($tableAlias === $alias); - - if ($correctAlias && $allowed) { - // Disambiguate fields in schema. As id is quite common. - if ($object->hasField($field)) { - $field = $alias . '.' . $field; - } - $tableOrder[$field] = $value; - } elseif ($correctAlias && $object->hasField($field)) { - $tableOrder[$tableAlias . '.' . $field] = $value; - } elseif (!$correctAlias && $allowed) { - $tableOrder[$alias . '.' . $field] = $value; - } - } - - return $tableOrder; - } - - /** - * Check the limit parameter and ensure it's within the maxLimit bounds. - * - * @param array $options An array of options with a limit key to be checked. - * @return array An array of options for pagination. - */ - public function checkLimit(array $options): array - { - $options['limit'] = (int)$options['limit']; - if ($options['limit'] < 1) { - $options['limit'] = 1; - } - $options['limit'] = max(min($options['limit'], $options['maxLimit']), 1); - - return $options; - } -} +class_exists('Cake\Datasource\Paging\NumericPaginator'); +deprecationWarning( + 'Use Cake\Datasource\Paging\NumericPaginator instead of Cake\Datasource\Paginator.' +); diff --git a/app/vendor/cakephp/cakephp/src/Datasource/PaginatorInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/PaginatorInterface.php index c2bff1a17..eb8b3b79f 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/PaginatorInterface.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/PaginatorInterface.php @@ -1,41 +1,7 @@ */ public function aliasField(string $field, ?string $alias = null): array; @@ -62,7 +62,7 @@ public function aliasField(string $field, ?string $alias = null): array; * * @param array $fields The fields to alias * @param string|null $defaultAlias The default alias - * @return array + * @return array */ public function aliasFields(array $fields, ?string $defaultAlias = null): array; diff --git a/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php b/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php index dd950dd74..6d70a77b5 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php @@ -224,7 +224,7 @@ public function eagerLoaded(bool $value) * * @param string $field The field to alias * @param string|null $alias the alias used to prefix the field - * @return array + * @return array */ public function aliasField(string $field, ?string $alias = null): array { @@ -247,7 +247,7 @@ public function aliasField(string $field, ?string $alias = null): array * * @param array $fields The fields to alias * @param string|null $defaultAlias The default alias - * @return array + * @return array */ public function aliasFields(array $fields, ?string $defaultAlias = null): array { @@ -549,9 +549,11 @@ public function __call(string $method, array $arguments) $resultSetClass = $this->_decoratorClass(); if (in_array($method, get_class_methods($resultSetClass), true)) { deprecationWarning(sprintf( - 'Calling result set method `%s()` directly on query instance is deprecated. ' . - 'You must call `all()` to retrieve the results first.', - $method + 'Calling `%s` methods, such as `%s()`, on queries is deprecated. ' . + 'You must call `all()` first (for example, `all()->%s()`).', + ResultSetInterface::class, + $method, + $method, ), 2); $results = $this->all(); diff --git a/app/vendor/cakephp/cakephp/src/Datasource/RepositoryInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/RepositoryInterface.php index df4ed7d6c..93a00416c 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/RepositoryInterface.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/RepositoryInterface.php @@ -242,7 +242,7 @@ public function patchEntity(EntityInterface $entity, array $data, array $options * $article = $this->Articles->patchEntities($articles, $this->request->getData()); * ``` * - * @param \Traversable|array<\Cake\Datasource\EntityInterface> $entities the entities that will get the + * @param iterable<\Cake\Datasource\EntityInterface> $entities the entities that will get the * data merged in * @param array $data list of arrays to be merged into the entities * @param array $options A list of options for the objects hydration. diff --git a/app/vendor/cakephp/cakephp/src/Datasource/RuleInvoker.php b/app/vendor/cakephp/cakephp/src/Datasource/RuleInvoker.php index 3f9fe54a6..8a80efc8e 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/RuleInvoker.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/RuleInvoker.php @@ -37,7 +37,7 @@ class RuleInvoker /** * Rule options * - * @var array + * @var array */ protected $options = []; diff --git a/app/vendor/cakephp/cakephp/src/Datasource/SchemaInterface.php b/app/vendor/cakephp/cakephp/src/Datasource/SchemaInterface.php index eef98d1bb..08ab8be25 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/SchemaInterface.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/SchemaInterface.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Datasource; diff --git a/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php b/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php index 705be9a2a..95499fb6d 100644 --- a/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php +++ b/app/vendor/cakephp/cakephp/src/Datasource/SimplePaginator.php @@ -1,40 +1,7 @@ =7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0", "psr/log": "^1.0 || ^2.0", "psr/simple-cache": "^1.0 || ^2.0" diff --git a/app/vendor/cakephp/cakephp/src/Error/BaseErrorHandler.php b/app/vendor/cakephp/cakephp/src/Error/BaseErrorHandler.php index c4b3f1d14..74963b2ab 100644 --- a/app/vendor/cakephp/cakephp/src/Error/BaseErrorHandler.php +++ b/app/vendor/cakephp/cakephp/src/Error/BaseErrorHandler.php @@ -88,6 +88,12 @@ abstract protected function _displayException(Throwable $exception): void; */ public function register(): void { + deprecationWarning( + 'Use of `BaseErrorHandler` and subclasses are deprecated. ' . + 'Upgrade to the new `ErrorTrap` and `ExceptionTrap` subsystem. ' . + 'See https://book.cakephp.org/4/en/appendices/4-4-migration-guide.html' + ); + $level = $this->_config['errorLevel'] ?? -1; error_reporting($level); set_error_handler([$this, 'handleError'], $level); @@ -330,6 +336,11 @@ public function logException(Throwable $exception, ?ServerRequestInterface $requ if (empty($this->_config['log'])) { return false; } + foreach ($this->_config['skipLog'] as $class) { + if ($exception instanceof $class) { + return false; + } + } return $this->getLogger()->log($exception, $request ?? Router::getRequest()); } diff --git a/app/vendor/cakephp/cakephp/src/Error/ConsoleErrorHandler.php b/app/vendor/cakephp/cakephp/src/Error/ConsoleErrorHandler.php index fa12c763c..78353d0ca 100644 --- a/app/vendor/cakephp/cakephp/src/Error/ConsoleErrorHandler.php +++ b/app/vendor/cakephp/cakephp/src/Error/ConsoleErrorHandler.php @@ -130,3 +130,10 @@ protected function _stop(int $code): void exit($code); } } + +// phpcs:disable +class_alias( + 'Cake\Error\ConsoleErrorHandler', + 'Cake\Console\ConsoleErrorHandler' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Error/Debugger.php b/app/vendor/cakephp/cakephp/src/Error/Debugger.php index ad4395dae..e8465bb1c 100644 --- a/app/vendor/cakephp/cakephp/src/Error/Debugger.php +++ b/app/vendor/cakephp/cakephp/src/Error/Debugger.php @@ -31,6 +31,8 @@ use Cake\Error\Debug\ScalarNode; use Cake\Error\Debug\SpecialNode; use Cake\Error\Debug\TextFormatter; +use Cake\Error\Renderer\HtmlErrorRenderer; +use Cake\Error\Renderer\TextErrorRenderer; use Cake\Log\Log; use Cake\Utility\Hash; use Cake\Utility\Security; @@ -81,6 +83,7 @@ class Debugger */ protected $_templates = [ 'log' => [ + // These templates are not actually used, as Debugger::log() is called instead. 'trace' => '{:reference} - {:path}, line {:line}', 'error' => '{:error} ({:code}): {:description} in [{:file}, line {:line}]', ], @@ -110,6 +113,21 @@ class Debugger ], ]; + /** + * Mapping for error renderers. + * + * Error renderers are replacing output formatting with + * an object based system. Having Debugger handle and render errors + * will be deprecated and the new ErrorTrap system should be used instead. + * + * @var array + */ + protected $renderers = [ + 'txt' => TextErrorRenderer::class, + // The html alias currently uses no JS and will be deprecated. + 'js' => HtmlErrorRenderer::class, + ]; + /** * A map of editors to their link templates. * @@ -442,9 +460,12 @@ public static function formatTrace($backtrace, array $options = []) if (in_array($signature, $options['exclude'], true)) { continue; } - if ($options['format'] === 'points' && $trace['file'] !== '[internal]') { - $back[] = ['file' => $trace['file'], 'line' => $trace['line']]; + if ($options['format'] === 'points') { + $back[] = ['file' => $trace['file'], 'line' => $trace['line'], 'reference' => $reference]; } elseif ($options['format'] === 'array') { + if (!$options['args']) { + unset($trace['args']); + } $back[] = $trace; } else { if (isset($self->_templates[$options['format']]['traceLine'])) { @@ -463,7 +484,10 @@ public static function formatTrace($backtrace, array $options = []) return $back; } - /** @psalm-suppress InvalidArgument */ + /** + * @psalm-suppress InvalidArgument + * @phpstan-ignore-next-line + */ return implode("\n", $back); } @@ -758,7 +782,7 @@ protected static function exportObject(object $var, DebugContext $context): Node if ($remaining > 0) { if (method_exists($var, '__debugInfo')) { try { - foreach ($var->__debugInfo() as $key => $val) { + foreach ((array)$var->__debugInfo() as $key => $val) { $node->addProperty(new PropertyNode("'{$key}'", null, static::export($val, $context))); } @@ -817,9 +841,12 @@ protected static function exportObject(object $var, DebugContext $context): Node * Get the output format for Debugger error rendering. * * @return string Returns the current format when getting. + * @deprecated 4.4.0 Update your application so use ErrorTrap instead. */ public static function getOutputFormat(): string { + deprecationWarning('Debugger::getOutputFormat() is deprecated.'); + return Debugger::getInstance()->_outputFormat; } @@ -829,9 +856,11 @@ public static function getOutputFormat(): string * @param string $format The format you want errors to be output as. * @return void * @throws \InvalidArgumentException When choosing a format that doesn't exist. + * @deprecated 4.4.0 Update your application so use ErrorTrap instead. */ public static function setOutputFormat(string $format): void { + deprecationWarning('Debugger::setOutputFormat() is deprecated.'); $self = Debugger::getInstance(); if (!isset($self->_templates[$format])) { @@ -882,9 +911,11 @@ public static function setOutputFormat(string $format): void * straight HTML output, or 'txt' for unformatted text. * @param array $strings Template strings, or a callback to be used for the output format. * @return array The resulting format string set. + * @deprecated 4.4.0 Update your application so use ErrorTrap instead. */ public static function addFormat(string $format, array $strings): array { + deprecationWarning('Debugger::addFormat() is deprecated.'); $self = Debugger::getInstance(); if (isset($self->_templates[$format])) { if (isset($strings['links'])) { @@ -898,15 +929,37 @@ public static function addFormat(string $format, array $strings): array } else { $self->_templates[$format] = $strings; } + unset($self->renderers[$format]); return $self->_templates[$format]; } + /** + * Add a renderer to the current instance. + * + * @param string $name The alias for the the renderer. + * @param class-string<\Cake\Error\ErrorRendererInterface> $class The classname of the renderer to use. + * @return void + * @deprecated 4.4.0 Update your application so use ErrorTrap instead. + */ + public static function addRenderer(string $name, string $class): void + { + deprecationWarning('Debugger::addRenderer() is deprecated.'); + if (!in_array(ErrorRendererInterface::class, class_implements($class))) { + throw new InvalidArgumentException( + 'Invalid renderer class. $class must implement ' . ErrorRendererInterface::class + ); + } + $self = Debugger::getInstance(); + $self->renderers[$name] = $class; + } + /** * Takes a processed array of data from an error and displays it in the chosen format. * * @param array $data Data to output. * @return void + * @deprecated 4.4.0 Update your application so use ErrorTrap instead. */ public function outputError(array $data): void { @@ -922,6 +975,17 @@ public function outputError(array $data): void ]; $data += $defaults; + $outputFormat = $this->_outputFormat; + if (isset($this->renderers[$outputFormat])) { + /** @var array $trace */ + $trace = static::trace(['start' => $data['start'], 'format' => 'points']); + $error = new PhpError($data['code'], $data['description'], $data['file'], $data['line'], $trace); + $renderer = new $this->renderers[$outputFormat](); + echo $renderer->render($error, Configure::read('debug')); + + return; + } + $files = static::trace(['start' => $data['start'], 'format' => 'points']); $code = ''; $file = null; @@ -956,7 +1020,7 @@ public function outputError(array $data): void $data['trace'] = $trace; $data['id'] = 'cakeErr' . uniqid(); - $tpl = $this->_templates[$this->_outputFormat] + $this->_templates['base']; + $tpl = $this->_templates[$outputFormat] + $this->_templates['base']; if (isset($tpl['links'])) { foreach ($tpl['links'] as $key => $val) { @@ -1064,9 +1128,8 @@ public static function formatHtmlMessage(string $message): string { $message = h($message); $message = preg_replace('/`([^`]+)`/', '$1', $message); - $message = nl2br($message); - return $message; + return nl2br($message); } /** diff --git a/app/vendor/cakephp/cakephp/src/Error/ErrorHandler.php b/app/vendor/cakephp/cakephp/src/Error/ErrorHandler.php index 540f02a87..f69193f3f 100644 --- a/app/vendor/cakephp/cakephp/src/Error/ErrorHandler.php +++ b/app/vendor/cakephp/cakephp/src/Error/ErrorHandler.php @@ -199,7 +199,7 @@ protected function _logInternalError(Throwable $exception): void /** * Method that can be easily stubbed in testing. * - * @param \Cake\Http\Response|string $response Either the message or response object. + * @param \Psr\Http\Message\ResponseInterface|string $response Either the message or response object. * @return void */ protected function _sendResponse($response): void diff --git a/app/vendor/cakephp/cakephp/src/Error/ErrorLogger.php b/app/vendor/cakephp/cakephp/src/Error/ErrorLogger.php index 91b81db0a..4e91d8b90 100644 --- a/app/vendor/cakephp/cakephp/src/Error/ErrorLogger.php +++ b/app/vendor/cakephp/cakephp/src/Error/ErrorLogger.php @@ -33,14 +33,11 @@ class ErrorLogger implements ErrorLoggerInterface /** * Default configuration values. * - * - `skipLog` List of exceptions to skip logging. Exceptions that - * extend one of the listed exceptions will also not be logged. * - `trace` Should error logs include stack traces? * * @var array */ protected $_defaultConfig = [ - 'skipLog' => [], 'trace' => false, ]; @@ -55,7 +52,59 @@ public function __construct(array $config = []) } /** - * @inheritDoc + * Log an error to Cake's Log subsystem + * + * @param \Cake\Error\PhpError $error The error to log + * @param ?\Psr\Http\Message\ServerRequestInterface $request The request if in an HTTP context. + * @param bool $includeTrace Should the log message include a stacktrace + * @return void + */ + public function logError(PhpError $error, ?ServerRequestInterface $request = null, bool $includeTrace = false): void + { + $message = $error->getMessage(); + if ($request) { + $message .= $this->getRequestContext($request); + } + if ($includeTrace) { + $message .= "\nTrace:\n" . $error->getTraceAsString() . "\n"; + } + $logMap = [ + 'strict' => LOG_NOTICE, + 'deprecated' => LOG_NOTICE, + ]; + $level = $error->getLabel(); + $level = $logMap[$level] ?? $level; + + Log::write($level, $message); + } + + /** + * Log an exception to Cake's Log subsystem + * + * @param \Throwable $exception The exception to log a message for. + * @param \Psr\Http\Message\ServerRequestInterface|null $request The current request if available. + * @param bool $includeTrace Whether or not a stack trace should be logged. + * @return void + */ + public function logException( + Throwable $exception, + ?ServerRequestInterface $request = null, + bool $includeTrace = false + ): void { + $message = $this->getMessage($exception, false, $includeTrace); + + if ($request !== null) { + $message .= $this->getRequestContext($request); + } + Log::error($message); + } + + /** + * @param string|int $level The logging level + * @param string $message The message to be logged. + * @param array $context Context. + * @return bool + * @deprecated 4.4.0 Use logError instead. */ public function logMessage($level, string $message, array $context = []): bool { @@ -65,22 +114,24 @@ public function logMessage($level, string $message, array $context = []): bool if (!empty($context['trace'])) { $message .= "\nTrace:\n" . $context['trace'] . "\n"; } + $logMap = [ + 'strict' => LOG_NOTICE, + 'deprecated' => LOG_NOTICE, + ]; + $level = $logMap[$level] ?? $level; return Log::write($level, $message); } /** - * @inheritDoc + * @param \Throwable $exception The exception to log a message for. + * @param \Psr\Http\Message\ServerRequestInterface|null $request The current request if available. + * @return bool + * @deprecated 4.4.0 Use logException instead. */ public function log(Throwable $exception, ?ServerRequestInterface $request = null): bool { - foreach ($this->getConfig('skipLog') as $class) { - if ($exception instanceof $class) { - return false; - } - } - - $message = $this->getMessage($exception); + $message = $this->getMessage($exception, false, $this->getConfig('trace')); if ($request !== null) { $message .= $this->getRequestContext($request); @@ -96,9 +147,10 @@ public function log(Throwable $exception, ?ServerRequestInterface $request = nul * * @param \Throwable $exception The exception to log a message for. * @param bool $isPrevious False for original exception, true for previous + * @param bool $includeTrace Whether or not to include a stack trace. * @return string Error message */ - protected function getMessage(Throwable $exception, bool $isPrevious = false): string + protected function getMessage(Throwable $exception, bool $isPrevious = false, bool $includeTrace = false): string { $message = sprintf( '%s[%s] %s in %s on line %s', @@ -117,7 +169,7 @@ protected function getMessage(Throwable $exception, bool $isPrevious = false): s } } - if ($this->getConfig('trace')) { + if ($includeTrace) { /** @var array $trace */ $trace = Debugger::formatTrace($exception, ['format' => 'points']); $message .= "\nStack Trace:\n"; @@ -132,7 +184,7 @@ protected function getMessage(Throwable $exception, bool $isPrevious = false): s $previous = $exception->getPrevious(); if ($previous) { - $message .= $this->getMessage($previous, true); + $message .= $this->getMessage($previous, true, $includeTrace); } return $message; diff --git a/app/vendor/cakephp/cakephp/src/Error/ErrorLoggerInterface.php b/app/vendor/cakephp/cakephp/src/Error/ErrorLoggerInterface.php index b8ee57c23..5a2626b24 100644 --- a/app/vendor/cakephp/cakephp/src/Error/ErrorLoggerInterface.php +++ b/app/vendor/cakephp/cakephp/src/Error/ErrorLoggerInterface.php @@ -24,6 +24,11 @@ * * Used by the ErrorHandlerMiddleware and global * error handlers to log exceptions and errors. + * + * @method void logException(\Throwable $exception, ?\Psr\Http\Message\ServerRequestInterface $request = null, bool $includeTrace = false) + * Log an exception with an optional HTTP request. + * @method void logError(\Cake\Error\PhpError $error, ?\Psr\Http\Message\ServerRequestInterface $request = null, bool $includeTrace = false) + * Log an error with an optional HTTP request. */ interface ErrorLoggerInterface { @@ -33,6 +38,7 @@ interface ErrorLoggerInterface * @param \Throwable $exception The exception to log a message for. * @param \Psr\Http\Message\ServerRequestInterface|null $request The current request if available. * @return bool + * @deprecated 4.4.0 Implement `logException` instead. */ public function log( Throwable $exception, @@ -46,6 +52,7 @@ public function log( * @param string $message The message to be logged. * @param array $context Context. * @return bool + * @deprecated 4.4.0 Implement `logError` instead. */ public function logMessage($level, string $message, array $context = []): bool; } diff --git a/app/vendor/cakephp/cakephp/src/Error/ExceptionRenderer.php b/app/vendor/cakephp/cakephp/src/Error/ExceptionRenderer.php index 9c0e6fad3..c4dab58a6 100644 --- a/app/vendor/cakephp/cakephp/src/Error/ExceptionRenderer.php +++ b/app/vendor/cakephp/cakephp/src/Error/ExceptionRenderer.php @@ -16,460 +16,13 @@ */ namespace Cake\Error; -use Cake\Controller\Controller; -use Cake\Controller\ControllerFactory; -use Cake\Controller\Exception\InvalidParameterException; -use Cake\Controller\Exception\MissingActionException; -use Cake\Core\App; -use Cake\Core\Configure; -use Cake\Core\Container; -use Cake\Core\Exception\CakeException; -use Cake\Core\Exception\MissingPluginException; -use Cake\Datasource\Exception\PageOutOfBoundsException; -use Cake\Datasource\Exception\RecordNotFoundException; -use Cake\Event\Event; -use Cake\Http\Exception\HttpException; -use Cake\Http\Exception\MissingControllerException; -use Cake\Http\Response; -use Cake\Http\ServerRequest; -use Cake\Http\ServerRequestFactory; -use Cake\Routing\Exception\MissingRouteException; -use Cake\Routing\Router; -use Cake\Utility\Inflector; -use Cake\View\Exception\MissingLayoutException; -use Cake\View\Exception\MissingTemplateException; -use PDOException; -use Psr\Http\Message\ResponseInterface; -use Throwable; +use Cake\Error\Renderer\WebExceptionRenderer; /** - * Exception Renderer. + * Backwards compatible Exception Renderer. * - * Captures and handles all unhandled exceptions. Displays helpful framework errors when debug is true. - * When debug is false a ExceptionRenderer will render 404 or 500 errors. If an uncaught exception is thrown - * and it is a type that ExceptionHandler does not know about it will be treated as a 500 error. - * - * ### Implementing application specific exception rendering - * - * You can implement application specific exception handling by creating a subclass of - * ExceptionRenderer and configure it to be the `exceptionRenderer` in config/error.php - * - * #### Using a subclass of ExceptionRenderer - * - * Using a subclass of ExceptionRenderer gives you full control over how Exceptions are rendered, you - * can configure your class in your config/app.php. + * @deprecated 4.4.0 Use `Cake\Error\Renderer\WebExceptionRenderer` instead. */ -class ExceptionRenderer implements ExceptionRendererInterface +class ExceptionRenderer extends WebExceptionRenderer { - /** - * The exception being handled. - * - * @var \Throwable - */ - protected $error; - - /** - * Controller instance. - * - * @var \Cake\Controller\Controller - */ - protected $controller; - - /** - * Template to render for {@link \Cake\Core\Exception\CakeException} - * - * @var string - */ - protected $template = ''; - - /** - * The method corresponding to the Exception this object is for. - * - * @var string - */ - protected $method = ''; - - /** - * If set, this will be request used to create the controller that will render - * the error. - * - * @var \Cake\Http\ServerRequest|null - */ - protected $request; - - /** - * Map of exceptions to http status codes. - * - * This can be customized for users that don't want specific exceptions to throw 404 errors - * or want their application exceptions to be automatically converted. - * - * @var array - * @psalm-var array, int> - */ - protected $exceptionHttpCodes = [ - // Controller exceptions - InvalidParameterException::class => 404, - MissingActionException::class => 404, - // Datasource exceptions - PageOutOfBoundsException::class => 404, - RecordNotFoundException::class => 404, - // Http exceptions - MissingControllerException::class => 404, - // Routing exceptions - MissingRouteException::class => 404, - ]; - - /** - * Creates the controller to perform rendering on the error response. - * - * @param \Throwable $exception Exception. - * @param \Cake\Http\ServerRequest|null $request The request if this is set it will be used - * instead of creating a new one. - */ - public function __construct(Throwable $exception, ?ServerRequest $request = null) - { - $this->error = $exception; - $this->request = $request; - $this->controller = $this->_getController(); - } - - /** - * Get the controller instance to handle the exception. - * Override this method in subclasses to customize the controller used. - * This method returns the built in `ErrorController` normally, or if an error is repeated - * a bare controller will be used. - * - * @return \Cake\Controller\Controller - * @triggers Controller.startup $controller - */ - protected function _getController(): Controller - { - $request = $this->request; - $routerRequest = Router::getRequest(); - // Fallback to the request in the router or make a new one from - // $_SERVER - if ($request === null) { - $request = $routerRequest ?: ServerRequestFactory::fromGlobals(); - } - - // If the current request doesn't have routing data, but we - // found a request in the router context copy the params over - if ($request->getParam('controller') === null && $routerRequest !== null) { - $request = $request->withAttribute('params', $routerRequest->getAttribute('params')); - } - - $errorOccured = false; - try { - $params = $request->getAttribute('params'); - $params['controller'] = 'Error'; - - $factory = new ControllerFactory(new Container()); - $class = $factory->getControllerClass($request->withAttribute('params', $params)); - - if (!$class) { - /** @var string $class */ - $class = App::className('Error', 'Controller', 'Controller'); - } - - /** @var \Cake\Controller\Controller $controller */ - $controller = new $class($request); - $controller->startupProcess(); - } catch (Throwable $e) { - $errorOccured = true; - } - - if (!isset($controller)) { - return new Controller($request); - } - - // Retry RequestHandler, as another aspect of startupProcess() - // could have failed. Ignore any exceptions out of startup, as - // there could be userland input data parsers. - if ($errorOccured && isset($controller->RequestHandler)) { - try { - $event = new Event('Controller.startup', $controller); - $controller->RequestHandler->startup($event); - } catch (Throwable $e) { - } - } - - return $controller; - } - - /** - * Clear output buffers so error pages display properly. - * - * @return void - */ - protected function clearOutput(): void - { - if (in_array(PHP_SAPI, ['cli', 'phpdbg'])) { - return; - } - while (ob_get_level()) { - ob_end_clean(); - } - } - - /** - * Renders the response for the exception. - * - * @return \Cake\Http\Response The response to be sent. - */ - public function render(): ResponseInterface - { - $exception = $this->error; - $code = $this->getHttpCode($exception); - $method = $this->_method($exception); - $template = $this->_template($exception, $method, $code); - $this->clearOutput(); - - if (method_exists($this, $method)) { - return $this->_customMethod($method, $exception); - } - - $message = $this->_message($exception, $code); - $url = $this->controller->getRequest()->getRequestTarget(); - $response = $this->controller->getResponse(); - - if ($exception instanceof CakeException) { - /** @psalm-suppress DeprecatedMethod */ - foreach ((array)$exception->responseHeader() as $key => $value) { - $response = $response->withHeader($key, $value); - } - } - if ($exception instanceof HttpException) { - foreach ($exception->getHeaders() as $name => $value) { - $response = $response->withHeader($name, $value); - } - } - $response = $response->withStatus($code); - - $viewVars = [ - 'message' => $message, - 'url' => h($url), - 'error' => $exception, - 'code' => $code, - ]; - $serialize = ['message', 'url', 'code']; - - $isDebug = Configure::read('debug'); - if ($isDebug) { - $trace = (array)Debugger::formatTrace($exception->getTrace(), [ - 'format' => 'array', - 'args' => false, - ]); - $origin = [ - 'file' => $exception->getFile() ?: 'null', - 'line' => $exception->getLine() ?: 'null', - ]; - // Traces don't include the origin file/line. - array_unshift($trace, $origin); - $viewVars['trace'] = $trace; - $viewVars += $origin; - $serialize[] = 'file'; - $serialize[] = 'line'; - } - $this->controller->set($viewVars); - $this->controller->viewBuilder()->setOption('serialize', $serialize); - - if ($exception instanceof CakeException && $isDebug) { - $this->controller->set($exception->getAttributes()); - } - $this->controller->setResponse($response); - - return $this->_outputMessage($template); - } - - /** - * Render a custom error method/template. - * - * @param string $method The method name to invoke. - * @param \Throwable $exception The exception to render. - * @return \Cake\Http\Response The response to send. - */ - protected function _customMethod(string $method, Throwable $exception): Response - { - $result = $this->{$method}($exception); - $this->_shutdown(); - if (is_string($result)) { - $result = $this->controller->getResponse()->withStringBody($result); - } - - return $result; - } - - /** - * Get method name - * - * @param \Throwable $exception Exception instance. - * @return string - */ - protected function _method(Throwable $exception): string - { - [, $baseClass] = namespaceSplit(get_class($exception)); - - if (substr($baseClass, -9) === 'Exception') { - $baseClass = substr($baseClass, 0, -9); - } - - // $baseClass would be an empty string if the exception class is \Exception. - $method = $baseClass === '' ? 'error500' : Inflector::variable($baseClass); - - return $this->method = $method; - } - - /** - * Get error message. - * - * @param \Throwable $exception Exception. - * @param int $code Error code. - * @return string Error message - */ - protected function _message(Throwable $exception, int $code): string - { - $message = $exception->getMessage(); - - if ( - !Configure::read('debug') && - !($exception instanceof HttpException) - ) { - if ($code < 500) { - $message = __d('cake', 'Not Found'); - } else { - $message = __d('cake', 'An Internal Error Has Occurred.'); - } - } - - return $message; - } - - /** - * Get template for rendering exception info. - * - * @param \Throwable $exception Exception instance. - * @param string $method Method name. - * @param int $code Error code. - * @return string Template name - */ - protected function _template(Throwable $exception, string $method, int $code): string - { - if ($exception instanceof HttpException || !Configure::read('debug')) { - return $this->template = $code < 500 ? 'error400' : 'error500'; - } - - if ($exception instanceof PDOException) { - return $this->template = 'pdo_error'; - } - - return $this->template = $method; - } - - /** - * Gets the appropriate http status code for exception. - * - * @param \Throwable $exception Exception. - * @return int A valid HTTP status code. - */ - protected function getHttpCode(Throwable $exception): int - { - if ($exception instanceof HttpException) { - return $exception->getCode(); - } - - return $this->exceptionHttpCodes[get_class($exception)] ?? 500; - } - - /** - * Generate the response using the controller object. - * - * @param string $template The template to render. - * @return \Cake\Http\Response A response object that can be sent. - */ - protected function _outputMessage(string $template): Response - { - try { - $this->controller->render($template); - - return $this->_shutdown(); - } catch (MissingTemplateException $e) { - $attributes = $e->getAttributes(); - if ( - $e instanceof MissingLayoutException || - strpos($attributes['file'], 'error500') !== false - ) { - return $this->_outputMessageSafe('error500'); - } - - return $this->_outputMessage('error500'); - } catch (MissingPluginException $e) { - $attributes = $e->getAttributes(); - if (isset($attributes['plugin']) && $attributes['plugin'] === $this->controller->getPlugin()) { - $this->controller->setPlugin(null); - } - - return $this->_outputMessageSafe('error500'); - } catch (Throwable $outer) { - try { - return $this->_outputMessageSafe('error500'); - } catch (Throwable $inner) { - throw $outer; - } - } - } - - /** - * A safer way to render error messages, replaces all helpers, with basics - * and doesn't call component methods. - * - * @param string $template The template to render. - * @return \Cake\Http\Response A response object that can be sent. - */ - protected function _outputMessageSafe(string $template): Response - { - $builder = $this->controller->viewBuilder(); - $builder - ->setHelpers([], false) - ->setLayoutPath('') - ->setTemplatePath('Error'); - $view = $this->controller->createView('View'); - - $response = $this->controller->getResponse() - ->withType('html') - ->withStringBody($view->render($template, 'error')); - $this->controller->setResponse($response); - - return $response; - } - - /** - * Run the shutdown events. - * - * Triggers the afterFilter and afterDispatch events. - * - * @return \Cake\Http\Response The response to serve. - */ - protected function _shutdown(): Response - { - $this->controller->dispatchEvent('Controller.shutdown'); - - return $this->controller->getResponse(); - } - - /** - * Returns an array that can be used to describe the internal state of this - * object. - * - * @return array - */ - public function __debugInfo(): array - { - return [ - 'error' => $this->error, - 'request' => $this->request, - 'controller' => $this->controller, - 'template' => $this->template, - 'method' => $this->method, - ]; - } } diff --git a/app/vendor/cakephp/cakephp/src/Error/ExceptionRendererInterface.php b/app/vendor/cakephp/cakephp/src/Error/ExceptionRendererInterface.php index 103e244ac..e6bc4f7a4 100644 --- a/app/vendor/cakephp/cakephp/src/Error/ExceptionRendererInterface.php +++ b/app/vendor/cakephp/cakephp/src/Error/ExceptionRendererInterface.php @@ -20,13 +20,17 @@ /** * Interface ExceptionRendererInterface + * + * @method \Psr\Http\Message\ResponseInterface|string render() Render the exception to a string or Http Response. + * @method void write(\Psr\Http\Message\ResponseInterface|string $output) Write the output to the output stream. + * This method is only called when exceptions are handled by a global default exception handler. */ interface ExceptionRendererInterface { /** * Renders the response for the exception. * - * @return \Cake\Http\Response The response to be sent. + * @return \Psr\Http\Message\ResponseInterface The response to be sent. */ public function render(): ResponseInterface; } diff --git a/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php b/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php index 565935446..d1e7efae7 100644 --- a/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php @@ -20,7 +20,8 @@ use Cake\Core\Configure; use Cake\Core\InstanceConfigTrait; use Cake\Error\ErrorHandler; -use Cake\Error\ExceptionRenderer; +use Cake\Error\ExceptionTrap; +use Cake\Error\Renderer\WebExceptionRenderer; use Cake\Http\Exception\RedirectException; use Cake\Http\Response; use InvalidArgumentException; @@ -44,28 +45,17 @@ class ErrorHandlerMiddleware implements MiddlewareInterface /** * Default configuration values. * - * Ignored if contructor is passed an ErrorHandler instance. + * Ignored if contructor is passed an ExceptionTrap instance. * - * - `log` Enable logging of exceptions. - * - `skipLog` List of exceptions to skip logging. Exceptions that - * extend one of the listed exceptions will also not be logged. Example: - * - * ``` - * 'skipLog' => ['Cake\Error\NotFoundException', 'Cake\Error\UnauthorizedException'] - * ``` - * - * - `trace` Should error logs include stack traces? - * - `exceptionRenderer` The renderer instance or class name to use or a callable factory - * which returns a \Cake\Error\ExceptionRendererInterface instance. - * Defaults to \Cake\Error\ExceptionRenderer + * Configuration keys and values are shared with `ExceptionTrap`. + * This class will pass its configuration onto the ExceptionTrap + * class if you are using the array style constructor. * * @var array + * @see \Cake\Error\ExceptionTrap */ protected $_defaultConfig = [ - 'skipLog' => [], - 'log' => true, - 'trace' => false, - 'exceptionRenderer' => ExceptionRenderer::class, + 'exceptionRenderer' => WebExceptionRenderer::class, ]; /** @@ -73,12 +63,19 @@ class ErrorHandlerMiddleware implements MiddlewareInterface * * @var \Cake\Error\ErrorHandler|null */ - protected $errorHandler; + protected $errorHandler = null; + + /** + * ExceptionTrap instance + * + * @var \Cake\Error\ExceptionTrap|null + */ + protected $exceptionTrap = null; /** * Constructor * - * @param \Cake\Error\ErrorHandler|array $errorHandler The error handler instance + * @param \Cake\Error\ErrorHandler|\Cake\Error\ExceptionTrap|array $errorHandler The error handler instance * or config array. * @throws \InvalidArgumentException */ @@ -102,15 +99,23 @@ public function __construct($errorHandler = []) return; } + if ($errorHandler instanceof ErrorHandler) { + deprecationWarning( + 'Using an `ErrorHandler` is deprecated. You should migate to the `ExceptionTrap` sub-system instead.' + ); + $this->errorHandler = $errorHandler; - if (!$errorHandler instanceof ErrorHandler) { - throw new InvalidArgumentException(sprintf( - '$errorHandler argument must be a config array or ErrorHandler instance. Got `%s` instead.', - getTypeName($errorHandler) - )); + return; } + if ($errorHandler instanceof ExceptionTrap) { + $this->exceptionTrap = $errorHandler; - $this->errorHandler = $errorHandler; + return; + } + throw new InvalidArgumentException(sprintf( + '$errorHandler argument must be a config array or ExceptionTrap instance. Got `%s` instead.', + getTypeName($errorHandler) + )); } /** @@ -118,7 +123,7 @@ public function __construct($errorHandler = []) * * @param \Psr\Http\Message\ServerRequestInterface $request The request. * @param \Psr\Http\Server\RequestHandlerInterface $handler The request handler. - * @return \Psr\Http\Message\ResponseInterface A response. + * @return \Psr\Http\Message\ResponseInterface A response */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { @@ -136,22 +141,35 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface * * @param \Throwable $exception The exception to handle. * @param \Psr\Http\Message\ServerRequestInterface $request The request. - * @return \Psr\Http\Message\ResponseInterface A response + * @return \Psr\Http\Message\ResponseInterface A response. */ public function handleException(Throwable $exception, ServerRequestInterface $request): ResponseInterface { - $errorHandler = $this->getErrorHandler(); - $renderer = $errorHandler->getRenderer($exception, $request); + if ($this->errorHandler === null) { + $handler = $this->getExceptionTrap(); + $handler->logException($exception, $request); + + $renderer = $handler->renderer($exception, $request); + } else { + $handler = $this->getErrorHandler(); + $handler->logException($exception, $request); + + $renderer = $handler->getRenderer($exception, $request); + } try { - $errorHandler->logException($exception, $request); + /** @var \Psr\Http\Message\ResponseInterface|string $response */ $response = $renderer->render(); + if (is_string($response)) { + return new Response(['body' => $response, 'status' => 500]); + } + + return $response; } catch (Throwable $internalException) { - $errorHandler->logException($internalException, $request); - $response = $this->handleInternalError(); - } + $handler->logException($internalException, $request); - return $response; + return $this->handleInternalError(); + } } /** @@ -176,9 +194,10 @@ public function handleRedirect(RedirectException $exception): ResponseInterface */ protected function handleInternalError(): ResponseInterface { - $response = new Response(['body' => 'An Internal Server Error Occurred']); - - return $response->withStatus(500); + return new Response([ + 'body' => 'An Internal Server Error Occurred', + 'status' => 500, + ]); } /** @@ -196,4 +215,20 @@ protected function getErrorHandler(): ErrorHandler return $this->errorHandler; } + + /** + * Get a exception trap instance + * + * @return \Cake\Error\ExceptionTrap The exception trap. + */ + protected function getExceptionTrap(): ExceptionTrap + { + if ($this->exceptionTrap === null) { + /** @var class-string<\Cake\Error\ExceptionTrap> $className */ + $className = App::className('ExceptionTrap', 'Error'); + $this->exceptionTrap = new $className($this->getConfig()); + } + + return $this->exceptionTrap; + } } diff --git a/app/vendor/cakephp/cakephp/src/Event/Event.php b/app/vendor/cakephp/cakephp/src/Event/Event.php index 12f7be341..86e3fd03f 100644 --- a/app/vendor/cakephp/cakephp/src/Event/Event.php +++ b/app/vendor/cakephp/cakephp/src/Event/Event.php @@ -22,6 +22,7 @@ * Class Event * * @template TSubject + * @implements \Cake\Event\EventInterface */ class Event implements EventInterface { @@ -105,7 +106,6 @@ public function getName(): string * @return object * @throws \Cake\Core\Exception\CakeException * @psalm-return TSubject - * @psalm-suppress LessSpecificImplementedReturnType */ public function getSubject() { @@ -172,8 +172,7 @@ public function getData(?string $key = null) return $this->_data[$key] ?? null; } - /** @psalm-suppress RedundantCastGivenDocblockType */ - return (array)$this->_data; + return $this->_data; } /** diff --git a/app/vendor/cakephp/cakephp/src/Event/EventInterface.php b/app/vendor/cakephp/cakephp/src/Event/EventInterface.php index f11cb6d45..aca9956d6 100644 --- a/app/vendor/cakephp/cakephp/src/Event/EventInterface.php +++ b/app/vendor/cakephp/cakephp/src/Event/EventInterface.php @@ -20,6 +20,8 @@ * Represents the transport class of events across the system. It receives a name, subject and an optional * payload. The name can be any string that uniquely identifies the event across the application, while the subject * represents the object that the event applies to. + * + * @template TSubject */ interface EventInterface { @@ -34,6 +36,7 @@ public function getName(): string; * Returns the subject of this event. * * @return object + * @psalm-return TSubject */ public function getSubject(); diff --git a/app/vendor/cakephp/cakephp/src/Event/EventManager.php b/app/vendor/cakephp/cakephp/src/Event/EventManager.php index 8bea9679a..278261d56 100644 --- a/app/vendor/cakephp/cakephp/src/Event/EventManager.php +++ b/app/vendor/cakephp/cakephp/src/Event/EventManager.php @@ -363,14 +363,13 @@ public function prioritisedListeners(string $eventKey): array public function matchingListeners(string $eventKeyPattern): array { $matchPattern = '/' . preg_quote($eventKeyPattern, '/') . '/'; - $matches = array_intersect_key( + + return array_intersect_key( $this->_listeners, array_flip( preg_grep($matchPattern, array_keys($this->_listeners), 0) ) ); - - return $matches; } /** diff --git a/app/vendor/cakephp/cakephp/src/Event/EventManagerInterface.php b/app/vendor/cakephp/cakephp/src/Event/EventManagerInterface.php index 1581f7699..492319b0f 100644 --- a/app/vendor/cakephp/cakephp/src/Event/EventManagerInterface.php +++ b/app/vendor/cakephp/cakephp/src/Event/EventManagerInterface.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.6.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Event; diff --git a/app/vendor/cakephp/cakephp/src/Event/composer.json b/app/vendor/cakephp/cakephp/src/Event/composer.json index d3a9bc50b..7e7ed7474 100644 --- a/app/vendor/cakephp/cakephp/src/Event/composer.json +++ b/app/vendor/cakephp/cakephp/src/Event/composer.json @@ -23,7 +23,7 @@ "source": "https://github.com/cakephp/event" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0" }, "autoload": { diff --git a/app/vendor/cakephp/cakephp/src/Filesystem/Filesystem.php b/app/vendor/cakephp/cakephp/src/Filesystem/Filesystem.php index d1ecebc3b..3f3921855 100644 --- a/app/vendor/cakephp/cakephp/src/Filesystem/Filesystem.php +++ b/app/vendor/cakephp/cakephp/src/Filesystem/Filesystem.php @@ -223,9 +223,7 @@ public function deleteDir(string $path): bool unset($iterator); // phpcs:ignore - $result = $result && @rmdir($path); - - return $result; + return $result && @rmdir($path); } /** diff --git a/app/vendor/cakephp/cakephp/src/Filesystem/Folder.php b/app/vendor/cakephp/cakephp/src/Filesystem/Folder.php index e593ccee8..00d11a454 100644 --- a/app/vendor/cakephp/cakephp/src/Filesystem/Folder.php +++ b/app/vendor/cakephp/cakephp/src/Filesystem/Folder.php @@ -617,7 +617,7 @@ public function tree(?string $path = null, $exceptions = false, ?string $type = * * @param string $pathname The directory structure to create. Either an absolute or relative * path. If the path is relative and exists in the process' cwd it will not be created. - * Otherwise relative paths will be prefixed with the current pwd(). + * Otherwise, relative paths will be prefixed with the current pwd(). * @param int|null $mode octal value 0755 * @return bool Returns TRUE on success, FALSE on failure */ @@ -646,13 +646,14 @@ public function create(string $pathname, ?int $mode = null): bool if ($this->create($nextPathname, $mode)) { if (!file_exists($pathname)) { $old = umask(0); - umask($old); if (mkdir($pathname, $mode, true)) { $this->_messages[] = sprintf('%s created', $pathname); + umask($old); return true; } $this->_errors[] = sprintf('%s NOT created', $pathname); + umask($old); return false; } diff --git a/app/vendor/cakephp/cakephp/src/Filesystem/composer.json b/app/vendor/cakephp/cakephp/src/Filesystem/composer.json index edaffd5b6..82688b7c1 100644 --- a/app/vendor/cakephp/cakephp/src/Filesystem/composer.json +++ b/app/vendor/cakephp/cakephp/src/Filesystem/composer.json @@ -23,7 +23,7 @@ "source": "https://github.com/cakephp/filesystem" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0" }, "autoload": { diff --git a/app/vendor/cakephp/cakephp/src/Form/composer.json b/app/vendor/cakephp/cakephp/src/Form/composer.json index 794281138..016644ca5 100644 --- a/app/vendor/cakephp/cakephp/src/Form/composer.json +++ b/app/vendor/cakephp/cakephp/src/Form/composer.json @@ -21,7 +21,7 @@ "source": "https://github.com/cakephp/form" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/event": "^4.0", "cakephp/validation": "^4.0" }, diff --git a/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php b/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php index 1b072a71b..a8c381db3 100644 --- a/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php +++ b/app/vendor/cakephp/cakephp/src/Http/BaseApplication.php @@ -294,7 +294,7 @@ public function services(ContainerInterface $container): void /** * Invoke the application. * - * - Convert the PSR response into CakePHP equivalents. + * - Add the request to the container, enabling its injection into other services. * - Create the controller that will handle this request. * - Invoke the controller. * @@ -304,8 +304,11 @@ public function services(ContainerInterface $container): void public function handle( ServerRequestInterface $request ): ResponseInterface { + $container = $this->getContainer(); + $container->add(ServerRequest::class, $request); + if ($this->controllerFactory === null) { - $this->controllerFactory = new ControllerFactory($this->getContainer()); + $this->controllerFactory = new ControllerFactory($container); } if (Router::getRequest() !== $request) { diff --git a/app/vendor/cakephp/cakephp/src/Http/Client.php b/app/vendor/cakephp/cakephp/src/Http/Client.php index 7fc14d8a2..e2dbd16ab 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Client.php +++ b/app/vendor/cakephp/cakephp/src/Http/Client.php @@ -111,6 +111,7 @@ class Client implements ClientInterface * @var array */ protected $_defaultConfig = [ + 'auth' => null, 'adapter' => null, 'host' => null, 'port' => null, @@ -174,6 +175,10 @@ class Client implements ClientInterface * \Cake\Http\Client\Adapter\Curl if `curl` extension is loaded else * \Cake\Http\Client\Adapter\Stream. * - protocolVersion - The HTTP protocol version to use. Defaults to 1.1 + * - auth - The authentication credentials to use. If a `username` and `password` + * key are provided without a `type` key Basic authentication will be assumed. + * You can use the `type` key to define the authentication adapter classname + * to use. Short class names are resolved to the `Http\Client\Auth` namespace. * * @param array $config Config options for scoped clients. * @throws \InvalidArgumentException diff --git a/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php b/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php index 18bfa0af9..d77fb0a6d 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php +++ b/app/vendor/cakephp/cakephp/src/Http/Client/Adapter/Stream.php @@ -41,14 +41,14 @@ class Stream implements AdapterInterface /** * Array of options/content for the HTTP stream context. * - * @var array + * @var array */ protected $_contextOptions = []; /** * Array of options/content for the SSL stream context. * - * @var array + * @var array */ protected $_sslContextOptions = []; @@ -320,7 +320,7 @@ protected function _open(string $url, RequestInterface $request): void restore_error_handler(); } - if (!$this->_stream || !empty($this->_connectionErrors)) { + if (!$this->_stream || $this->_connectionErrors) { throw new RequestException(implode("\n", $this->_connectionErrors), $request); } } @@ -330,7 +330,7 @@ protected function _open(string $url, RequestInterface $request): void * * Useful for debugging and testing context creation. * - * @return array + * @return array */ public function contextOptions(): array { diff --git a/app/vendor/cakephp/cakephp/src/Http/Client/FormData.php b/app/vendor/cakephp/cakephp/src/Http/Client/FormData.php index 286b842eb..329702195 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Client/FormData.php +++ b/app/vendor/cakephp/cakephp/src/Http/Client/FormData.php @@ -17,6 +17,7 @@ use Countable; use finfo; +use Psr\Http\Message\UploadedFileInterface; /** * Provides an interface for building @@ -101,7 +102,7 @@ public function add($name, $value = null) if (is_string($name)) { if (is_array($value)) { $this->addRecursive($name, $value); - } elseif (is_resource($value)) { + } elseif (is_resource($value) || $value instanceof UploadedFileInterface) { $this->addFile($name, $value); } else { $this->_parts[] = $this->newPart($name, (string)$value); @@ -136,7 +137,8 @@ public function addMany(array $data) * or a file handle. * * @param string $name The name to use. - * @param mixed $value Either a string filename, or a filehandle. + * @param string|resource|\Psr\Http\Message\UploadedFileInterface $value Either a string filename, or a filehandle, + * or a UploadedFileInterface instance. * @return \Cake\Http\Client\FormDataPart */ public function addFile(string $name, $value): FormDataPart @@ -145,7 +147,11 @@ public function addFile(string $name, $value): FormDataPart $filename = false; $contentType = 'application/octet-stream'; - if (is_resource($value)) { + if ($value instanceof UploadedFileInterface) { + $content = (string)$value->getStream(); + $contentType = $value->getClientMediaType(); + $filename = $value->getClientFilename(); + } elseif (is_resource($value)) { $content = stream_get_contents($value); if (stream_is_local($value)) { $finfo = new finfo(FILEINFO_MIME); diff --git a/app/vendor/cakephp/cakephp/src/Http/Client/Response.php b/app/vendor/cakephp/cakephp/src/Http/Client/Response.php index 74b3818be..13df4d3d1 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Client/Response.php +++ b/app/vendor/cakephp/cakephp/src/Http/Client/Response.php @@ -115,7 +115,7 @@ class Response extends Message implements ResponseInterface /** * Cached decoded JSON data. * - * @var array + * @var mixed */ protected $_json; diff --git a/app/vendor/cakephp/cakephp/src/Http/Cookie/Cookie.php b/app/vendor/cakephp/cakephp/src/Http/Cookie/Cookie.php index 9ab9ed3ca..f4fea6736 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Cookie/Cookie.php +++ b/app/vendor/cakephp/cakephp/src/Http/Cookie/Cookie.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Http\Cookie; @@ -134,7 +134,7 @@ class Cookie implements CookieInterface * The only difference is the 3rd argument which excepts null or an * DateTime or DateTimeImmutable object instead an integer. * - * @link http://php.net/manual/en/function.setcookie.php + * @link https://php.net/manual/en/function.setcookie.php * @param string $name Cookie name * @param array|string $value Value of the cookie * @param \DateTime|\DateTimeImmutable|null $expiresAt Expiration time and date @@ -236,7 +236,7 @@ public static function create(string $name, $value, array $options = []) * Converts non null expiry value into DateTimeInterface instance. * * @param mixed $expires Expiry value. - * @return \DateTime|\DatetimeImmutable|null + * @return \DateTime|\DateTimeImmutable|null */ protected static function dateTimeInstance($expires): ?DateTimeInterface { diff --git a/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php b/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php index 93057cbe2..d7c13295f 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php +++ b/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieCollection.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Http\Cookie; diff --git a/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieInterface.php b/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieInterface.php index dfcdeae1a..2befd1e11 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieInterface.php +++ b/app/vendor/cakephp/cakephp/src/Http/Cookie/CookieInterface.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Http\Cookie; diff --git a/app/vendor/cakephp/cakephp/src/Http/Exception/HttpException.php b/app/vendor/cakephp/cakephp/src/Http/Exception/HttpException.php index 0a81d2476..e39ea89d2 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Exception/HttpException.php +++ b/app/vendor/cakephp/cakephp/src/Http/Exception/HttpException.php @@ -32,7 +32,7 @@ class HttpException extends CakeException protected $_defaultCode = 500; /** - * @var array + * @var array */ protected $headers = []; @@ -51,7 +51,7 @@ public function setHeader(string $header, $value = null): void /** * Sets HTTP response headers. * - * @param array $headers Array of header name and value pairs. + * @param array $headers Array of header name and value pairs. * @return void */ public function setHeaders(array $headers): void @@ -62,7 +62,7 @@ public function setHeaders(array $headers): void /** * Returns array of response headers. * - * @return array + * @return array */ public function getHeaders(): array { diff --git a/app/vendor/cakephp/cakephp/src/Http/Exception/MissingControllerException.php b/app/vendor/cakephp/cakephp/src/Http/Exception/MissingControllerException.php index 4cbe6c15f..63152bd05 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Exception/MissingControllerException.php +++ b/app/vendor/cakephp/cakephp/src/Http/Exception/MissingControllerException.php @@ -32,3 +32,10 @@ class MissingControllerException extends CakeException */ protected $_messageTemplate = 'Controller class %s could not be found.'; } + +// phpcs:disable +class_alias( + 'Cake\Http\Exception\MissingControllerException', + 'Cake\Routing\Exception\MissingControllerException' +); +// phpcs:enable diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/BodyParserMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/BodyParserMiddleware.php index bd8f0d201..8432bc610 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/BodyParserMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/BodyParserMiddleware.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.6.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Http\Middleware; diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/CspMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/CspMiddleware.php index 082e4dec4..91d44d302 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/CspMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/CspMiddleware.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 4.0.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Http\Middleware; diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php index 28e33bdf1..a350b24f4 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Http\Middleware; @@ -429,7 +429,7 @@ protected function _validateToken(ServerRequestInterface $request): void */ protected function _createCookie(string $value, ServerRequestInterface $request): CookieInterface { - $cookie = Cookie::create( + return Cookie::create( $this->_config['cookieName'], $value, [ @@ -440,7 +440,5 @@ protected function _createCookie(string $value, ServerRequestInterface $request) 'samesite' => $this->_config['samesite'], ] ); - - return $cookie; } } diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/EncryptedCookieMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/EncryptedCookieMiddleware.php index f9e0a4dca..c40e349ea 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/EncryptedCookieMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/EncryptedCookieMiddleware.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Http\Middleware; diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php index 9176b9a43..709cc6f10 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/HttpsEnforcerMiddleware.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 4.0.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Http\Middleware; @@ -23,6 +23,7 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; +use UnexpectedValueException; /** * Enforces use of HTTPS (SSL) for requests. @@ -38,6 +39,12 @@ class HttpsEnforcerMiddleware implements MiddlewareInterface * - `statusCode` - Status code to use in case of redirect, defaults to 301 - Permanent redirect. * - `headers` - Array of response headers in case of redirect. * - `disableOnDebug` - Whether HTTPS check should be disabled when debug is on. Default `true`. + * - 'hsts' - Strict-Transport-Security header for HTTPS response configuration. Defaults to `null`. + * If enabled, an array of config options: + * + * - 'maxAge' - `max-age` directive value in seconds. + * - 'includeSubDomains' - Whether to include `includeSubDomains` directive. Defaults to `false`. + * - 'preload' - Whether to include 'preload' directive. Defauls to `false`. * * @var array */ @@ -46,6 +53,7 @@ class HttpsEnforcerMiddleware implements MiddlewareInterface 'statusCode' => 301, 'headers' => [], 'disableOnDebug' => true, + 'hsts' => null, ]; /** @@ -77,7 +85,12 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface || ($this->config['disableOnDebug'] && Configure::read('debug')) ) { - return $handler->handle($request); + $response = $handler->handle($request); + if ($this->config['hsts']) { + $response = $this->addHsts($response); + } + + return $response; } if ($this->config['redirect'] && $request->getMethod() === 'GET') { @@ -98,4 +111,28 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface 'Requests to this URL must be made with HTTPS.' ); } + + /** + * Adds Strict-Transport-Security header to response. + * + * @param \Psr\Http\Message\ResponseInterface $response Response + * @return \Psr\Http\Message\ResponseInterface + */ + protected function addHsts(ResponseInterface $response): ResponseInterface + { + $config = $this->config['hsts']; + if (!is_array($config)) { + throw new UnexpectedValueException('The `hsts` config must be an array.'); + } + + $value = 'max-age=' . $config['maxAge']; + if ($config['includeSubDomains'] ?? false) { + $value .= '; includeSubDomains'; + } + if ($config['preload'] ?? false) { + $value .= '; preload'; + } + + return $response->withHeader('strict-transport-security', $value); + } } diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/SecurityHeadersMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/SecurityHeadersMiddleware.php index f8249b9a6..eeb05e14b 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/SecurityHeadersMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/SecurityHeadersMiddleware.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Http\Middleware; @@ -98,7 +98,7 @@ class SecurityHeadersMiddleware implements MiddlewareInterface /** * Security related headers to set * - * @var array + * @var array */ protected $headers = []; diff --git a/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php b/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php index b4c0b0734..abba6cd1a 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 4.2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Http\Middleware; @@ -43,7 +43,7 @@ * * If you use this middleware *do not* also use CsrfProtectionMiddleware. * - * @see https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#sychronizer-token-pattern + * @see https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#synchronizer-token-pattern */ class SessionCsrfProtectionMiddleware implements MiddlewareInterface { diff --git a/app/vendor/cakephp/cakephp/src/Http/Response.php b/app/vendor/cakephp/cakephp/src/Http/Response.php index 6bf4bea2a..3feb4b4b1 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Response.php +++ b/app/vendor/cakephp/cakephp/src/Http/Response.php @@ -401,7 +401,7 @@ class Response implements ResponseInterface * Holds all the cache directives that will be converted * into headers when sending the request * - * @var array + * @var array */ protected $_cacheDirectives = []; @@ -660,7 +660,7 @@ protected function _setStatus(int $code, string $reasonPhrase = ''): void * status code. * * @link https://tools.ietf.org/html/rfc7231#section-6 - * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml + * @link https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml * @return string Reason phrase; must return an empty string if none present. */ public function getReasonPhrase(): string @@ -989,10 +989,15 @@ public function withModified($time) * * *Warning* This method mutates the response in-place and should be avoided. * + * @deprecated 4.4.0 Use `withNotModified()` instead. * @return void */ public function notModified(): void { + deprecationWarning( + 'The `notModified()` method is deprecated. ' . + 'Use `withNotModified() instead, and remember immutability of with* methods.' + ); $this->_createStream(); $this->_setStatus(304); @@ -1192,19 +1197,16 @@ public function withAddedLink(string $url, array $options = []) /** * Checks whether a response has not been modified according to the 'If-None-Match' * (Etags) and 'If-Modified-Since' (last modification date) request - * headers. If the response is detected to be not modified, it - * is marked as so accordingly so the client can be informed of that. - * - * In order to mark a response as not modified, you need to set at least - * the Last-Modified etag response header before calling this method. Otherwise - * a comparison will not be possible. + * headers. * - * *Warning* This method mutates the response in-place and should be avoided. + * In order to interact with this method you must mark responses as not modified. + * You need to set at least one of the `Last-Modified` or `Etag` response headers + * before calling this method. Otherwise, a comparison will not be possible. * * @param \Cake\Http\ServerRequest $request Request object - * @return bool Whether the response was marked as not modified or not. + * @return bool Whether the response is 'modified' based on cache headers. */ - public function checkNotModified(ServerRequest $request): bool + public function isNotModified(ServerRequest $request): bool { $etags = preg_split('/\s*,\s*/', $request->getHeaderLine('If-None-Match'), 0, PREG_SPLIT_NO_EMPTY); $responseTag = $this->getHeaderLine('Etag'); @@ -1221,12 +1223,39 @@ public function checkNotModified(ServerRequest $request): bool if ($etagMatches === null && $timeMatches === null) { return false; } - $notModified = $etagMatches !== false && $timeMatches !== false; - if ($notModified) { + + return $etagMatches !== false && $timeMatches !== false; + } + + /** + * Checks whether a response has not been modified according to the 'If-None-Match' + * (Etags) and 'If-Modified-Since' (last modification date) request + * headers. If the response is detected to be not modified, it + * is marked as so accordingly so the client can be informed of that. + * + * In order to mark a response as not modified, you need to set at least + * the Last-Modified etag response header before calling this method. Otherwise + * a comparison will not be possible. + * + * *Warning* This method mutates the response in-place and should be avoided. + * + * @param \Cake\Http\ServerRequest $request Request object + * @return bool Whether the response was marked as not modified or not. + * @deprecated 4.4.0 Use `isNotModified()` and `withNotModified()` instead. + */ + public function checkNotModified(ServerRequest $request): bool + { + deprecationWarning( + 'The `checkNotModified()` method is deprecated. ' . + 'Use `isNotModified() instead and `withNoModified()` instead.' + ); + if ($this->isNotModified($request)) { $this->notModified(); + + return true; } - return $notModified; + return false; } /** @@ -1310,7 +1339,7 @@ public function getCookie(string $name): ?array * * Returns an associative array of cookie name => cookie data. * - * @return array + * @return array */ public function getCookies(): array { diff --git a/app/vendor/cakephp/cakephp/src/Http/Runner.php b/app/vendor/cakephp/cakephp/src/Http/Runner.php index f9ced44c3..dc8498424 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Runner.php +++ b/app/vendor/cakephp/cakephp/src/Http/Runner.php @@ -77,12 +77,10 @@ public function handle(ServerRequestInterface $request): ResponseInterface return $this->fallbackHandler->handle($request); } - $response = new Response([ + return new Response([ 'body' => 'Middleware queue was exhausted without returning a response ' . 'and no fallback request handler was set for Runner', 'status' => 500, ]); - - return $response; } } diff --git a/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php b/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php index 183d01ebb..eaf661177 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php +++ b/app/vendor/cakephp/cakephp/src/Http/ServerRequest.php @@ -69,14 +69,14 @@ class ServerRequest implements ServerRequestInterface /** * Array of cookie data. * - * @var array + * @var array */ protected $cookies = []; /** * Array of environment data. * - * @var array + * @var array */ protected $_environment = []; @@ -129,13 +129,18 @@ class ServerRequest implements ServerRequestInterface 'ssl' => ['env' => 'HTTPS', 'options' => [1, 'on']], 'ajax' => ['env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'], 'json' => ['accept' => ['application/json'], 'param' => '_ext', 'value' => 'json'], - 'xml' => ['accept' => ['application/xml', 'text/xml'], 'param' => '_ext', 'value' => 'xml'], + 'xml' => [ + 'accept' => ['application/xml', 'text/xml'], + 'exclude' => ['text/html'], + 'param' => '_ext', + 'value' => 'xml', + ], ]; /** * Instance cache for results of is(something) calls * - * @var array + * @var array */ protected $_detectorCache = []; @@ -170,7 +175,7 @@ class ServerRequest implements ServerRequestInterface /** * Store the additional attributes attached to the request. * - * @var array + * @var array */ protected $attributes = []; @@ -404,6 +409,7 @@ public function setTrustedProxies(array $proxies): void { $this->trustedProxies = $proxies; $this->trustProxy = true; + $this->uri = $this->uri->withScheme($this->scheme()); } /** @@ -552,14 +558,26 @@ protected function _is(string $type, array $args): bool */ protected function _acceptHeaderDetector(array $detect): bool { - $acceptHeaders = explode(',', (string)$this->getEnv('HTTP_ACCEPT')); - foreach ($detect['accept'] as $header) { - if (in_array($header, $acceptHeaders, true)) { - return true; - } + $content = new ContentTypeNegotiation(); + $options = $detect['accept']; + + // Some detectors overlap with the default browser Accept header + // For these types we use an exclude list to refine our content type + // detection. + $exclude = $detect['exclude'] ?? null; + if ($exclude) { + $options = array_merge($options, $exclude); } - return false; + $accepted = $content->preferredType($this, $options); + if ($accepted === null) { + return false; + } + if ($exclude && in_array($accepted, $exclude, true)) { + return false; + } + + return true; } /** @@ -769,7 +787,7 @@ protected function normalizeHeaderName(string $name): string * the headers. * * @return array An associative array of headers and their values. - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function getHeaders(): array { @@ -797,7 +815,7 @@ public function getHeaders(): array * * @param string $name The header you want to get (case-insensitive) * @return bool Whether the header is defined. - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function hasHeader($name): bool { @@ -815,7 +833,7 @@ public function hasHeader($name): bool * @param string $name The header you want to get (case-insensitive) * @return array An associative array of headers and their values. * If the header doesn't exist, an empty array will be returned. - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function getHeader($name): array { @@ -832,7 +850,7 @@ public function getHeader($name): array * * @param string $name The header you want to get (case-insensitive) * @return string Header values collapsed into a comma separated string. - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function getHeaderLine($name): string { @@ -847,7 +865,7 @@ public function getHeaderLine($name): string * @param string $name The header name. * @param array|string $value The header value * @return static - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function withHeader($name, $value) { @@ -867,7 +885,7 @@ public function withHeader($name, $value) * @param string $name The header name. * @param array|string $value The header value * @return static - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function withAddedHeader($name, $value) { @@ -888,7 +906,7 @@ public function withAddedHeader($name, $value) * * @param string $name The header name to remove. * @return static - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function withoutHeader($name) { @@ -911,7 +929,7 @@ public function withoutHeader($name) * by CakePHP internally, and will effect the result of this method. * * @return string The name of the HTTP method used. - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function getMethod(): string { @@ -923,7 +941,7 @@ public function getMethod(): string * * @param string $method The HTTP method to use. * @return static A new instance with the updated method. - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function withMethod($method) { @@ -950,7 +968,7 @@ public function withMethod($method) * used to create this request. * * @return array - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function getServerParams(): array { @@ -962,7 +980,7 @@ public function getServerParams(): array * use the alternative getQuery() method. * * @return array - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function getQueryParams(): array { @@ -974,7 +992,7 @@ public function getQueryParams(): array * * @param array $query The query string data to use * @return static A new instance with the updated query string data. - * @link http://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. + * @link https://www.php-fig.org/psr/psr-7/ This method is part of the PSR-7 server request interface. */ public function withQueryParams(array $query) { @@ -1092,16 +1110,17 @@ public function subdomains(int $tldLength = 1): array */ public function accepts(?string $type = null) { - $raw = $this->parseAccept(); + $content = new ContentTypeNegotiation(); + if ($type) { + return $content->preferredType($this, [$type]) !== null; + } + $accept = []; - foreach ($raw as $types) { + foreach ($content->parseAccept($this) as $types) { $accept = array_merge($accept, $types); } - if ($type === null) { - return $accept; - } - return in_array($type, $accept, true); + return $accept; } /** @@ -1112,10 +1131,11 @@ public function accepts(?string $type = null) * of the accepted content types. * * @return array An array of `prefValue => [content/types]` + * @deprecated 4.4.0 Use `accepts()` or `ContentTypeNegotiation` class instead. */ public function parseAccept(): array { - return $this->_parseAcceptWithQualifier($this->getHeaderLine('Accept')); + return (new ContentTypeNegotiation())->parseAccept($this); } /** @@ -1123,74 +1143,23 @@ public function parseAccept(): array * * Get the list of accepted languages: * - * ``` \Cake\Http\ServerRequest::acceptLanguage(); ``` + * ```$request->acceptLanguage();``` * * Check if a specific language is accepted: * - * ``` \Cake\Http\ServerRequest::acceptLanguage('es-es'); ``` + * ```$request->acceptLanguage('es-es');``` * * @param string|null $language The language to test. - * @return array|bool If a $language is provided, a boolean. Otherwise the array of accepted languages. + * @return array|bool If a $language is provided, a boolean. Otherwise, the array of accepted languages. */ public function acceptLanguage(?string $language = null) { - $raw = $this->_parseAcceptWithQualifier($this->getHeaderLine('Accept-Language')); - $accept = []; - foreach ($raw as $languages) { - foreach ($languages as &$lang) { - if (strpos($lang, '_')) { - $lang = str_replace('_', '-', $lang); - } - $lang = strtolower($lang); - } - $accept = array_merge($accept, $languages); - } - if ($language === null) { - return $accept; - } - - return in_array(strtolower($language), $accept, true); - } - - /** - * Parse Accept* headers with qualifier options. - * - * Only qualifiers will be extracted, any other accept extensions will be - * discarded as they are not frequently used. - * - * @param string $header Header to parse. - * @return array - */ - protected function _parseAcceptWithQualifier(string $header): array - { - $accept = []; - $headers = explode(',', $header); - foreach (array_filter($headers) as $value) { - $prefValue = '1.0'; - $value = trim($value); - - $semiPos = strpos($value, ';'); - if ($semiPos !== false) { - $params = explode(';', $value); - $value = trim($params[0]); - foreach ($params as $param) { - $qPos = strpos($param, 'q='); - if ($qPos !== false) { - $prefValue = substr($param, $qPos + 2); - } - } - } - - if (!isset($accept[$prefValue])) { - $accept[$prefValue] = []; - } - if ($prefValue) { - $accept[$prefValue][] = $value; - } + $content = new ContentTypeNegotiation(); + if ($language !== null) { + return $content->acceptLanguage($this, $language); } - krsort($accept); - return $accept; + return $content->acceptedLanguages($this); } /** @@ -1363,7 +1332,7 @@ public function withCookieCollection(CookieCollection $cookies) /** * Get all the cookie data from the request. * - * @return array An array of cookie data. + * @return array An array of cookie data. */ public function getCookieParams(): array { @@ -1667,7 +1636,7 @@ public function getAttribute($name, $default = null) * This will include the params, webroot, base, and here attributes that CakePHP * provides. * - * @return array + * @return array */ public function getAttributes(): array { diff --git a/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php b/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php index 4746fb78a..fe6e4f9f4 100644 --- a/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php +++ b/app/vendor/cakephp/cakephp/src/Http/ServerRequestFactory.php @@ -17,6 +17,7 @@ namespace Cake\Http; use Cake\Core\Configure; +use Cake\Http\Uri as CakeUri; use Cake\Utility\Hash; use Psr\Http\Message\ServerRequestFactoryInterface; use Psr\Http\Message\ServerRequestInterface; @@ -29,9 +30,9 @@ /** * Factory for making ServerRequest instances. * - * This subclass adds in CakePHP specific behavior to populate - * the basePath and webroot attributes. Furthermore the Uri's path - * is corrected to only contain the 'virtual' path for the request. + * This adds in CakePHP specific behavior to populate the basePath and webroot + * attributes. Furthermore the Uri's path is corrected to only contain the + * 'virtual' path for the request. */ abstract class ServerRequestFactory implements ServerRequestFactoryInterface { @@ -41,10 +42,6 @@ abstract class ServerRequestFactory implements ServerRequestFactoryInterface * If any argument is not supplied, the corresponding superglobal value will * be used. * - * The ServerRequest created is then passed to the fromServer() method in - * order to marshal the request URI and headers. - * - * @see fromServer() * @param array|null $server $_SERVER superglobal * @param array|null $query $_GET superglobal * @param array|null $parsedBody $_POST superglobal @@ -63,29 +60,44 @@ public static function fromGlobals( $server = normalizeServer($server ?: $_SERVER); $uri = static::createUri($server); + $webroot = ''; + $base = ''; + if ($uri instanceof CakeUri) { + // Unwrap our shim for base and webroot. + // For 5.x we should change the interface on createUri() to return a + // tuple of [$uri, $base, $webroot] and remove the wrapper. + $webroot = $uri->getWebroot(); + $base = $uri->getBase(); + $uri->getUri(); + } + /** @psalm-suppress NoInterfaceProperties */ $sessionConfig = (array)Configure::read('Session') + [ 'defaults' => 'php', - 'cookiePath' => $uri->webroot, + 'cookiePath' => $webroot, ]; $session = Session::create($sessionConfig); - /** @psalm-suppress NoInterfaceProperties */ $request = new ServerRequest([ 'environment' => $server, 'uri' => $uri, 'cookies' => $cookies ?: $_COOKIE, 'query' => $query ?: $_GET, - 'webroot' => $uri->webroot, - 'base' => $uri->base, + 'webroot' => $webroot, + 'base' => $base, 'session' => $session, 'input' => $server['CAKEPHP_INPUT'] ?? null, ]); $request = static::marshalBodyAndRequestMethod($parsedBody ?? $_POST, $request); - $request = static::marshalFiles($files ?? $_FILES, $request); - - return $request; + // This is required as `ServerRequest::scheme()` ignores the value of + // `HTTP_X_FORWARDED_PROTO` unless `trustProxy` is enabled, while the + // `Uri` instance intially created always takes values of `HTTP_X_FORWARDED_PROTO` + // into account. + $uri = $request->getUri()->withScheme($request->scheme()); + $request = $request->withUri($uri, true); + + return static::marshalFiles($files ?? $_FILES, $request); } /** @@ -228,10 +240,11 @@ public static function createUri(array $server = []): UriInterface * * @param array $server The server parameters. * @param array $headers The normalized headers - * @return \Psr\Http\Message\UriInterface a constructed Uri + * @return \Cake\Http\Uri A constructed Uri */ protected static function marshalUriFromSapi(array $server, array $headers): UriInterface { + /** @psalm-suppress DeprecatedFunction */ $uri = marshalUriFromSapi($server, $headers); [$base, $webroot] = static::getBase($uri, $server); @@ -248,14 +261,7 @@ protected static function marshalUriFromSapi(array $server, array $headers): Uri $uri = $uri->withHost('localhost'); } - // Splat on some extra attributes to save - // some method calls. - /** @psalm-suppress NoInterfaceProperties */ - $uri->base = $base; - /** @psalm-suppress NoInterfaceProperties */ - $uri->webroot = $webroot; - - return $uri; + return new CakeUri($uri, $base, $webroot); } /** diff --git a/app/vendor/cakephp/cakephp/src/Http/Session.php b/app/vendor/cakephp/cakephp/src/Http/Session.php index 19b83d5f4..a9a0687b0 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Session.php +++ b/app/vendor/cakephp/cakephp/src/Http/Session.php @@ -263,22 +263,16 @@ public function engine($class = null, array $options = []): ?SessionHandlerInter if ($class instanceof SessionHandlerInterface) { return $this->setEngine($class); } - $className = App::className($class, 'Http/Session'); - if (!$className) { + /** @var class-string<\SessionHandlerInterface>|null $className */ + $className = App::className($class, 'Http/Session'); + if ($className === null) { throw new InvalidArgumentException( sprintf('The class "%s" does not exist and cannot be used as a session engine', $class) ); } - $handler = new $className($options); - if (!($handler instanceof SessionHandlerInterface)) { - throw new InvalidArgumentException( - 'The chosen SessionHandler does not implement SessionHandlerInterface, it cannot be used as an engine.' - ); - } - - return $this->setEngine($handler); + return $this->setEngine(new $className($options)); } /** @@ -560,13 +554,12 @@ public function delete(string $name): void */ protected function _overwrite(array &$old, array $new): void { - if (!empty($old)) { - foreach ($old as $key => $var) { - if (!isset($new[$key])) { - unset($old[$key]); - } + foreach ($old as $key => $var) { + if (!isset($new[$key])) { + unset($old[$key]); } } + foreach ($new as $key => $var) { $old[$key] = $var; } diff --git a/app/vendor/cakephp/cakephp/src/Http/Session/CacheSession.php b/app/vendor/cakephp/cakephp/src/Http/Session/CacheSession.php index 668ba0e76..2959521c5 100644 --- a/app/vendor/cakephp/cakephp/src/Http/Session/CacheSession.php +++ b/app/vendor/cakephp/cakephp/src/Http/Session/CacheSession.php @@ -32,7 +32,7 @@ class CacheSession implements SessionHandlerInterface /** * Options for this session engine * - * @var array + * @var array */ protected $_options = []; diff --git a/app/vendor/cakephp/cakephp/src/Http/composer.json b/app/vendor/cakephp/cakephp/src/Http/composer.json index 5802f3e21..c5d38425d 100644 --- a/app/vendor/cakephp/cakephp/src/Http/composer.json +++ b/app/vendor/cakephp/cakephp/src/Http/composer.json @@ -23,7 +23,7 @@ "source": "https://github.com/cakephp/http" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0", "cakephp/event": "^4.0", "cakephp/utility": "^4.0", diff --git a/app/vendor/cakephp/cakephp/src/I18n/Date.php b/app/vendor/cakephp/cakephp/src/I18n/Date.php index 0ba24c7e0..3dcc47eb2 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/Date.php +++ b/app/vendor/cakephp/cakephp/src/I18n/Date.php @@ -36,7 +36,7 @@ class Date extends MutableDate implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position @@ -52,7 +52,7 @@ class Date extends MutableDate implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position @@ -77,7 +77,7 @@ class Date extends MutableDate implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position diff --git a/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php b/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php index a42d79bb2..bd23d8cb5 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php +++ b/app/vendor/cakephp/cakephp/src/I18n/DateFormatTrait.php @@ -16,7 +16,9 @@ */ namespace Cake\I18n; +use Cake\Chronos\ChronosInterface; use Cake\Chronos\DifferenceFormatterInterface; +use Cake\Core\Exception\CakeException; use Closure; use DateTime; use DateTimeZone; @@ -287,7 +289,7 @@ public static function resetToStringFormat(): void * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position @@ -359,6 +361,9 @@ public static function parseDateTime(string $time, $format = null, $tz = null) null, $pattern ); + if (!$formatter) { + throw new CakeException('Unable to create IntlDateFormatter instance'); + } $formatter->setLenient(static::$lenientParsing); $time = $formatter->parse($time); @@ -479,6 +484,34 @@ public static function setDiffFormatter(DifferenceFormatterInterface $formatter) static::$diffFormatter = $formatter; } + /** + * Get the difference in a human readable format. + * + * When comparing a value in the past to default now: + * 1 hour ago + * 5 months ago + * + * When comparing a value in the future to default now: + * 1 hour from now + * 5 months from now + * + * When comparing a value in the past to another value: + * 1 hour before + * 5 months before + * + * When comparing a value in the future to another value: + * 1 hour after + * 5 months after + * + * @param \Cake\Chronos\ChronosInterface|null $other The datetime to compare with. + * @param bool $absolute removes time difference modifiers ago, after, etc + * @return string + */ + public function diffForHumans(?ChronosInterface $other = null, bool $absolute = false): string + { + return static::getDiffFormatter()->diffForHumans($this, $other, $absolute); + } + /** * Returns the data that should be displayed when debugging this object * diff --git a/app/vendor/cakephp/cakephp/src/I18n/FormatterLocator.php b/app/vendor/cakephp/cakephp/src/I18n/FormatterLocator.php index 53631f9cc..d1d1fa0be 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/FormatterLocator.php +++ b/app/vendor/cakephp/cakephp/src/I18n/FormatterLocator.php @@ -29,7 +29,7 @@ class FormatterLocator /** * A registry to retain formatter objects. * - * @var array + * @var array> */ protected $registry = []; @@ -44,7 +44,7 @@ class FormatterLocator /** * Constructor. * - * @param array $registry An array of key-value pairs where the key is the + * @param array> $registry An array of key-value pairs where the key is the * formatter name the value is a FQCN for the formatter. */ public function __construct(array $registry = []) @@ -58,7 +58,7 @@ public function __construct(array $registry = []) * Sets a formatter into the registry by name. * * @param string $name The formatter name. - * @param string $className A FQCN for a formatter. + * @param class-string<\Cake\I18n\FormatterInterface> $className A FQCN for a formatter. * @return void */ public function set(string $name, string $className): void @@ -81,10 +81,13 @@ public function get(string $name): FormatterInterface } if (!$this->converted[$name]) { - $this->registry[$name] = new $this->registry[$name](); + /** @var class-string<\Cake\I18n\FormatterInterface> $formatter */ + $formatter = $this->registry[$name]; + $this->registry[$name] = new $formatter(); $this->converted[$name] = true; } + /** @var \Cake\I18n\FormatterInterface */ return $this->registry[$name]; } } diff --git a/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php b/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php index c20fe7f68..4596bb0ea 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php +++ b/app/vendor/cakephp/cakephp/src/I18n/FrozenDate.php @@ -36,7 +36,7 @@ class FrozenDate extends ChronosDate implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position @@ -52,7 +52,7 @@ class FrozenDate extends ChronosDate implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position @@ -77,7 +77,7 @@ class FrozenDate extends ChronosDate implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position diff --git a/app/vendor/cakephp/cakephp/src/I18n/FrozenTime.php b/app/vendor/cakephp/cakephp/src/I18n/FrozenTime.php index 9711bf479..f1e6d6215 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/FrozenTime.php +++ b/app/vendor/cakephp/cakephp/src/I18n/FrozenTime.php @@ -37,7 +37,7 @@ class FrozenTime extends Chronos implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position @@ -53,7 +53,7 @@ class FrozenTime extends Chronos implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position @@ -69,7 +69,7 @@ class FrozenTime extends Chronos implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position diff --git a/app/vendor/cakephp/cakephp/src/I18n/I18nDateTimeInterface.php b/app/vendor/cakephp/cakephp/src/I18n/I18nDateTimeInterface.php index 5ccc6b0c8..52a5fc153 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/I18nDateTimeInterface.php +++ b/app/vendor/cakephp/cakephp/src/I18n/I18nDateTimeInterface.php @@ -60,7 +60,7 @@ public function nice($timezone = null, $locale = null): string; * It is possible to specify the desired format for the string to be displayed. * You can either pass `IntlDateFormatter` constants as the first argument of this * function, or pass a full ICU date formatting string as specified in the following - * resource: http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details. + * resource: https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details. * * Additional to `IntlDateFormatter` constants and date formatting string you can use * Time::UNIX_TIMESTAMP_FORMAT to get a unix timestamp @@ -132,7 +132,7 @@ public static function setToStringFormat($format): void; * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position diff --git a/app/vendor/cakephp/cakephp/src/I18n/PackageLocator.php b/app/vendor/cakephp/cakephp/src/I18n/PackageLocator.php index cbc037cff..e4d4296a6 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/PackageLocator.php +++ b/app/vendor/cakephp/cakephp/src/I18n/PackageLocator.php @@ -33,7 +33,7 @@ class PackageLocator * key is a package name, the second key is a locale code, and the value * is a callable that returns a Package object for that name and locale. * - * @var array + * @var array> */ protected $registry = []; @@ -41,14 +41,14 @@ class PackageLocator * Tracks whether a registry entry has been converted from a * callable to a Package object. * - * @var array + * @var array> */ protected $converted = []; /** * Constructor. * - * @param array $registry A registry of packages. + * @param array> $registry A registry of packages. * @see PackageLocator::$registry */ public function __construct(array $registry = []) @@ -88,11 +88,13 @@ public function get(string $name, string $locale): Package } if (!$this->converted[$name][$locale]) { + /** @var callable $func */ $func = $this->registry[$name][$locale]; $this->registry[$name][$locale] = $func(); $this->converted[$name][$locale] = true; } + /** @var \Cake\I18n\Package */ return $this->registry[$name][$locale]; } diff --git a/app/vendor/cakephp/cakephp/src/I18n/Time.php b/app/vendor/cakephp/cakephp/src/I18n/Time.php index e82f29a3e..9528e9de3 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/Time.php +++ b/app/vendor/cakephp/cakephp/src/I18n/Time.php @@ -37,7 +37,7 @@ class Time extends MutableDateTime implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position @@ -53,7 +53,7 @@ class Time extends MutableDateTime implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position @@ -69,7 +69,7 @@ class Time extends MutableDateTime implements I18nDateTimeInterface * * The format should be either the formatting constants from IntlDateFormatter as * described in (https://secure.php.net/manual/en/class.intldateformatter.php) or a pattern - * as specified in (http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details) + * as specified in (https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classSimpleDateFormat.html#details) * * It is possible to provide an array of 2 constants. In this case, the first position * will be used for formatting the date part of the object and the second position diff --git a/app/vendor/cakephp/cakephp/src/I18n/Translator.php b/app/vendor/cakephp/cakephp/src/I18n/Translator.php index 879591a3f..f657ac81a 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/Translator.php +++ b/app/vendor/cakephp/cakephp/src/I18n/Translator.php @@ -157,6 +157,11 @@ public function translate(string $key, array $tokensValues = []): string if ($message === '') { $message = $key; + + // If singular haven't been translated, fallback to the key. + if (isset($tokensValues['_singular']) && $tokensValues['_count'] === 1) { + $message = $tokensValues['_singular']; + } } unset($tokensValues['_count'], $tokensValues['_singular']); diff --git a/app/vendor/cakephp/cakephp/src/I18n/TranslatorRegistry.php b/app/vendor/cakephp/cakephp/src/I18n/TranslatorRegistry.php index 2895b61ed..0ba3cee7b 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/TranslatorRegistry.php +++ b/app/vendor/cakephp/cakephp/src/I18n/TranslatorRegistry.php @@ -340,7 +340,8 @@ public function setLoaderFallback(string $name, callable $loader): callable if (!$this->_useFallback || $name === $fallbackDomain) { return $loader; } - $loader = function () use ($loader, $fallbackDomain) { + + return function () use ($loader, $fallbackDomain) { /** @var \Cake\I18n\Package $package */ $package = $loader(); if (!$package->getFallback()) { @@ -349,7 +350,5 @@ public function setLoaderFallback(string $name, callable $loader): callable return $package; }; - - return $loader; } } diff --git a/app/vendor/cakephp/cakephp/src/I18n/composer.json b/app/vendor/cakephp/cakephp/src/I18n/composer.json index 8b75144a9..5b75e5983 100644 --- a/app/vendor/cakephp/cakephp/src/I18n/composer.json +++ b/app/vendor/cakephp/cakephp/src/I18n/composer.json @@ -28,7 +28,7 @@ "source": "https://github.com/cakephp/i18n" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "ext-intl": "*", "cakephp/core": "^4.0", "cakephp/chronos": "^2.0.0" diff --git a/app/vendor/cakephp/cakephp/src/Log/Engine/ArrayLog.php b/app/vendor/cakephp/cakephp/src/Log/Engine/ArrayLog.php index c82e183ec..1083f5ded 100644 --- a/app/vendor/cakephp/cakephp/src/Log/Engine/ArrayLog.php +++ b/app/vendor/cakephp/cakephp/src/Log/Engine/ArrayLog.php @@ -44,7 +44,7 @@ class ArrayLog extends BaseLog /** * Captured messages * - * @var array + * @var array */ protected $content = []; diff --git a/app/vendor/cakephp/cakephp/src/Log/README.md b/app/vendor/cakephp/cakephp/src/Log/README.md index 5056f84e5..d43cb9e55 100644 --- a/app/vendor/cakephp/cakephp/src/Log/README.md +++ b/app/vendor/cakephp/cakephp/src/Log/README.md @@ -8,28 +8,26 @@ multiple logging backends using a simple interface. With the `Log` class it is possible to send a single message to multiple logging backends at the same time or just a subset of them based on the log level or context. -By default, you can use Files or Syslog as logging backends, but you can use any +By default, you can use `File` or `Syslog` as logging backends, but you can use any object implementing `Psr\Log\LoggerInterface` as an engine for the `Log` class. ## Usage You can define as many or as few loggers as your application needs. Loggers -should be configured using `Cake\Core\Log.` An example would be: +should be configured using `Cake\Log\Log.` An example would be: ```php -use Cake\Cache\Cache; - use Cake\Log\Log; // Short classname -Log::config('local', [ - 'className' => 'FileLog', +Log::setConfig('local', [ + 'className' => 'File', 'levels' => ['notice', 'info', 'debug'], 'file' => '/path/to/file.log', ]); // Fully namespaced name. -Log::config('production', [ +Log::setConfig('production', [ 'className' => \Cake\Log\Engine\SyslogLog::class, 'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'], ]); @@ -38,7 +36,7 @@ Log::config('production', [ It is also possible to create loggers by providing a closure. ```php -Log::config('special', function () { +Log::setConfig('special', function () { // Return any PSR-3 compatible logger return new MyPSR3CompatibleLogger(); }); @@ -47,7 +45,7 @@ Log::config('special', function () { Or by injecting an instance directly: ```php -Log::config('special', new MyPSR3CompatibleLogger()); +Log::setConfig('special', new MyPSR3CompatibleLogger()); ``` You can then use the `Log` class to pass messages to the logging backends: @@ -68,8 +66,8 @@ you can limit the logging engines that receive a particular message. ```php // Configure /logs/payments.log to receive all levels, but only // those with `payments` scope. -Log::config('payments', [ - 'className' => 'FileLog', +Log::setConfig('payments', [ + 'className' => 'File', 'levels' => ['error', 'info', 'warning'], 'scopes' => ['payments'], 'file' => '/logs/payments.log', diff --git a/app/vendor/cakephp/cakephp/src/Log/composer.json b/app/vendor/cakephp/cakephp/src/Log/composer.json index 81d234e8d..25512558f 100644 --- a/app/vendor/cakephp/cakephp/src/Log/composer.json +++ b/app/vendor/cakephp/cakephp/src/Log/composer.json @@ -23,7 +23,7 @@ "source": "https://github.com/cakephp/log" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0", "psr/log": "^1.0 || ^2.0" }, diff --git a/app/vendor/cakephp/cakephp/src/Mailer/Email.php b/app/vendor/cakephp/cakephp/src/Mailer/Email.php index 27323f3c1..bc2358b13 100644 --- a/app/vendor/cakephp/cakephp/src/Mailer/Email.php +++ b/app/vendor/cakephp/cakephp/src/Mailer/Email.php @@ -93,7 +93,7 @@ class Email implements JsonSerializable, Serializable * A copy of the configuration profile for this * instance. This copy can be modified with Email::profile(). * - * @var array + * @var array */ protected $_profile = []; @@ -207,7 +207,7 @@ public function getViewRenderer(): string /** * Sets variables to be set on render. * - * @param array $viewVars Variables to set for view. + * @param array $viewVars Variables to set for view. * @return $this */ public function setViewVars(array $viewVars) @@ -220,7 +220,7 @@ public function setViewVars(array $viewVars) /** * Gets variables to be set on render. * - * @return array + * @return array */ public function getViewVars(): array { @@ -305,7 +305,7 @@ public function setProfile($config) unset($name); } - $this->_profile = array_merge($this->_profile, $config); + $this->_profile = $config + $this->_profile; $simpleMethods = [ 'transport', @@ -348,7 +348,7 @@ public function setProfile($config) /** * Gets the configuration profile to use for this instance. * - * @return array + * @return array */ public function getProfile(): array { @@ -443,7 +443,7 @@ public function setRenderer(Renderer $renderer) /** * Log the email message delivery. * - * @param array $contents The content with 'headers' and 'message' keys. + * @param array $contents The content with 'headers' and 'message' keys. * @return void */ protected function _logDelivery(array $contents): void diff --git a/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php b/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php index 9c8e67783..ce1b87fab 100644 --- a/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php +++ b/app/vendor/cakephp/cakephp/src/Mailer/Mailer.php @@ -131,6 +131,7 @@ * @method array|string getBody(?string $type = null) Get generated message body as array. * {@see \Cake\Mailer\Message::getBody()} */ +#[\AllowDynamicProperties] class Mailer implements EventListenerInterface { use ModelAwareTrait; @@ -458,6 +459,12 @@ public function setProfile($config) $this->viewBuilder()->setVars($config['viewVars']); unset($config['viewVars']); } + if (isset($config['autoLayout'])) { + if ($config['autoLayout'] === false) { + $this->viewBuilder()->disableAutoLayout(); + } + unset($config['autoLayout']); + } if (isset($config['log'])) { $this->setLogConfig($config['log']); diff --git a/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php b/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php index 863236065..68be51147 100644 --- a/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php +++ b/app/vendor/cakephp/cakephp/src/Mailer/Transport/SmtpTransport.php @@ -28,6 +28,9 @@ */ class SmtpTransport extends AbstractTransport { + protected const AUTH_PLAIN = 'PLAIN'; + protected const AUTH_LOGIN = 'LOGIN'; + /** * Default config for this class * @@ -54,7 +57,7 @@ class SmtpTransport extends AbstractTransport /** * Content of email to return * - * @var array + * @var array */ protected $_content = []; @@ -65,6 +68,13 @@ class SmtpTransport extends AbstractTransport */ protected $_lastResponse = []; + /** + * Detected authentication type. + * + * @var string|null + */ + protected $authType = null; + /** * Destructor * @@ -169,9 +179,8 @@ public function getLastResponse(): array * Send mail * * @param \Cake\Mailer\Message $message Message instance - * @return array + * @return array{headers: string, message: string} * @throws \Cake\Network\Exception\SocketException - * @psalm-return array{headers: string, message: string} */ public function send(Message $message): array { @@ -214,6 +223,36 @@ protected function _bufferResponseLines(array $responseLines): void $this->_lastResponse = array_merge($this->_lastResponse, $response); } + /** + * Parses the last response line and extract the preferred authentication type. + * + * @return void + */ + protected function _parseAuthType(): void + { + $this->authType = null; + + $auth = ''; + foreach ($this->_lastResponse as $line) { + if (strlen($line['message']) === 0 || substr($line['message'], 0, 5) === 'AUTH ') { + $auth = $line['message']; + break; + } + } + + if (strpos($auth, self::AUTH_PLAIN) !== false) { + $this->authType = self::AUTH_PLAIN; + + return; + } + + if (strpos($auth, self::AUTH_LOGIN) !== false) { + $this->authType = self::AUTH_LOGIN; + + return; + } + } + /** * Connect to SMTP Server * @@ -265,6 +304,8 @@ protected function _connect(): void throw new SocketException('SMTP server did not accept the connection.', null, $e2); } } + + $this->_parseAuthType(); } /** @@ -281,13 +322,28 @@ protected function _auth(): void $username = $this->_config['username']; $password = $this->_config['password']; + if (empty($this->authType)) { + $replyCode = $this->_authPlain($username, $password); + if ($replyCode === '235') { + return; + } + + $this->_authLogin($username, $password); - $replyCode = $this->_authPlain($username, $password); - if ($replyCode === '235') { return; } - $this->_authLogin($username, $password); + if ($this->authType === self::AUTH_PLAIN) { + $this->_authPlain($username, $password); + + return; + } + + if ($this->authType === self::AUTH_LOGIN) { + $this->_authLogin($username, $password); + + return; + } } /** @@ -415,7 +471,7 @@ protected function _prepareMessage(Message $message): string /** * Send emails * - * @param \Cake\Mailer\Message $message Message message + * @param \Cake\Mailer\Message $message Message instance * @throws \Cake\Network\Exception\SocketException * @return void */ @@ -433,7 +489,7 @@ protected function _sendRcpt(Message $message): void /** * Send Data * - * @param \Cake\Mailer\Message $message Message message + * @param \Cake\Mailer\Message $message Message instance * @return void * @throws \Cake\Network\Exception\SocketException */ @@ -467,6 +523,7 @@ protected function _disconnect(): void { $this->_smtpSend('QUIT', false); $this->_socket()->disconnect(); + $this->authType = null; } /** diff --git a/app/vendor/cakephp/cakephp/src/Network/Socket.php b/app/vendor/cakephp/cakephp/src/Network/Socket.php index 0bc610e03..e94d8eab9 100644 --- a/app/vendor/cakephp/cakephp/src/Network/Socket.php +++ b/app/vendor/cakephp/cakephp/src/Network/Socket.php @@ -63,7 +63,7 @@ class Socket /** * This variable contains an array with the last error number (num) and string (str) * - * @var array + * @var array */ protected $lastError = []; @@ -96,7 +96,7 @@ class Socket * Used to capture connection warnings which can happen when there are * SSL errors for example. * - * @var array + * @var array */ protected $_connectionErrors = []; diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association.php b/app/vendor/cakephp/cakephp/src/ORM/Association.php index 86ef6984c..9621dd2c4 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association.php @@ -17,11 +17,13 @@ namespace Cake\ORM; use Cake\Collection\Collection; +use Cake\Collection\CollectionInterface; use Cake\Core\App; use Cake\Core\ConventionsTrait; use Cake\Database\Expression\IdentifierExpression; use Cake\Datasource\EntityInterface; use Cake\Datasource\ResultSetDecorator; +use Cake\Datasource\ResultSetInterface; use Cake\ORM\Locator\LocatorAwareTrait; use Cake\Utility\Inflector; use Closure; @@ -837,10 +839,10 @@ public function transformRow(array $row, string $nestKey, bool $joined, ?string * with the default empty value according to whether the association was * joined or fetched externally. * - * @param array $row The row to set a default on. + * @param array $row The row to set a default on. * @param bool $joined Whether the row is a result of a direct join * with this association - * @return array + * @return array */ public function defaultRowValue(array $row, bool $joined): array { @@ -1003,35 +1005,40 @@ protected function _formatAssociationResults(Query $query, Query $surrogate, arr $property = $options['propertyPath']; $propertyPath = explode('.', $property); - $query->formatResults(function ($results, $query) use ($formatters, $property, $propertyPath) { - $extracted = []; - foreach ($results as $result) { - foreach ($propertyPath as $propertyPathItem) { - if (!isset($result[$propertyPathItem])) { - $result = null; - break; + $query->formatResults( + function (CollectionInterface $results, $query) use ($formatters, $property, $propertyPath) { + $extracted = []; + foreach ($results as $result) { + foreach ($propertyPath as $propertyPathItem) { + if (!isset($result[$propertyPathItem])) { + $result = null; + break; + } + $result = $result[$propertyPathItem]; + } + $extracted[] = $result; + } + $extracted = new Collection($extracted); + foreach ($formatters as $callable) { + $extracted = $callable($extracted, $query); + if (!$extracted instanceof ResultSetInterface) { + $extracted = new ResultSetDecorator($extracted); } - $result = $result[$propertyPathItem]; } - $extracted[] = $result; - } - $extracted = new Collection($extracted); - foreach ($formatters as $callable) { - $extracted = new ResultSetDecorator($callable($extracted, $query)); - } - /** @var \Cake\Collection\CollectionInterface $results */ - $results = $results->insert($property, $extracted); - if ($query->isHydrationEnabled()) { - $results = $results->map(function ($result) { - $result->clean(); + $results = $results->insert($property, $extracted); + if ($query->isHydrationEnabled()) { + $results = $results->map(function ($result) { + $result->clean(); - return $result; - }); - } + return $result; + }); + } - return $results; - }, Query::PREPEND); + return $results; + }, + Query::PREPEND + ); } /** diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php b/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php index a781e32ba..f43402258 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association/BelongsToMany.php @@ -36,6 +36,7 @@ * that contains the association fields between the source and the target table. * * An example of a BelongsToMany association would be Article belongs to many Tags. + * In this example 'Article' is the source table and 'Tags' is the target table. */ class BelongsToMany extends Association { @@ -1266,26 +1267,42 @@ protected function _diffLinks( $assocForeignKey = (array)$belongsTo->getForeignKey(); $keys = array_merge($foreignKey, $assocForeignKey); - $deletes = $indexed = $present = []; + $deletes = $unmatchedEntityKeys = $present = []; foreach ($jointEntities as $i => $entity) { - $indexed[$i] = $entity->extract($keys); + $unmatchedEntityKeys[$i] = $entity->extract($keys); $present[$i] = array_values($entity->extract($assocForeignKey)); } - foreach ($existing as $result) { - $fields = $result->extract($keys); + foreach ($existing as $existingLink) { + $existingKeys = $existingLink->extract($keys); $found = false; - foreach ($indexed as $i => $data) { - if ($fields === $data) { - unset($indexed[$i]); + foreach ($unmatchedEntityKeys as $i => $unmatchedKeys) { + $matched = false; + foreach ($keys as $key) { + if (is_object($unmatchedKeys[$key]) && is_object($existingKeys[$key])) { + // If both sides are an object then use == so that value objects + // are seen as equivalent. + $matched = $existingKeys[$key] == $unmatchedKeys[$key]; + } else { + // Use strict equality for all other values. + $matched = $existingKeys[$key] === $unmatchedKeys[$key]; + } + // Stop checks on first failure. + if (!$matched) { + break; + } + } + if ($matched) { + // Remove the unmatched entity so we don't look at it again. + unset($unmatchedEntityKeys[$i]); $found = true; break; } } if (!$found) { - $deletes[] = $result; + $deletes[] = $existingLink; } } diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association/DependentDeleteHelper.php b/app/vendor/cakephp/cakephp/src/ORM/Association/DependentDeleteHelper.php index 52b6289b1..e965d5de3 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association/DependentDeleteHelper.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association/DependentDeleteHelper.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\ORM\Association; diff --git a/app/vendor/cakephp/cakephp/src/ORM/Association/Loader/SelectLoader.php b/app/vendor/cakephp/cakephp/src/ORM/Association/Loader/SelectLoader.php index 6a2591d49..dce3b3200 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Association/Loader/SelectLoader.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Association/Loader/SelectLoader.php @@ -133,7 +133,7 @@ public function buildEagerLoader(array $options): Closure /** * Returns the default options to use for the eagerLoader * - * @return array + * @return array */ protected function _defaultOptions(): array { diff --git a/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php b/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php index f73f05923..5e7d6ff2c 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php +++ b/app/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php @@ -82,6 +82,7 @@ public function add(string $alias, Association $association): Association * @param array $options List of options to configure the association definition. * @return \Cake\ORM\Association * @throws \InvalidArgumentException + * @psalm-param class-string<\Cake\ORM\Association> $className */ public function load(string $className, string $associated, array $options = []): Association { @@ -90,14 +91,6 @@ public function load(string $className, string $associated, array $options = []) ]; $association = new $className($associated, $options); - if (!$association instanceof Association) { - $message = sprintf( - 'The association must extend `%s` class, `%s` given.', - Association::class, - get_class($association) - ); - throw new InvalidArgumentException($message); - } return $this->add($association->getName(), $association); } diff --git a/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php b/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php index 328fbcbe5..a4ac9764b 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/ShadowTableStrategy.php @@ -593,7 +593,7 @@ protected function bundleTranslatedFields($entity) /** * Lazy define and return the main table fields. * - * @return array + * @return array */ protected function mainFields() { @@ -613,7 +613,7 @@ protected function mainFields() /** * Lazy define and return the translation table fields. * - * @return array + * @return array */ protected function translatedFields() { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/TranslateStrategyInterface.php b/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/TranslateStrategyInterface.php index 9f8d9a200..41536e6c4 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/TranslateStrategyInterface.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Behavior/Translate/TranslateStrategyInterface.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 4.0.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\ORM\Behavior\Translate; diff --git a/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php b/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php index 154d10d20..b009d0d52 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php @@ -75,6 +75,7 @@ class TreeBehavior extends Behavior 'scope' => null, 'level' => null, 'recoverOrder' => null, + 'cascadeCallbacks' => false, ]; /** @@ -227,15 +228,22 @@ public function beforeDelete(EventInterface $event, EntityInterface $entity) if ($diff > 2) { $query = $this->_scope($this->_table->query()) - ->delete() ->where(function ($exp) use ($config, $left, $right) { /** @var \Cake\Database\Expression\QueryExpression $exp */ return $exp ->gte($config['leftField'], $left + 1) ->lte($config['leftField'], $right - 1); }); - $statement = $query->execute(); - $statement->closeCursor(); + if ($this->getConfig('cascadeCallbacks')) { + $entities = $query->toArray(); + foreach ($entities as $entityToDelete) { + $this->_table->delete($entityToDelete, ['atomic' => false]); + } + } else { + $query->delete(); + $statement = $query->execute(); + $statement->closeCursor(); + } } $this->_sync($diff, '-', "> {$right}"); diff --git a/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php b/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php index 9afbb9a62..e4b76e1c3 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php +++ b/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php @@ -46,14 +46,14 @@ class BehaviorRegistry extends ObjectRegistry implements EventDispatcherInterfac /** * Method mappings. * - * @var array + * @var array */ protected $_methodMap = []; /** * Finder method mappings. * - * @var array + * @var array */ protected $_finderMap = []; diff --git a/app/vendor/cakephp/cakephp/src/ORM/EagerLoadable.php b/app/vendor/cakephp/cakephp/src/ORM/EagerLoadable.php index 411f1ebb7..fc5e226f2 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/EagerLoadable.php +++ b/app/vendor/cakephp/cakephp/src/ORM/EagerLoadable.php @@ -51,7 +51,7 @@ class EagerLoadable * A list of options to pass to the association object for loading * the records. * - * @var array + * @var array */ protected $_config = []; @@ -250,7 +250,7 @@ public function setConfig(array $config) * Gets the list of options to pass to the association object for loading * the records. * - * @return array + * @return array */ public function getConfig(): array { @@ -291,7 +291,7 @@ public function targetProperty(): ?string * Returns a representation of this object that can be passed to * Cake\ORM\EagerLoader::contain() * - * @return array + * @return array */ public function asContainArray(): array { diff --git a/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php b/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php index 44412c04b..1778c32de 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php +++ b/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php @@ -91,7 +91,7 @@ class EagerLoader * A map of table aliases pointing to the association objects they represent * for the query. * - * @var array + * @var array */ protected $_joinsMap = []; @@ -706,9 +706,8 @@ public function associationsMap(Table $table): array /** @psalm-suppress PossiblyNullReference */ $map = $this->_buildAssociationsMap($map, $this->_matching->normalized($table), true); $map = $this->_buildAssociationsMap($map, $this->normalized($table)); - $map = $this->_buildAssociationsMap($map, $this->_joinsMap); - return $map; + return $this->_buildAssociationsMap($map, $this->_joinsMap); } /** diff --git a/app/vendor/cakephp/cakephp/src/ORM/LazyEagerLoader.php b/app/vendor/cakephp/cakephp/src/ORM/LazyEagerLoader.php index 2fd6cb9e2..0e7a0103d 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/LazyEagerLoader.php +++ b/app/vendor/cakephp/cakephp/src/ORM/LazyEagerLoader.php @@ -135,11 +135,11 @@ protected function _getPropertyMap(Table $source, array $associations): array * Injects the results of the eager loader query into the original list of * entities. * - * @param \Traversable|array<\Cake\Datasource\EntityInterface> $objects The original list of entities + * @param iterable<\Cake\Datasource\EntityInterface> $objects The original list of entities * @param \Cake\ORM\Query $results The loaded results * @param array $associations The top level associations that were loaded * @param \Cake\ORM\Table $source The table where the entities came from - * @return array + * @return array<\Cake\Datasource\EntityInterface> */ protected function _injectResults(iterable $objects, $results, array $associations, Table $source): array { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Locator/LocatorAwareTrait.php b/app/vendor/cakephp/cakephp/src/ORM/Locator/LocatorAwareTrait.php index 157130527..1aa4a9e39 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Locator/LocatorAwareTrait.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Locator/LocatorAwareTrait.php @@ -16,9 +16,9 @@ */ namespace Cake\ORM\Locator; -use Cake\Core\Exception\CakeException; use Cake\Datasource\FactoryLocator; use Cake\ORM\Table; +use UnexpectedValueException; /** * Contains method for setting and accessing LocatorInterface instance @@ -83,8 +83,10 @@ public function getTableLocator(): LocatorInterface public function fetchTable(?string $alias = null, array $options = []): Table { $alias = $alias ?? $this->defaultTable; - if ($alias === null) { - throw new CakeException('You must provide an `$alias` or set the `$defaultTable` property.'); + if (empty($alias)) { + throw new UnexpectedValueException( + 'You must provide an `$alias` or set the `$defaultTable` property to a non empty string.' + ); } return $this->getTableLocator()->get($alias, $options); diff --git a/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php b/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php index 7f9fd0294..67a875201 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Locator/TableLocator.php @@ -215,8 +215,6 @@ protected function createInstance(string $alias, array $options) $options = ['alias' => $classAlias] + $options; } elseif (!isset($options['alias'])) { $options['className'] = $alias; - /** @psalm-suppress PossiblyFalseOperand */ - $alias = substr($alias, strrpos($alias, '\\') + 1, -5); } if (isset($this->_config[$alias])) { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php b/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php index 6d52e7e16..7511aafa4 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Marshaller.php @@ -287,7 +287,7 @@ protected function _prepareDataAndOptions(array $data, array $options): array $options += ['validate' => true]; $tableName = $this->_table->getAlias(); - if (isset($data[$tableName])) { + if (isset($data[$tableName]) && is_array($data[$tableName])) { $data += $data[$tableName]; unset($data[$tableName]); } diff --git a/app/vendor/cakephp/cakephp/src/ORM/Query.php b/app/vendor/cakephp/cakephp/src/ORM/Query.php index cdba19ae6..7ba368007 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Query.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Query.php @@ -43,7 +43,7 @@ * @method \Cake\ORM\Table getRepository() Returns the default table object that will be used by this query, * that is, the table that will appear in the from clause. * @method \Cake\Collection\CollectionInterface each(callable $c) Passes each of the query results to the callable - * @method \Cake\Collection\CollectionInterface sortBy($callback, int $dir) Sorts the query with the callback + * @method \Cake\Collection\CollectionInterface sortBy(callable|string $path, int $order = \SORT_DESC, int $sort = \SORT_NUMERIC) Sorts the query with the callback * @method \Cake\Collection\CollectionInterface filter(callable $c = null) Keeps the results using passing the callable test * @method \Cake\Collection\CollectionInterface reject(callable $c) Removes the results passing the callable test * @method bool every(callable $c) Returns true if all the results pass the callable test @@ -1306,7 +1306,7 @@ public function delete(?string $table = null) * Can be combined with the where() method to create delete queries. * * @param array $columns The columns to insert into. - * @param array $types A map between columns & their datatypes. + * @param array $types A map between columns & their datatypes. * @return $this */ public function insert(array $columns, array $types = []) diff --git a/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php b/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php index d81d63510..1fe3cf69d 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php +++ b/app/vendor/cakephp/cakephp/src/ORM/ResultSet.php @@ -73,7 +73,7 @@ class ResultSet implements ResultSetInterface * List of associations that should be placed under the `_matchingData` * result key. * - * @var array + * @var array */ protected $_matchingMap = []; @@ -88,7 +88,7 @@ class ResultSet implements ResultSetInterface * Map of fields that are fetched from the statement with * their type and the table they belong to * - * @var array + * @var array */ protected $_map = []; @@ -96,7 +96,7 @@ class ResultSet implements ResultSetInterface * List of matching associations and the column keys to expect * from each of them. * - * @var array + * @var array */ protected $_matchingMapColumns = []; @@ -568,12 +568,17 @@ protected function _groupResult(array $row) * Returns an array that can be used to describe the internal state of this * object. * - * @return array + * @return array */ public function __debugInfo() { + $currentIndex = $this->_index; + // toArray() adjusts the current index, so we have to reset it + $items = $this->toArray(); + $this->_index = $currentIndex; + return [ - 'items' => $this->toArray(), + 'items' => $items, ]; } } diff --git a/app/vendor/cakephp/cakephp/src/ORM/Rule/IsUnique.php b/app/vendor/cakephp/cakephp/src/ORM/Rule/IsUnique.php index f06f51400..a86bfe3e2 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Rule/IsUnique.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Rule/IsUnique.php @@ -93,7 +93,7 @@ public function __invoke(EntityInterface $entity, array $options): bool * * @param string $alias The alias to add. * @param array $conditions The conditions to alias. - * @return array + * @return array */ protected function _alias(string $alias, array $conditions): array { diff --git a/app/vendor/cakephp/cakephp/src/ORM/SaveOptionsBuilder.php b/app/vendor/cakephp/cakephp/src/ORM/SaveOptionsBuilder.php index 96023d0f6..ad81f9055 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/SaveOptionsBuilder.php +++ b/app/vendor/cakephp/cakephp/src/ORM/SaveOptionsBuilder.php @@ -26,6 +26,7 @@ * you to avoid mistakes by validating the options as you build them. * * @see \Cake\Datasource\RulesChecker + * @deprecated 4.4.0 Use a normal array for options instead. */ class SaveOptionsBuilder extends ArrayObject { @@ -34,7 +35,7 @@ class SaveOptionsBuilder extends ArrayObject /** * Options * - * @var array + * @var array */ protected $_options = []; @@ -65,7 +66,7 @@ public function __construct(Table $table, array $options = []) * This can be used to turn an options array into the object. * * @throws \InvalidArgumentException If a given option key does not exist. - * @param array $array Options array. + * @param array $array Options array. * @return $this */ public function parseArrayOptions(array $array) @@ -200,7 +201,7 @@ public function atomic(bool $atomic) } /** - * @return array + * @return array */ public function toArray(): array { diff --git a/app/vendor/cakephp/cakephp/src/ORM/Table.php b/app/vendor/cakephp/cakephp/src/ORM/Table.php index 859eff21a..0c8250691 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/Table.php +++ b/app/vendor/cakephp/cakephp/src/ORM/Table.php @@ -20,6 +20,7 @@ use BadMethodCallException; use Cake\Core\App; use Cake\Core\Configure; +use Cake\Core\Exception\CakeException; use Cake\Database\Connection; use Cake\Database\Schema\TableSchemaInterface; use Cake\Database\TypeFactory; @@ -387,9 +388,11 @@ public function getTable(): string { if ($this->_table === null) { $table = namespaceSplit(static::class); - $table = substr(end($table), 0, -5); + $table = substr(end($table), 0, -5) ?: $this->_alias; if (!$table) { - $table = $this->getAlias(); + throw new CakeException( + 'You must specify either the `alias` or the `table` option for the constructor.' + ); } $this->_table = Inflector::underscore($table); } @@ -419,7 +422,12 @@ public function getAlias(): string { if ($this->_alias === null) { $alias = namespaceSplit(static::class); - $alias = substr(end($alias), 0, -5) ?: $this->getTable(); + $alias = substr(end($alias), 0, -5) ?: $this->_table; + if (!$alias) { + throw new CakeException( + 'You must specify either the `alias` or the `table` option for the constructor.' + ); + } $this->_alias = $alias; } @@ -859,9 +867,7 @@ public function getBehavior(string $name): Behavior )); } - $behavior = $this->_behaviors->get($name); - - return $behavior; + return $this->_behaviors->get($name); } /** @@ -1446,7 +1452,7 @@ public function findThreaded(Query $query, array $options): Query * @param array $options the original options passed to a finder * @param array $keys the keys to check in $options to build matchers from * the associated value - * @return array + * @return array */ protected function _setFieldMatchers(array $options, array $keys): array { @@ -1498,12 +1504,21 @@ protected function _setFieldMatchers(array $options, array $keys): array */ public function get($primaryKey, array $options = []): EntityInterface { + if ($primaryKey === null) { + throw new InvalidPrimaryKeyException(sprintf( + 'Record not found in table "%s" with primary key [NULL]', + $this->getTable() + )); + } + $key = (array)$this->getPrimaryKey(); $alias = $this->getAlias(); foreach ($key as $index => $keyname) { $key[$index] = $alias . '.' . $keyname; } - $primaryKey = (array)$primaryKey; + if (!is_array($primaryKey)) { + $primaryKey = [$primaryKey]; + } if (count($key) !== count($primaryKey)) { $primaryKey = $primaryKey ?: [null]; $primaryKey = array_map(function ($key) { @@ -1843,6 +1858,7 @@ public function exists($conditions): bool public function save(EntityInterface $entity, $options = []) { if ($options instanceof SaveOptionsBuilder) { + deprecationWarning('SaveOptionsBuilder is deprecated. Use a normal array for options instead.'); $options = $options->toArray(); } @@ -1852,6 +1868,7 @@ public function save(EntityInterface $entity, $options = []) 'checkRules' => true, 'checkExisting' => true, '_primary' => true, + '_cleanOnSuccess' => true, ]); if ($entity->hasErrors((bool)$options['associated'])) { @@ -1871,8 +1888,10 @@ public function save(EntityInterface $entity, $options = []) $this->dispatchEvent('Model.afterSaveCommit', compact('entity', 'options')); } if ($options['atomic'] || $options['_primary']) { - $entity->clean(); - $entity->setNew(false); + if ($options['_cleanOnSuccess']) { + $entity->clean(); + $entity->setNew(false); + } $entity->setSource($this->getRegistryAlias()); } } @@ -2167,9 +2186,9 @@ protected function _update(EntityInterface $entity, array $data) * any one of the records fails to save due to failed validation or database * error. * - * @param \Cake\Datasource\ResultSetInterface|array<\Cake\Datasource\EntityInterface> $entities Entities to save. + * @param iterable<\Cake\Datasource\EntityInterface> $entities Entities to save. * @param \Cake\ORM\SaveOptionsBuilder|\ArrayAccess|array $options Options used when calling Table::save() for each entity. - * @return \Cake\Datasource\ResultSetInterface|array<\Cake\Datasource\EntityInterface>|false False on failure, entities list on success. + * @return iterable<\Cake\Datasource\EntityInterface>|false False on failure, entities list on success. * @throws \Exception */ public function saveMany(iterable $entities, $options = []) @@ -2188,9 +2207,9 @@ public function saveMany(iterable $entities, $options = []) * any one of the records fails to save due to failed validation or database * error. * - * @param \Cake\Datasource\ResultSetInterface|array<\Cake\Datasource\EntityInterface> $entities Entities to save. + * @param iterable<\Cake\Datasource\EntityInterface> $entities Entities to save. * @param \ArrayAccess|array $options Options used when calling Table::save() for each entity. - * @return \Cake\Datasource\ResultSetInterface|array<\Cake\Datasource\EntityInterface> Entities list. + * @return iterable<\Cake\Datasource\EntityInterface> Entities list. * @throws \Exception * @throws \Cake\ORM\Exception\PersistenceFailedException If an entity couldn't be saved. */ @@ -2200,14 +2219,19 @@ public function saveManyOrFail(iterable $entities, $options = []): iterable } /** - * @param \Cake\Datasource\ResultSetInterface|array<\Cake\Datasource\EntityInterface> $entities Entities to save. + * @param iterable<\Cake\Datasource\EntityInterface> $entities Entities to save. * @param \Cake\ORM\SaveOptionsBuilder|\ArrayAccess|array $options Options used when calling Table::save() for each entity. * @throws \Cake\ORM\Exception\PersistenceFailedException If an entity couldn't be saved. * @throws \Exception If an entity couldn't be saved. - * @return \Cake\Datasource\ResultSetInterface|array<\Cake\Datasource\EntityInterface> Entities list. + * @return iterable<\Cake\Datasource\EntityInterface> Entities list. */ protected function _saveMany(iterable $entities, $options = []): iterable { + if ($options instanceof SaveOptionsBuilder) { + deprecationWarning('SaveOptionsBuilder is deprecated. Use a normal array for options instead.'); + $options = $options->toArray(); + } + $options = new ArrayObject( (array)$options + [ 'atomic' => true, @@ -2215,10 +2239,11 @@ protected function _saveMany(iterable $entities, $options = []): iterable '_primary' => true, ] ); + $options['_cleanOnSuccess'] = false; /** @var array $isNew */ $isNew = []; - $cleanup = function ($entities) use (&$isNew): void { + $cleanupOnFailure = function ($entities) use (&$isNew): void { /** @var array<\Cake\Datasource\EntityInterface> $entities */ foreach ($entities as $key => $entity) { if (isset($isNew[$key]) && $isNew[$key]) { @@ -2243,20 +2268,40 @@ protected function _saveMany(iterable $entities, $options = []): iterable } }); } catch (Exception $e) { - $cleanup($entities); + $cleanupOnFailure($entities); throw $e; } if ($failed !== null) { - $cleanup($entities); + $cleanupOnFailure($entities); throw new PersistenceFailedException($failed, ['saveMany']); } + $cleanupOnSuccess = function (EntityInterface $entity) use (&$cleanupOnSuccess) { + $entity->clean(); + $entity->setNew(false); + + foreach (array_keys($entity->toArray()) as $field) { + $value = $entity->get($field); + + if ($value instanceof EntityInterface) { + $cleanupOnSuccess($value); + } elseif (is_array($value) && current($value) instanceof EntityInterface) { + foreach ($value as $associated) { + $cleanupOnSuccess($associated); + } + } + } + }; + if ($this->_transactionCommitted($options['atomic'], $options['_primary'])) { foreach ($entities as $entity) { $this->dispatchEvent('Model.afterSaveCommit', compact('entity', 'options')); + if ($options['atomic'] || $options['_primary']) { + $cleanupOnSuccess($entity); + } } } @@ -2322,9 +2367,9 @@ public function delete(EntityInterface $entity, $options = []): bool * any one of the records fails to delete due to failed validation or database * error. * - * @param \Cake\Datasource\ResultSetInterface|array<\Cake\Datasource\EntityInterface> $entities Entities to delete. + * @param iterable<\Cake\Datasource\EntityInterface> $entities Entities to delete. * @param \ArrayAccess|array $options Options used when calling Table::save() for each entity. - * @return \Cake\Datasource\ResultSetInterface|array<\Cake\Datasource\EntityInterface>|false Entities list + * @return iterable<\Cake\Datasource\EntityInterface>|false Entities list * on success, false on failure. * @see \Cake\ORM\Table::delete() for options and events related to this method. */ @@ -2346,9 +2391,9 @@ public function deleteMany(iterable $entities, $options = []) * any one of the records fails to delete due to failed validation or database * error. * - * @param \Cake\Datasource\ResultSetInterface|array<\Cake\Datasource\EntityInterface> $entities Entities to delete. + * @param iterable<\Cake\Datasource\EntityInterface> $entities Entities to delete. * @param \ArrayAccess|array $options Options used when calling Table::save() for each entity. - * @return \Cake\Datasource\ResultSetInterface|array<\Cake\Datasource\EntityInterface> Entities list. + * @return iterable<\Cake\Datasource\EntityInterface> Entities list. * @throws \Cake\ORM\Exception\PersistenceFailedException * @see \Cake\ORM\Table::delete() for options and events related to this method. */ @@ -2364,7 +2409,7 @@ public function deleteManyOrFail(iterable $entities, $options = []): iterable } /** - * @param \Cake\Datasource\ResultSetInterface|array<\Cake\Datasource\EntityInterface> $entities Entities to delete. + * @param iterable<\Cake\Datasource\EntityInterface> $entities Entities to delete. * @param \ArrayAccess|array $options Options used. * @return \Cake\Datasource\EntityInterface|null */ @@ -2866,7 +2911,7 @@ public function patchEntity(EntityInterface $entity, array $data, array $options * You can use the `Model.beforeMarshal` event to modify request data * before it is converted into entities. * - * @param \Traversable|array<\Cake\Datasource\EntityInterface> $entities the entities that will get the + * @param iterable<\Cake\Datasource\EntityInterface> $entities the entities that will get the * data merged in * @param array $data list of arrays to be merged into the entities * @param array $options A list of options for the objects hydration. @@ -3014,6 +3059,7 @@ public function buildRules(RulesChecker $rules): RulesChecker * * @param array $options Options to parse by the builder. * @return \Cake\ORM\SaveOptionsBuilder + * @deprecated 4.4.0 Use a normal array for options instead. */ public function getSaveOptionsBuilder(array $options = []): SaveOptionsBuilder { @@ -3067,7 +3113,7 @@ protected function validationMethodExists(string $name): bool * Returns an array that can be used to describe the internal state of this * object. * - * @return array + * @return array */ public function __debugInfo() { diff --git a/app/vendor/cakephp/cakephp/src/ORM/composer.json b/app/vendor/cakephp/cakephp/src/ORM/composer.json index c0f2675d5..d3f1c8802 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/composer.json +++ b/app/vendor/cakephp/cakephp/src/ORM/composer.json @@ -23,7 +23,7 @@ "source": "https://github.com/cakephp/orm" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/collection": "^4.0", "cakephp/core": "^4.0", "cakephp/datasource": "^4.0", diff --git a/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php b/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php index 9cd4351c6..7ea24dde5 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Exception/MissingControllerException.php @@ -1,10 +1,7 @@ $stream]); - $contentType = $response->getMimeType($file->getExtension()) ?: 'application/octet-stream'; + $contentType = (array)($response->getMimeType($file->getExtension()) ?: 'application/octet-stream'); $modified = $file->getMTime(); $expire = strtotime($this->cacheTime); $maxAge = $expire - time(); return $response - ->withHeader('Content-Type', $contentType) + ->withHeader('Content-Type', $contentType[0]) ->withHeader('Cache-Control', 'public,max-age=' . $maxAge) ->withHeader('Date', gmdate(DATE_RFC7231, time())) ->withHeader('Last-Modified', gmdate(DATE_RFC7231, $modified)) diff --git a/app/vendor/cakephp/cakephp/src/Routing/Middleware/RoutingMiddleware.php b/app/vendor/cakephp/cakephp/src/Routing/Middleware/RoutingMiddleware.php index 66d56a80b..6c46dc803 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Middleware/RoutingMiddleware.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Middleware/RoutingMiddleware.php @@ -17,14 +17,17 @@ namespace Cake\Routing\Middleware; use Cake\Cache\Cache; +use Cake\Cache\InvalidArgumentException; use Cake\Core\PluginApplicationInterface; use Cake\Http\Exception\RedirectException; use Cake\Http\MiddlewareQueue; use Cake\Http\Runner; +use Cake\Routing\Exception\FailedRouteCacheException; use Cake\Routing\Exception\RedirectException as DeprecatedRedirectException; use Cake\Routing\RouteCollection; use Cake\Routing\Router; use Cake\Routing\RoutingApplicationInterface; +use Exception; use Laminas\Diactoros\Response\RedirectResponse; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -67,6 +70,13 @@ class RoutingMiddleware implements MiddlewareInterface */ public function __construct(RoutingApplicationInterface $app, ?string $cacheConfig = null) { + if ($cacheConfig !== null) { + deprecationWarning( + 'Use of routing cache is deprecated and will be removed in 5.0. ' . + 'Upgrade to the new `CakeDC/CachedRouting` plugin. ' . + 'See https://github.com/CakeDC/cakephp-cached-routing' + ); + } $this->app = $app; $this->cacheConfig = $cacheConfig; } @@ -94,9 +104,21 @@ protected function loadRoutes(): void protected function buildRouteCollection(): RouteCollection { if (Cache::enabled() && $this->cacheConfig !== null) { - return Cache::remember(static::ROUTE_COLLECTION_CACHE_KEY, function () { - return $this->prepareRouteCollection(); - }, $this->cacheConfig); + try { + return Cache::remember(static::ROUTE_COLLECTION_CACHE_KEY, function () { + return $this->prepareRouteCollection(); + }, $this->cacheConfig); + } catch (InvalidArgumentException $e) { + throw $e; + } catch (Exception $e) { + throw new FailedRouteCacheException( + 'Unable to cache route collection. Cached routes must be serializable. Check for route-specific + middleware or other unserializable settings in your routes. The original exception message can + show what type of object failed to serialize.', + null, + $e + ); + } } return $this->prepareRouteCollection(); @@ -139,8 +161,11 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $params = Router::parseRequest($request) + $params; if (isset($params['_middleware'])) { $middleware = $params['_middleware']; - unset($params['_middleware']); } + $route = $params['_route']; + unset($params['_middleware'], $params['_route']); + + $request = $request->withAttribute('route', $route); /** @var \Cake\Http\ServerRequest $request */ $request = $request->withAttribute('params', $params); Router::setRequest($request); diff --git a/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php b/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php index 89ce7d3fe..2315a07f2 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Route/Route.php @@ -16,6 +16,7 @@ */ namespace Cake\Routing\Route; +use Cake\Http\Exception\BadRequestException; use InvalidArgumentException; use Psr\Http\Message\ServerRequestInterface; @@ -457,13 +458,18 @@ public function parseRequest(ServerRequestInterface $request): ?array * @param string $url The URL to attempt to parse. * @param string $method The HTTP method of the request being parsed. * @return array|null An array of request parameters, or `null` on failure. - * @throws \InvalidArgumentException When method is not an empty string or in `VALID_METHODS` list. + * @throws \Cake\Http\Exception\BadRequestException When method is not an empty string and not in `VALID_METHODS` list. */ public function parse(string $url, string $method): ?array { - if ($method !== '') { - $method = $this->normalizeAndValidateMethods($method); + try { + if ($method !== '') { + $method = $this->normalizeAndValidateMethods($method); + } + } catch (InvalidArgumentException $e) { + throw new BadRequestException($e->getMessage()); } + $compiledRoute = $this->compile(); [$url, $ext] = $this->_parseExtension($url); @@ -533,6 +539,8 @@ public function parse(string $url, string $method): ?array } } } + + $route['_route'] = $this; $route['_matchedRoute'] = $this->template; if (count($this->middleware) > 0) { $route['_middleware'] = $this->middleware; @@ -807,7 +815,10 @@ protected function _matchMethod(array $url): bool */ protected function _writeUrl(array $params, array $pass = [], array $query = []): string { - $pass = implode('/', array_map('rawurlencode', $pass)); + $pass = array_map(function ($value) { + return rawurlencode((string)$value); + }, $pass); + $pass = implode('/', $pass); $out = $this->template; $search = $replace = []; diff --git a/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php b/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php index 16aec336a..80952eee0 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php +++ b/app/vendor/cakephp/cakephp/src/Routing/RouteBuilder.php @@ -720,6 +720,7 @@ protected function parseDefaults($defaults): array protected function _makeRoute($route, $defaults, $options): Route { if (is_string($route)) { + /** @var class-string<\Cake\Routing\Route\Route>|null $routeClass */ $routeClass = App::className($options['routeClass'], 'Routing/Route'); if ($routeClass === null) { throw new InvalidArgumentException(sprintf( @@ -754,12 +755,7 @@ protected function _makeRoute($route, $defaults, $options): Route $route = new $routeClass($route, $defaults, $options); } - if ($route instanceof Route) { - return $route; - } - throw new InvalidArgumentException( - 'Route class not found, or route class is not a subclass of Cake\Routing\Route\Route' - ); + return $route; } /** diff --git a/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php b/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php index 122606058..5ceadaf14 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php +++ b/app/vendor/cakephp/cakephp/src/Routing/RouteCollection.php @@ -218,9 +218,9 @@ protected function _getNames(array $url): array $action = strtolower($url['action']); $names = [ - "${controller}:${action}", - "${controller}:_action", - "_controller:${action}", + "{$controller}:{$action}", + "{$controller}:_action", + "_controller:{$action}", '_controller:_action', ]; @@ -232,13 +232,13 @@ protected function _getNames(array $url): array // Only a plugin if ($prefix === false) { return [ - "${plugin}.${controller}:${action}", - "${plugin}.${controller}:_action", - "${plugin}._controller:${action}", - "${plugin}._controller:_action", - "_plugin.${controller}:${action}", - "_plugin.${controller}:_action", - "_plugin._controller:${action}", + "{$plugin}.{$controller}:{$action}", + "{$plugin}.{$controller}:_action", + "{$plugin}._controller:{$action}", + "{$plugin}._controller:_action", + "_plugin.{$controller}:{$action}", + "_plugin.{$controller}:_action", + "_plugin._controller:{$action}", '_plugin._controller:_action', ]; } @@ -246,13 +246,13 @@ protected function _getNames(array $url): array // Only a prefix if ($plugin === false) { return [ - "${prefix}:${controller}:${action}", - "${prefix}:${controller}:_action", - "${prefix}:_controller:${action}", - "${prefix}:_controller:_action", - "_prefix:${controller}:${action}", - "_prefix:${controller}:_action", - "_prefix:_controller:${action}", + "{$prefix}:{$controller}:{$action}", + "{$prefix}:{$controller}:_action", + "{$prefix}:_controller:{$action}", + "{$prefix}:_controller:_action", + "_prefix:{$controller}:{$action}", + "_prefix:{$controller}:_action", + "_prefix:_controller:{$action}", '_prefix:_controller:_action', ]; } @@ -260,21 +260,21 @@ protected function _getNames(array $url): array // Prefix and plugin has the most options // as there are 4 factors. return [ - "${prefix}:${plugin}.${controller}:${action}", - "${prefix}:${plugin}.${controller}:_action", - "${prefix}:${plugin}._controller:${action}", - "${prefix}:${plugin}._controller:_action", - "${prefix}:_plugin.${controller}:${action}", - "${prefix}:_plugin.${controller}:_action", - "${prefix}:_plugin._controller:${action}", - "${prefix}:_plugin._controller:_action", - "_prefix:${plugin}.${controller}:${action}", - "_prefix:${plugin}.${controller}:_action", - "_prefix:${plugin}._controller:${action}", - "_prefix:${plugin}._controller:_action", - "_prefix:_plugin.${controller}:${action}", - "_prefix:_plugin.${controller}:_action", - "_prefix:_plugin._controller:${action}", + "{$prefix}:{$plugin}.{$controller}:{$action}", + "{$prefix}:{$plugin}.{$controller}:_action", + "{$prefix}:{$plugin}._controller:{$action}", + "{$prefix}:{$plugin}._controller:_action", + "{$prefix}:_plugin.{$controller}:{$action}", + "{$prefix}:_plugin.{$controller}:_action", + "{$prefix}:_plugin._controller:{$action}", + "{$prefix}:_plugin._controller:_action", + "_prefix:{$plugin}.{$controller}:{$action}", + "_prefix:{$plugin}.{$controller}:_action", + "_prefix:{$plugin}._controller:{$action}", + "_prefix:{$plugin}._controller:_action", + "_prefix:_plugin.{$controller}:{$action}", + "_prefix:_plugin.{$controller}:_action", + "_prefix:_plugin._controller:{$action}", '_prefix:_plugin._controller:_action', ]; } diff --git a/app/vendor/cakephp/cakephp/src/Routing/Router.php b/app/vendor/cakephp/cakephp/src/Routing/Router.php index c6808c922..9b4235cc3 100644 --- a/app/vendor/cakephp/cakephp/src/Routing/Router.php +++ b/app/vendor/cakephp/cakephp/src/Routing/Router.php @@ -107,7 +107,7 @@ class Router /** * A hash of request context data. * - * @var array + * @var array */ protected static $_requestContext = []; @@ -159,7 +159,7 @@ class Router /** * Cache of parsed route paths * - * @var array + * @var array */ protected static $_routePaths = []; @@ -221,7 +221,7 @@ public static function connect($route, $defaults = [], $options = []): void } /** - * Get the routing parameters for the request is possible. + * Get the routing parameters for the request if possible. * * @param \Cake\Http\ServerRequest $request The request to parse request data from. * @return array Parsed elements from URL. @@ -643,7 +643,9 @@ public static function fullBaseUrl(?string $base = null): string */ public static function reverseToArray($params): array { + $route = null; if ($params instanceof ServerRequest) { + $route = $params->getAttribute('route'); $queryString = $params->getQueryParams(); $params = $params->getAttribute('params'); $params['?'] = $queryString; @@ -656,8 +658,7 @@ public static function reverseToArray($params): array $params['_matchedRoute'], $params['_name'] ); - $route = null; - if ($template) { + if (!$route && $template) { // Locate the route that was used to match this route // so we can access the pass parameter configuration. foreach (static::getRouteCollection()->routes() as $maybe) { @@ -672,9 +673,8 @@ public static function reverseToArray($params): array $routePass = $route->options['pass'] ?? []; $pass = array_slice($pass, count($routePass)); } - $params = array_merge($params, $pass); - return $params; + return array_merge($params, $pass); } /** diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/ConsoleIntegrationTestCase.php b/app/vendor/cakephp/cakephp/src/TestSuite/ConsoleIntegrationTestCase.php index 5e42cdeae..09c2252d8 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/ConsoleIntegrationTestCase.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/ConsoleIntegrationTestCase.php @@ -2,19 +2,21 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite; +use Cake\Console\TestSuite\ConsoleIntegrationTestTrait; + /** * A test case class intended to make integration tests of cake console commands * easier. diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/ConsoleIntegrationTestTrait.php b/app/vendor/cakephp/cakephp/src/TestSuite/ConsoleIntegrationTestTrait.php index e29330321..2b41c39f1 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/ConsoleIntegrationTestTrait.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/ConsoleIntegrationTestTrait.php @@ -1,347 +1,6 @@ makeRunner(); - - if ($this->_out === null) { - $this->_out = new ConsoleOutput(); - } - if ($this->_err === null) { - $this->_err = new ConsoleOutput(); - } - if ($this->_in === null) { - $this->_in = new ConsoleInput($input); - } elseif ($input) { - throw new RuntimeException('You can use `$input` only if `$_in` property is null and will be reset.'); - } - - $args = $this->commandStringToArgs("cake $command"); - $io = new ConsoleIo($this->_out, $this->_err, $this->_in); - - try { - $this->_exitCode = $runner->run($args, $io); - } catch (MissingConsoleInputException $e) { - $messages = $this->_out->messages(); - if (count($messages)) { - $e->setQuestion($messages[count($messages) - 1]); - } - throw $e; - } catch (StopException $exception) { - $this->_exitCode = $exception->getCode(); - } - } - - /** - * Cleans state to get ready for the next test - * - * @after - * @return void - * @psalm-suppress PossiblyNullPropertyAssignmentValue - */ - public function cleanupConsoleTrait(): void - { - $this->_exitCode = null; - $this->_out = null; - $this->_err = null; - $this->_in = null; - $this->_useCommandRunner = false; - } - - /** - * Set this test case to use the CommandRunner rather than the legacy - * ShellDispatcher - * - * @return void - */ - public function useCommandRunner(): void - { - $this->_useCommandRunner = true; - } - - /** - * Asserts shell exited with the expected code - * - * @param int $expected Expected exit code - * @param string $message Failure message - * @return void - */ - public function assertExitCode(int $expected, string $message = ''): void - { - $this->assertThat($expected, new ExitCode($this->_exitCode), $message); - } - - /** - * Asserts shell exited with the Command::CODE_SUCCESS - * - * @param string $message Failure message - * @return void - */ - public function assertExitSuccess($message = '') - { - $this->assertThat(Command::CODE_SUCCESS, new ExitCode($this->_exitCode), $message); - } - - /** - * Asserts shell exited with Command::CODE_ERROR - * - * @param string $message Failure message - * @return void - */ - public function assertExitError($message = '') - { - $this->assertThat(Command::CODE_ERROR, new ExitCode($this->_exitCode), $message); - } - - /** - * Asserts that `stdout` is empty - * - * @param string $message The message to output when the assertion fails. - * @return void - */ - public function assertOutputEmpty(string $message = ''): void - { - $this->assertThat(null, new ContentsEmpty($this->_out->messages(), 'output'), $message); - } - - /** - * Asserts `stdout` contains expected output - * - * @param string $expected Expected output - * @param string $message Failure message - * @return void - */ - public function assertOutputContains(string $expected, string $message = ''): void - { - $this->assertThat($expected, new ContentsContain($this->_out->messages(), 'output'), $message); - } - - /** - * Asserts `stdout` does not contain expected output - * - * @param string $expected Expected output - * @param string $message Failure message - * @return void - */ - public function assertOutputNotContains(string $expected, string $message = ''): void - { - $this->assertThat($expected, new ContentsNotContain($this->_out->messages(), 'output'), $message); - } - - /** - * Asserts `stdout` contains expected regexp - * - * @param string $pattern Expected pattern - * @param string $message Failure message - * @return void - */ - public function assertOutputRegExp(string $pattern, string $message = ''): void - { - $this->assertThat($pattern, new ContentsRegExp($this->_out->messages(), 'output'), $message); - } - - /** - * Check that a row of cells exists in the output. - * - * @param array $row Row of cells to ensure exist in the output. - * @param string $message Failure message. - * @return void - */ - protected function assertOutputContainsRow(array $row, string $message = ''): void - { - $this->assertThat($row, new ContentsContainRow($this->_out->messages(), 'output'), $message); - } - - /** - * Asserts `stderr` contains expected output - * - * @param string $expected Expected output - * @param string $message Failure message - * @return void - */ - public function assertErrorContains(string $expected, string $message = ''): void - { - $this->assertThat($expected, new ContentsContain($this->_err->messages(), 'error output'), $message); - } - - /** - * Asserts `stderr` contains expected regexp - * - * @param string $pattern Expected pattern - * @param string $message Failure message - * @return void - */ - public function assertErrorRegExp(string $pattern, string $message = ''): void - { - $this->assertThat($pattern, new ContentsRegExp($this->_err->messages(), 'error output'), $message); - } - - /** - * Asserts that `stderr` is empty - * - * @param string $message The message to output when the assertion fails. - * @return void - */ - public function assertErrorEmpty(string $message = ''): void - { - $this->assertThat(null, new ContentsEmpty($this->_err->messages(), 'error output'), $message); - } - - /** - * Builds the appropriate command dispatcher - * - * @return \Cake\Console\CommandRunner|\Cake\TestSuite\LegacyCommandRunner - */ - protected function makeRunner() - { - if ($this->_useCommandRunner) { - /** @var \Cake\Core\ConsoleApplicationInterface $app */ - $app = $this->createApp(); - - return new CommandRunner($app); - } - - return new LegacyCommandRunner(); - } - - /** - * Creates an $argv array from a command string - * - * @param string $command Command string - * @return array - */ - protected function commandStringToArgs(string $command): array - { - $charCount = strlen($command); - $argv = []; - $arg = ''; - $inDQuote = false; - $inSQuote = false; - for ($i = 0; $i < $charCount; $i++) { - $char = substr($command, $i, 1); - - // end of argument - if ($char === ' ' && !$inDQuote && !$inSQuote) { - if ($arg !== '') { - $argv[] = $arg; - } - $arg = ''; - continue; - } - - // exiting single quote - if ($inSQuote && $char === "'") { - $inSQuote = false; - continue; - } - - // exiting double quote - if ($inDQuote && $char === '"') { - $inDQuote = false; - continue; - } - - // entering double quote - if ($char === '"' && !$inSQuote) { - $inDQuote = true; - continue; - } - - // entering single quote - if ($char === "'" && !$inDQuote) { - $inSQuote = true; - continue; - } - - $arg .= $char; - } - $argv[] = $arg; - - return $argv; - } -} +class_alias(ConsoleIntegrationTestTrait::class, 'Cake\TestSuite\ConsoleIntegrationTestTrait'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsBase.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsBase.php index 9ebd33fe7..81653f83d 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsBase.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsBase.php @@ -1,48 +1,6 @@ $contents Contents - * @param string $output Output type - */ - public function __construct(array $contents, string $output) - { - $this->contents = implode(PHP_EOL, $contents); - $this->output = $output; - } -} +class_alias(ContentsBase::class, 'Cake\TestSuite\Constraint\Console\ContentsBase'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsContain.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsContain.php index d700c9664..e8a76013d 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsContain.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsContain.php @@ -1,45 +1,6 @@ contents, $other) !== false; - } - - /** - * Assertion message - * - * @return string - */ - public function toString(): string - { - return sprintf('is in %s,' . PHP_EOL . 'actual result:' . PHP_EOL, $this->output) . $this->contents; - } -} +class_alias(ContentsContain::class, 'Cake\TestSuite\Constraint\Console\ContentsContain'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsContainRow.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsContainRow.php index 3ee85920e..6ea1f2597 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsContainRow.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsContainRow.php @@ -1,61 +1,6 @@ contents) > 0; - } - - /** - * Assertion message - * - * @return string - */ - public function toString(): string - { - return sprintf('row was in %s', $this->output); - } - - /** - * @param mixed $other Expected content - * @return string - */ - public function failureDescription($other): string - { - return '`' . $this->exporter()->shortenedExport($other) . '` ' . $this->toString(); - } -} +class_alias(ContentsContainRow::class, 'Cake\TestSuite\Constraint\Console\ContentsContainRow'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsEmpty.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsEmpty.php index cbc96d2ce..250e7acef 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsEmpty.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsEmpty.php @@ -1,56 +1,6 @@ contents === ''; - } - - /** - * Assertion message - * - * @return string - */ - public function toString(): string - { - return sprintf('%s is empty', $this->output); - } - - /** - * Overwrites the descriptions so we can remove the automatic "expected" message - * - * @param mixed $other Value - * @return string - */ - protected function failureDescription($other): string - { - return $this->toString(); - } -} +class_alias(ContentsEmpty::class, 'Cake\TestSuite\Constraint\Console\ContentsEmpty'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsNotContain.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsNotContain.php index 9515c37d9..e53d68b62 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsNotContain.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsNotContain.php @@ -1,45 +1,6 @@ contents, $other) === false; - } - - /** - * Assertion message - * - * @return string - */ - public function toString(): string - { - return sprintf('is not in %s', $this->output); - } -} +class_alias(ContentsNotContain::class, 'Cake\TestSuite\Constraint\Console\ContentsNotContain'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsRegExp.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsRegExp.php index e97b08540..eb9652e07 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsRegExp.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ContentsRegExp.php @@ -1,54 +1,6 @@ contents) > 0; - } - - /** - * Assertion message - * - * @return string - */ - public function toString(): string - { - return sprintf('PCRE pattern found in %s', $this->output); - } - - /** - * @param mixed $other Expected - * @return string - */ - public function failureDescription($other): string - { - return '`' . $other . '` ' . $this->toString(); - } -} +class_alias(ContentsRegExp::class, 'Cake\TestSuite\Constraint\Console\ContentsRegExp'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ExitCode.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ExitCode.php index 913bbc4ab..311eeb535 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ExitCode.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Console/ExitCode.php @@ -1,62 +1,6 @@ exitCode = $exitCode; - } - - /** - * Checks if event is in fired array - * - * @param mixed $other Constraint check - * @return bool - */ - public function matches($other): bool - { - return $other === $this->exitCode; - } - - /** - * Assertion message string - * - * @return string - */ - public function toString(): string - { - return sprintf('matches exit code %s', $this->exitCode ?? 'null'); - } -} +class_alias(ExitCode::class, 'Cake\TestSuite\Constraint\Console\ExitCode'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Email/MailSentWith.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Email/MailSentWith.php index 46aa85fa2..16a9e761c 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Email/MailSentWith.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Email/MailSentWith.php @@ -55,15 +55,16 @@ public function matches($other): bool $emails = $this->getMessages(); foreach ($emails as $email) { $value = $email->{'get' . ucfirst($this->method)}(); + if ($value === $other) { + return true; + } if ( - in_array($this->method, ['to', 'cc', 'bcc', 'from', 'replyTo', 'sender'], true) + !is_array($other) + && in_array($this->method, ['to', 'cc', 'bcc', 'from', 'replyTo', 'sender']) && array_key_exists($other, $value) ) { return true; } - if ($value === $other) { - return true; - } } return false; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/EventFired.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/EventFired.php index dfb29f289..a02964f93 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/EventFired.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/EventFired.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.2.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyContains.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyContains.php index 357f6bee3..b63c482d6 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyContains.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyContains.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyEmpty.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyEmpty.php index 1f74ed403..c1b076a77 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyEmpty.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyEmpty.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyEquals.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyEquals.php index 5d8bfea56..19e61cd65 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyEquals.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyEquals.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotContains.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotContains.php index 7914cfe3d..66fe3fef4 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotContains.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotContains.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotEmpty.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotEmpty.php index 8ec4a568d..8ae4bfc05 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotEmpty.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotEmpty.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotEquals.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotEquals.php index 88e75e006..1cd4385ce 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotEquals.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotEquals.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotRegExp.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotRegExp.php index 9b1a4d241..6bb16968f 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotRegExp.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyNotRegExp.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyRegExp.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyRegExp.php index bace6d6ec..bf35f12cc 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyRegExp.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/BodyRegExp.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ContentType.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ContentType.php index 93b38d912..7a21522c6 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ContentType.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ContentType.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEncryptedEquals.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEncryptedEquals.php index 7cc9ff58c..3bc281407 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEncryptedEquals.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEncryptedEquals.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php index 3b5ca1081..0522f86cd 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieEquals.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieNotSet.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieNotSet.php index bfd7fa7c6..f67e58102 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieNotSet.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieNotSet.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php index 7c56262fa..370c40c6d 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/CookieSet.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/FileSent.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/FileSent.php index e11e21f0c..6143eab4c 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/FileSent.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/FileSent.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/FileSentAs.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/FileSentAs.php index 5c995af59..7ea144e84 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/FileSentAs.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/FileSentAs.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; @@ -35,8 +35,12 @@ class FileSentAs extends ResponseBase */ public function matches($other): bool { - /** @psalm-suppress PossiblyNullReference */ - return $this->response->getFile()->getPathName() === $other; + $file = $this->response->getFile(); + if (!$file) { + return false; + } + + return $file->getPathName() === $other; } /** diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderContains.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderContains.php index c0e1bb181..1fef513bd 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderContains.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderContains.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderEquals.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderEquals.php index 35bace044..a00756393 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderEquals.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderEquals.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderNotContains.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderNotContains.php index 51f29a923..3717e72f5 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderNotContains.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderNotContains.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderNotSet.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderNotSet.php index 671090fd8..2e655925f 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderNotSet.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderNotSet.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderSet.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderSet.php index 9fc5e4843..4ec5d2dad 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderSet.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/HeaderSet.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php index 2ba009db5..c17f9956d 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/ResponseBase.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusCode.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusCode.php index c2387bc99..2ef29e4f0 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusCode.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusCode.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusCodeBase.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusCodeBase.php index d41e4da33..7e9ae6488 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusCodeBase.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusCodeBase.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusError.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusError.php index b46c155df..30448297b 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusError.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusError.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusFailure.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusFailure.php index 21561261e..71d23ca77 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusFailure.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusFailure.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusOk.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusOk.php index c8f67d868..1d2496402 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusOk.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusOk.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusSuccess.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusSuccess.php index f7dfff5aa..6248457fd 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusSuccess.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Response/StatusSuccess.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Response; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/FlashParamEquals.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/FlashParamEquals.php index a1de975d0..592ceecae 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/FlashParamEquals.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/FlashParamEquals.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Session; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/SessionEquals.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/SessionEquals.php index 6d96c2707..577d8d7df 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/SessionEquals.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/SessionEquals.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Session; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/SessionHasKey.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/SessionHasKey.php index e529249c8..d7ffa7872 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/SessionHasKey.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/Session/SessionHasKey.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 4.1.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\Session; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/View/LayoutFileEquals.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/View/LayoutFileEquals.php index 650c4a968..662bb24aa 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/View/LayoutFileEquals.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/View/LayoutFileEquals.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\View; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/View/TemplateFileEquals.php b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/View/TemplateFileEquals.php index d55c73f4a..1f7fff21d 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/View/TemplateFileEquals.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Constraint/View/TemplateFileEquals.php @@ -2,16 +2,16 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * @since 3.7.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\TestSuite\Constraint\View; diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php b/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php index 0ca276906..7e564fc3d 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/ContainerStubTrait.php @@ -1,169 +1,6 @@ |class-string<\Cake\Core\ConsoleApplicationInterface>|null - * @var string|null - */ - protected $_appClass; - - /** - * The customized application constructor arguments. - * - * @var array|null - */ - protected $_appArgs; - - /** - * The collection of container services. - * - * @var array - */ - private $containerServices = []; - - /** - * Configure the application class to use in integration tests. - * - * @param string $class The application class name. - * @param array|null $constructorArgs The constructor arguments for your application class. - * @return void - * @psalm-param class-string<\Cake\Core\HttpApplicationInterface>|class-string<\Cake\Core\ConsoleApplicationInterface> $class - */ - public function configApplication(string $class, ?array $constructorArgs): void - { - $this->_appClass = $class; - $this->_appArgs = $constructorArgs; - } - - /** - * Create an application instance. - * - * Uses the configuration set in `configApplication()`. - * - * @return \Cake\Core\HttpApplicationInterface|\Cake\Core\ConsoleApplicationInterface - */ - protected function createApp() - { - if ($this->_appClass) { - $appClass = $this->_appClass; - } else { - /** @psalm-var class-string<\Cake\Http\BaseApplication> */ - $appClass = Configure::read('App.namespace') . '\Application'; - } - if (!class_exists($appClass)) { - throw new LogicException("Cannot load `{$appClass}` for use in integration testing."); - } - $appArgs = $this->_appArgs ?: [CONFIG]; - - $app = new $appClass(...$appArgs); - if (!empty($this->containerServices) && method_exists($app, 'getEventManager')) { - $app->getEventManager()->on('Application.buildContainer', [$this, 'modifyContainer']); - } - - return $app; - } - - /** - * Add a mocked service to the container. - * - * When the container is created the provided classname - * will be mapped to the factory function. The factory - * function will be used to create mocked services. - * - * @param string $class The class or interface you want to define. - * @param \Closure $factory The factory function for mocked services. - * @return $this - */ - public function mockService(string $class, Closure $factory) - { - $this->containerServices[$class] = $factory; - - return $this; - } - - /** - * Remove a mocked service to the container. - * - * @param string $class The class or interface you want to remove. - * @return $this - */ - public function removeMockService(string $class) - { - unset($this->containerServices[$class]); - - return $this; - } - - /** - * Wrap the application's container with one containing mocks. - * - * If any mocked services are defined, the application's container - * will be replaced with one containing mocks. The original - * container will be set as a delegate to the mock container. - * - * @param \Cake\Event\EventInterface $event The event - * @param \Cake\Core\ContainerInterface $container The container to wrap. - * @return \Cake\Core\ContainerInterface|null - */ - public function modifyContainer(EventInterface $event, ContainerInterface $container): ?ContainerInterface - { - if (empty($this->containerServices)) { - return null; - } - foreach ($this->containerServices as $key => $factory) { - if ($container->has($key)) { - $container->extend($key)->setConcrete($factory); - } else { - $container->add($key, $factory); - } - } - - return $container; - } - - /** - * Clears any mocks that were defined and cleans - * up application class configuration. - * - * @after - * @return void - */ - public function cleanupContainer(): void - { - $this->_appArgs = null; - $this->_appClass = null; - $this->containerServices = []; - } -} +class_alias(ContainerStubTrait::class, 'Cake\TestSuite\ContainerStubTrait'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/EmailTrait.php b/app/vendor/cakephp/cakephp/src/TestSuite/EmailTrait.php index 7d6926af5..e07b5aef4 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/EmailTrait.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/EmailTrait.php @@ -175,11 +175,11 @@ public function assertMailSentTo(string $address, string $message = ''): void /** * Asserts an email was sent from an address * - * @param string $address Email address + * @param array|string $address Email address * @param string $message Message * @return void */ - public function assertMailSentFrom(string $address, string $message = ''): void + public function assertMailSentFrom($address, string $message = ''): void { $this->assertThat($address, new MailSentFrom(), $message); } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureHelper.php b/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureHelper.php index ce8210e60..fb61a9572 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureHelper.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureHelper.php @@ -272,7 +272,7 @@ protected function sortByConstraint(Connection $connection, array $fixtures): ?a * * @param \Cake\Database\Connection $connection Database connection * @param \Cake\Datasource\FixtureInterface $fixture Database fixture - * @return array + * @return array */ protected function getForeignReferences(Connection $connection, FixtureInterface $fixture): array { diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php b/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php index 7f78675a2..c20b154db 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/HttpClientTrait.php @@ -1,117 +1,6 @@ $headers A list of headers for the response. Example `Content-Type: application/json` - * @param string $body The body for the response. - * @return \Cake\Http\Client\Response - */ - public function newClientResponse(int $code = 200, array $headers = [], string $body = ''): Response - { - $headers = array_merge(["HTTP/1.1 {$code}"], $headers); - - return new Response($headers, $body); - } - - /** - * Add a mock response for a POST request. - * - * @param string $url The URL to mock - * @param \Cake\Http\Client\Response $response The response for the mock. - * @param array $options Additional options. See Client::addMockResponse() - * @return void - */ - public function mockClientPost(string $url, Response $response, array $options = []): void - { - Client::addMockResponse('POST', $url, $response, $options); - } - - /** - * Add a mock response for a GET request. - * - * @param string $url The URL to mock - * @param \Cake\Http\Client\Response $response The response for the mock. - * @param array $options Additional options. See Client::addMockResponse() - * @return void - */ - public function mockClientGet(string $url, Response $response, array $options = []): void - { - Client::addMockResponse('GET', $url, $response, $options); - } - - /** - * Add a mock response for a PATCH request. - * - * @param string $url The URL to mock - * @param \Cake\Http\Client\Response $response The response for the mock. - * @param array $options Additional options. See Client::addMockResponse() - * @return void - */ - public function mockClientPatch(string $url, Response $response, array $options = []): void - { - Client::addMockResponse('PATCH', $url, $response, $options); - } - - /** - * Add a mock response for a PUT request. - * - * @param string $url The URL to mock - * @param \Cake\Http\Client\Response $response The response for the mock. - * @param array $options Additional options. See Client::addMockResponse() - * @return void - */ - public function mockClientPut(string $url, Response $response, array $options = []): void - { - Client::addMockResponse('PUT', $url, $response, $options); - } - - /** - * Add a mock response for a DELETE request. - * - * @param string $url The URL to mock - * @param \Cake\Http\Client\Response $response The response for the mock. - * @param array $options Additional options. See Client::addMockResponse() - * @return void - */ - public function mockClientDelete(string $url, Response $response, array $options = []): void - { - Client::addMockResponse('DELETE', $url, $response, $options); - } -} +class_alias(HttpClientTrait::class, 'Cake\TestSuite\HttpClientTrait'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/IntegrationTestTrait.php b/app/vendor/cakephp/cakephp/src/TestSuite/IntegrationTestTrait.php index 04973d038..d367ba6c6 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/IntegrationTestTrait.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/IntegrationTestTrait.php @@ -17,8 +17,9 @@ use Cake\Controller\Controller; use Cake\Core\Configure; +use Cake\Core\TestSuite\ContainerStubTrait; use Cake\Database\Exception\DatabaseException; -use Cake\Error\ExceptionRenderer; +use Cake\Error\Renderer\WebExceptionRenderer; use Cake\Event\EventInterface; use Cake\Event\EventManager; use Cake\Form\FormProtector; @@ -553,9 +554,9 @@ protected function _handleError(Throwable $exception): void { $class = Configure::read('Error.exceptionRenderer'); if (empty($class) || !class_exists($class)) { - $class = ExceptionRenderer::class; + $class = WebExceptionRenderer::class; } - /** @var \Cake\Error\ExceptionRenderer $instance */ + /** @var \Cake\Error\Renderer\WebExceptionRenderer $instance */ $instance = new $class($exception); $this->_response = $instance->render(); } @@ -627,9 +628,8 @@ protected function _buildRequest(string $url, $method, $data = []): array $props['cookies'] = $this->_cookie; $session->write($this->_session); - $props = Hash::merge($props, $this->_request); - return $props; + return Hash::merge($props, $this->_request); } /** @@ -1320,6 +1320,11 @@ public function assertFileResponse(string $expected, string $message = ''): void $verboseMessage = $this->extractVerboseMessage($message); $this->assertThat(null, new FileSent($this->_response), $verboseMessage); $this->assertThat($expected, new FileSentAs($this->_response), $verboseMessage); + + if (!$this->_response) { + return; + } + $this->_response->getBody()->close(); } /** @@ -1352,10 +1357,26 @@ protected function extractVerboseMessage(string $message): string */ protected function extractExceptionMessage(Exception $exception): string { - return PHP_EOL . - sprintf('Possibly related to %s: "%s" ', get_class($exception), $exception->getMessage()) . - PHP_EOL . - $exception->getTraceAsString(); + $exceptions = [$exception]; + $previous = $exception->getPrevious(); + while ($previous != null) { + $exceptions[] = $previous; + $previous = $previous->getPrevious(); + } + $message = PHP_EOL; + foreach ($exceptions as $i => $error) { + if ($i == 0) { + $message .= sprintf('Possibly related to %s: "%s"', get_class($error), $error->getMessage()); + $message .= PHP_EOL; + } else { + $message .= sprintf('Caused by %s: "%s"', get_class($error), $error->getMessage()); + $message .= PHP_EOL; + } + $message .= $error->getTraceAsString(); + $message .= PHP_EOL; + } + + return $message; } /** diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php b/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php index 33dca5c32..e598b17f4 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/LegacyCommandRunner.php @@ -1,39 +1,6 @@ dispatch(); - } -} +class_alias(LegacyCommandRunner::class, 'Cake\TestSuite\LegacyCommandRunner'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/LegacyShellDispatcher.php b/app/vendor/cakephp/cakephp/src/TestSuite/LegacyShellDispatcher.php index dcf258c83..a1dda1744 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/LegacyShellDispatcher.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/LegacyShellDispatcher.php @@ -1,64 +1,6 @@ _io = $io; - parent::__construct($args, $bootstrap); - } - - /** - * Injects mock and stub io components into the shell - * - * @param string $className Class name - * @param string $shortName Short name - * @return \Cake\Console\Shell - */ - protected function _createShell(string $className, string $shortName): Shell - { - [$plugin] = pluginSplit($shortName); - /** @var \Cake\Console\Shell $instance */ - $instance = new $className($this->_io); - if ($plugin) { - $instance->plugin = trim($plugin, '.'); - } - - return $instance; - } -} +class_alias(LegacyShellDispatcher::class, 'Cake\TestSuite\LegacyShellDispatcher'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/MiddlewareDispatcher.php b/app/vendor/cakephp/cakephp/src/TestSuite/MiddlewareDispatcher.php index f9ce0efe6..6ca6e767e 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/MiddlewareDispatcher.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/MiddlewareDispatcher.php @@ -121,11 +121,10 @@ protected function _createRequest(array $spec): ServerRequest $spec['cookies'], $spec['files'] ); - $request = $request + + return $request ->withAttribute('session', $spec['session']) ->withAttribute('flash', new FlashMessage($spec['session'])); - - return $request; } /** diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Stub/ConsoleInput.php b/app/vendor/cakephp/cakephp/src/TestSuite/Stub/ConsoleInput.php index 80cd376ed..0a84f53a8 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Stub/ConsoleInput.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Stub/ConsoleInput.php @@ -1,88 +1,6 @@ - */ - protected $replies = []; - - /** - * Current message index - * - * @var int - */ - protected $currentIndex = -1; - - /** - * Constructor - * - * @param array $replies A list of replies for read() - */ - public function __construct(array $replies) - { - parent::__construct(); - - $this->replies = $replies; - } - - /** - * Read a reply - * - * @return string The value of the reply - */ - public function read(): string - { - $this->currentIndex += 1; - - if (!isset($this->replies[$this->currentIndex])) { - $total = count($this->replies); - $formatter = new NumberFormatter('en', NumberFormatter::ORDINAL); - $nth = $formatter->format($this->currentIndex + 1); - - $replies = implode(', ', $this->replies); - $message = "There are no more input replies available. This is the {$nth} read operation, " . - "only {$total} replies were set.\nThe provided replies are: {$replies}"; - throw new MissingConsoleInputException($message); - } - - return $this->replies[$this->currentIndex]; - } - - /** - * Check if data is available on stdin - * - * @param int $timeout An optional time to wait for data - * @return bool True for data available, false otherwise - */ - public function dataAvailable($timeout = 0): bool - { - return true; - } -} +class_alias(StubConsoleInput::class, 'Cake\TestSuite\Stub\ConsoleInput'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Stub/ConsoleOutput.php b/app/vendor/cakephp/cakephp/src/TestSuite/Stub/ConsoleOutput.php index 24ee50d1d..3d299a8e9 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Stub/ConsoleOutput.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Stub/ConsoleOutput.php @@ -1,84 +1,6 @@ - */ - protected $_out = []; - - /** - * Write output to the buffer. - * - * @param array|string $message A string or an array of strings to output - * @param int $newlines Number of newlines to append - * @return int - */ - public function write($message, int $newlines = 1): int - { - foreach ((array)$message as $line) { - $this->_out[] = $line; - } - - $newlines--; - while ($newlines > 0) { - $this->_out[] = ''; - $newlines--; - } - - return 0; - } - - /** - * Get the buffered output. - * - * @return array - */ - public function messages(): array - { - return $this->_out; - } - - /** - * Get the output as a string - * - * @return string - */ - public function output(): string - { - return implode("\n", $this->_out); - } -} +class_alias(StubConsoleOutput::class, 'Cake\TestSuite\Stub\ConsoleOutput'); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Stub/MissingConsoleInputException.php b/app/vendor/cakephp/cakephp/src/TestSuite/Stub/MissingConsoleInputException.php index 3055b282a..bb023f841 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Stub/MissingConsoleInputException.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Stub/MissingConsoleInputException.php @@ -1,35 +1,6 @@ message .= "\nThe question asked was: " . $question; - } -} +class_exists(MissingConsoleInputException::class); diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/Stub/TestExceptionRenderer.php b/app/vendor/cakephp/cakephp/src/TestSuite/Stub/TestExceptionRenderer.php index 3122bdac7..89107c76a 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/Stub/TestExceptionRenderer.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/Stub/TestExceptionRenderer.php @@ -16,6 +16,9 @@ */ namespace Cake\TestSuite\Stub; +use Cake\Error\ExceptionRendererInterface; +use LogicException; +use Psr\Http\Message\ResponseInterface; use Throwable; /** @@ -28,7 +31,7 @@ * @see \Cake\TestSuite\IntegrationTestCase::disableErrorHandlerMiddleware() * @internal */ -class TestExceptionRenderer +class TestExceptionRenderer implements ExceptionRendererInterface { /** * Simply rethrow the given exception @@ -41,4 +44,22 @@ public function __construct(Throwable $exception) { throw $exception; } + + /** + * @inheritDoc + */ + public function render(): ResponseInterface + { + throw new LogicException('You cannot use this class to render exceptions.'); + } + + /** + * Part of upcoming interface requirements + * + * @param \Psr\Http\Message\ResponseInterface|string $output The output or response to send. + * @return void + */ + public function write($output): void + { + } } diff --git a/app/vendor/cakephp/cakephp/src/TestSuite/TestEmailTransport.php b/app/vendor/cakephp/cakephp/src/TestSuite/TestEmailTransport.php index 8d2694d77..dee56b7d6 100644 --- a/app/vendor/cakephp/cakephp/src/TestSuite/TestEmailTransport.php +++ b/app/vendor/cakephp/cakephp/src/TestSuite/TestEmailTransport.php @@ -38,8 +38,7 @@ class TestEmailTransport extends DebugTransport * Stores email for later assertions * * @param \Cake\Mailer\Message $message Message - * @return array - * @psalm-return array{headers: string, message: string} + * @return array{headers: string, message: string} */ public function send(Message $message): array { diff --git a/app/vendor/cakephp/cakephp/src/Utility/Hash.php b/app/vendor/cakephp/cakephp/src/Utility/Hash.php index af52e9039..f30cc8271 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Hash.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Hash.php @@ -728,25 +728,28 @@ public static function flatten(array $data, string $separator = '.'): array */ public static function expand(array $data, string $separator = '.'): array { - $result = []; - foreach ($data as $flat => $value) { - $keys = explode($separator, (string)$flat); - $keys = array_reverse($keys); - $child = [ - $keys[0] => $value, - ]; - array_shift($keys); - foreach ($keys as $k) { - $child = [ - $k => $child, - ]; + $hash = []; + foreach ($data as $path => $value) { + $keys = explode($separator, (string)$path); + if (count($keys) === 1) { + $hash[$path] = $value; + continue; } - $stack = [[$child, &$result]]; - static::_merge($stack, $result); + $valueKey = end($keys); + $keys = array_slice($keys, 0, -1); + + $keyHash = &$hash; + foreach ($keys as $key) { + if (!array_key_exists($key, $keyHash)) { + $keyHash[$key] = []; + } + $keyHash = &$keyHash[$key]; + } + $keyHash[$valueKey] = $value; } - return $result; + return $hash; } /** @@ -1116,6 +1119,7 @@ public static function diff(array $data, array $compare): array next($intersection); } + /** @phpstan-ignore-next-line */ return $data + $compare; } diff --git a/app/vendor/cakephp/cakephp/src/Utility/Inflector.php b/app/vendor/cakephp/cakephp/src/Utility/Inflector.php index 33438c34d..9cb8c1f44 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Inflector.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Inflector.php @@ -166,7 +166,7 @@ class Inflector /** * Method cache array. * - * @var array + * @var array */ protected static $_cache = []; diff --git a/app/vendor/cakephp/cakephp/src/Utility/Security.php b/app/vendor/cakephp/cakephp/src/Utility/Security.php index df3952a7e..a46d3222b 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Security.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Security.php @@ -163,18 +163,16 @@ public static function insecureRandomBytes(int $length): string */ public static function engine($instance = null) { - if ($instance === null && static::$_instance === null) { - if (extension_loaded('openssl')) { - $instance = new OpenSsl(); - } - } if ($instance) { - static::$_instance = $instance; + return static::$_instance = $instance; } if (isset(static::$_instance)) { /** @psalm-suppress LessSpecificReturnStatement */ return static::$_instance; } + if (extension_loaded('openssl')) { + return static::$_instance = new OpenSsl(); + } throw new InvalidArgumentException( 'No compatible crypto engine available. ' . 'Load the openssl extension.' diff --git a/app/vendor/cakephp/cakephp/src/Utility/Text.php b/app/vendor/cakephp/cakephp/src/Utility/Text.php index 570a24745..3c3e15453 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Text.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Text.php @@ -53,7 +53,7 @@ class Text * Generate a random UUID version 4 * * Warning: This method should not be used as a random seed for any cryptographic operations. - * Instead, you should use the openssl or mcrypt extensions. + * Instead, you should use `Security::randomBytes()` or `Security::randomString()` instead. * * It should also not be used to create identifiers that have security implications, such as * 'unguessable' URL identifiers. Instead, you should use {@link \Cake\Utility\Security::randomBytes()}` for that. @@ -377,6 +377,7 @@ public static function wrapBlock(string $text, $options = []): string } $options += ['width' => 72, 'wordWrap' => true, 'indent' => null, 'indentAt' => 0]; + /** @phpstan-ignore-next-line */ if (!empty($options['indentAt']) && $options['indentAt'] === 0) { $indentLength = !empty($options['indent']) ? strlen($options['indent']) : 0; $options['width'] -= $indentLength; @@ -904,9 +905,8 @@ public static function excerpt(string $text, string $phrase, int $radius = 100, } $excerpt = mb_substr($text, $startPos, $endPos - $startPos); - $excerpt = $prepend . $excerpt . $append; - return $excerpt; + return $prepend . $excerpt . $append; } /** @@ -955,7 +955,7 @@ public static function isMultibyte(string $string): bool * to the decimal value of the character * * @param string $string String to convert. - * @return array + * @return array */ public static function utf8(string $string): array { @@ -1180,8 +1180,7 @@ public static function slug(string $string, $options = []): string if (is_string($options['replacement']) && $options['replacement'] !== '') { $map[sprintf('/[%s]+/mu', $quotedReplacement)] = $options['replacement']; } - $string = preg_replace(array_keys($map), $map, $string); - return $string; + return preg_replace(array_keys($map), $map, $string); } } diff --git a/app/vendor/cakephp/cakephp/src/Utility/Xml.php b/app/vendor/cakephp/cakephp/src/Utility/Xml.php index d02f59135..069177af4 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/Xml.php +++ b/app/vendor/cakephp/cakephp/src/Utility/Xml.php @@ -51,7 +51,7 @@ class Xml * Building XML from a file path: * * ``` - * $xml = Xml::build('/path/to/an/xml/file.xml'); + * $xml = Xml::build('/path/to/an/xml/file.xml', ['readFile' => true]); * ``` * * Building XML from a remote URL: @@ -453,7 +453,7 @@ public static function toArray($obj): array * Recursive method to toArray * * @param \SimpleXMLElement $xml SimpleXMLElement object - * @param array $parentData Parent array with data + * @param array $parentData Parent array with data * @param string $ns Namespace of current child * @param array $namespaces List of namespaces in XML * @return void diff --git a/app/vendor/cakephp/cakephp/src/Utility/composer.json b/app/vendor/cakephp/cakephp/src/Utility/composer.json index fccb2f884..949ca6012 100644 --- a/app/vendor/cakephp/cakephp/src/Utility/composer.json +++ b/app/vendor/cakephp/cakephp/src/Utility/composer.json @@ -25,7 +25,7 @@ "source": "https://github.com/cakephp/utility" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0" }, "suggest": { diff --git a/app/vendor/cakephp/cakephp/src/Validation/ValidatableInterface.php b/app/vendor/cakephp/cakephp/src/Validation/ValidatableInterface.php index 9defaa34a..d37b09c15 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/ValidatableInterface.php +++ b/app/vendor/cakephp/cakephp/src/Validation/ValidatableInterface.php @@ -18,6 +18,8 @@ /** * Describes objects that can be validated by passing a Validator object. + * + * @deprecated 4.4.5 This interface is unused. */ interface ValidatableInterface { diff --git a/app/vendor/cakephp/cakephp/src/Validation/Validation.php b/app/vendor/cakephp/cakephp/src/Validation/Validation.php index d250a53a2..c70c3d80e 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/Validation.php +++ b/app/vendor/cakephp/cakephp/src/Validation/Validation.php @@ -696,7 +696,7 @@ public static function localizedTime($check, string $type = 'datetime', $format * The list of what is considered to be boolean values, may be set via $booleanValues. * * @param string|int|bool $check Value to check. - * @param array $booleanValues List of valid boolean values, defaults to `[true, false, 0, 1, '0', '1']`. + * @param array $booleanValues List of valid boolean values, defaults to `[true, false, 0, 1, '0', '1']`. * @return bool Success. */ public static function boolean($check, array $booleanValues = []): bool @@ -714,7 +714,7 @@ public static function boolean($check, array $booleanValues = []): bool * The list of what is considered to be truthy values, may be set via $truthyValues. * * @param string|int|bool $check Value to check. - * @param array $truthyValues List of valid truthy values, defaults to `[true, 1, '1']`. + * @param array $truthyValues List of valid truthy values, defaults to `[true, 1, '1']`. * @return bool Success. */ public static function truthy($check, array $truthyValues = []): bool @@ -732,7 +732,7 @@ public static function truthy($check, array $truthyValues = []): bool * The list of what is considered to be falsey values, may be set via $falseyValues. * * @param string|int|bool $check Value to check. - * @param array $falseyValues List of valid falsey values, defaults to `[false, 0, '0']`. + * @param array $falseyValues List of valid falsey values, defaults to `[false, 0, '0']`. * @return bool Success. */ public static function falsey($check, array $falseyValues = []): bool @@ -1332,7 +1332,11 @@ public static function uploadError($check, bool $allowNoFile = false): bool { if ($check instanceof UploadedFileInterface) { $code = $check->getError(); - } elseif (is_array($check) && isset($check['error'])) { + } elseif (is_array($check)) { + if (!isset($check['error'])) { + return false; + } + $code = $check['error']; } else { $code = $check; diff --git a/app/vendor/cakephp/cakephp/src/Validation/ValidationRule.php b/app/vendor/cakephp/cakephp/src/Validation/ValidationRule.php index 326e7556e..6ebd5a749 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/ValidationRule.php +++ b/app/vendor/cakephp/cakephp/src/Validation/ValidationRule.php @@ -74,7 +74,7 @@ class ValidationRule /** * Constructor * - * @param array $validator [optional] The validator properties + * @param array $validator [optional] The validator properties */ public function __construct(array $validator = []) { @@ -184,7 +184,7 @@ protected function _skip(array $context): bool /** * Sets the rule properties from the rule entry in validate * - * @param array $validator [optional] + * @param array $validator [optional] * @return void */ protected function _addValidatorProps(array $validator = []): void diff --git a/app/vendor/cakephp/cakephp/src/Validation/Validator.php b/app/vendor/cakephp/cakephp/src/Validation/Validator.php index ef574a78b..bbc06bef3 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/Validator.php +++ b/app/vendor/cakephp/cakephp/src/Validation/Validator.php @@ -155,7 +155,7 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable * Contains the validation messages associated with checking the presence * for each corresponding field. * - * @var array + * @var array */ protected $_presenceMessages = []; @@ -170,14 +170,14 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable * Contains the validation messages associated with checking the emptiness * for each corresponding field. * - * @var array + * @var array */ protected $_allowEmptyMessages = []; /** * Contains the flags which specify what is empty for each corresponding field. * - * @var array + * @var array */ protected $_allowEmptyFlags = []; diff --git a/app/vendor/cakephp/cakephp/src/Validation/ValidatorAwareInterface.php b/app/vendor/cakephp/cakephp/src/Validation/ValidatorAwareInterface.php index 9b71ef267..ee7425506 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/ValidatorAwareInterface.php +++ b/app/vendor/cakephp/cakephp/src/Validation/ValidatorAwareInterface.php @@ -2,17 +2,17 @@ declare(strict_types=1); /** - * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) - * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) + * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) + * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * - * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://cakephp.org CakePHP(tm) Project + * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) + * @link https://cakephp.org CakePHP(tm) Project * @since 3.5.0 - * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @license https://www.opensource.org/licenses/mit-license.php MIT License */ namespace Cake\Validation; diff --git a/app/vendor/cakephp/cakephp/src/Validation/composer.json b/app/vendor/cakephp/cakephp/src/Validation/composer.json index eceaafd2e..a8998a9c1 100644 --- a/app/vendor/cakephp/cakephp/src/Validation/composer.json +++ b/app/vendor/cakephp/cakephp/src/Validation/composer.json @@ -22,7 +22,7 @@ "source": "https://github.com/cakephp/validation" }, "require": { - "php": ">=7.2.0", + "php": ">=7.4.0", "cakephp/core": "^4.0", "cakephp/utility": "^4.0", "psr/http-message": "^1.0.0" diff --git a/app/vendor/cakephp/cakephp/src/View/AjaxView.php b/app/vendor/cakephp/cakephp/src/View/AjaxView.php index 064f31fad..a99c14574 100644 --- a/app/vendor/cakephp/cakephp/src/View/AjaxView.php +++ b/app/vendor/cakephp/cakephp/src/View/AjaxView.php @@ -29,11 +29,12 @@ class AjaxView extends View protected $layout = 'ajax'; /** - * @inheritDoc + * Get content type for this view. + * + * @return string */ - public function initialize(): void + public static function contentType(): string { - parent::initialize(); - $this->setResponse($this->getResponse()->withType('ajax')); + return 'text/html'; } } diff --git a/app/vendor/cakephp/cakephp/src/View/Cell.php b/app/vendor/cakephp/cakephp/src/View/Cell.php index 00ac8e652..49cf528b5 100644 --- a/app/vendor/cakephp/cakephp/src/View/Cell.php +++ b/app/vendor/cakephp/cakephp/src/View/Cell.php @@ -36,6 +36,7 @@ /** * Cell base. */ +#[\AllowDynamicProperties] abstract class Cell implements EventDispatcherInterface { use EventDispatcherTrait; diff --git a/app/vendor/cakephp/cakephp/src/View/CellTrait.php b/app/vendor/cakephp/cakephp/src/View/CellTrait.php index c1a1c810a..5252c98c9 100644 --- a/app/vendor/cakephp/cakephp/src/View/CellTrait.php +++ b/app/vendor/cakephp/cakephp/src/View/CellTrait.php @@ -76,9 +76,8 @@ protected function cell(string $cell, array $data = [], array $options = []): Ce $data = array_values($data); } $options = ['action' => $action, 'args' => $data] + $options; - $cell = $this->_createCell($className, $action, $plugin, $options); - return $cell; + return $this->_createCell($className, $action, $plugin, $options); } /** diff --git a/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php b/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php index 5abddef3f..8271c92b9 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/ArrayContext.php @@ -73,7 +73,7 @@ class ArrayContext implements ContextInterface /** * Context data for this object. * - * @var array + * @var array */ protected $_context; diff --git a/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php b/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php index 30d7a6799..87e2ce4e1 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/EntityContext.php @@ -55,7 +55,7 @@ class EntityContext implements ContextInterface /** * Context data for this object. * - * @var array + * @var array */ protected $_context; @@ -91,7 +91,7 @@ class EntityContext implements ContextInterface /** * Constructor. * - * @param array $context Context info. + * @param array $context Context info. */ public function __construct(array $context) { @@ -400,7 +400,7 @@ public function entity(?array $path = null) * * Traverse the path until an entity cannot be found. Lists containing * entities will be traversed if the first element contains an entity. - * Otherwise the containing Entity will be assumed to be the terminal one. + * Otherwise, the containing Entity will be assumed to be the terminal one. * * @param array|null $path Each one of the parts in a path for a field name * or null to get the entity passed in constructor context. diff --git a/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php b/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php index 32c9ffdaf..007e2dcb1 100644 --- a/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php +++ b/app/vendor/cakephp/cakephp/src/View/Form/FormContext.php @@ -16,6 +16,8 @@ */ namespace Cake\View\Form; +use Cake\Core\Exception\CakeException; +use Cake\Form\Form; use Cake\Utility\Hash; /** @@ -33,17 +35,31 @@ class FormContext implements ContextInterface */ protected $_form; + /** + * Validator name. + * + * @var string|null + */ + protected $_validator = null; + /** * Constructor. * * @param array $context Context info. + * + * Keys: + * + * - `entity` The Form class instance this context is operating on. **(required)** + * - `validator` Optional name of the validation method to call on the Form object. */ public function __construct(array $context) { - $context += [ - 'entity' => null, - ]; + if (!isset($context['entity']) || !$context['entity'] instanceof Form) { + throw new CakeException('`$context[\'entity\']` must be an instance of Cake\Form\Form'); + } + $this->_form = $context['entity']; + $this->_validator = $context['validator'] ?? null; } /** @@ -126,7 +142,7 @@ protected function _schemaDefault(string $field) */ public function isRequired(string $field): ?bool { - $validator = $this->_form->getValidator(); + $validator = $this->_form->getValidator($this->_validator); if (!$validator->hasField($field)) { return null; } @@ -144,7 +160,7 @@ public function getRequiredMessage(string $field): ?string { $parts = explode('.', $field); - $validator = $this->_form->getValidator(); + $validator = $this->_form->getValidator($this->_validator); $fieldName = array_pop($parts); if (!$validator->hasField($fieldName)) { return null; @@ -163,7 +179,7 @@ public function getRequiredMessage(string $field): ?string */ public function getMaxLength(string $field): ?int { - $validator = $this->_form->getValidator(); + $validator = $this->_form->getValidator($this->_validator); if (!$validator->hasField($field)) { return null; } diff --git a/app/vendor/cakephp/cakephp/src/View/Helper.php b/app/vendor/cakephp/cakephp/src/View/Helper.php index 69530b026..35ca7dbbe 100644 --- a/app/vendor/cakephp/cakephp/src/View/Helper.php +++ b/app/vendor/cakephp/cakephp/src/View/Helper.php @@ -40,6 +40,7 @@ * - `afterRenderFile(EventInterface $event, $viewFile, $content)` - Called after any view fragment is rendered. * If a listener returns a non-null value, the output of the rendered file will be set to that. */ +#[\AllowDynamicProperties] class Helper implements EventListenerInterface { use InstanceConfigTrait; diff --git a/app/vendor/cakephp/cakephp/src/View/Helper/BreadcrumbsHelper.php b/app/vendor/cakephp/cakephp/src/View/Helper/BreadcrumbsHelper.php index d96a70a28..cc930d210 100644 --- a/app/vendor/cakephp/cakephp/src/View/Helper/BreadcrumbsHelper.php +++ b/app/vendor/cakephp/cakephp/src/View/Helper/BreadcrumbsHelper.php @@ -320,13 +320,11 @@ public function render(array $attributes = [], array $separator = []): string $crumbTrail .= $this->formatTemplate($template, $templateParams); } - $crumbTrail = $this->formatTemplate('wrapper', [ + return $this->formatTemplate('wrapper', [ 'content' => $crumbTrail, 'attrs' => $templater->formatAttributes($attributes, ['templateVars']), 'templateVars' => $attributes['templateVars'] ?? [], ]); - - return $crumbTrail; } /** diff --git a/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php b/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php index 1486b1cde..2b298118d 100644 --- a/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php +++ b/app/vendor/cakephp/cakephp/src/View/Helper/FormHelper.php @@ -506,9 +506,7 @@ protected function _formUrl(ContextInterface $context, array $options) 'action' => $request->getParam('action'), ]; - $action = (array)$options['url'] + $actionDefaults; - - return $action; + return (array)$options['url'] + $actionDefaults; } /** @@ -1028,7 +1026,7 @@ public function fieldset(string $fields = '', array $options = []): string * @param string $fieldName This should be "modelname.fieldname" * @param array $options Each type of input takes different options. * @return string Completed form widget. - * @link https://book.cakephp.org/4/en/views/helpers/form.html#creating-form-inputs + * @link https://book.cakephp.org/4/en/views/helpers/form.html#creating-form-controls * @psalm-suppress InvalidReturnType * @psalm-suppress InvalidReturnStatement */ @@ -1234,9 +1232,7 @@ protected function _parseOptions(string $fieldName, array $options): array $options['type'] = $this->_inputType($fieldName, $options); } - $options = $this->_magicOptions($fieldName, $options, $needsMagicType); - - return $options; + return $this->_magicOptions($fieldName, $options, $needsMagicType); } /** @@ -1294,7 +1290,7 @@ protected function _inputType(string $fieldName, array $options): string * * @param string $fieldName The name of the field to find options for. * @param array $options Options list. - * @return array + * @return array */ protected function _optionsOptions(string $fieldName, array $options): array { @@ -1555,21 +1551,30 @@ public function radio(string $fieldName, iterable $options = [], array $attribut { $attributes['options'] = $options; $attributes['idPrefix'] = $this->_idPrefix; + + $generatedHiddenId = false; + if (!isset($attributes['id'])) { + $attributes['id'] = true; + $generatedHiddenId = true; + } $attributes = $this->_initInputField($fieldName, $attributes); $hiddenField = $attributes['hiddenField'] ?? true; unset($attributes['hiddenField']); - $radio = $this->widget('radio', $attributes); - $hidden = ''; if ($hiddenField !== false && is_scalar($hiddenField)) { $hidden = $this->hidden($fieldName, [ 'value' => $hiddenField === true ? '' : (string)$hiddenField, 'form' => $attributes['form'] ?? null, 'name' => $attributes['name'], + 'id' => $attributes['id'], ]); } + if ($generatedHiddenId) { + unset($attributes['id']); + } + $radio = $this->widget('radio', $attributes); return $hidden . $radio; } @@ -2112,6 +2117,13 @@ public function multiCheckbox(string $fieldName, iterable $options, array $attri 'hiddenField' => true, 'secure' => true, ]; + + $generatedHiddenId = false; + if (!isset($attributes['id'])) { + $attributes['id'] = true; + $generatedHiddenId = true; + } + $attributes = $this->_initInputField($fieldName, $attributes); $attributes['options'] = $options; $attributes['idPrefix'] = $this->_idPrefix; @@ -2123,11 +2135,16 @@ public function multiCheckbox(string $fieldName, iterable $options, array $attri 'value' => '', 'secure' => false, 'disabled' => $attributes['disabled'] === true || $attributes['disabled'] === 'disabled', + 'id' => $attributes['id'], ]; $hidden = $this->hidden($fieldName, $hiddenAttributes); } unset($attributes['hiddenField']); + if ($generatedHiddenId) { + unset($attributes['id']); + } + return $hidden . $this->widget('multicheckbox', $attributes); } diff --git a/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php b/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php index 1a2df5cd9..aa2d5ed02 100644 --- a/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php +++ b/app/vendor/cakephp/cakephp/src/View/Helper/HtmlHelper.php @@ -850,9 +850,9 @@ public function tableCell(string $content, array $options = []): string * - `escape` Whether the contents should be html_entity escaped. * * @param string $name Tag name. - * @param string|null $text String content that will appear inside the div element. + * @param string|null $text String content that will appear inside the HTML element. * If null, only a start tag will be printed - * @param array $options Additional HTML attributes of the DIV tag, see above. + * @param array $options Additional HTML attributes of the HTML tag, see above. * @return string The formatted tag element */ public function tag(string $name, ?string $text = null, array $options = []): string diff --git a/app/vendor/cakephp/cakephp/src/View/JsonView.php b/app/vendor/cakephp/cakephp/src/View/JsonView.php index 02d47783f..ef9fc9162 100644 --- a/app/vendor/cakephp/cakephp/src/View/JsonView.php +++ b/app/vendor/cakephp/cakephp/src/View/JsonView.php @@ -72,13 +72,6 @@ class JsonView extends SerializedView */ protected $subDir = 'json'; - /** - * Response type. - * - * @var string - */ - protected $_responseType = 'json'; - /** * Default config options. * @@ -102,6 +95,16 @@ class JsonView extends SerializedView 'jsonp' => null, ]; + /** + * Mime-type this view class renders as. + * + * @return string The JSON content type. + */ + public static function contentType(): string + { + return 'application/json'; + } + /** * Render a JSON view. * diff --git a/app/vendor/cakephp/cakephp/src/View/SerializedView.php b/app/vendor/cakephp/cakephp/src/View/SerializedView.php index a8a83bf04..b71bf84f6 100644 --- a/app/vendor/cakephp/cakephp/src/View/SerializedView.php +++ b/app/vendor/cakephp/cakephp/src/View/SerializedView.php @@ -29,6 +29,7 @@ abstract class SerializedView extends View * Response type. * * @var string + * @deprecated 4.4.0 Implement ``public static contentType(): string`` instead. */ protected $_responseType; @@ -54,7 +55,10 @@ abstract class SerializedView extends View public function initialize(): void { parent::initialize(); - $this->setResponse($this->getResponse()->withType($this->_responseType)); + if ($this->_responseType) { + $response = $this->getResponse()->withType($this->_responseType); + $this->setResponse($response); + } } /** diff --git a/app/vendor/cakephp/cakephp/src/View/StringTemplate.php b/app/vendor/cakephp/cakephp/src/View/StringTemplate.php index 442ad4a63..d5f875bed 100644 --- a/app/vendor/cakephp/cakephp/src/View/StringTemplate.php +++ b/app/vendor/cakephp/cakephp/src/View/StringTemplate.php @@ -182,7 +182,7 @@ protected function _compileTemplates(array $templates = []): void } $template = str_replace('%', '%%', $template); - preg_match_all('#\{\{([\w\._]+)\}\}#', $template, $matches); + preg_match_all('#\{\{([\w\.]+)\}\}#', $template, $matches); $this->_compiled[$name] = [ str_replace($matches[0], '%s', $template), $matches[1], @@ -373,8 +373,6 @@ public function addClass($input, $newClass, string $useIndex = 'class') $class = array_unique(array_merge($class, $newClass)); - $input = Hash::insert($input, $useIndex, $class); - - return $input; + return Hash::insert($input, $useIndex, $class); } } diff --git a/app/vendor/cakephp/cakephp/src/View/View.php b/app/vendor/cakephp/cakephp/src/View/View.php index 2e3c51950..2f6c65e54 100644 --- a/app/vendor/cakephp/cakephp/src/View/View.php +++ b/app/vendor/cakephp/cakephp/src/View/View.php @@ -70,6 +70,7 @@ * @property \Cake\View\Helper\UrlHelper $Url * @property \Cake\View\ViewBlock $Blocks */ +#[\AllowDynamicProperties] class View implements EventDispatcherInterface { use CellTrait { @@ -313,6 +314,14 @@ class View implements EventDispatcherInterface */ public const PLUGIN_TEMPLATE_FOLDER = 'plugin'; + /** + * The magic 'match-all' content type that views can use to + * behave as a fallback during content-type negotiation. + * + * @var string + */ + public const TYPE_MATCH_ALL = '_match_all_'; + /** * Constructor * @@ -363,6 +372,36 @@ public function __construct( */ public function initialize(): void { + $this->setContentType(); + } + + /** + * Set the response content-type based on the view's contentType() + * + * @return void + */ + protected function setContentType(): void + { + $viewContentType = $this->contentType(); + if (!$viewContentType || $viewContentType == static::TYPE_MATCH_ALL) { + return; + } + $response = $this->getResponse(); + $responseType = $response->getHeaderLine('Content-Type'); + if ($responseType === '' || substr($responseType, 0, 9) === 'text/html') { + $response = $response->withType($viewContentType); + } + $this->setResponse($response); + } + + /** + * Mime-type this view class renders as. + * + * @return string Either the content type or '' which means no type. + */ + public static function contentType(): string + { + return ''; } /** diff --git a/app/vendor/cakephp/cakephp/src/View/XmlView.php b/app/vendor/cakephp/cakephp/src/View/XmlView.php index d7cfb03c5..94f33a19d 100644 --- a/app/vendor/cakephp/cakephp/src/View/XmlView.php +++ b/app/vendor/cakephp/cakephp/src/View/XmlView.php @@ -74,13 +74,6 @@ class XmlView extends SerializedView */ protected $subDir = 'xml'; - /** - * Response type. - * - * @var string - */ - protected $_responseType = 'xml'; - /** * Default config options. * @@ -102,6 +95,16 @@ class XmlView extends SerializedView 'rootNode' => null, ]; + /** + * Mime-type this view class renders as. + * + * @return string The JSON content type. + */ + public static function contentType(): string + { + return 'application/xml'; + } + /** * @inheritDoc */ diff --git a/app/vendor/cakephp/cakephp/src/basics.php b/app/vendor/cakephp/cakephp/src/basics.php index c44a79741..7df55e2a7 100644 --- a/app/vendor/cakephp/cakephp/src/basics.php +++ b/app/vendor/cakephp/cakephp/src/basics.php @@ -105,7 +105,7 @@ function stackTrace(array $options = []): void * ``` * * @return string|null - * @link http://psysh.org/ + * @link https://psysh.org/ */ function breakpoint(): ?string { diff --git a/app/vendor/cakephp/cakephp/templates/element/exception_stack_trace.php b/app/vendor/cakephp/cakephp/templates/element/exception_stack_trace.php index c6a8aa4dd..b535be9b5 100644 --- a/app/vendor/cakephp/cakephp/templates/element/exception_stack_trace.php +++ b/app/vendor/cakephp/cakephp/templates/element/exception_stack_trace.php @@ -17,58 +17,64 @@ */ use Cake\Error\Debugger; -foreach ($trace as $i => $stack): - $excerpt = $params = []; +foreach ($exceptions as $level => $exc): + $stackTrace = Debugger::formatTrace($exc->getTrace(), [ + 'format' => 'array', + 'args' => true, + ]); + foreach ($stackTrace as $i => $stack): + $excerpt = $params = []; - $line = null; - if (isset($stack['file'], $stack['line']) && is_numeric($stack['line'])): - $line = $stack['line']; - $excerpt = Debugger::excerpt($stack['file'], $line, 4); - endif; - - if (isset($stack['file'])): - $file = $stack['file']; - else: - $file = '[internal function]'; - endif; + $line = null; + if (isset($stack['file'], $stack['line']) && is_numeric($stack['line'])): + $line = $stack['line']; + $excerpt = Debugger::excerpt($stack['file'], $line, 4); + endif; - if (isset($stack['function'])): - if (!empty($stack['args'])): - foreach ((array)$stack['args'] as $arg): - $params[] = Debugger::exportVar($arg, 4); - endforeach; + if (isset($stack['file'])): + $file = $stack['file']; else: - $params[] = 'No arguments'; + $file = '[internal function]'; endif; - endif; -?> -
-
- - - Html->link(Debugger::trimPath($file), Debugger::editorUrl($file, $line)); ?> - - - - - Toggle Arguments -
- - - $line): ?> - - - - - -
+ if (isset($stack['function'])): + if (!empty($stack['args'])): + foreach ((array)$stack['args'] as $arg): + $params[] = Debugger::exportVar($arg, 4); + endforeach; + else: + $params[] = 'No arguments'; + endif; + endif; + ?> +
+
+ + + Html->link(Debugger::trimPath($file), Debugger::editorUrl($file, $line)); ?> + + + + + Toggle Arguments +
- -
+ diff --git a/app/vendor/cakephp/cakephp/templates/element/exception_stack_trace_nav.php b/app/vendor/cakephp/cakephp/templates/element/exception_stack_trace_nav.php index 3c78b47d9..a152958e2 100644 --- a/app/vendor/cakephp/cakephp/templates/element/exception_stack_trace_nav.php +++ b/app/vendor/cakephp/cakephp/templates/element/exception_stack_trace_nav.php @@ -12,32 +12,42 @@ * @since 3.0.0 * @license https://opensource.org/licenses/mit-license.php MIT License * @var array $trace + * @var \Throwable $error + * @var array<\Throwable> $exceptions */ use Cake\Error\Debugger; ?> Toggle Vendor Stack Frames diff --git a/app/vendor/cakephp/cakephp/templates/layout/dev_error.php b/app/vendor/cakephp/cakephp/templates/layout/dev_error.php index 3d12ded10..96e09e98b 100644 --- a/app/vendor/cakephp/cakephp/templates/layout/dev_error.php +++ b/app/vendor/cakephp/cakephp/templates/layout/dev_error.php @@ -146,6 +146,9 @@ margin: 0; padding: 0; } + .stack-previous { + margin: 24px 0 12px 8px; + } .stack-frame { background: #e5e5e5; padding: 10px; @@ -260,6 +263,7 @@ border-bottom: 1px solid #ccc; } +
diff --git a/app/vendor/cakephp/cakephp/tests/Fixture/ProfilesFixture.php b/app/vendor/cakephp/cakephp/tests/Fixture/ProfilesFixture.php index 21b284e6d..8ba428744 100644 --- a/app/vendor/cakephp/cakephp/tests/Fixture/ProfilesFixture.php +++ b/app/vendor/cakephp/cakephp/tests/Fixture/ProfilesFixture.php @@ -1,16 +1,16 @@ 'composite_key_articles', + 'columns' => [ + 'author_id' => [ + 'type' => 'integer', + 'null' => false, + ], + 'created' => [ + 'type' => 'datetime', + 'null' => false, + ], + 'body' => [ + 'type' => 'text', + ], + ], + 'constraints' => [ + 'composite_article_pk' => [ + 'type' => 'primary', + 'columns' => [ + 'author_id', + 'created', + ], + ], + ], + ], + [ + 'table' => 'composite_key_articles_tags', + 'columns' => [ + 'author_id' => [ + 'type' => 'integer', + 'null' => false, + ], + 'created' => [ + 'type' => 'datetime', + 'null' => false, + ], + 'tag_id' => [ + 'type' => 'integer', + 'null' => false, + ], + ], + 'constraints' => [ + 'composite_article_tags_pk' => [ + 'type' => 'primary', + 'columns' => [ + 'author_id', + 'created', + 'tag_id', + ], + ], + ], + ], [ 'table' => 'profiles', 'columns' => [ @@ -1259,6 +1311,36 @@ ], ], ], + [ + 'table' => 'number_trees_articles', + 'columns' => [ + 'id' => [ + 'type' => 'integer', + ], + 'number_tree_id' => [ + 'type' => 'integer', + 'null' => true, + ], + 'title' => [ + 'type' => 'string', + 'null' => true, + ], + 'body' => 'text', + 'published' => [ + 'type' => 'string', + 'length' => 1, + 'default' => 'N', + ], + ], + 'constraints' => [ + 'primary' => [ + 'type' => 'primary', + 'columns' => [ + 'id', + ], + ], + ], + ], [ 'table' => 'composite_increments', 'columns' => [ diff --git a/app/vendor/cakephp/chronos/composer.json b/app/vendor/cakephp/chronos/composer.json index efce15054..6d83b7727 100644 --- a/app/vendor/cakephp/chronos/composer.json +++ b/app/vendor/cakephp/chronos/composer.json @@ -7,7 +7,7 @@ "time", "DateTime" ], - "homepage": "http://cakephp.org", + "homepage": "https://cakephp.org", "license": "MIT", "authors": [ { @@ -17,12 +17,11 @@ }, { "name": "The CakePHP Team", - "homepage": "http://cakephp.org" + "homepage": "https://cakephp.org" } ], "support": { "issues": "https://github.com/cakephp/chronos/issues", - "irc": "irc://irc.freenode.org/cakephp", "source": "https://github.com/cakephp/chronos" }, "require": { @@ -57,7 +56,12 @@ "stan": [ "@phpstan" ], - "stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:^0.12.54 && mv composer.backup composer.json", + "stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:~1.8.0 && mv composer.backup composer.json", "test": "phpunit" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } } diff --git a/app/vendor/cakephp/chronos/docs.Dockerfile b/app/vendor/cakephp/chronos/docs.Dockerfile index 3c6a7f509..032ed39c6 100644 --- a/app/vendor/cakephp/chronos/docs.Dockerfile +++ b/app/vendor/cakephp/chronos/docs.Dockerfile @@ -4,14 +4,20 @@ FROM markstory/cakephp-docs-builder as builder RUN pip install git+https://github.com/sphinx-contrib/video.git@master COPY docs /data/docs +ENV LANGS="en fr ja pt" # build docs with sphinx RUN cd /data/docs-builder && \ - make website LANGS="en fr ja pt" SOURCE=/data/docs DEST=/data/website + make website LANGS="$LANGS" SOURCE=/data/docs DEST=/data/website # Build a small nginx container with just the static site in it. -FROM nginx:1.15-alpine +FROM markstory/cakephp-docs-builder:runtime as runtime +ENV LANGS="en fr ja pt" +ENV SEARCH_SOURCE="/usr/share/nginx/html" +ENV SEARCH_URL_PREFIX="/chronos/2" + +COPY --from=builder /data/docs /data/docs COPY --from=builder /data/website /data/website COPY --from=builder /data/docs-builder/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/app/vendor/cakephp/chronos/src/DifferenceFormatter.php b/app/vendor/cakephp/chronos/src/DifferenceFormatter.php index d1a47cd29..ad10c9582 100644 --- a/app/vendor/cakephp/chronos/src/DifferenceFormatter.php +++ b/app/vendor/cakephp/chronos/src/DifferenceFormatter.php @@ -64,17 +64,17 @@ public function diffForHumans( $unit = 'year'; $count = $diffInterval->y; break; - case $diffInterval->m > 0: + case $diffInterval->m >= 2: $unit = 'month'; $count = $diffInterval->m; break; + case $diffInterval->days >= ChronosInterface::DAYS_PER_WEEK * 3: + $unit = 'week'; + $count = (int)($diffInterval->days / ChronosInterface::DAYS_PER_WEEK); + break; case $diffInterval->d > 0: $unit = 'day'; $count = $diffInterval->d; - if ($count >= ChronosInterface::DAYS_PER_WEEK) { - $unit = 'week'; - $count = (int)($count / ChronosInterface::DAYS_PER_WEEK); - } break; case $diffInterval->h > 0: $unit = 'hour'; diff --git a/app/vendor/cakephp/chronos/src/Traits/DifferenceTrait.php b/app/vendor/cakephp/chronos/src/Traits/DifferenceTrait.php index e3f997988..7d4c74e58 100644 --- a/app/vendor/cakephp/chronos/src/Traits/DifferenceTrait.php +++ b/app/vendor/cakephp/chronos/src/Traits/DifferenceTrait.php @@ -36,7 +36,7 @@ trait DifferenceTrait /** * Instance of the diff formatting object. * - * @var \Cake\Chronos\DifferenceFormatterInterface + * @var \Cake\Chronos\DifferenceFormatterInterface|null */ protected static $diffFormatter; diff --git a/app/vendor/cakephp/chronos/src/Traits/ModifierTrait.php b/app/vendor/cakephp/chronos/src/Traits/ModifierTrait.php index f60f53cf4..adf177d7e 100644 --- a/app/vendor/cakephp/chronos/src/Traits/ModifierTrait.php +++ b/app/vendor/cakephp/chronos/src/Traits/ModifierTrait.php @@ -277,7 +277,7 @@ public function microsecond(int $value): ChronosInterface public function addYears(int $value): ChronosInterface { $month = $this->month; - $date = $this->modify($value . ' year'); + $date = $this->modify($value . ' years'); if ($date->month !== $month) { return $date->modify('last day of previous month'); @@ -309,7 +309,7 @@ public function addYear(int $value = 1): ChronosInterface */ public function subYears(int $value): ChronosInterface { - return $this->addYears(-1 * $value); + return $this->addYears(-$value); } /** @@ -322,7 +322,7 @@ public function subYears(int $value): ChronosInterface */ public function subYear(int $value = 1): ChronosInterface { - return $this->subYears($value); + return $this->addYears(-$value); } /** @@ -406,7 +406,7 @@ public function subYearWithOverflow(int $value = 1): ChronosInterface public function addMonths(int $value): ChronosInterface { $day = $this->day; - $date = $this->modify($value . ' month'); + $date = $this->modify($value . ' months'); if ($date->day !== $day) { return $date->modify('last day of previous month'); @@ -438,7 +438,7 @@ public function addMonth(int $value = 1): ChronosInterface */ public function subMonth(int $value = 1): ChronosInterface { - return $this->subMonths($value); + return $this->addMonths(-$value); } /** @@ -451,7 +451,7 @@ public function subMonth(int $value = 1): ChronosInterface */ public function subMonths(int $value): ChronosInterface { - return $this->addMonths(-1 * $value); + return $this->addMonths(-$value); } /** @@ -471,7 +471,7 @@ public function subMonths(int $value): ChronosInterface */ public function addMonthsWithOverflow(int $value): ChronosInterface { - return $this->modify($value . ' month'); + return $this->modify($value . ' months'); } /** @@ -484,7 +484,7 @@ public function addMonthsWithOverflow(int $value): ChronosInterface */ public function addMonthWithOverflow(int $value = 1): ChronosInterface { - return $this->modify($value . ' month'); + return $this->modify($value . ' months'); } /** @@ -522,7 +522,7 @@ public function subMonthWithOverflow(int $value = 1): ChronosInterface */ public function addDays(int $value): ChronosInterface { - return $this->modify("$value day"); + return $this->modify("$value days"); } /** @@ -533,7 +533,7 @@ public function addDays(int $value): ChronosInterface */ public function addDay(int $value = 1): ChronosInterface { - return $this->modify("$value day"); + return $this->modify("$value days"); } /** @@ -544,7 +544,7 @@ public function addDay(int $value = 1): ChronosInterface */ public function subDay(int $value = 1): ChronosInterface { - return $this->modify("-$value day"); + return $this->addDays(-$value); } /** @@ -555,7 +555,7 @@ public function subDay(int $value = 1): ChronosInterface */ public function subDays(int $value): ChronosInterface { - return $this->modify("-$value day"); + return $this->addDays(-$value); } /** @@ -567,7 +567,7 @@ public function subDays(int $value): ChronosInterface */ public function addWeekdays(int $value): ChronosInterface { - return $this->modify((int)$value . ' weekdays ' . $this->format('H:i:s')); + return $this->modify($value . ' weekdays, ' . $this->format('H:i:s')); } /** @@ -589,7 +589,7 @@ public function addWeekday(int $value = 1): ChronosInterface */ public function subWeekdays(int $value): ChronosInterface { - return $this->modify("$value weekdays ago, " . $this->format('H:i:s')); + return $this->addWeekdays(-$value); } /** @@ -600,7 +600,7 @@ public function subWeekdays(int $value): ChronosInterface */ public function subWeekday(int $value = 1): ChronosInterface { - return $this->subWeekdays($value); + return $this->addWeekdays(-$value); } /** @@ -634,7 +634,7 @@ public function addWeek(int $value = 1): ChronosInterface */ public function subWeek(int $value = 1): ChronosInterface { - return $this->modify("-$value week"); + return $this->addWeeks(-$value); } /** @@ -645,7 +645,7 @@ public function subWeek(int $value = 1): ChronosInterface */ public function subWeeks(int $value): ChronosInterface { - return $this->modify("-$value week"); + return $this->addWeeks(-$value); } /** @@ -679,7 +679,7 @@ public function addHour(int $value = 1): ChronosInterface */ public function subHour(int $value = 1): ChronosInterface { - return $this->modify("-$value hour"); + return $this->addHours(-$value); } /** @@ -690,7 +690,7 @@ public function subHour(int $value = 1): ChronosInterface */ public function subHours(int $value): ChronosInterface { - return $this->modify("-$value hour"); + return $this->addHours(-$value); } /** @@ -724,7 +724,7 @@ public function addMinute(int $value = 1): ChronosInterface */ public function subMinute(int $value = 1): ChronosInterface { - return $this->modify("-$value minute"); + return $this->addMinutes(-$value); } /** @@ -735,7 +735,7 @@ public function subMinute(int $value = 1): ChronosInterface */ public function subMinutes(int $value): ChronosInterface { - return $this->modify("-$value minute"); + return $this->addMinutes(-$value); } /** @@ -769,7 +769,7 @@ public function addSecond(int $value = 1): ChronosInterface */ public function subSecond(int $value = 1): ChronosInterface { - return $this->modify("-$value second"); + return $this->addSeconds(-$value); } /** @@ -780,7 +780,7 @@ public function subSecond(int $value = 1): ChronosInterface */ public function subSeconds(int $value): ChronosInterface { - return $this->modify("-$value second"); + return $this->addSeconds(-$value); } /** diff --git a/app/vendor/cakephp/debug_kit/composer.json b/app/vendor/cakephp/debug_kit/composer.json index 133ee97ed..248275f19 100644 --- a/app/vendor/cakephp/debug_kit/composer.json +++ b/app/vendor/cakephp/debug_kit/composer.json @@ -23,8 +23,8 @@ "source": "https://github.com/cakephp/debug_kit" }, "require": { - "php": ">=7.2", - "cakephp/cakephp": "^4.3.0", + "php": ">=7.4", + "cakephp/cakephp": "^4.4.0", "cakephp/chronos": "^2.0", "composer/composer": "^1.3 | ^2.0", "jdorn/sql-formatter": "^1.2" @@ -54,9 +54,21 @@ "scripts": { "cs-check": "phpcs --colors --parallel=16 -p src/ tests/", "cs-fix": "phpcbf --colors --parallel=16 -p src/ tests/", - "test": "phpunit", + "phpstan": "phpstan.phar analyse", "psalm": "psalm.phar --show-info=false", - "psalm-setup": "cp composer.json composer.backup && composer require --dev psalm/phar:^4.10 && mv composer.backup composer.json" + "stan": [ + "@phpstan", + "@psalm" + ], + "stan-baseline": "phpstan.phar --generate-baseline", + "psalm-baseline": "psalm.phar --set-baseline=psalm-baseline.xml", + "stan-setup": "cp composer.json composer.backup && composer require --dev symfony/polyfill-php81 phpstan/phpstan:~1.7.0 psalm/phar:~4.23.0 && mv composer.backup composer.json", + "test": "phpunit" }, - "prefer-stable": true + "prefer-stable": true, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } } diff --git a/app/vendor/cakephp/debug_kit/docs.Dockerfile b/app/vendor/cakephp/debug_kit/docs.Dockerfile index aa10f4314..cb30b3edf 100644 --- a/app/vendor/cakephp/debug_kit/docs.Dockerfile +++ b/app/vendor/cakephp/debug_kit/docs.Dockerfile @@ -19,7 +19,7 @@ FROM markstory/cakephp-docs-builder:runtime as runtime # Configure search index script ENV LANGS="en fr ja pt" -ENV SEARCH_SOURCE="/data/docs" +ENV SEARCH_SOURCE="/usr/share/nginx/html" ENV SEARCH_URL_PREFIX="/debugkit/4" COPY --from=builder /data/docs /data/docs diff --git a/app/vendor/cakephp/debug_kit/docs/en/index.rst b/app/vendor/cakephp/debug_kit/docs/en/index.rst index d672de9bd..049294e13 100644 --- a/app/vendor/cakephp/debug_kit/docs/en/index.rst +++ b/app/vendor/cakephp/debug_kit/docs/en/index.rst @@ -291,6 +291,20 @@ to include the panel:: The above would load all the default panels as well as the ``AppPanel``, and ``MyCustomPanel`` panel from ``MyPlugin``. +Accessing Toolbar without a frontend +==================================== + +If you have an application which only provides an API (and therefore no frontend) +the usual way of accessing the toolbar can't be used. + +Instead you have to call http://localhost/debug-kit/toolbar/```` + +The ```` can be found inside the HTTP headers of your API response. It should look something like that:: + + X-DEBUGKIT-ID: 5ef39604-ad5d-4ca4-85d8-8595e52373bb + +So you would have to call http://localhost/debug-kit/toolbar/5ef39604-ad5d-4ca4-85d8-8595e52373bb + Helper Functions ================ diff --git a/app/vendor/cakephp/debug_kit/docs/pt/index.rst b/app/vendor/cakephp/debug_kit/docs/pt/index.rst index 583de577e..e5ba22bc0 100644 --- a/app/vendor/cakephp/debug_kit/docs/pt/index.rst +++ b/app/vendor/cakephp/debug_kit/docs/pt/index.rst @@ -93,7 +93,7 @@ O painel History é uma das características mais frequentemente confundidas do DebugKit. Ele oferece uma forma de visualizar os dados de requisições anteriores na barra de ferramentas, incluindo erros e redirecionamentos. -.. figure:: /_static/img/history-panel.png +.. figure:: ../_static/history-panel.png :alt: Screenshot do painel History no DebugKit. Como você pode ver, o painel contém uma lista de requisições. Na esquerda você @@ -104,7 +104,7 @@ alternativos foram carregados. .. only:: html or epub - .. figure:: /_static/img/history-panel-use.gif + .. video:: ../_static/history-panel-use.mp4 :alt: Video do painel History em ação. Desenvolvendo seus próprios painéis diff --git a/app/vendor/cakephp/debug_kit/psalm-baseline.xml b/app/vendor/cakephp/debug_kit/psalm-baseline.xml index 2a067dad1..44e591c5d 100644 --- a/app/vendor/cakephp/debug_kit/psalm-baseline.xml +++ b/app/vendor/cakephp/debug_kit/psalm-baseline.xml @@ -45,11 +45,6 @@ new $className($config) - - - $request - - $pluginName @@ -66,11 +61,6 @@ $vendorName - - - count - - string|null @@ -83,16 +73,10 @@ - - !$connection instanceof ConnectionInterface - genericInstances - - - makeNeatArray diff --git a/app/vendor/cakephp/debug_kit/psalm.xml b/app/vendor/cakephp/debug_kit/psalm.xml index 02997ec3b..afe253290 100644 --- a/app/vendor/cakephp/debug_kit/psalm.xml +++ b/app/vendor/cakephp/debug_kit/psalm.xml @@ -1,7 +1,6 @@ + * @var array|\Cake\Cache\CacheEngine + * @psalm-suppress NonInvariantDocblockPropertyType */ protected $_config; /** * Proxied engine * - * @var mixed + * @var \Cake\Cache\CacheEngine */ protected $_engine; @@ -64,7 +65,7 @@ class DebugEngine extends CacheEngine /** * Constructor * - * @param mixed $config Config data or the proxied adapter. + * @param array|\Cake\Cache\CacheEngine $config Config data or the proxied adapter. * @param string $name The name of the proxied cache engine. * @param \Psr\Log\LoggerInterface $logger Logger for collecting cache operation logs. */ @@ -83,7 +84,7 @@ public function __construct($config, string $name, LoggerInterface $logger) */ public function init(array $config = []): bool { - if (is_object($this->_config)) { + if (!is_array($this->_config)) { $this->_engine = $this->_config; return true; @@ -311,7 +312,9 @@ public function getConfig(?string $key = null, $default = null) */ public function setConfig($key, $value = null, $merge = true) { - return $this->_engine->setConfig($key, $value, $merge); + $this->_engine->setConfig($key, $value, $merge); + + return $this; } /** @@ -336,12 +339,14 @@ public function clearGroup(string $group): bool */ public function __toString() { - if (!empty($this->_engine)) { + /** @psalm-suppress RedundantPropertyInitializationCheck */ + if (isset($this->_engine)) { [$ns, $class] = namespaceSplit(get_class($this->_engine)); return str_replace('Engine', '', $class); } + /** @psalm-suppress UndefinedMethod */ return $this->_config['className']; } } diff --git a/app/vendor/cakephp/debug_kit/src/Command/BenchmarkCommand.php b/app/vendor/cakephp/debug_kit/src/Command/BenchmarkCommand.php index 16ac83407..b93ff0c22 100644 --- a/app/vendor/cakephp/debug_kit/src/Command/BenchmarkCommand.php +++ b/app/vendor/cakephp/debug_kit/src/Command/BenchmarkCommand.php @@ -54,7 +54,7 @@ public function execute(Arguments $args, ConsoleIo $io): ?int $options = array_merge($defaults, $args->getOptions()); $times = []; - $io->out(Text::insert(__d('debug_kit', '-> Testing :url'), compact('url'))); + $io->out(Text::insert('-> Testing :url', compact('url'))); $io->out(''); for ($i = 0; $i < $options['n']; $i++) { /** @psalm-suppress PossiblyInvalidOperand */ @@ -84,25 +84,25 @@ protected function _results($times) $duration = array_sum($times); $requests = count($times); - $this->io->out(Text::insert(__d('debug_kit', 'Total Requests made: :requests'), compact('requests'))); - $this->io->out(Text::insert(__d('debug_kit', 'Total Time elapsed: :duration (seconds)'), compact('duration'))); + $this->io->out(Text::insert('Total Requests made: :requests', compact('requests'))); + $this->io->out(Text::insert('Total Time elapsed: :duration (seconds)', compact('duration'))); $this->io->out(''); - $this->io->out(Text::insert(__d('debug_kit', 'Requests/Second: :rps req/sec'), [ + $this->io->out(Text::insert('Requests/Second: :rps req/sec', [ 'rps' => round($requests / $duration, 3), ])); - $this->io->out(Text::insert(__d('debug_kit', 'Average request time: :average-time seconds'), [ + $this->io->out(Text::insert('Average request time: :average-time seconds', [ 'average-time' => round($duration / $requests, 3), ])); - $this->io->out(Text::insert(__d('debug_kit', 'Standard deviation of average request time: :std-dev'), [ + $this->io->out(Text::insert('Standard deviation of average request time: :std-dev', [ 'std-dev' => round($this->_deviation($times, true), 3), ])); if (!empty($times)) { - $this->io->out(Text::insert(__d('debug_kit', 'Longest/shortest request: :longest sec/:shortest sec'), [ + $this->io->out(Text::insert('Longest/shortest request: :longest sec/:shortest sec', [ 'longest' => round(max($times), 3), 'shortest' => round(min($times), 3), ])); @@ -161,32 +161,28 @@ protected function _deviation($times, $sample = true) */ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { - $parser->setDescription(__d( - 'debug_kit', + $parser->setDescription( 'Allows you to obtain some rough benchmarking statistics' . 'about a fully qualified URL.' - )) + ) ->addArgument('url', [ - 'help' => __d('debug_kit', 'The URL to request.'), + 'help' => 'The URL to request.', 'required' => true, ]) ->addOption('n', [ 'default' => 10, - 'help' => __d('debug_kit', 'Number of iterations to perform.'), + 'help' => 'Number of iterations to perform.', ]) ->addOption('t', [ 'default' => 100, - 'help' => __d( - 'debug_kit', - 'Maximum total time for all iterations, in seconds.' . - 'If a single iteration takes more than the timeout, only one request will be made' - ), + 'help' => + 'Maximum total time for all iterations, in seconds. ' . + 'If a single iteration takes more than the timeout, only one request will be made', ]) - ->setEpilog(__d( - 'debug_kit', + ->setEpilog( 'Example Use: `cake benchmark --n 10 --t 100 http://localhost/testsite`. ' . 'Note: this benchmark does not include browser render times.' - )); + ); return $parser; } diff --git a/app/vendor/cakephp/debug_kit/src/Controller/ComposerController.php b/app/vendor/cakephp/debug_kit/src/Controller/ComposerController.php index f26d379d6..c86cdaabe 100644 --- a/app/vendor/cakephp/debug_kit/src/Controller/ComposerController.php +++ b/app/vendor/cakephp/debug_kit/src/Controller/ComposerController.php @@ -56,7 +56,7 @@ public function checkDependencies() $packages = []; foreach ($dependencies as $dependency) { if (strpos($dependency, 'php_network_getaddresses') !== false) { - throw new \RuntimeException(__d('debug_kit', 'You have to be connected to the internet')); + throw new \RuntimeException('You have to be connected to the internet'); } if (strpos($dependency, '') !== false) { $packages['semverCompatible'][] = $dependency; diff --git a/app/vendor/cakephp/debug_kit/src/Controller/DashboardController.php b/app/vendor/cakephp/debug_kit/src/Controller/DashboardController.php index a4cd4fa15..cbd635a13 100644 --- a/app/vendor/cakephp/debug_kit/src/Controller/DashboardController.php +++ b/app/vendor/cakephp/debug_kit/src/Controller/DashboardController.php @@ -62,6 +62,7 @@ public function index() public function reset() { $this->request->allowMethod('post'); + /** @var \DebugKit\Model\Table\RequestsTable $requestsModel */ $requestsModel = $this->fetchTable('DebugKit.Requests'); $requestsModel->Panels->deleteAll('1=1'); diff --git a/app/vendor/cakephp/debug_kit/src/Controller/MailPreviewController.php b/app/vendor/cakephp/debug_kit/src/Controller/MailPreviewController.php index 8378d593c..f261f021b 100644 --- a/app/vendor/cakephp/debug_kit/src/Controller/MailPreviewController.php +++ b/app/vendor/cakephp/debug_kit/src/Controller/MailPreviewController.php @@ -71,7 +71,7 @@ public function sent($panelId, $number) // @codingStandardsIgnoreEnd if (empty($content['emails'][$number])) { - throw new NotFoundException(__d('debug_kit', 'No emails found in this request')); + throw new NotFoundException('No emails found in this request'); } $email = $content['emails'][$number]; @@ -99,7 +99,7 @@ public function sent($panelId, $number) * * @param string $name The Mailer name * @param string $method The mailer preview method - * @return \Psr\Http\Message\ResponseInterface|null + * @return \Psr\Http\Message\ResponseInterface|void */ public function email($name, $method) { @@ -150,17 +150,16 @@ protected function respondWithPart($email, $partType) { $part = $this->findPart($email, $partType); - if ($part === false) { - throw new NotFoundException(__d('debug_kit', "Email part ''{0}'' not found in email", $partType)); + if ($part === null) { + throw new NotFoundException(sprintf("Email part '%s' not found in email", $partType)); } $response = $this->response->withType($partType); if ($partType === 'text') { - $part = '
' . (string)$part . '
'; + $part = '
' . $part . '
'; } - $response = $response->withStringBody($part); - return $response; + return $response->withStringBody($part); } /** @@ -188,7 +187,7 @@ protected function getMailPreviewClasses() return [[CorePlugin::classPath($plugin) . 'Mailer/Preview/'], "$plugin."]; }); - $appPaths = [App::path('Mailer/Preview'), '']; + $appPaths = [App::classPath('Mailer/Preview'), '']; return collection([$appPaths]) ->append($pluginPaths) @@ -274,9 +273,8 @@ protected function findPreview($previewName, $emailName, $plugin = '') $email = $mailPreview->find($emailName); if (!$email) { - throw new NotFoundException(__d( - 'debug_kit', - 'Mailer preview {0}::{1} not found', + throw new NotFoundException(sprintf( + 'Mailer preview %s::%s not found', $previewName, $emailName )); diff --git a/app/vendor/cakephp/debug_kit/src/Controller/ToolbarController.php b/app/vendor/cakephp/debug_kit/src/Controller/ToolbarController.php index b047dcf2d..299824f88 100644 --- a/app/vendor/cakephp/debug_kit/src/Controller/ToolbarController.php +++ b/app/vendor/cakephp/debug_kit/src/Controller/ToolbarController.php @@ -48,11 +48,15 @@ public function initialize(): void public function clearCache() { $this->request->allowMethod('post'); - if (!$this->request->getData('name')) { - throw new NotFoundException(__d('debug_kit', 'Invalid cache engine name.')); + $name = $this->request->getData('name'); + if (!$name) { + throw new NotFoundException('Invalid cache engine name.'); } - $result = Cache::clear($this->request->getData('name')); - $this->set('success', $result); - $this->viewBuilder()->setOption('serialize', ['success']); + $success = Cache::clear($name); + $message = $success ? + sprintf('%s cache cleared.', $name) : + sprintf('%s cache could not be cleared.', $name); + $this->set(compact('success', 'message')); + $this->viewBuilder()->setOption('serialize', ['success', 'message']); } } diff --git a/app/vendor/cakephp/debug_kit/src/DebugSql.php b/app/vendor/cakephp/debug_kit/src/DebugSql.php index 72d3c843f..84a8ebb3e 100644 --- a/app/vendor/cakephp/debug_kit/src/DebugSql.php +++ b/app/vendor/cakephp/debug_kit/src/DebugSql.php @@ -73,7 +73,7 @@ public static function sql(Query $query, $showValues = true, $showHtml = null, $ $sql = (string)$query; if ($showValues) { - $sql = static::interpolate($sql, $query->getValueBinder()->bindings()); + $sql = self::interpolate($sql, $query->getValueBinder()->bindings()); } /** @var array $trace */ @@ -92,16 +92,16 @@ public static function sql(Query $query, $showValues = true, $showHtml = null, $ $file = str_replace($search, '', $file); } - $template = static::$templateHtml; + $template = self::$templateHtml; $sqlHighlight = true; if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') || $showHtml === false) { - $template = static::$templateText; + $template = self::$templateText; $sqlHighlight = false; if ($file && $line) { $lineInfo = sprintf('%s (line %s)', $file, $line); } } - if ($showHtml === null && $template !== static::$templateText) { + if ($showHtml === null && $template !== self::$templateText) { $showHtml = true; } @@ -113,7 +113,7 @@ public static function sql(Query $query, $showValues = true, $showHtml = null, $ ); if ($showHtml) { - $template = static::$templateHtml; + $template = self::$templateHtml; if ($file && $line) { $lineInfo = sprintf('%s (line %s)', $file, $line); } diff --git a/app/vendor/cakephp/debug_kit/src/DebugTimer.php b/app/vendor/cakephp/debug_kit/src/DebugTimer.php index 23e8deef9..0ab8779d5 100644 --- a/app/vendor/cakephp/debug_kit/src/DebugTimer.php +++ b/app/vendor/cakephp/debug_kit/src/DebugTimer.php @@ -132,7 +132,7 @@ public static function getAll($clear = false) $_end = $now; } $times['Core Processing (Derived from $_SERVER["REQUEST_TIME"])'] = [ - 'message' => __d('debug_kit', 'Core Processing (Derived from $_SERVER["REQUEST_TIME"])'), + 'message' => 'Core Processing (Derived from $_SERVER["REQUEST_TIME"])', 'start' => 0, 'end' => $_end - $start, 'time' => round($_end - $start, 6), diff --git a/app/vendor/cakephp/debug_kit/src/Locale/debug_kit.pot b/app/vendor/cakephp/debug_kit/src/Locale/debug_kit.pot deleted file mode 100644 index df4988dd1..000000000 --- a/app/vendor/cakephp/debug_kit/src/Locale/debug_kit.pot +++ /dev/null @@ -1,138 +0,0 @@ -# LANGUAGE translation of Debug Kit Application -# Copyright 2008 Andy Dawson -# No version information was available in the source files. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: debug_kit-\n" -"POT-Creation-Date: 2009-05-27 09:47+0200\n" -"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" -"Last-Translator: Andy Dawson \n" -"Language-Team:\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Poedit-Basepath: ../../../\n" - -#: controllers/components/toolbar.php:91 -msgid "Component initialization and startup" -msgstr "" - -#: controllers/components/toolbar.php:140 -msgid "Controller Action" -msgstr "" - -#: controllers/components/toolbar.php:167 -msgid "Render Controller Action" -msgstr "" - -#: controllers/components/toolbar.php:231 -msgid "Could not load DebugToolbar panel %s" -msgstr "" - -#: views/elements/debug_toolbar.ctp:25 -msgid "There are no active panels. You must enable a panel to see its output." -msgstr "" - -#: views/elements/history_panel.ctp:21 -msgid "Request History" -msgstr "" - -#: views/elements/history_panel.ctp:23 -msgid "No previous requests logged." -msgstr "" - -#: views/elements/history_panel.ctp:25 -msgid "previous requests available" -msgstr "" - -#: views/elements/history_panel.ctp:27 -msgid "Restore to current request" -msgstr "" - -#: views/elements/log_panel.ctp:21 -msgid "Logs" -msgstr "" - -#: views/elements/log_panel.ctp:28 -msgid "Time" -msgstr "" - -#: views/elements/log_panel.ctp:28 -#: views/elements/timer_panel.ctp:54 -msgid "Message" -msgstr "" - -#: views/elements/log_panel.ctp:37 -msgid "There were no log entries made this request" -msgstr "" - -#: views/elements/request_panel.ctp:21 -msgid "Request" -msgstr "" - -#: views/elements/request_panel.ctp:35 -msgid "Current Route" -msgstr "" - -#: views/elements/session_panel.ctp:21 -msgid "Session" -msgstr "" - -#: views/elements/sql_log_panel.ctp:21 -msgid "Sql Logs" -msgstr "" - -#: views/elements/sql_log_panel.ctp:31 -msgid "toggle (%s) query explains for %s" -msgstr "" - -#: views/elements/sql_log_panel.ctp:39 -msgid "No slow queries!, or your database does not support EXPLAIN" -msgstr "" - -#: views/elements/sql_log_panel.ctp:44 -msgid "No active database connections" -msgstr "" - -#: views/elements/timer_panel.ctp:33 -msgid "Memory" -msgstr "" - -#: views/elements/timer_panel.ctp:35 -msgid "Current Memory Use" -msgstr "" - -#: views/elements/timer_panel.ctp:39 -msgid "Peak Memory Use" -msgstr "" - -#: views/elements/timer_panel.ctp:43 -msgid "Timers" -msgstr "" - -#: views/elements/timer_panel.ctp:45 -msgid "%s (ms)" -msgstr "" - -#: views/elements/timer_panel.ctp:46 -msgid "Total Request Time:" -msgstr "" - -#: views/elements/timer_panel.ctp:54 -msgid "Time in ms" -msgstr "" - -#: views/elements/timer_panel.ctp:54 -msgid "Graph" -msgstr "" - -#: views/elements/variables_panel.ctp:21 -msgid "View Variables" -msgstr "" - -#: views/helpers/simple_graph.php:79 -msgid "Starting %sms into the request, taking %sms" -msgstr "" - diff --git a/app/vendor/cakephp/debug_kit/src/Locale/eng/LC_MESSAGES/debug_kit.po b/app/vendor/cakephp/debug_kit/src/Locale/eng/LC_MESSAGES/debug_kit.po deleted file mode 100644 index 9aec83297..000000000 --- a/app/vendor/cakephp/debug_kit/src/Locale/eng/LC_MESSAGES/debug_kit.po +++ /dev/null @@ -1,135 +0,0 @@ -# LANGUAGE translation of CakePHP Application -# Copyright YEAR NAME -# No version information was available in the source files. -# -#, fuzzy -msgid "" -msgstr "Project-Id-Version: PROJECT VERSION\n" - "POT-Creation-Date: 2009-05-27 09:47+0200\n" - "PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" - "Last-Translator: NAME \n" - "Language-Team: LANGUAGE \n" - "MIME-Version: 1.0\n" - "Content-Type: text/plain; charset=UTF-8\n" - "Content-Transfer-Encoding: 8bit\n" - "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" - -#: controllers/components/toolbar.php:91 -msgid "Component initialization and startup" -msgstr "" - -#: controllers/components/toolbar.php:140 -msgid "Controller Action" -msgstr "" - -#: controllers/components/toolbar.php:167 -msgid "Render Controller Action" -msgstr "" - -#: controllers/components/toolbar.php:231 -msgid "Could not load DebugToolbar panel %s" -msgstr "" - -#: views/elements/debug_toolbar.ctp:25 -msgid "There are no active panels. You must enable a panel to see its output." -msgstr "" - -#: views/elements/history_panel.ctp:21 -msgid "Request History" -msgstr "" - -#: views/elements/history_panel.ctp:23 -msgid "No previous requests logged." -msgstr "" - -#: views/elements/history_panel.ctp:25 -msgid "previous requests available" -msgstr "" - -#: views/elements/history_panel.ctp:27 -msgid "Restore to current request" -msgstr "" - -#: views/elements/log_panel.ctp:21 -msgid "Logs" -msgstr "" - -#: views/elements/log_panel.ctp:28 -msgid "Time" -msgstr "" - -#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54 -msgid "Message" -msgstr "" - -#: views/elements/log_panel.ctp:37 -msgid "There were no log entries made this request" -msgstr "" - -#: views/elements/request_panel.ctp:21 -msgid "Request" -msgstr "" - -#: views/elements/request_panel.ctp:35 -msgid "Current Route" -msgstr "" - -#: views/elements/session_panel.ctp:21 -msgid "Session" -msgstr "" - -#: views/elements/sql_log_panel.ctp:21 -msgid "Sql Logs" -msgstr "" - -#: views/elements/sql_log_panel.ctp:31 -msgid "toggle (%s) query explains for %s" -msgstr "" - -#: views/elements/sql_log_panel.ctp:39 -msgid "No slow queries!, or your database does not support EXPLAIN" -msgstr "" - -#: views/elements/sql_log_panel.ctp:44 -msgid "No active database connections" -msgstr "" - -#: views/elements/timer_panel.ctp:33 -msgid "Memory" -msgstr "" - -#: views/elements/timer_panel.ctp:35 -msgid "Current Memory Use" -msgstr "" - -#: views/elements/timer_panel.ctp:39 -msgid "Peak Memory Use" -msgstr "" - -#: views/elements/timer_panel.ctp:43 -msgid "Timers" -msgstr "" - -#: views/elements/timer_panel.ctp:45 -msgid "%s (ms)" -msgstr "" - -#: views/elements/timer_panel.ctp:46 -msgid "Total Request Time:" -msgstr "" - -#: views/elements/timer_panel.ctp:54 -msgid "Time in ms" -msgstr "" - -#: views/elements/timer_panel.ctp:54 -msgid "Graph" -msgstr "" - -#: views/elements/variables_panel.ctp:21 -msgid "View Variables" -msgstr "" - -#: views/helpers/simple_graph.php:79 -msgid "Starting %sms into the request, taking %sms" -msgstr "" diff --git a/app/vendor/cakephp/debug_kit/src/Locale/fra/LC_MESSAGES/debug_kit.po b/app/vendor/cakephp/debug_kit/src/Locale/fra/LC_MESSAGES/debug_kit.po deleted file mode 100644 index 515574de0..000000000 --- a/app/vendor/cakephp/debug_kit/src/Locale/fra/LC_MESSAGES/debug_kit.po +++ /dev/null @@ -1,135 +0,0 @@ -# LANGUAGE translation of CakePHP Application -# Copyright YEAR NAME -# No version information was available in the source files. -# -#, fuzzy -msgid "" -msgstr "Project-Id-Version: PROJECT VERSION\n" - "POT-Creation-Date: 2013-06-04 12:00+0200\n" - "PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" - "Last-Translator: cake17 \n" - "Language-Team: \n" - "MIME-Version: 1.0\n" - "Content-Type: text/plain; charset=UTF-8\n" - "Content-Transfer-Encoding: 8bit\n" - "Plural-Forms: nplurals=2; plural=n>1;\n" - -#: controllers/components/toolbar.php:91 -msgid "Component initialization and startup" -msgstr "Initialisation du component et démarrage" - -#: controllers/components/toolbar.php:140 -msgid "Controller Action" -msgstr "Action du Controller" - -#: controllers/components/toolbar.php:167 -msgid "Render Controller Action" -msgstr "Rendu de l'Action du Controller" - -#: controllers/components/toolbar.php:231 -msgid "Could not load DebugToolbar panel %s" -msgstr "Ne peut charger le panel %s de DebugToolbar" - -#: views/elements/debug_toolbar.ctp:25 -msgid "There are no active panels. You must enable a panel to see its output." -msgstr "Il n'y a pas de panels actifs. Vous devez activer le panel pour voir sa sortie." - -#: views/elements/history_panel.ctp:21 -msgid "Request History" -msgstr "Historique des Requêtes" - -#: views/elements/history_panel.ctp:23 -msgid "No previous requests logged." -msgstr "Pas de demandes antérieures enregistrées." - -#: views/elements/history_panel.ctp:25 -msgid "previous requests available" -msgstr "Des requêtes antérieures sont disponibles" - -#: views/elements/history_panel.ctp:27 -msgid "Restore to current request" -msgstr "Restaure la requête actuelle" - -#: views/elements/log_panel.ctp:21 -msgid "Logs" -msgstr "Logs" - -#: views/elements/log_panel.ctp:28 -msgid "Time" -msgstr "Date" - -#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54 -msgid "Message" -msgstr "Message" - -#: views/elements/log_panel.ctp:37 -msgid "There were no log entries made this request" -msgstr "Il n'y avait pas d'entrées de log faîtes pour cette requête" - -#: views/elements/request_panel.ctp:21 -msgid "Request" -msgstr "Requête" - -#: views/elements/request_panel.ctp:35 -msgid "Current Route" -msgstr "Route actuelle" - -#: views/elements/session_panel.ctp:21 -msgid "Session" -msgstr "Session" - -#: views/elements/sql_log_panel.ctp:21 -msgid "Sql Logs" -msgstr "Logs Sql" - -#: views/elements/sql_log_panel.ctp:31 -msgid "toggle (%s) query explains for %s" -msgstr "bascule (%s) requêtes expliquées pour %s" - -#: views/elements/sql_log_panel.ctp:39 -msgid "No slow queries!, or your database does not support EXPLAIN" -msgstr "Pas de requêtes lentes!, ou votre base de données ne supporte pas EXPLAIN" - -#: views/elements/sql_log_panel.ctp:44 -msgid "No active database connections" -msgstr "Pas de connections actives de la base de données" - -#: views/elements/timer_panel.ctp:33 -msgid "Memory" -msgstr "Mémoire" - -#: views/elements/timer_panel.ctp:35 -msgid "Current Memory Use" -msgstr "Utilisation de la Mémoire Actuelle" - -#: views/elements/timer_panel.ctp:39 -msgid "Peak Memory Use" -msgstr "Utilisation de la Mémoire au niveau maximum" - -#: views/elements/timer_panel.ctp:43 -msgid "Timers" -msgstr "Timers" - -#: views/elements/timer_panel.ctp:45 -msgid "%s (ms)" -msgstr "%s (ms)" - -#: views/elements/timer_panel.ctp:46 -msgid "Total Request Time:" -msgstr "Total du Temps de Requête" - -#: views/elements/timer_panel.ctp:54 -msgid "Time in ms" -msgstr "Temps en ms" - -#: views/elements/timer_panel.ctp:54 -msgid "Graph" -msgstr "Graph" - -#: views/elements/variables_panel.ctp:21 -msgid "View Variables" -msgstr "Variables du View" - -#: views/helpers/simple_graph.php:79 -msgid "Starting %sms into the request, taking %sms" -msgstr "Début en %sms de la requête, et prend %sms" diff --git a/app/vendor/cakephp/debug_kit/src/Locale/lim/LC_MESSAGES/debug_kit.po b/app/vendor/cakephp/debug_kit/src/Locale/lim/LC_MESSAGES/debug_kit.po deleted file mode 100644 index bf3894ada..000000000 --- a/app/vendor/cakephp/debug_kit/src/Locale/lim/LC_MESSAGES/debug_kit.po +++ /dev/null @@ -1,136 +0,0 @@ -# LANGUAGE translation of Debug Kit Application -# Copyright 2008 Andy Dawson -# No version information was available in the source files. -# -msgid "" -msgstr "" -"Project-Id-Version: debug_kit-\n" -"POT-Creation-Date: 2009-05-27 09:47+0200\n" -"PO-Revision-Date: 2009-05-27 09:47+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team:none\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Poedit-Basepath: ../../../\n" -"Language: lim\n" - -#: controllers/components/toolbar.php:91 -msgid "Component initialization and startup" -msgstr "" - -#: controllers/components/toolbar.php:140 -msgid "Controller Action" -msgstr "" - -#: controllers/components/toolbar.php:167 -msgid "Render Controller Action" -msgstr "" - -#: controllers/components/toolbar.php:231 -msgid "Could not load DebugToolbar panel %s" -msgstr "" - -#: views/elements/debug_toolbar.ctp:25 -msgid "There are no active panels. You must enable a panel to see its output." -msgstr "" - -#: views/elements/history_panel.ctp:21 -msgid "Request History" -msgstr "" - -#: views/elements/history_panel.ctp:23 -msgid "No previous requests logged." -msgstr "" - -#: views/elements/history_panel.ctp:25 -msgid "previous requests available" -msgstr "" - -#: views/elements/history_panel.ctp:27 -msgid "Restore to current request" -msgstr "" - -#: views/elements/log_panel.ctp:21 -msgid "Logs" -msgstr "" - -#: views/elements/log_panel.ctp:28 -msgid "Time" -msgstr "" - -#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54 -msgid "Message" -msgstr "" - -#: views/elements/log_panel.ctp:37 -msgid "There were no log entries made this request" -msgstr "" - -#: views/elements/request_panel.ctp:21 -msgid "Request" -msgstr "" - -#: views/elements/request_panel.ctp:35 -msgid "Current Route" -msgstr "" - -#: views/elements/session_panel.ctp:21 -msgid "Session" -msgstr "" - -#: views/elements/sql_log_panel.ctp:21 -msgid "Sql Logs" -msgstr "" - -#: views/elements/sql_log_panel.ctp:31 -msgid "toggle (%s) query explains for %s" -msgstr "" - -#: views/elements/sql_log_panel.ctp:39 -msgid "No slow queries!, or your database does not support EXPLAIN" -msgstr "" - -#: views/elements/sql_log_panel.ctp:44 -msgid "No active database connections" -msgstr "" - -#: views/elements/timer_panel.ctp:33 -msgid "Memory" -msgstr "" - -#: views/elements/timer_panel.ctp:35 -msgid "Current Memory Use" -msgstr "" - -#: views/elements/timer_panel.ctp:39 -msgid "Peak Memory Use" -msgstr "" - -#: views/elements/timer_panel.ctp:43 -msgid "Timers" -msgstr "" - -#: views/elements/timer_panel.ctp:45 -msgid "%s (ms)" -msgstr "" - -#: views/elements/timer_panel.ctp:46 -msgid "Total Request Time:" -msgstr "" - -#: views/elements/timer_panel.ctp:54 -msgid "Time in ms" -msgstr "" - -#: views/elements/timer_panel.ctp:54 -msgid "Graph" -msgstr "" - -#: views/elements/variables_panel.ctp:21 -msgid "View Variables" -msgstr "" - -#: views/helpers/simple_graph.php:79 -msgid "Starting %sms into the request, taking %sms" -msgstr "" diff --git a/app/vendor/cakephp/debug_kit/src/Locale/nld/LC_MESSAGES/debug_kit.po b/app/vendor/cakephp/debug_kit/src/Locale/nld/LC_MESSAGES/debug_kit.po deleted file mode 100644 index b6b754fe5..000000000 --- a/app/vendor/cakephp/debug_kit/src/Locale/nld/LC_MESSAGES/debug_kit.po +++ /dev/null @@ -1,141 +0,0 @@ -# LANGUAGE translation of Debug Kit Application -# Copyright 2008 Andy Dawson -# No version information was available in the source files. -# -msgid "" -msgstr "" -"Project-Id-Version: debug_kit-\n" -"POT-Creation-Date: 2009-05-27 09:47+0200\n" -"PO-Revision-Date: 2014-07-17 17:04+0200\n" -"Last-Translator: Marlin Cremers \n" -"Language-Team: \n" -"Language: nld\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 1.9\n" -"X-Poedit-Basepath: ../../../\n" - -#: controllers/components/toolbar.php:91 -msgid "Component initialization and startup" -msgstr "Component initializatie en opstarten" - -#: controllers/components/toolbar.php:140 -msgid "Controller Action" -msgstr "Controller Actie" - -#: controllers/components/toolbar.php:167 -msgid "Render Controller Action" -msgstr "Produceer Controller Actie" - -#: controllers/components/toolbar.php:231 -msgid "Could not load DebugToolbar panel %s" -msgstr "Kon DebugToolbar paneel %s niet laden" - -#: views/elements/debug_toolbar.ctp:25 -msgid "There are no active panels. You must enable a panel to see its output." -msgstr "" -"Er zijn geen actieve panelen. Je moet een paneel aanzetten om de uitvoer te " -"zien." - -#: views/elements/history_panel.ctp:21 -msgid "Request History" -msgstr "Aanvraag Geschiedenis" - -#: views/elements/history_panel.ctp:23 -msgid "No previous requests logged." -msgstr "Geen vorige aanvragen gelogged." - -#: views/elements/history_panel.ctp:25 -msgid "previous requests available" -msgstr "vorige aanvraag beschikbaar" - -#: views/elements/history_panel.ctp:27 -msgid "Restore to current request" -msgstr "Herstel naar actuele aanvraag" - -#: views/elements/log_panel.ctp:21 -msgid "Logs" -msgstr "Logs" - -#: views/elements/log_panel.ctp:28 -msgid "Time" -msgstr "Tijd" - -#: views/elements/log_panel.ctp:28 -#: views/elements/timer_panel.ctp:54 -msgid "Message" -msgstr "Bericht" - -#: views/elements/log_panel.ctp:37 -msgid "There were no log entries made this request" -msgstr "Er zijn geen log vermeldingen gemaakt in deze aanvraag" - -#: views/elements/request_panel.ctp:21 -msgid "Request" -msgstr "Aanvraag" - -#: views/elements/request_panel.ctp:35 -msgid "Current Route" -msgstr "Huide Route" - -#: views/elements/session_panel.ctp:21 -msgid "Session" -msgstr "Sessie" - -#: views/elements/sql_log_panel.ctp:21 -msgid "Sql Logs" -msgstr "Sql Logs" - -#: views/elements/sql_log_panel.ctp:31 -msgid "toggle (%s) query explains for %s" -msgstr "schakel (%s) aanvraag uitleg voor %s" - -#: views/elements/sql_log_panel.ctp:39 -msgid "No slow queries!, or your database does not support EXPLAIN" -msgstr "Geen langzame vragen!, of je database ondersteund geen EXPLAIN" - -#: views/elements/sql_log_panel.ctp:44 -msgid "No active database connections" -msgstr "Geen actieve database verbindingen" - -#: views/elements/timer_panel.ctp:33 -msgid "Memory" -msgstr "Geheugen" - -#: views/elements/timer_panel.ctp:35 -msgid "Current Memory Use" -msgstr "Actueel Geheugen Gebruik" - -#: views/elements/timer_panel.ctp:39 -msgid "Peak Memory Use" -msgstr "Hoogste Geheugen Gebruik" - -#: views/elements/timer_panel.ctp:43 -msgid "Timers" -msgstr "Timers" - -#: views/elements/timer_panel.ctp:45 -msgid "%s (ms)" -msgstr "%s (ms)" - -#: views/elements/timer_panel.ctp:46 -msgid "Total Request Time:" -msgstr "Totale Aanvraag Tijd:" - -#: views/elements/timer_panel.ctp:54 -msgid "Time in ms" -msgstr "Tijd in ms" - -#: views/elements/timer_panel.ctp:54 -msgid "Graph" -msgstr "Diagram" - -#: views/elements/variables_panel.ctp:21 -msgid "View Variables" -msgstr "View Variabelen" - -#: views/helpers/simple_graph.php:79 -msgid "Starting %sms into the request, taking %sms" -msgstr "Starten %sms in de aanvraag, neemt %sms" diff --git a/app/vendor/cakephp/debug_kit/src/Locale/pt_BR/LC_MESSAGES/debug_kit.po b/app/vendor/cakephp/debug_kit/src/Locale/pt_BR/LC_MESSAGES/debug_kit.po deleted file mode 100644 index e1e4c4551..000000000 --- a/app/vendor/cakephp/debug_kit/src/Locale/pt_BR/LC_MESSAGES/debug_kit.po +++ /dev/null @@ -1,135 +0,0 @@ -# LANGUAGE translation of CakePHP Application -# Copyright YEAR NAME -# No version information was available in the source files. -# -#, fuzzy -msgid "" -msgstr "Project-Id-Version: PROJECT VERSION\n" - "POT-Creation-Date: 2014-01-23 08:29+0200\n" - "PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" - "Last-Translator: Lincoln Brito \n" - "Language-Team: LANGUAGE \n" - "MIME-Version: 1.0\n" - "Content-Type: text/plain; charset=UTF-8\n" - "Content-Transfer-Encoding: 8bit\n" - "Plural-Forms: nplurals=2; plural=n>1;\n" - -#: controllers/components/toolbar.php:91 -msgid "Component initialization and startup" -msgstr "Inicialização de componente" - -#: controllers/components/toolbar.php:140 -msgid "Controller Action" -msgstr "Action do Controller" - -#: controllers/components/toolbar.php:167 -msgid "Render Controller Action" -msgstr "Renderizar Action do Controller" - -#: controllers/components/toolbar.php:231 -msgid "Could not load DebugToolbar panel %s" -msgstr "Não foi possível carregar o painel %s do DebugToolbar" - -#: views/elements/debug_toolbar.ctp:25 -msgid "There are no active panels. You must enable a panel to see its output." -msgstr "Não existem painéis ativos. Você deve habilitar um painel para visualizar sua saída." - -#: views/elements/history_panel.ctp:21 -msgid "Request History" -msgstr "Histórico de requisições" - -#: views/elements/history_panel.ctp:23 -msgid "No previous requests logged." -msgstr "Sem requisições anteriores logadas." - -#: views/elements/history_panel.ctp:25 -msgid "previous requests available" -msgstr "requisições anteriores disponíveis" - -#: views/elements/history_panel.ctp:27 -msgid "Restore to current request" -msgstr "Restaurar para requisição atual" - -#: views/elements/log_panel.ctp:21 -msgid "Logs" -msgstr "Logs" - -#: views/elements/log_panel.ctp:28 -msgid "Time" -msgstr "Tempo" - -#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54 -msgid "Message" -msgstr "Mensagem" - -#: views/elements/log_panel.ctp:37 -msgid "There were no log entries made this request" -msgstr "Não houveram entradas no log para essa requisição " - -#: views/elements/request_panel.ctp:21 -msgid "Request" -msgstr "Requisição" - -#: views/elements/request_panel.ctp:35 -msgid "Current Route" -msgstr "Rota Atual" - -#: views/elements/session_panel.ctp:21 -msgid "Session" -msgstr "Sessão" - -#: views/elements/sql_log_panel.ctp:21 -msgid "Sql Logs" -msgstr "Logs Sql" - -#: views/elements/sql_log_panel.ctp:31 -msgid "toggle (%s) query explains for %s" -msgstr "alternar (%s) query explains por %s" - -#: views/elements/sql_log_panel.ctp:39 -msgid "No slow queries!, or your database does not support EXPLAIN" -msgstr "Sem consultas lentas!, ou o seu banco de dados não suporta EXPLAIN" - -#: views/elements/sql_log_panel.ctp:44 -msgid "No active database connections" -msgstr "Sem conexões ativas de banco de dados" - -#: views/elements/timer_panel.ctp:33 -msgid "Memory" -msgstr "Memória" - -#: views/elements/timer_panel.ctp:35 -msgid "Current Memory Use" -msgstr "Uso atual de memória" - -#: views/elements/timer_panel.ctp:39 -msgid "Peak Memory Use" -msgstr "Pico de uso de memória" - -#: views/elements/timer_panel.ctp:43 -msgid "Timers" -msgstr "Tempos" - -#: views/elements/timer_panel.ctp:45 -msgid "%s (ms)" -msgstr "%s (ms)" - -#: views/elements/timer_panel.ctp:46 -msgid "Total Request Time:" -msgstr "Tempo Total de Requisição" - -#: views/elements/timer_panel.ctp:54 -msgid "Time in ms" -msgstr "Tempo em ms" - -#: views/elements/timer_panel.ctp:54 -msgid "Graph" -msgstr "Gráfico" - -#: views/elements/variables_panel.ctp:21 -msgid "View Variables" -msgstr "Visualizar Variáveis" - -#: views/helpers/simple_graph.php:79 -msgid "Starting %sms into the request, taking %sms" -msgstr "Começando %sms na requisição, levando %sms" diff --git a/app/vendor/cakephp/debug_kit/src/Locale/spa/LC_MESSAGES/debug_kit.po b/app/vendor/cakephp/debug_kit/src/Locale/spa/LC_MESSAGES/debug_kit.po deleted file mode 100644 index 0833a4942..000000000 --- a/app/vendor/cakephp/debug_kit/src/Locale/spa/LC_MESSAGES/debug_kit.po +++ /dev/null @@ -1,135 +0,0 @@ -# LANGUAGE translation of CakePHP Application -# Copyright YEAR NAME -# No version information was available in the source files. -# -#, fuzzy -msgid "" -msgstr "Project-Id-Version: PROJECT VERSION\n" - "POT-Creation-Date: 2009-05-27 09:47+0200\n" - "PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" - "Last-Translator: NAME \n" - "Language-Team: LANGUAGE \n" - "MIME-Version: 1.0\n" - "Content-Type: text/plain; charset=UTF-8\n" - "Content-Transfer-Encoding: 8bit\n" - "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" - -#: controllers/components/toolbar.php:91 -msgid "Component initialization and startup" -msgstr "" - -#: controllers/components/toolbar.php:140 -msgid "Controller Action" -msgstr "" - -#: controllers/components/toolbar.php:167 -msgid "Render Controller Action" -msgstr "" - -#: controllers/components/toolbar.php:231 -msgid "Could not load DebugToolbar panel %s" -msgstr "" - -#: views/elements/debug_toolbar.ctp:25 -msgid "There are no active panels. You must enable a panel to see its output." -msgstr "" - -#: views/elements/history_panel.ctp:21 -msgid "Request History" -msgstr "" - -#: views/elements/history_panel.ctp:23 -msgid "No previous requests logged." -msgstr "" - -#: views/elements/history_panel.ctp:25 -msgid "previous requests available" -msgstr "" - -#: views/elements/history_panel.ctp:27 -msgid "Restore to current request" -msgstr "" - -#: views/elements/log_panel.ctp:21 -msgid "Logs" -msgstr "" - -#: views/elements/log_panel.ctp:28 -msgid "Time" -msgstr "" - -#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54 -msgid "Message" -msgstr "" - -#: views/elements/log_panel.ctp:37 -msgid "There were no log entries made this request" -msgstr "" - -#: views/elements/request_panel.ctp:21 -msgid "Request" -msgstr "" - -#: views/elements/request_panel.ctp:35 -msgid "Current Route" -msgstr "" - -#: views/elements/session_panel.ctp:21 -msgid "Session" -msgstr "" - -#: views/elements/sql_log_panel.ctp:21 -msgid "Sql Logs" -msgstr "" - -#: views/elements/sql_log_panel.ctp:31 -msgid "toggle (%s) query explains for %s" -msgstr "" - -#: views/elements/sql_log_panel.ctp:39 -msgid "No slow queries!, or your database does not support EXPLAIN" -msgstr "" - -#: views/elements/sql_log_panel.ctp:44 -msgid "No active database connections" -msgstr "" - -#: views/elements/timer_panel.ctp:33 -msgid "Memory" -msgstr "" - -#: views/elements/timer_panel.ctp:35 -msgid "Current Memory Use" -msgstr "" - -#: views/elements/timer_panel.ctp:39 -msgid "Peak Memory Use" -msgstr "" - -#: views/elements/timer_panel.ctp:43 -msgid "Timers" -msgstr "" - -#: views/elements/timer_panel.ctp:45 -msgid "%s (ms)" -msgstr "" - -#: views/elements/timer_panel.ctp:46 -msgid "Total Request Time:" -msgstr "" - -#: views/elements/timer_panel.ctp:54 -msgid "Time in ms" -msgstr "" - -#: views/elements/timer_panel.ctp:54 -msgid "Graph" -msgstr "" - -#: views/elements/variables_panel.ctp:21 -msgid "View Variables" -msgstr "" - -#: views/helpers/simple_graph.php:79 -msgid "Starting %sms into the request, taking %sms" -msgstr "" \ No newline at end of file diff --git a/app/vendor/cakephp/debug_kit/src/Mailer/MailPreview.php b/app/vendor/cakephp/debug_kit/src/Mailer/MailPreview.php index 6663b07eb..0c33bf37a 100644 --- a/app/vendor/cakephp/debug_kit/src/Mailer/MailPreview.php +++ b/app/vendor/cakephp/debug_kit/src/Mailer/MailPreview.php @@ -14,8 +14,8 @@ */ namespace DebugKit\Mailer; -use Cake\Datasource\ModelAwareTrait; use Cake\Mailer\MailerAwareTrait; +use Cake\ORM\Locator\LocatorAwareTrait; use ReflectionClass; use ReflectionException; use ReflectionMethod; @@ -26,7 +26,7 @@ class MailPreview { use MailerAwareTrait; - use ModelAwareTrait; + use LocatorAwareTrait; /** * Returns the name of an email if it is valid diff --git a/app/vendor/cakephp/debug_kit/src/Mailer/Transport/DebugKitTransport.php b/app/vendor/cakephp/debug_kit/src/Mailer/Transport/DebugKitTransport.php index e0f796803..82656de5e 100644 --- a/app/vendor/cakephp/debug_kit/src/Mailer/Transport/DebugKitTransport.php +++ b/app/vendor/cakephp/debug_kit/src/Mailer/Transport/DebugKitTransport.php @@ -16,7 +16,7 @@ class DebugKitTransport extends AbstractTransport /** * The transport object this class is decorating * - * @var \Cake\Mailer\AbstractTransport + * @var \Cake\Mailer\AbstractTransport|null */ protected $originalTransport; diff --git a/app/vendor/cakephp/debug_kit/src/Middleware/DebugKitMiddleware.php b/app/vendor/cakephp/debug_kit/src/Middleware/DebugKitMiddleware.php index c53994611..feb30d266 100644 --- a/app/vendor/cakephp/debug_kit/src/Middleware/DebugKitMiddleware.php +++ b/app/vendor/cakephp/debug_kit/src/Middleware/DebugKitMiddleware.php @@ -63,6 +63,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface return $response; } + /** @psalm-suppress ArgumentTypeCoercion */ $row = $this->service->saveData($request, $response); if (!$row) { return $response; diff --git a/app/vendor/cakephp/debug_kit/src/Model/Table/PanelsTable.php b/app/vendor/cakephp/debug_kit/src/Model/Table/PanelsTable.php index f70b773fc..dca4d12fe 100644 --- a/app/vendor/cakephp/debug_kit/src/Model/Table/PanelsTable.php +++ b/app/vendor/cakephp/debug_kit/src/Model/Table/PanelsTable.php @@ -57,7 +57,7 @@ public function initialize(array $config): void public function findByRequest(Query $query, array $options) { if (empty($options['requestId'])) { - throw new \RuntimeException(__d('debug_kit', 'Missing request id in {0}.', 'findByRequest()')); + throw new \RuntimeException('Missing request id in findByRequest().'); } return $query->where(['Panels.request_id' => $options['requestId']]) diff --git a/app/vendor/cakephp/debug_kit/src/Model/Table/RequestsTable.php b/app/vendor/cakephp/debug_kit/src/Model/Table/RequestsTable.php index 6461cfcae..a24bc0459 100644 --- a/app/vendor/cakephp/debug_kit/src/Model/Table/RequestsTable.php +++ b/app/vendor/cakephp/debug_kit/src/Model/Table/RequestsTable.php @@ -24,6 +24,7 @@ /** * The requests table tracks basic information about each request. * + * @property \DebugKit\Model\Table\PanelsTable $Panels * @method \DebugKit\Model\Entity\Request get($primaryKey, $options = []) * @method \DebugKit\Model\Entity\Request newEntity($data = null, array $options = []) * @method \DebugKit\Model\Entity\Request[] newEntities(array $data, array $options = []) diff --git a/app/vendor/cakephp/debug_kit/src/Panel/CachePanel.php b/app/vendor/cakephp/debug_kit/src/Panel/CachePanel.php index 9c86ca2f0..8cf2f3317 100644 --- a/app/vendor/cakephp/debug_kit/src/Panel/CachePanel.php +++ b/app/vendor/cakephp/debug_kit/src/Panel/CachePanel.php @@ -50,6 +50,7 @@ public function __construct() public function initialize() { foreach (Cache::configured() as $name) { + /** @var array $config */ $config = Cache::getConfig($name); if (isset($config['className']) && $config['className'] instanceof DebugEngine) { $instance = $config['className']; diff --git a/app/vendor/cakephp/debug_kit/src/Panel/DeprecationsPanel.php b/app/vendor/cakephp/debug_kit/src/Panel/DeprecationsPanel.php index 3ee9e0932..9780904b3 100644 --- a/app/vendor/cakephp/debug_kit/src/Panel/DeprecationsPanel.php +++ b/app/vendor/cakephp/debug_kit/src/Panel/DeprecationsPanel.php @@ -59,10 +59,6 @@ protected function _prepare() foreach ($errors as $error) { $file = $error['file']; $line = $error['line']; - if (isset($error['context']['frame'])) { - $file = $error['context']['frame']['file']; - $line = $error['context']['frame']['line']; - } $errorData = [ 'file' => $file, @@ -93,15 +89,9 @@ protected function _prepare() } } - ksort($return['app']); - ksort($return['cake']); ksort($return['plugins']); ksort($return['vendor']); - foreach ($return['plugins'] as &$plugin) { - ksort($plugin); - } - return $return; } diff --git a/app/vendor/cakephp/debug_kit/src/Panel/EnvironmentPanel.php b/app/vendor/cakephp/debug_kit/src/Panel/EnvironmentPanel.php index 23433342a..8cd38e352 100644 --- a/app/vendor/cakephp/debug_kit/src/Panel/EnvironmentPanel.php +++ b/app/vendor/cakephp/debug_kit/src/Panel/EnvironmentPanel.php @@ -75,10 +75,6 @@ protected function _prepare() $var = get_defined_constants(true); $return['app'] = array_diff_key($var['user'], $return['cake'], $hiddenCakeConstants); - if (isset($var['hidef'])) { - $return['hidef'] = $var['hidef']; - } - return $return; } diff --git a/app/vendor/cakephp/debug_kit/src/Panel/LogPanel.php b/app/vendor/cakephp/debug_kit/src/Panel/LogPanel.php index 3aa23a69e..294b0c883 100644 --- a/app/vendor/cakephp/debug_kit/src/Panel/LogPanel.php +++ b/app/vendor/cakephp/debug_kit/src/Panel/LogPanel.php @@ -56,6 +56,7 @@ public function data() */ public function summary() { + /** @var \DebugKit\Log\Engine\DebugKitLog|null $logger */ $logger = Log::engine('debug_kit_log_panel'); if (!$logger) { return '0'; diff --git a/app/vendor/cakephp/debug_kit/src/Panel/PanelRegistry.php b/app/vendor/cakephp/debug_kit/src/Panel/PanelRegistry.php index cc6871b15..4814930f0 100644 --- a/app/vendor/cakephp/debug_kit/src/Panel/PanelRegistry.php +++ b/app/vendor/cakephp/debug_kit/src/Panel/PanelRegistry.php @@ -63,7 +63,7 @@ protected function _resolveClassName(string $class): ?string */ protected function _throwMissingClassError(string $class, ?string $plugin): void { - throw new \RuntimeException(__d('debug_kit', "Unable to find ''{0}'' panel.", $class)); + throw new \RuntimeException(sprintf("Unable to find '%s' panel.", $class)); } /** diff --git a/app/vendor/cakephp/debug_kit/src/Panel/RequestPanel.php b/app/vendor/cakephp/debug_kit/src/Panel/RequestPanel.php index 4cc705aea..feecec957 100644 --- a/app/vendor/cakephp/debug_kit/src/Panel/RequestPanel.php +++ b/app/vendor/cakephp/debug_kit/src/Panel/RequestPanel.php @@ -16,6 +16,7 @@ use Cake\Event\EventInterface; use DebugKit\DebugPanel; +use Exception; /** * Provides debug information on the Current request params. @@ -33,8 +34,19 @@ public function shutdown(EventInterface $event) /** @var \Cake\Controller\Controller $controller */ $controller = $event->getSubject(); $request = $controller->getRequest(); + + $attributes = []; + foreach ($request->getAttributes() as $attr => $value) { + try { + serialize($value); + } catch (Exception $e) { + $value = "Could not serialize `{$attr}`. It failed with {$e->getMessage()}"; + } + $attributes[$attr] = $value; + } + $this->_data = [ - 'attributes' => $request->getAttributes(), + 'attributes' => $attributes, 'query' => $request->getQueryParams(), 'data' => $request->getData(), 'cookie' => $request->getCookieParams(), diff --git a/app/vendor/cakephp/debug_kit/src/Panel/SessionPanel.php b/app/vendor/cakephp/debug_kit/src/Panel/SessionPanel.php index 217887eab..66876c8be 100644 --- a/app/vendor/cakephp/debug_kit/src/Panel/SessionPanel.php +++ b/app/vendor/cakephp/debug_kit/src/Panel/SessionPanel.php @@ -30,7 +30,7 @@ class SessionPanel extends DebugPanel */ public function shutdown(EventInterface $event) { - /** @var \Cake\Http\ServerRequest $request */ + /** @var \Cake\Http\ServerRequest|null $request */ $request = $event->getSubject()->getRequest(); if ($request) { $this->_data = ['content' => $request->getSession()->read()]; diff --git a/app/vendor/cakephp/debug_kit/src/Panel/VariablesPanel.php b/app/vendor/cakephp/debug_kit/src/Panel/VariablesPanel.php index 1fdf04e02..91853cb5f 100644 --- a/app/vendor/cakephp/debug_kit/src/Panel/VariablesPanel.php +++ b/app/vendor/cakephp/debug_kit/src/Panel/VariablesPanel.php @@ -66,9 +66,8 @@ protected function _walkDebugInfo(callable $walker, $item) try { $info = $item->__debugInfo(); } catch (\Exception $exception) { - return __d( - 'debug_kit', - 'Could not retrieve debug info - {0}. Error: {1} in {2}, line {3}', + return sprintf( + 'Could not retrieve debug info - %s. Error: %s in %s, line %d', get_class($item), $exception->getMessage(), $exception->getFile(), diff --git a/app/vendor/cakephp/debug_kit/src/Plugin.php b/app/vendor/cakephp/debug_kit/src/Plugin.php index f9ff8cba7..03b4b9ea1 100644 --- a/app/vendor/cakephp/debug_kit/src/Plugin.php +++ b/app/vendor/cakephp/debug_kit/src/Plugin.php @@ -19,6 +19,8 @@ use Cake\Core\BasePlugin; use Cake\Core\Configure; use Cake\Core\PluginApplicationInterface; +use Cake\Error\PhpError; +use Cake\Event\EventInterface; use Cake\Event\EventManager; use Cake\Http\MiddlewareQueue; use DebugKit\Command\BenchmarkCommand; @@ -31,7 +33,7 @@ class Plugin extends BasePlugin { /** - * @var \DebugKit\ToolbarService + * @var \DebugKit\ToolbarService|null */ protected $service; @@ -45,12 +47,11 @@ public function bootstrap(PluginApplicationInterface $app): void { $service = new ToolbarService(EventManager::instance(), (array)Configure::read('DebugKit')); - if (!$service->isEnabled() || php_sapi_name() === 'cli' || php_sapi_name() === 'phpdbg') { + if (!$service->isEnabled()) { return; } $this->service = $service; - $this->setDeprecationHandler($service); // will load `config/bootstrap.php`. @@ -65,6 +66,7 @@ public function bootstrap(PluginApplicationInterface $app): void */ public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue { + // Only insert middleware if Toolbar Service is available (not in phpunit run) if ($this->service) { $middlewareQueue->insertAt(0, new DebugKitMiddleware($this->service)); } @@ -92,40 +94,30 @@ public function console(CommandCollection $commands): CommandCollection public function setDeprecationHandler($service) { if (!empty($service->getConfig('panels')['DebugKit.Deprecations'])) { - $previousHandler = set_error_handler( - function ($code, $message, $file, $line, $context = null) use (&$previousHandler) { - if ($code == E_USER_DEPRECATED || $code == E_DEPRECATED) { - // In PHP 8.0+ the $context variable has been removed from the set_error_handler callback - // Therefore we need to fetch the correct file and line string ourselves - if (PHP_VERSION_ID >= 80000) { - $trace = debug_backtrace(); - foreach ($trace as $idx => $traceEntry) { - if ($traceEntry['function'] !== 'deprecationWarning') { - continue; - } - $offset = 1; - // ['args'][1] refers to index of $stackFrame argument in deprecationWarning() - if (isset($traceEntry['args'][1])) { - $offset = $traceEntry['args'][1]; - } - $file = $trace[$idx + $offset]['file']; - $line = $trace[$idx + $offset]['line']; - break; - } - } - DeprecationsPanel::addDeprecatedError(compact('code', 'message', 'file', 'line', 'context')); - - return; - } - if ($previousHandler) { - $context['_trace_frame_offset'] = 1; - - return $previousHandler($code, $message, $file, $line, $context); - } + EventManager::instance()->on('Error.beforeRender', function (EventInterface $event, PhpError $error) { + $code = $error->getCode(); + if ($code !== E_USER_DEPRECATED && $code !== E_DEPRECATED) { + return; + } + $file = $error->getFile(); + $line = $error->getLine(); - return false; + // Extract the line/file from the message as deprecationWarning + // will calculate the application frame when generating the message. + preg_match('/\\n([^\n,]+?), line: (\d+)\\n/', $error->getMessage(), $matches); + if ($matches) { + $file = $matches[1]; + $line = $matches[2]; } - ); + + DeprecationsPanel::addDeprecatedError([ + 'code' => $code, + 'message' => $error->getMessage(), + 'file' => $file, + 'line' => $line, + ]); + $event->stopPropagation(); + }); } } } diff --git a/app/vendor/cakephp/debug_kit/src/ToolbarService.php b/app/vendor/cakephp/debug_kit/src/ToolbarService.php index e7ba153a4..ac9e75bbd 100644 --- a/app/vendor/cakephp/debug_kit/src/ToolbarService.php +++ b/app/vendor/cakephp/debug_kit/src/ToolbarService.php @@ -100,9 +100,14 @@ public function registry() */ public function isEnabled() { - $enabled = (bool)Configure::read('debug'); + if (isset($GLOBALS['__PHPUNIT_BOOTSTRAP'])) { + return false; + } + $enabled = (bool)Configure::read('debug') + && !$this->isSuspiciouslyProduction() + && php_sapi_name() !== 'phpdbg'; - if ($enabled && !$this->isSuspiciouslyProduction()) { + if ($enabled) { return true; } $force = $this->getConfig('forceEnable'); @@ -140,9 +145,8 @@ protected function isSuspiciouslyProduction() $isIp = filter_var($host, FILTER_VALIDATE_IP) !== false; if ($isIp) { $flags = FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE; - $isPublicIp = filter_var($host, FILTER_VALIDATE_IP, $flags) !== false; - return $isPublicIp; + return filter_var($host, FILTER_VALIDATE_IP, $flags) !== false; } // So it's not an IP address. It must be a domain name. @@ -311,7 +315,7 @@ public function saveData(ServerRequest $request, ResponseInterface $response) */ public function getToolbarUrl() { - $url = 'js/toolbar.js'; + $url = 'js/inject-iframe.js'; $filePaths = [ str_replace('/', DIRECTORY_SEPARATOR, WWW_ROOT . 'debug_kit/' . $url), str_replace('/', DIRECTORY_SEPARATOR, CorePlugin::path('DebugKit') . 'webroot/' . $url), @@ -356,7 +360,7 @@ public function injectScripts($row, ResponseInterface $response) $url = Router::url('/', true); $script = sprintf( - '', + '', $row->id, $url, Router::url($this->getToolbarUrl()) diff --git a/app/vendor/cakephp/debug_kit/src/View/Helper/CredentialsHelper.php b/app/vendor/cakephp/debug_kit/src/View/Helper/CredentialsHelper.php index 253fabd85..39a25bf51 100644 --- a/app/vendor/cakephp/debug_kit/src/View/Helper/CredentialsHelper.php +++ b/app/vendor/cakephp/debug_kit/src/View/Helper/CredentialsHelper.php @@ -39,7 +39,7 @@ class CredentialsHelper extends Helper * Replace credentials in url's by ***** * Example mysql://username:password@localhost/my_db -> mysql://******@localhost/my_db * - * @param string $in variable to filter + * @param mixed $in variable to filter * @return string */ public function filter($in) diff --git a/app/vendor/cakephp/debug_kit/src/View/Helper/SimpleGraphHelper.php b/app/vendor/cakephp/debug_kit/src/View/Helper/SimpleGraphHelper.php index 340ad1cda..cf7cb493a 100644 --- a/app/vendor/cakephp/debug_kit/src/View/Helper/SimpleGraphHelper.php +++ b/app/vendor/cakephp/debug_kit/src/View/Helper/SimpleGraphHelper.php @@ -70,10 +70,10 @@ public function bar($value, $offset, $options = []) } return sprintf( - '
', + '
', "width: {$width}px", "margin-left: {$graphOffset}px; width: {$graphValue}px", - __d('debug_kit', 'Starting {0}ms into the request, taking {1}ms', $offset, $value) + "Starting {$offset}ms into the request, taking {$value}ms" ); } } diff --git a/app/vendor/cakephp/debug_kit/src/View/Helper/ToolbarHelper.php b/app/vendor/cakephp/debug_kit/src/View/Helper/ToolbarHelper.php index d59a8e12e..82875388b 100644 --- a/app/vendor/cakephp/debug_kit/src/View/Helper/ToolbarHelper.php +++ b/app/vendor/cakephp/debug_kit/src/View/Helper/ToolbarHelper.php @@ -15,15 +15,12 @@ */ namespace DebugKit\View\Helper; -use ArrayAccess; use Cake\Error\Debug\ArrayItemNode; use Cake\Error\Debug\ArrayNode; use Cake\Error\Debug\HtmlFormatter; use Cake\Error\Debug\ScalarNode; use Cake\Error\Debugger; use Cake\View\Helper; -use Closure; -use Iterator; /** * Provides Base methods for content specific debug toolbar helpers. @@ -119,101 +116,4 @@ public function dump($value) '
', ]); } - - /** - * Recursively goes through an array and makes neat HTML out of it. - * - * @param mixed $values Array to make pretty. - * @param int $openDepth Depth to add open class - * @param int $currentDepth current depth. - * @param bool $doubleEncode Whether or not to double encode. - * @param \SplObjectStorage $currentAncestors Object references found down - * the path. - * @return string - * @deprecated 4.4.0 Use ToolbarHelper::dump() instead. - */ - public function makeNeatArray( - $values, - $openDepth = 0, - $currentDepth = 0, - $doubleEncode = false, - ?\SplObjectStorage $currentAncestors = null - ) { - if ($currentAncestors === null) { - $ancestors = new \SplObjectStorage(); - } elseif (is_object($values)) { - $ancestors = new \SplObjectStorage(); - $ancestors->addAll($currentAncestors); - $ancestors->attach($values); - } else { - $ancestors = $currentAncestors; - } - $className = "neat-array depth-$currentDepth"; - if ($openDepth > $currentDepth) { - $className .= ' expanded'; - } - $nextDepth = $currentDepth + 1; - $out = "
    "; - if (!is_array($values)) { - if (is_bool($values)) { - $values = [$values]; - } - if ($values === null) { - $values = [null]; - } - if (is_object($values) && method_exists($values, 'toArray')) { - $values = $values->toArray(); - } - } - if (empty($values)) { - $values[] = '(empty)'; - } - if ($this->sort && is_array($values) && $currentDepth === 0) { - ksort($values); - } - foreach ($values as $key => $value) { - $out .= '
  • ' . h($key, $doubleEncode) . ' '; - if (is_array($value) && count($value) > 0) { - $out .= '(array)'; - } elseif (is_object($value)) { - $out .= '(' . (get_class($value) ?: 'object') . ')'; - } - if ($value === null) { - $value = '(null)'; - } - if ($value === false) { - $value = '(false)'; - } - if ($value === true) { - $value = '(true)'; - } - if (empty($value) && $value != 0) { - $value = '(empty)'; - } - if ($value instanceof Closure) { - $value = 'function'; - } - - if (is_object($value) && $ancestors->contains($value)) { - $value = ' - recursion'; - } - - if ( - ( - $value instanceof ArrayAccess || - $value instanceof Iterator || - is_array($value) || - is_object($value) - ) && !empty($value) - ) { - $out .= $this->makeNeatArray($value, $openDepth, $nextDepth, $doubleEncode, $ancestors); - } else { - $out .= h($value, $doubleEncode); - } - $out .= '
  • '; - } - $out .= '
'; - - return $out; - } } diff --git a/app/vendor/cakephp/debug_kit/templates/Dashboard/index.php b/app/vendor/cakephp/debug_kit/templates/Dashboard/index.php index ee3566fd5..d7468e1f2 100644 --- a/app/vendor/cakephp/debug_kit/templates/Dashboard/index.php +++ b/app/vendor/cakephp/debug_kit/templates/Dashboard/index.php @@ -3,18 +3,18 @@ * @var \App\View\AppView $this */ ?> -

+

Debug Kit Dashboard

-

+

Database

    -
  • :
  • +
  • Driver:
  • -
  • : Number->format($connection['rows']) ?>
  • +
  • Requests: Number->format($connection['rows']) ?>
Form->postLink( - __d('debug_kit', 'Reset database'), + 'Reset database', ['_method' => 'POST', 'action' => 'reset'], ['confirm' => 'Are you sure?'] ); ?> @@ -22,5 +22,5 @@

Actions

    -
  • Html->link(__d('debug_kit', 'Mail Preview'), ['controller' => 'MailPreview']); ?>
  • +
  • Html->link('Mail Preview', ['controller' => 'MailPreview']); ?>
diff --git a/app/vendor/cakephp/debug_kit/templates/MailPreview/email.php b/app/vendor/cakephp/debug_kit/templates/MailPreview/email.php index 622089681..2529d93e1 100644 --- a/app/vendor/cakephp/debug_kit/templates/MailPreview/email.php +++ b/app/vendor/cakephp/debug_kit/templates/MailPreview/email.php @@ -1,4 +1,4 @@ -', - '' - ].join('') + it('should skip hidden element when using keyboard navigation', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - const keydown = createEvent('keydown') - keydown.key = 'ArrowDown' + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + const keydown = createEvent('keydown') + keydown.key = 'ArrowDown' - triggerDropdown.dispatchEvent(keydown) + triggerDropdown.dispatchEvent(keydown) - expect(document.activeElement.classList.contains('d-none')).toEqual(false, '.d-none not focused') - expect(document.activeElement.style.display).not.toBe('none', '"display: none" not focused') - expect(document.activeElement.style.visibility).not.toBe('hidden', '"visibility: hidden" not focused') + expect(document.activeElement).not.toHaveClass('d-none') + expect(document.activeElement.style.display).not.toEqual('none') + expect(document.activeElement.style.visibility).not.toEqual('hidden') - done() - }) + resolve() + }) - triggerDropdown.click() + triggerDropdown.click() + }) }) - it('should focus next/previous element when using keyboard navigation', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should focus next/previous element when using keyboard navigation', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const item1 = fixtureEl.querySelector('#item1') - const item2 = fixtureEl.querySelector('#item2') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const item1 = fixtureEl.querySelector('#item1') + const item2 = fixtureEl.querySelector('#item2') - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - const keydownArrowDown = createEvent('keydown') - keydownArrowDown.key = 'ArrowDown' + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + const keydownArrowDown = createEvent('keydown') + keydownArrowDown.key = 'ArrowDown' - triggerDropdown.dispatchEvent(keydownArrowDown) - expect(document.activeElement).toEqual(item1, 'item1 is focused') + triggerDropdown.dispatchEvent(keydownArrowDown) + expect(document.activeElement).toEqual(item1, 'item1 is focused') - document.activeElement.dispatchEvent(keydownArrowDown) - expect(document.activeElement).toEqual(item2, 'item2 is focused') + document.activeElement.dispatchEvent(keydownArrowDown) + expect(document.activeElement).toEqual(item2, 'item2 is focused') - const keydownArrowUp = createEvent('keydown') - keydownArrowUp.key = 'ArrowUp' + const keydownArrowUp = createEvent('keydown') + keydownArrowUp.key = 'ArrowUp' - document.activeElement.dispatchEvent(keydownArrowUp) - expect(document.activeElement).toEqual(item1, 'item1 is focused') + document.activeElement.dispatchEvent(keydownArrowUp) + expect(document.activeElement).toEqual(item1, 'item1 is focused') - done() - }) + resolve() + }) - triggerDropdown.click() + triggerDropdown.click() + }) }) - it('should open the dropdown and focus on the last item when using ArrowUp for the first time', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should open the dropdown and focus on the last item when using ArrowUp for the first time', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const lastItem = fixtureEl.querySelector('#item2') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const lastItem = fixtureEl.querySelector('#item2') - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - setTimeout(() => { - expect(document.activeElement).toEqual(lastItem, 'item2 is focused') - done() + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + setTimeout(() => { + expect(document.activeElement).toEqual(lastItem, 'item2 is focused') + resolve() + }) }) - }) - const keydown = createEvent('keydown') - keydown.key = 'ArrowUp' - triggerDropdown.dispatchEvent(keydown) + const keydown = createEvent('keydown') + keydown.key = 'ArrowUp' + triggerDropdown.dispatchEvent(keydown) + }) }) - it('should open the dropdown and focus on the first item when using ArrowDown for the first time', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should open the dropdown and focus on the first item when using ArrowDown for the first time', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const firstItem = fixtureEl.querySelector('#item1') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const firstItem = fixtureEl.querySelector('#item1') - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - setTimeout(() => { - expect(document.activeElement).toEqual(firstItem, 'item1 is focused') - done() + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + setTimeout(() => { + expect(document.activeElement).toEqual(firstItem, 'item1 is focused') + resolve() + }) }) - }) - const keydown = createEvent('keydown') - keydown.key = 'ArrowDown' - triggerDropdown.dispatchEvent(keydown) + const keydown = createEvent('keydown') + keydown.key = 'ArrowDown' + triggerDropdown.dispatchEvent(keydown) + }) }) - it('should not close the dropdown if the user clicks on a text field within dropdown-menu', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should not close the dropdown if the user clicks on a text field within dropdown-menu', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const input = fixtureEl.querySelector('input') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const input = fixtureEl.querySelector('input') - input.addEventListener('click', () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown') - done() - }) + input.addEventListener('click', () => { + expect(triggerDropdown).toHaveClass('show') + resolve() + }) - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown') - input.dispatchEvent(createEvent('click')) - }) + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + expect(triggerDropdown).toHaveClass('show') + input.dispatchEvent(createEvent('click')) + }) - triggerDropdown.click() + triggerDropdown.click() + }) }) - it('should not close the dropdown if the user clicks on a textarea within dropdown-menu', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should not close the dropdown if the user clicks on a textarea within dropdown-menu', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const textarea = fixtureEl.querySelector('textarea') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const textarea = fixtureEl.querySelector('textarea') - textarea.addEventListener('click', () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown') - done() - }) + textarea.addEventListener('click', () => { + expect(triggerDropdown).toHaveClass('show') + resolve() + }) - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true, 'dropdown menu is shown') - textarea.dispatchEvent(createEvent('click')) - }) + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + expect(triggerDropdown).toHaveClass('show') + textarea.dispatchEvent(createEvent('click')) + }) - triggerDropdown.click() + triggerDropdown.click() + }) }) - it('should close the dropdown if the user clicks on a text field that is not contained within dropdown-menu', done => { - fixtureEl.innerHTML = [ - '', - '' - ] + it('should close the dropdown if the user clicks on a text field that is not contained within dropdown-menu', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const input = fixtureEl.querySelector('input') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const input = fixtureEl.querySelector('input') - triggerDropdown.addEventListener('hidden.bs.dropdown', () => { - expect().nothing() - done() - }) + triggerDropdown.addEventListener('hidden.bs.dropdown', () => { + expect().nothing() + resolve() + }) - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - input.dispatchEvent(createEvent('click', { - bubbles: true - })) - }) + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + input.dispatchEvent(createEvent('click', { + bubbles: true + })) + }) - triggerDropdown.click() - }) + triggerDropdown.click() + }) + }) + + it('should ignore keyboard events for s and ', + '
', + '' + ].join('') + + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const input = fixtureEl.querySelector('input') + const textarea = fixtureEl.querySelector('textarea') + + const test = (eventKey, elementToDispatch) => { + const event = createEvent('keydown') + event.key = eventKey + elementToDispatch.focus() + elementToDispatch.dispatchEvent(event) + expect(document.activeElement).toEqual(elementToDispatch, `${elementToDispatch.tagName} still focused`) + } - it('should ignore keyboard events for s and ', - ' ', - '' - ].join('') + const keydownEscape = createEvent('keydown') + keydownEscape.key = 'Escape' - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const input = fixtureEl.querySelector('input') - const textarea = fixtureEl.querySelector('textarea') + triggerDropdown.addEventListener('shown.bs.dropdown', () => { + // Key Space + test('Space', input) + + test('Space', textarea) + + // Key ArrowUp + test('ArrowUp', input) + + test('ArrowUp', textarea) - const keydownSpace = createEvent('keydown') - keydownSpace.key = 'Space' + // Key ArrowDown + test('ArrowDown', input) - const keydownArrowUp = createEvent('keydown') - keydownArrowUp.key = 'ArrowUp' + test('ArrowDown', textarea) - const keydownArrowDown = createEvent('keydown') - keydownArrowDown.key = 'ArrowDown' + // Key Escape + input.focus() + input.dispatchEvent(keydownEscape) - const keydownEscape = createEvent('keydown') - keydownEscape.key = 'Escape' + expect(triggerDropdown).not.toHaveClass('show') + resolve() + }) - triggerDropdown.addEventListener('shown.bs.dropdown', () => { - // Key Space - input.focus() - input.dispatchEvent(keydownSpace) + triggerDropdown.click() + }) + }) - expect(document.activeElement).toEqual(input, 'input still focused') + it('should not open dropdown if escape key was pressed on the toggle', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + '
' + ].join('') - textarea.focus() - textarea.dispatchEvent(keydownSpace) + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const dropdown = new Dropdown(triggerDropdown) + const button = fixtureEl.querySelector('button[data-bs-toggle="dropdown"]') - expect(document.activeElement).toEqual(textarea, 'textarea still focused') + const spy = spyOn(dropdown, 'toggle') - // Key ArrowUp - input.focus() - input.dispatchEvent(keydownArrowUp) + // Key escape + button.focus() + // Key escape + const keydownEscape = createEvent('keydown') + keydownEscape.key = 'Escape' + button.dispatchEvent(keydownEscape) - expect(document.activeElement).toEqual(input, 'input still focused') + setTimeout(() => { + expect(spy).not.toHaveBeenCalled() + expect(triggerDropdown).not.toHaveClass('show') + resolve() + }, 20) + }) + }) + + it('should propagate escape key events if dropdown is closed', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + '
' + ].join('') + + const parent = fixtureEl.querySelector('.parent') + const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + + const parentKeyHandler = jasmine.createSpy('parentKeyHandler') + + parent.addEventListener('keydown', parentKeyHandler) + parent.addEventListener('keyup', () => { + expect(parentKeyHandler).toHaveBeenCalled() + resolve() + }) - textarea.focus() - textarea.dispatchEvent(keydownArrowUp) + const keydownEscape = createEvent('keydown', { bubbles: true }) + keydownEscape.key = 'Escape' + const keyupEscape = createEvent('keyup', { bubbles: true }) + keyupEscape.key = 'Escape' - expect(document.activeElement).toEqual(textarea, 'textarea still focused') + toggle.focus() + toggle.dispatchEvent(keydownEscape) + toggle.dispatchEvent(keyupEscape) + }) + }) - // Key ArrowDown - input.focus() - input.dispatchEvent(keydownArrowDown) + it('should not propagate escape key events if dropdown is open', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + '
' + ].join('') - expect(document.activeElement).toEqual(input, 'input still focused') + const parent = fixtureEl.querySelector('.parent') + const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - textarea.focus() - textarea.dispatchEvent(keydownArrowDown) + const parentKeyHandler = jasmine.createSpy('parentKeyHandler') - expect(document.activeElement).toEqual(textarea, 'textarea still focused') + parent.addEventListener('keydown', parentKeyHandler) + parent.addEventListener('keyup', () => { + expect(parentKeyHandler).not.toHaveBeenCalled() + resolve() + }) - // Key Escape - input.focus() - input.dispatchEvent(keydownEscape) + const keydownEscape = createEvent('keydown', { bubbles: true }) + keydownEscape.key = 'Escape' + const keyupEscape = createEvent('keyup', { bubbles: true }) + keyupEscape.key = 'Escape' - expect(triggerDropdown.classList.contains('show')).toEqual(false, 'dropdown menu is not shown') - done() + toggle.click() + toggle.dispatchEvent(keydownEscape) + toggle.dispatchEvent(keyupEscape) }) - - triggerDropdown.click() }) - it('should not open dropdown if escape key was pressed on the toggle', done => { - fixtureEl.innerHTML = [ - '
', - ' ', - '
' - ] + it('should close dropdown using `escape` button, and return focus to its trigger', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const dropdown = new Dropdown(triggerDropdown) - const button = fixtureEl.querySelector('button[data-bs-toggle="dropdown"]') + const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - spyOn(dropdown, 'toggle') + toggle.addEventListener('shown.bs.dropdown', () => { + const keydownEvent = createEvent('keydown', { bubbles: true }) + keydownEvent.key = 'ArrowDown' + toggle.dispatchEvent(keydownEvent) + keydownEvent.key = 'Escape' + toggle.dispatchEvent(keydownEvent) + }) - // Key escape - button.focus() - // Key escape - const keydownEscape = createEvent('keydown') - keydownEscape.key = 'Escape' - button.dispatchEvent(keydownEscape) + toggle.addEventListener('hidden.bs.dropdown', () => setTimeout(() => { + expect(document.activeElement).toEqual(toggle) + resolve() + })) - setTimeout(() => { - expect(dropdown.toggle).not.toHaveBeenCalled() - expect(triggerDropdown.classList.contains('show')).toEqual(false) - done() - }, 20) + toggle.click() + }) }) - it('should propagate escape key events if dropdown is closed', done => { - fixtureEl.innerHTML = [ - '
', - ' ', - '
' - ] + it('should close dropdown (only) by clicking inside the dropdown menu when it has data-attribute `data-bs-auto-close="inside"`', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const parent = fixtureEl.querySelector('.parent') - const toggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') - const parentKeyHandler = jasmine.createSpy('parentKeyHandler') + const expectDropdownToBeOpened = () => setTimeout(() => { + expect(dropdownToggle).toHaveClass('show') + dropdownMenu.click() + }, 150) - parent.addEventListener('keydown', parentKeyHandler) - parent.addEventListener('keyup', () => { - expect(parentKeyHandler).toHaveBeenCalled() - done() - }) + dropdownToggle.addEventListener('shown.bs.dropdown', () => { + document.documentElement.click() + expectDropdownToBeOpened() + }) - const keydownEscape = createEvent('keydown', { bubbles: true }) - keydownEscape.key = 'Escape' - const keyupEscape = createEvent('keyup', { bubbles: true }) - keyupEscape.key = 'Escape' + dropdownToggle.addEventListener('hidden.bs.dropdown', () => setTimeout(() => { + expect(dropdownToggle).not.toHaveClass('show') + resolve() + })) - toggle.focus() - toggle.dispatchEvent(keydownEscape) - toggle.dispatchEvent(keyupEscape) + dropdownToggle.click() + }) }) - it('should close dropdown (only) by clicking inside the dropdown menu when it has data-attribute `data-bs-auto-close="inside"`', done => { - fixtureEl.innerHTML = [ - '' - ] + it('should close dropdown (only) by clicking outside the dropdown menu when it has data-attribute `data-bs-auto-close="outside"`', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') + const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') - const expectDropdownToBeOpened = () => setTimeout(() => { - expect(dropdownToggle.classList.contains('show')).toEqual(true) - dropdownMenu.click() - }, 150) + const expectDropdownToBeOpened = () => setTimeout(() => { + expect(dropdownToggle).toHaveClass('show') + document.documentElement.click() + }, 150) - dropdownToggle.addEventListener('shown.bs.dropdown', () => { - document.documentElement.click() - expectDropdownToBeOpened() - }) + dropdownToggle.addEventListener('shown.bs.dropdown', () => { + dropdownMenu.click() + expectDropdownToBeOpened() + }) - dropdownToggle.addEventListener('hidden.bs.dropdown', () => setTimeout(() => { - expect(dropdownToggle.classList.contains('show')).toEqual(false) - done() - })) + dropdownToggle.addEventListener('hidden.bs.dropdown', () => { + expect(dropdownToggle).not.toHaveClass('show') + resolve() + }) - dropdownToggle.click() + dropdownToggle.click() + }) }) - it('should close dropdown (only) by clicking outside the dropdown menu when it has data-attribute `data-bs-auto-close="outside"`', done => { - fixtureEl.innerHTML = [ - '' - ] + it('should not close dropdown by clicking inside or outside the dropdown menu when it has data-attribute `data-bs-auto-close="false"`', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') + const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') - const expectDropdownToBeOpened = () => setTimeout(() => { - expect(dropdownToggle.classList.contains('show')).toEqual(true) - document.documentElement.click() - }, 150) + const expectDropdownToBeOpened = (shouldTriggerClick = true) => setTimeout(() => { + expect(dropdownToggle).toHaveClass('show') + if (shouldTriggerClick) { + document.documentElement.click() + } else { + resolve() + } - dropdownToggle.addEventListener('shown.bs.dropdown', () => { - dropdownMenu.click() - expectDropdownToBeOpened() - }) + expectDropdownToBeOpened(false) + }, 150) - dropdownToggle.addEventListener('hidden.bs.dropdown', () => { - expect(dropdownToggle.classList.contains('show')).toEqual(false) - done() - }) + dropdownToggle.addEventListener('shown.bs.dropdown', () => { + dropdownMenu.click() + expectDropdownToBeOpened() + }) - dropdownToggle.click() + dropdownToggle.click() + }) }) - it('should not close dropdown by clicking inside or outside the dropdown menu when it has data-attribute `data-bs-auto-close="false"`', done => { + it('should be able to identify clicked dropdown, no matter the markup order', () => { fixtureEl.innerHTML = [ '', + ' ', '' - ] + ].join('') const dropdownToggle = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') const dropdownMenu = fixtureEl.querySelector('.dropdown-menu') - - const expectDropdownToBeOpened = (shouldTriggerClick = true) => setTimeout(() => { - expect(dropdownToggle.classList.contains('show')).toEqual(true) - if (shouldTriggerClick) { - document.documentElement.click() - } else { - done() - } - - expectDropdownToBeOpened(false) - }, 150) - - dropdownToggle.addEventListener('shown.bs.dropdown', () => { - dropdownMenu.click() - expectDropdownToBeOpened() - }) + const spy = spyOn(Dropdown, 'getOrCreateInstance').and.callThrough() dropdownToggle.click() + expect(spy).toHaveBeenCalledWith(dropdownToggle) + dropdownMenu.click() + expect(spy).toHaveBeenCalledWith(dropdownToggle) }) }) @@ -1965,7 +2271,7 @@ describe('Dropdown', () => { const div = fixtureEl.querySelector('div') - expect(Dropdown.getInstance(div)).toEqual(null) + expect(Dropdown.getInstance(div)).toBeNull() }) }) @@ -1986,7 +2292,7 @@ describe('Dropdown', () => { const div = fixtureEl.querySelector('div') - expect(Dropdown.getInstance(div)).toEqual(null) + expect(Dropdown.getInstance(div)).toBeNull() expect(Dropdown.getOrCreateInstance(div)).toBeInstanceOf(Dropdown) }) @@ -1995,7 +2301,7 @@ describe('Dropdown', () => { const div = fixtureEl.querySelector('div') - expect(Dropdown.getInstance(div)).toEqual(null) + expect(Dropdown.getInstance(div)).toBeNull() const dropdown = Dropdown.getOrCreateInstance(div, { display: 'dynamic' }) @@ -2023,52 +2329,54 @@ describe('Dropdown', () => { }) }) - it('should open dropdown when pressing keydown or keyup', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should open dropdown when pressing keydown or keyup', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const dropdown = fixtureEl.querySelector('.dropdown') + const triggerDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const dropdown = fixtureEl.querySelector('.dropdown') - const keydown = createEvent('keydown') - keydown.key = 'ArrowDown' + const keydown = createEvent('keydown') + keydown.key = 'ArrowDown' - const keyup = createEvent('keyup') - keyup.key = 'ArrowUp' + const keyup = createEvent('keyup') + keyup.key = 'ArrowUp' - const handleArrowDown = () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true) - expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true') - setTimeout(() => { - dropdown.hide() - keydown.key = 'ArrowUp' - triggerDropdown.dispatchEvent(keyup) - }, 20) - } - - const handleArrowUp = () => { - expect(triggerDropdown.classList.contains('show')).toEqual(true) - expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true') - done() - } - - dropdown.addEventListener('shown.bs.dropdown', event => { - if (event.target.key === 'ArrowDown') { - handleArrowDown() - } else { - handleArrowUp() + const handleArrowDown = () => { + expect(triggerDropdown).toHaveClass('show') + expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true') + setTimeout(() => { + dropdown.hide() + keydown.key = 'ArrowUp' + triggerDropdown.dispatchEvent(keyup) + }, 20) } - }) - triggerDropdown.dispatchEvent(keydown) + const handleArrowUp = () => { + expect(triggerDropdown).toHaveClass('show') + expect(triggerDropdown.getAttribute('aria-expanded')).toEqual('true') + resolve() + } + + dropdown.addEventListener('shown.bs.dropdown', event => { + if (event.target.key === 'ArrowDown') { + handleArrowDown() + } else { + handleArrowUp() + } + }) + + triggerDropdown.dispatchEvent(keydown) + }) }) it('should allow `data-bs-toggle="dropdown"` click events to bubble up', () => { @@ -2094,27 +2402,29 @@ describe('Dropdown', () => { expect(delegatedClickListener).toHaveBeenCalled() }) - it('should open the dropdown when clicking the child element inside `data-bs-toggle="dropdown"`', done => { - fixtureEl.innerHTML = [ - '
', - ' ', - '
' - ].join('') + it('should open the dropdown when clicking the child element inside `data-bs-toggle="dropdown"`', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + '
' + ].join('') - const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') - const childElement = fixtureEl.querySelector('#childElement') + const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]') + const childElement = fixtureEl.querySelector('#childElement') - btnDropdown.addEventListener('shown.bs.dropdown', () => setTimeout(() => { - expect(btnDropdown.classList.contains('show')).toEqual(true) - expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') - done() - })) + btnDropdown.addEventListener('shown.bs.dropdown', () => setTimeout(() => { + expect(btnDropdown).toHaveClass('show') + expect(btnDropdown.getAttribute('aria-expanded')).toEqual('true') + resolve() + })) - childElement.click() + childElement.click() + }) }) }) diff --git a/app/vendor/twbs/bootstrap/js/tests/unit/jquery.spec.js b/app/vendor/twbs/bootstrap/js/tests/unit/jquery.spec.js index 7513341a4..7da39d630 100644 --- a/app/vendor/twbs/bootstrap/js/tests/unit/jquery.spec.js +++ b/app/vendor/twbs/bootstrap/js/tests/unit/jquery.spec.js @@ -1,4 +1,5 @@ /* eslint-env jquery */ + import Alert from '../../src/alert' import Button from '../../src/button' import Carousel from '../../src/carousel' @@ -11,9 +12,7 @@ import ScrollSpy from '../../src/scrollspy' import Tab from '../../src/tab' import Toast from '../../src/toast' import Tooltip from '../../src/tooltip' - -/** Test helpers */ -import { getFixture, clearFixture } from '../helpers/fixture' +import { clearFixture, getFixture } from '../helpers/fixture' describe('jQuery', () => { let fixtureEl @@ -41,19 +40,21 @@ describe('jQuery', () => { expect(Tooltip.jQueryInterface).toEqual(jQuery.fn.tooltip) }) - it('should use jQuery event system', done => { - fixtureEl.innerHTML = [ - '
', - ' ', - '
' - ].join('') - - $(fixtureEl).find('.alert') - .one('closed.bs.alert', () => { - expect($(fixtureEl).find('.alert').length).toEqual(0) - done() - }) - - $(fixtureEl).find('button').trigger('click') + it('should use jQuery event system', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + ' ', + '
' + ].join('') + + $(fixtureEl).find('.alert') + .one('closed.bs.alert', () => { + expect($(fixtureEl).find('.alert')).toHaveSize(0) + resolve() + }) + + $(fixtureEl).find('button').trigger('click') + }) }) }) diff --git a/app/vendor/twbs/bootstrap/js/tests/unit/modal.spec.js b/app/vendor/twbs/bootstrap/js/tests/unit/modal.spec.js index 9632fa6cf..fdee29e95 100644 --- a/app/vendor/twbs/bootstrap/js/tests/unit/modal.spec.js +++ b/app/vendor/twbs/bootstrap/js/tests/unit/modal.spec.js @@ -1,8 +1,6 @@ import Modal from '../../src/modal' import EventHandler from '../../src/dom/event-handler' import ScrollBarHelper from '../../src/util/scrollbar' - -/** Test helpers */ import { clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' describe('Modal', () => { @@ -17,10 +15,9 @@ describe('Modal', () => { clearBodyAndDocument() document.body.classList.remove('modal-open') - document.querySelectorAll('.modal-backdrop') - .forEach(backdrop => { - backdrop.remove() - }) + for (const backdrop of document.querySelectorAll('.modal-backdrop')) { + backdrop.remove() + } }) beforeEach(() => { @@ -59,95 +56,101 @@ describe('Modal', () => { }) describe('toggle', () => { - it('should call ScrollBarHelper to handle scrollBar on body', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should call ScrollBarHelper to handle scrollBar on body', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' + + const spyHide = spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() + const spyReset = spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) + + modalEl.addEventListener('shown.bs.modal', () => { + expect(spyHide).toHaveBeenCalled() + modal.toggle() + }) - spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() - spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(spyReset).toHaveBeenCalled() + resolve() + }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(ScrollBarHelper.prototype.hide).toHaveBeenCalled() modal.toggle() }) - - modalEl.addEventListener('hidden.bs.modal', () => { - expect(ScrollBarHelper.prototype.reset).toHaveBeenCalled() - done() - }) - - modal.toggle() }) }) describe('show', () => { - it('should show a modal', done => { - fixtureEl.innerHTML = '' + it('should show a modal', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - modalEl.addEventListener('show.bs.modal', event => { - expect(event).toBeDefined() - }) + modalEl.addEventListener('show.bs.modal', event => { + expect(event).toBeDefined() + }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toEqual('true') - expect(modalEl.getAttribute('role')).toEqual('dialog') - expect(modalEl.getAttribute('aria-hidden')).toBeNull() - expect(modalEl.style.display).toEqual('block') - expect(document.querySelector('.modal-backdrop')).not.toBeNull() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toEqual('true') + expect(modalEl.getAttribute('role')).toEqual('dialog') + expect(modalEl.getAttribute('aria-hidden')).toBeNull() + expect(modalEl.style.display).toEqual('block') + expect(document.querySelector('.modal-backdrop')).not.toBeNull() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should show a modal without backdrop', done => { - fixtureEl.innerHTML = '' + it('should show a modal without backdrop', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: false - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: false + }) - modalEl.addEventListener('show.bs.modal', event => { - expect(event).toBeDefined() - }) + modalEl.addEventListener('show.bs.modal', event => { + expect(event).toBeDefined() + }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toEqual('true') - expect(modalEl.getAttribute('role')).toEqual('dialog') - expect(modalEl.getAttribute('aria-hidden')).toBeNull() - expect(modalEl.style.display).toEqual('block') - expect(document.querySelector('.modal-backdrop')).toBeNull() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toEqual('true') + expect(modalEl.getAttribute('role')).toEqual('dialog') + expect(modalEl.getAttribute('aria-hidden')).toBeNull() + expect(modalEl.style.display).toEqual('block') + expect(document.querySelector('.modal-backdrop')).toBeNull() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should show a modal and append the element', done => { - const modalEl = document.createElement('div') - const id = 'dynamicModal' + it('should show a modal and append the element', () => { + return new Promise(resolve => { + const modalEl = document.createElement('div') + const id = 'dynamicModal' - modalEl.setAttribute('id', id) - modalEl.classList.add('modal') - modalEl.innerHTML = '' + modalEl.setAttribute('id', id) + modalEl.classList.add('modal') + modalEl.innerHTML = '' - const modal = new Modal(modalEl) + const modal = new Modal(modalEl) - modalEl.addEventListener('shown.bs.modal', () => { - const dynamicModal = document.getElementById(id) - expect(dynamicModal).not.toBeNull() - dynamicModal.remove() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + const dynamicModal = document.getElementById(id) + expect(dynamicModal).not.toBeNull() + dynamicModal.remove() + resolve() + }) - modal.show() + modal.show() + }) }) it('should do nothing if a modal is shown', () => { @@ -156,12 +159,12 @@ describe('Modal', () => { const modalEl = fixtureEl.querySelector('.modal') const modal = new Modal(modalEl) - spyOn(EventHandler, 'trigger') + const spy = spyOn(EventHandler, 'trigger') modal._isShown = true modal.show() - expect(EventHandler.trigger).not.toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() }) it('should do nothing if a modal is transitioning', () => { @@ -170,488 +173,595 @@ describe('Modal', () => { const modalEl = fixtureEl.querySelector('.modal') const modal = new Modal(modalEl) - spyOn(EventHandler, 'trigger') + const spy = spyOn(EventHandler, 'trigger') modal._isTransitioning = true modal.show() - expect(EventHandler.trigger).not.toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() }) - it('should not fire shown event when show is prevented', done => { - fixtureEl.innerHTML = '' + it('should not fire shown event when show is prevented', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - modalEl.addEventListener('show.bs.modal', event => { - event.preventDefault() + modalEl.addEventListener('show.bs.modal', event => { + event.preventDefault() - const expectedDone = () => { - expect().nothing() - done() - } + const expectedDone = () => { + expect().nothing() + resolve() + } - setTimeout(expectedDone, 10) - }) + setTimeout(expectedDone, 10) + }) - modalEl.addEventListener('shown.bs.modal', () => { - throw new Error('shown event triggered') - }) + modalEl.addEventListener('shown.bs.modal', () => { + reject(new Error('shown event triggered')) + }) - modal.show() + modal.show() + }) }) - it('should be shown after the first call to show() has been prevented while fading is enabled ', done => { - fixtureEl.innerHTML = '' + it('should be shown after the first call to show() has been prevented while fading is enabled ', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - let prevented = false - modalEl.addEventListener('show.bs.modal', event => { - if (!prevented) { - event.preventDefault() - prevented = true + let prevented = false + modalEl.addEventListener('show.bs.modal', event => { + if (!prevented) { + event.preventDefault() + prevented = true - setTimeout(() => { - modal.show() - }) - } - }) + setTimeout(() => { + modal.show() + }) + } + }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(prevented).toBeTrue() - expect(modal._isAnimated()).toBeTrue() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(prevented).toBeTrue() + expect(modal._isAnimated()).toBeTrue() + resolve() + }) - modal.show() + modal.show() + }) }) + it('should set is transitioning if fade class is present', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - it('should set is transitioning if fade class is present', done => { - fixtureEl.innerHTML = '' + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + modalEl.addEventListener('show.bs.modal', () => { + setTimeout(() => { + expect(modal._isTransitioning).toBeTrue() + }) + }) - modalEl.addEventListener('show.bs.modal', () => { - setTimeout(() => { - expect(modal._isTransitioning).toEqual(true) + modalEl.addEventListener('shown.bs.modal', () => { + expect(modal._isTransitioning).toBeFalse() + resolve() }) - }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(modal._isTransitioning).toEqual(false) - done() + modal.show() }) - - modal.show() }) - it('should close modal when a click occurred on data-bs-dismiss="modal" inside modal', done => { - fixtureEl.innerHTML = [ - '' - ].join('') - - const modalEl = fixtureEl.querySelector('.modal') - const btnClose = fixtureEl.querySelector('[data-bs-dismiss="modal"]') - const modal = new Modal(modalEl) - - spyOn(modal, 'hide').and.callThrough() + it('should close modal when a click occurred on data-bs-dismiss="modal" inside modal', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const btnClose = fixtureEl.querySelector('[data-bs-dismiss="modal"]') + const modal = new Modal(modalEl) + + const spy = spyOn(modal, 'hide').and.callThrough() + + modalEl.addEventListener('shown.bs.modal', () => { + btnClose.click() + }) - modalEl.addEventListener('shown.bs.modal', () => { - btnClose.click() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modal.hide).toHaveBeenCalled() - done() + modal.show() }) - - modal.show() }) - it('should close modal when a click occurred on a data-bs-dismiss="modal" with "bs-target" outside of modal element', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + it('should close modal when a click occurred on a data-bs-dismiss="modal" with "bs-target" outside of modal element', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - const modalEl = fixtureEl.querySelector('.modal') - const btnClose = fixtureEl.querySelector('[data-bs-dismiss="modal"]') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const btnClose = fixtureEl.querySelector('[data-bs-dismiss="modal"]') + const modal = new Modal(modalEl) - spyOn(modal, 'hide').and.callThrough() + const spy = spyOn(modal, 'hide').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - btnClose.click() - }) + modalEl.addEventListener('shown.bs.modal', () => { + btnClose.click() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modal.hide).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should set .modal\'s scroll top to 0', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should set .modal\'s scroll top to 0', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalEl.scrollTop).toEqual(0) - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalEl.scrollTop).toEqual(0) + resolve() + }) - modal.show() + modal.show() + }) }) - it('should set modal body scroll top to 0 if modal body do not exists', done => { - fixtureEl.innerHTML = [ - '' - ].join('') - - const modalEl = fixtureEl.querySelector('.modal') - const modalBody = modalEl.querySelector('.modal-body') - const modal = new Modal(modalEl) + it('should set modal body scroll top to 0 if modal body do not exists', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const modalBody = modalEl.querySelector('.modal-body') + const modal = new Modal(modalEl) + + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalBody.scrollTop).toEqual(0) + resolve() + }) - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalBody.scrollTop).toEqual(0) - done() + modal.show() }) - - modal.show() }) - it('should not trap focus if focus equal to false', done => { - fixtureEl.innerHTML = '' + it('should not trap focus if focus equal to false', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - focus: false - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + focus: false + }) - spyOn(modal._focustrap, 'activate').and.callThrough() + const spy = spyOn(modal._focustrap, 'activate').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - expect(modal._focustrap.activate).not.toHaveBeenCalled() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(spy).not.toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should add listener when escape touch is pressed', done => { - fixtureEl.innerHTML = '' + it('should add listener when escape touch is pressed', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - spyOn(modal, 'hide').and.callThrough() + const spy = spyOn(modal, 'hide').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - const keydownEscape = createEvent('keydown') - keydownEscape.key = 'Escape' + modalEl.addEventListener('shown.bs.modal', () => { + const keydownEscape = createEvent('keydown') + keydownEscape.key = 'Escape' - modalEl.dispatchEvent(keydownEscape) - }) + modalEl.dispatchEvent(keydownEscape) + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modal.hide).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should do nothing when the pressed key is not escape', done => { - fixtureEl.innerHTML = '' + it('should do nothing when the pressed key is not escape', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - spyOn(modal, 'hide') + const spy = spyOn(modal, 'hide') - const expectDone = () => { - expect(modal.hide).not.toHaveBeenCalled() + const expectDone = () => { + expect(spy).not.toHaveBeenCalled() - done() - } + resolve() + } - modalEl.addEventListener('shown.bs.modal', () => { - const keydownTab = createEvent('keydown') - keydownTab.key = 'Tab' + modalEl.addEventListener('shown.bs.modal', () => { + const keydownTab = createEvent('keydown') + keydownTab.key = 'Tab' - modalEl.dispatchEvent(keydownTab) - setTimeout(expectDone, 30) - }) + modalEl.dispatchEvent(keydownTab) + setTimeout(expectDone, 30) + }) - modal.show() + modal.show() + }) }) - it('should adjust dialog on resize', done => { - fixtureEl.innerHTML = '' + it('should adjust dialog on resize', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - spyOn(modal, '_adjustDialog').and.callThrough() + const spy = spyOn(modal, '_adjustDialog').and.callThrough() - const expectDone = () => { - expect(modal._adjustDialog).toHaveBeenCalled() + const expectDone = () => { + expect(spy).toHaveBeenCalled() - done() - } + resolve() + } - modalEl.addEventListener('shown.bs.modal', () => { - const resizeEvent = createEvent('resize') + modalEl.addEventListener('shown.bs.modal', () => { + const resizeEvent = createEvent('resize') - window.dispatchEvent(resizeEvent) - setTimeout(expectDone, 10) - }) + window.dispatchEvent(resizeEvent) + setTimeout(expectDone, 10) + }) - modal.show() + modal.show() + }) }) - it('should not close modal when clicking outside of modal-content if backdrop = false', done => { - fixtureEl.innerHTML = '' + it('should not close modal when clicking on modal-content', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = [ + '' + ].join('') - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: false - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - const shownCallback = () => { - setTimeout(() => { - expect(modal._isShown).toEqual(true) - done() - }, 10) - } + const shownCallback = () => { + setTimeout(() => { + expect(modal._isShown).toEqual(true) + resolve() + }, 10) + } - modalEl.addEventListener('shown.bs.modal', () => { - modalEl.click() - shownCallback() - }) + modalEl.addEventListener('shown.bs.modal', () => { + fixtureEl.querySelector('.modal-dialog').click() + fixtureEl.querySelector('.modal-content').click() + shownCallback() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - throw new Error('Should not hide a modal') - }) + modalEl.addEventListener('hidden.bs.modal', () => { + reject(new Error('Should not hide a modal')) + }) - modal.show() + modal.show() + }) }) - it('should not close modal when clicking outside of modal-content if backdrop = static', done => { - fixtureEl.innerHTML = '' + it('should not close modal when clicking outside of modal-content if backdrop = false', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: 'static' - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: false + }) - const shownCallback = () => { - setTimeout(() => { - expect(modal._isShown).toEqual(true) - done() - }, 10) - } + const shownCallback = () => { + setTimeout(() => { + expect(modal._isShown).toBeTrue() + resolve() + }, 10) + } - modalEl.addEventListener('shown.bs.modal', () => { - modalEl.click() - shownCallback() - }) + modalEl.addEventListener('shown.bs.modal', () => { + modalEl.click() + shownCallback() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - throw new Error('Should not hide a modal') - }) + modalEl.addEventListener('hidden.bs.modal', () => { + reject(new Error('Should not hide a modal')) + }) - modal.show() + modal.show() + }) }) - it('should close modal when escape key is pressed with keyboard = true and backdrop is static', done => { - fixtureEl.innerHTML = '' + it('should not close modal when clicking outside of modal-content if backdrop = static', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: 'static', - keyboard: true - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: 'static' + }) - const shownCallback = () => { - setTimeout(() => { - expect(modal._isShown).toEqual(false) - done() - }, 10) - } + const shownCallback = () => { + setTimeout(() => { + expect(modal._isShown).toBeTrue() + resolve() + }, 10) + } - modalEl.addEventListener('shown.bs.modal', () => { - const keydownEscape = createEvent('keydown') - keydownEscape.key = 'Escape' + modalEl.addEventListener('shown.bs.modal', () => { + modalEl.click() + shownCallback() + }) - modalEl.dispatchEvent(keydownEscape) - shownCallback() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + reject(new Error('Should not hide a modal')) + }) - modal.show() + modal.show() + }) }) + it('should close modal when escape key is pressed with keyboard = true and backdrop is static', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' + + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: 'static', + keyboard: true + }) - it('should not close modal when escape key is pressed with keyboard = false', done => { - fixtureEl.innerHTML = '' + const shownCallback = () => { + setTimeout(() => { + expect(modal._isShown).toBeFalse() + resolve() + }, 10) + } - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - keyboard: false + modalEl.addEventListener('shown.bs.modal', () => { + const keydownEscape = createEvent('keydown') + keydownEscape.key = 'Escape' + + modalEl.dispatchEvent(keydownEscape) + shownCallback() + }) + + modal.show() }) + }) - const shownCallback = () => { - setTimeout(() => { - expect(modal._isShown).toEqual(true) - done() - }, 10) - } + it('should not close modal when escape key is pressed with keyboard = false', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = '' - modalEl.addEventListener('shown.bs.modal', () => { - const keydownEscape = createEvent('keydown') - keydownEscape.key = 'Escape' + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + keyboard: false + }) - modalEl.dispatchEvent(keydownEscape) - shownCallback() - }) + const shownCallback = () => { + setTimeout(() => { + expect(modal._isShown).toBeTrue() + resolve() + }, 10) + } - modalEl.addEventListener('hidden.bs.modal', () => { - throw new Error('Should not hide a modal') - }) + modalEl.addEventListener('shown.bs.modal', () => { + const keydownEscape = createEvent('keydown') + keydownEscape.key = 'Escape' - modal.show() - }) + modalEl.dispatchEvent(keydownEscape) + shownCallback() + }) - it('should not overflow when clicking outside of modal-content if backdrop = static', done => { - fixtureEl.innerHTML = '' + modalEl.addEventListener('hidden.bs.modal', () => { + reject(new Error('Should not hide a modal')) + }) - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: 'static' + modal.show() }) + }) - modalEl.addEventListener('shown.bs.modal', () => { - modalEl.click() - setTimeout(() => { - expect(modalEl.clientHeight).toEqual(modalEl.scrollHeight) - done() - }, 20) - }) + it('should not overflow when clicking outside of modal-content if backdrop = static', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - modal.show() - }) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: 'static' + }) - it('should not queue multiple callbacks when clicking outside of modal-content and backdrop = static', done => { - fixtureEl.innerHTML = '' + modalEl.addEventListener('shown.bs.modal', () => { + modalEl.click() + setTimeout(() => { + expect(modalEl.clientHeight).toEqual(modalEl.scrollHeight) + resolve() + }, 20) + }) - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl, { - backdrop: 'static' + modal.show() }) + }) - modalEl.addEventListener('shown.bs.modal', () => { - const spy = spyOn(modal, '_queueCallback').and.callThrough() + it('should not queue multiple callbacks when clicking outside of modal-content and backdrop = static', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - modalEl.click() - modalEl.click() + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl, { + backdrop: 'static' + }) - setTimeout(() => { - expect(spy).toHaveBeenCalledTimes(1) - done() - }, 20) - }) + modalEl.addEventListener('shown.bs.modal', () => { + const spy = spyOn(modal, '_queueCallback').and.callThrough() + const mouseDown = createEvent('mousedown') - modal.show() + modalEl.dispatchEvent(mouseDown) + modalEl.click() + modalEl.dispatchEvent(mouseDown) + modalEl.click() + + setTimeout(() => { + expect(spy).toHaveBeenCalledTimes(1) + resolve() + }, 20) + }) + + modal.show() + }) }) - it('should trap focus', done => { - fixtureEl.innerHTML = '' + it('should trap focus', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - spyOn(modal._focustrap, 'activate').and.callThrough() + const spy = spyOn(modal._focustrap, 'activate').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - expect(modal._focustrap.activate).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) }) describe('hide', () => { - it('should hide a modal', done => { - fixtureEl.innerHTML = '' + it('should hide a modal', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) + const backdropSpy = spyOn(modal._backdrop, 'hide').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - modal.hide() - }) + modalEl.addEventListener('shown.bs.modal', () => { + modal.hide() + }) - modalEl.addEventListener('hide.bs.modal', event => { - expect(event).toBeDefined() - }) + modalEl.addEventListener('hide.bs.modal', event => { + expect(event).toBeDefined() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toBeNull() - expect(modalEl.getAttribute('role')).toBeNull() - expect(modalEl.getAttribute('aria-hidden')).toEqual('true') - expect(modalEl.style.display).toEqual('none') - expect(document.querySelector('.modal-backdrop')).toBeNull() - done() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toBeNull() + expect(modalEl.getAttribute('role')).toBeNull() + expect(modalEl.getAttribute('aria-hidden')).toEqual('true') + expect(modalEl.style.display).toEqual('none') + expect(backdropSpy).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) - it('should close modal when clicking outside of modal-content', done => { - fixtureEl.innerHTML = '' + it('should close modal when clicking outside of modal-content', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const dialogEl = modalEl.querySelector('.modal-dialog') + const modal = new Modal(modalEl) - modalEl.addEventListener('shown.bs.modal', () => { - modalEl.click() - }) + const spy = spyOn(modal, 'hide') + + modalEl.addEventListener('shown.bs.modal', () => { + const mouseDown = createEvent('mousedown') + + dialogEl.dispatchEvent(mouseDown) + modalEl.click() + expect(spy).not.toHaveBeenCalled() - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toBeNull() - expect(modalEl.getAttribute('role')).toBeNull() - expect(modalEl.getAttribute('aria-hidden')).toEqual('true') - expect(modalEl.style.display).toEqual('none') - expect(document.querySelector('.modal-backdrop')).toBeNull() - done() + modalEl.dispatchEvent(mouseDown) + modalEl.click() + expect(spy).toHaveBeenCalled() + resolve() + }) + + modal.show() }) + }) - modal.show() + it('should not close modal when clicking on an element removed from modal content', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const buttonEl = modalEl.querySelector('.btn') + const modal = new Modal(modalEl) + + const spy = spyOn(modal, 'hide') + buttonEl.addEventListener('click', () => { + buttonEl.remove() + }) + + modalEl.addEventListener('shown.bs.modal', () => { + modalEl.dispatchEvent(createEvent('mousedown')) + buttonEl.click() + expect(spy).not.toHaveBeenCalled() + resolve() + }) + + modal.show() + }) }) it('should do nothing is the modal is not shown', () => { @@ -677,52 +787,56 @@ describe('Modal', () => { expect().nothing() }) - it('should not hide a modal if hide is prevented', done => { - fixtureEl.innerHTML = '' + it('should not hide a modal if hide is prevented', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) - modalEl.addEventListener('shown.bs.modal', () => { - modal.hide() - }) + modalEl.addEventListener('shown.bs.modal', () => { + modal.hide() + }) - const hideCallback = () => { - setTimeout(() => { - expect(modal._isShown).toEqual(true) - done() - }, 10) - } + const hideCallback = () => { + setTimeout(() => { + expect(modal._isShown).toBeTrue() + resolve() + }, 10) + } - modalEl.addEventListener('hide.bs.modal', event => { - event.preventDefault() - hideCallback() - }) + modalEl.addEventListener('hide.bs.modal', event => { + event.preventDefault() + hideCallback() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - throw new Error('should not trigger hidden') - }) + modalEl.addEventListener('hidden.bs.modal', () => { + reject(new Error('should not trigger hidden')) + }) - modal.show() + modal.show() + }) }) - it('should release focus trap', done => { - fixtureEl.innerHTML = '' + it('should release focus trap', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '' - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) - spyOn(modal._focustrap, 'deactivate').and.callThrough() + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) + const spy = spyOn(modal._focustrap, 'deactivate').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - modal.hide() - }) + modalEl.addEventListener('shown.bs.modal', () => { + modal.hide() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modal._focustrap.deactivate).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) }) @@ -733,17 +847,17 @@ describe('Modal', () => { const modalEl = fixtureEl.querySelector('.modal') const modal = new Modal(modalEl) const focustrap = modal._focustrap - spyOn(focustrap, 'deactivate').and.callThrough() + const spyDeactivate = spyOn(focustrap, 'deactivate').and.callThrough() expect(Modal.getInstance(modalEl)).toEqual(modal) - spyOn(EventHandler, 'off') + const spyOff = spyOn(EventHandler, 'off') modal.dispose() expect(Modal.getInstance(modalEl)).toBeNull() - expect(EventHandler.off).toHaveBeenCalledTimes(3) - expect(focustrap.deactivate).toHaveBeenCalled() + expect(spyOff).toHaveBeenCalledTimes(3) + expect(spyDeactivate).toHaveBeenCalled() }) }) @@ -754,255 +868,269 @@ describe('Modal', () => { const modalEl = fixtureEl.querySelector('.modal') const modal = new Modal(modalEl) - spyOn(modal, '_adjustDialog') + const spy = spyOn(modal, '_adjustDialog') modal.handleUpdate() - expect(modal._adjustDialog).toHaveBeenCalled() + expect(spy).toHaveBeenCalled() }) }) describe('data-api', () => { - it('should toggle modal', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + it('should toggle modal', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toEqual('true') + expect(modalEl.getAttribute('role')).toEqual('dialog') + expect(modalEl.getAttribute('aria-hidden')).toBeNull() + expect(modalEl.style.display).toEqual('block') + expect(document.querySelector('.modal-backdrop')).not.toBeNull() + setTimeout(() => trigger.click(), 10) + }) - const modalEl = fixtureEl.querySelector('.modal') - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toEqual('true') - expect(modalEl.getAttribute('role')).toEqual('dialog') - expect(modalEl.getAttribute('aria-hidden')).toBeNull() - expect(modalEl.style.display).toEqual('block') - expect(document.querySelector('.modal-backdrop')).not.toBeNull() - setTimeout(() => trigger.click(), 10) - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toBeNull() + expect(modalEl.getAttribute('role')).toBeNull() + expect(modalEl.getAttribute('aria-hidden')).toEqual('true') + expect(modalEl.style.display).toEqual('none') + expect(document.querySelector('.modal-backdrop')).toBeNull() + resolve() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toBeNull() - expect(modalEl.getAttribute('role')).toBeNull() - expect(modalEl.getAttribute('aria-hidden')).toEqual('true') - expect(modalEl.style.display).toEqual('none') - expect(document.querySelector('.modal-backdrop')).toBeNull() - done() + trigger.click() }) - - trigger.click() }) - it('should not recreate a new modal', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + it('should not recreate a new modal', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - const modalEl = fixtureEl.querySelector('.modal') - const modal = new Modal(modalEl) - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + const modalEl = fixtureEl.querySelector('.modal') + const modal = new Modal(modalEl) + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - spyOn(modal, 'show').and.callThrough() + const spy = spyOn(modal, 'show').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - expect(modal.show).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('shown.bs.modal', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) - trigger.click() + trigger.click() + }) }) - it('should prevent default when the trigger is or ', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + it('should prevent default when the trigger is or ', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + + const spy = spyOn(Event.prototype, 'preventDefault').and.callThrough() + + modalEl.addEventListener('shown.bs.modal', () => { + expect(modalEl.getAttribute('aria-modal')).toEqual('true') + expect(modalEl.getAttribute('role')).toEqual('dialog') + expect(modalEl.getAttribute('aria-hidden')).toBeNull() + expect(modalEl.style.display).toEqual('block') + expect(document.querySelector('.modal-backdrop')).not.toBeNull() + expect(spy).toHaveBeenCalled() + resolve() + }) - const modalEl = fixtureEl.querySelector('.modal') - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - - spyOn(Event.prototype, 'preventDefault').and.callThrough() - - modalEl.addEventListener('shown.bs.modal', () => { - expect(modalEl.getAttribute('aria-modal')).toEqual('true') - expect(modalEl.getAttribute('role')).toEqual('dialog') - expect(modalEl.getAttribute('aria-hidden')).toBeNull() - expect(modalEl.style.display).toEqual('block') - expect(document.querySelector('.modal-backdrop')).not.toBeNull() - expect(Event.prototype.preventDefault).toHaveBeenCalled() - done() + trigger.click() }) - - trigger.click() }) - it('should focus the trigger on hide', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + it('should focus the trigger on hide', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - const modalEl = fixtureEl.querySelector('.modal') - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + const modalEl = fixtureEl.querySelector('.modal') + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - spyOn(trigger, 'focus') + const spy = spyOn(trigger, 'focus') - modalEl.addEventListener('shown.bs.modal', () => { - const modal = Modal.getInstance(modalEl) + modalEl.addEventListener('shown.bs.modal', () => { + const modal = Modal.getInstance(modalEl) - modal.hide() - }) + modal.hide() + }) - const hideListener = () => { - setTimeout(() => { - expect(trigger.focus).toHaveBeenCalled() - done() - }, 20) - } + const hideListener = () => { + setTimeout(() => { + expect(spy).toHaveBeenCalled() + resolve() + }, 20) + } - modalEl.addEventListener('hidden.bs.modal', () => { - hideListener() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + hideListener() + }) - trigger.click() + trigger.click() + }) }) + it('should not prevent default when a click occurred on data-bs-dismiss="modal" where tagName is DIFFERENT than or ', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const modalEl = fixtureEl.querySelector('.modal') + const btnClose = fixtureEl.querySelector('button[data-bs-dismiss="modal"]') + const modal = new Modal(modalEl) + + const spy = spyOn(Event.prototype, 'preventDefault').and.callThrough() + + modalEl.addEventListener('shown.bs.modal', () => { + btnClose.click() + }) - it('should not prevent default when a click occurred on data-bs-dismiss="modal" where tagName is DIFFERENT than or ', done => { - fixtureEl.innerHTML = [ - '' - ].join('') - - const modalEl = fixtureEl.querySelector('.modal') - const btnClose = fixtureEl.querySelector('button[data-bs-dismiss="modal"]') - const modal = new Modal(modalEl) - - spyOn(Event.prototype, 'preventDefault').and.callThrough() - - modalEl.addEventListener('shown.bs.modal', () => { - btnClose.click() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(spy).not.toHaveBeenCalled() + resolve() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(Event.prototype.preventDefault).not.toHaveBeenCalled() - done() + modal.show() }) - - modal.show() }) - it('should prevent default when a click occurred on data-bs-dismiss="modal" where tagName is or ', done => { - fixtureEl.innerHTML = [ - '' - ].join('') + it('should prevent default when a click occurred on data-bs-dismiss="modal" where tagName is or ', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '' + ].join('') - const modalEl = fixtureEl.querySelector('.modal') - const btnClose = fixtureEl.querySelector('a[data-bs-dismiss="modal"]') - const modal = new Modal(modalEl) + const modalEl = fixtureEl.querySelector('.modal') + const btnClose = fixtureEl.querySelector('a[data-bs-dismiss="modal"]') + const modal = new Modal(modalEl) - spyOn(Event.prototype, 'preventDefault').and.callThrough() + const spy = spyOn(Event.prototype, 'preventDefault').and.callThrough() - modalEl.addEventListener('shown.bs.modal', () => { - btnClose.click() - }) + modalEl.addEventListener('shown.bs.modal', () => { + btnClose.click() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - expect(Event.prototype.preventDefault).toHaveBeenCalled() - done() - }) + modalEl.addEventListener('hidden.bs.modal', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) - modal.show() + modal.show() + }) }) + it('should not focus the trigger if the modal is not visible', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - it('should not focus the trigger if the modal is not visible', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + const modalEl = fixtureEl.querySelector('.modal') + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - const modalEl = fixtureEl.querySelector('.modal') - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + const spy = spyOn(trigger, 'focus') - spyOn(trigger, 'focus') + modalEl.addEventListener('shown.bs.modal', () => { + const modal = Modal.getInstance(modalEl) - modalEl.addEventListener('shown.bs.modal', () => { - const modal = Modal.getInstance(modalEl) + modal.hide() + }) - modal.hide() - }) + const hideListener = () => { + setTimeout(() => { + expect(spy).not.toHaveBeenCalled() + resolve() + }, 20) + } - const hideListener = () => { - setTimeout(() => { - expect(trigger.focus).not.toHaveBeenCalled() - done() - }, 20) - } + modalEl.addEventListener('hidden.bs.modal', () => { + hideListener() + }) - modalEl.addEventListener('hidden.bs.modal', () => { - hideListener() + trigger.click() }) - - trigger.click() }) + it('should not focus the trigger if the modal is not shown', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '' + ].join('') - it('should not focus the trigger if the modal is not shown', done => { - fixtureEl.innerHTML = [ - '', - '' - ].join('') + const modalEl = fixtureEl.querySelector('.modal') + const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') - const modalEl = fixtureEl.querySelector('.modal') - const trigger = fixtureEl.querySelector('[data-bs-toggle="modal"]') + const spy = spyOn(trigger, 'focus') - spyOn(trigger, 'focus') + const showListener = () => { + setTimeout(() => { + expect(spy).not.toHaveBeenCalled() + resolve() + }, 10) + } - const showListener = () => { - setTimeout(() => { - expect(trigger.focus).not.toHaveBeenCalled() - done() - }, 10) - } + modalEl.addEventListener('show.bs.modal', event => { + event.preventDefault() + showListener() + }) - modalEl.addEventListener('show.bs.modal', event => { - event.preventDefault() - showListener() + trigger.click() }) - - trigger.click() }) - it('should call hide first, if another modal is open', done => { - fixtureEl.innerHTML = [ - '', - '', - '' - ].join('') - - const trigger2 = fixtureEl.querySelector('button') - const modalEl1 = document.querySelector('#modal1') - const modalEl2 = document.querySelector('#modal2') - const modal1 = new Modal(modalEl1) - - modalEl1.addEventListener('shown.bs.modal', () => { - trigger2.click() - }) - modalEl1.addEventListener('hidden.bs.modal', () => { - expect(Modal.getInstance(modalEl2)).not.toBeNull() - expect(modalEl2.classList.contains('show')).toBeTrue() - done() + it('should call hide first, if another modal is open', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '', + '' + ].join('') + + const trigger2 = fixtureEl.querySelector('button') + const modalEl1 = document.querySelector('#modal1') + const modalEl2 = document.querySelector('#modal2') + const modal1 = new Modal(modalEl1) + + modalEl1.addEventListener('shown.bs.modal', () => { + trigger2.click() + }) + modalEl1.addEventListener('hidden.bs.modal', () => { + expect(Modal.getInstance(modalEl2)).not.toBeNull() + expect(modalEl2).toHaveClass('show') + resolve() + }) + modal1.show() }) - modal1.show() }) }) - describe('jQueryInterface', () => { it('should create a modal', () => { fixtureEl.innerHTML = '' @@ -1026,12 +1154,12 @@ describe('Modal', () => { jQueryMock.elements = [div] jQueryMock.fn.modal.call(jQueryMock, { keyboard: false }) - spyOn(Modal.prototype, 'constructor') - expect(Modal.prototype.constructor).not.toHaveBeenCalledWith(div, { keyboard: false }) + const spy = spyOn(Modal.prototype, 'constructor') + expect(spy).not.toHaveBeenCalledWith(div, { keyboard: false }) const modal = Modal.getInstance(div) expect(modal).not.toBeNull() - expect(modal._config.keyboard).toBe(false) + expect(modal._config.keyboard).toBeFalse() }) it('should not re create a modal', () => { @@ -1071,11 +1199,11 @@ describe('Modal', () => { jQueryMock.fn.modal = Modal.jQueryInterface jQueryMock.elements = [div] - spyOn(modal, 'show') + const spy = spyOn(modal, 'show') jQueryMock.fn.modal.call(jQueryMock, 'show') - expect(modal.show).toHaveBeenCalled() + expect(spy).toHaveBeenCalled() }) it('should not call show method', () => { @@ -1086,11 +1214,11 @@ describe('Modal', () => { jQueryMock.fn.modal = Modal.jQueryInterface jQueryMock.elements = [div] - spyOn(Modal.prototype, 'show') + const spy = spyOn(Modal.prototype, 'show') jQueryMock.fn.modal.call(jQueryMock) - expect(Modal.prototype.show).not.toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() }) }) @@ -1131,7 +1259,7 @@ describe('Modal', () => { const div = fixtureEl.querySelector('div') - expect(Modal.getInstance(div)).toEqual(null) + expect(Modal.getInstance(div)).toBeNull() expect(Modal.getOrCreateInstance(div)).toBeInstanceOf(Modal) }) @@ -1140,13 +1268,13 @@ describe('Modal', () => { const div = fixtureEl.querySelector('div') - expect(Modal.getInstance(div)).toEqual(null) + expect(Modal.getInstance(div)).toBeNull() const modal = Modal.getOrCreateInstance(div, { backdrop: true }) expect(modal).toBeInstanceOf(Modal) - expect(modal._config.backdrop).toEqual(true) + expect(modal._config.backdrop).toBeTrue() }) it('should return the instance when exists without given configuration', () => { @@ -1164,7 +1292,7 @@ describe('Modal', () => { expect(modal).toBeInstanceOf(Modal) expect(modal2).toEqual(modal) - expect(modal2._config.backdrop).toEqual(true) + expect(modal2._config.backdrop).toBeTrue() }) }) }) diff --git a/app/vendor/twbs/bootstrap/js/tests/unit/offcanvas.spec.js b/app/vendor/twbs/bootstrap/js/tests/unit/offcanvas.spec.js index 877d2e7f3..da2fb9748 100644 --- a/app/vendor/twbs/bootstrap/js/tests/unit/offcanvas.spec.js +++ b/app/vendor/twbs/bootstrap/js/tests/unit/offcanvas.spec.js @@ -1,9 +1,7 @@ import Offcanvas from '../../src/offcanvas' import EventHandler from '../../src/dom/event-handler' - -/** Test helpers */ import { clearBodyAndDocument, clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' -import { isVisible } from '../../src/util' +import { isVisible } from '../../src/util/index' import ScrollBarHelper from '../../src/util/scrollbar' describe('Offcanvas', () => { @@ -53,12 +51,12 @@ describe('Offcanvas', () => { const closeEl = fixtureEl.querySelector('a') const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas, 'hide') + const spy = spyOn(offCanvas, 'hide') closeEl.click() - expect(offCanvas._config.keyboard).toBe(true) - expect(offCanvas.hide).toHaveBeenCalled() + expect(offCanvas._config.keyboard).toBeTrue() + expect(spy).toHaveBeenCalled() }) it('should hide if esc is pressed', () => { @@ -69,11 +67,26 @@ describe('Offcanvas', () => { const keyDownEsc = createEvent('keydown') keyDownEsc.key = 'Escape' - spyOn(offCanvas, 'hide') + const spy = spyOn(offCanvas, 'hide') + + offCanvasEl.dispatchEvent(keyDownEsc) + + expect(spy).toHaveBeenCalled() + }) + + it('should hide if esc is pressed and backdrop is static', () => { + fixtureEl.innerHTML = '
' + + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl, { backdrop: 'static' }) + const keyDownEsc = createEvent('keydown') + keyDownEsc.key = 'Escape' + + const spy = spyOn(offCanvas, 'hide') offCanvasEl.dispatchEvent(keyDownEsc) - expect(offCanvas.hide).toHaveBeenCalled() + expect(spy).toHaveBeenCalled() }) it('should not hide if esc is not pressed', () => { @@ -84,66 +97,115 @@ describe('Offcanvas', () => { const keydownTab = createEvent('keydown') keydownTab.key = 'Tab' - spyOn(offCanvas, 'hide') + const spy = spyOn(offCanvas, 'hide') - document.dispatchEvent(keydownTab) + offCanvasEl.dispatchEvent(keydownTab) - expect(offCanvas.hide).not.toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() }) it('should not hide if esc is pressed but with keyboard = false', () => { - fixtureEl.innerHTML = '
' + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl, { keyboard: false }) - const keyDownEsc = createEvent('keydown') - keyDownEsc.key = 'Escape' + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl, { keyboard: false }) + const keyDownEsc = createEvent('keydown') + keyDownEsc.key = 'Escape' + + const spy = spyOn(offCanvas, 'hide') + const hidePreventedSpy = jasmine.createSpy('hidePrevented') + offCanvasEl.addEventListener('hidePrevented.bs.offcanvas', hidePreventedSpy) - spyOn(offCanvas, 'hide') + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvas._config.keyboard).toBeFalse() + offCanvasEl.dispatchEvent(keyDownEsc) - document.dispatchEvent(keyDownEsc) + expect(hidePreventedSpy).toHaveBeenCalled() + expect(spy).not.toHaveBeenCalled() + resolve() + }) - expect(offCanvas._config.keyboard).toBe(false) - expect(offCanvas.hide).not.toHaveBeenCalled() + offCanvas.show() + }) + }) + + it('should not hide if user clicks on static backdrop', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' + + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl, { backdrop: 'static' }) + + const clickEvent = new Event('mousedown', { bubbles: true, cancelable: true }) + const spyClick = spyOn(offCanvas._backdrop._config, 'clickCallback').and.callThrough() + const spyHide = spyOn(offCanvas._backdrop, 'hide').and.callThrough() + const hidePreventedSpy = jasmine.createSpy('hidePrevented') + offCanvasEl.addEventListener('hidePrevented.bs.offcanvas', hidePreventedSpy) + + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(spyClick).toEqual(jasmine.any(Function)) + + offCanvas._backdrop._getElement().dispatchEvent(clickEvent) + expect(hidePreventedSpy).toHaveBeenCalled() + expect(spyHide).not.toHaveBeenCalled() + resolve() + }) + + offCanvas.show() + }) + }) + + it('should call `hide` on resize, if element\'s position is not fixed any more', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' + + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl) + + const spy = spyOn(offCanvas, 'hide').and.callThrough() + + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + const resizeEvent = createEvent('resize') + offCanvasEl.style.removeProperty('position') + + window.dispatchEvent(resizeEvent) + expect(spy).toHaveBeenCalled() + resolve() + }) + + offCanvas.show() + }) }) }) describe('config', () => { it('should have default values', () => { - fixtureEl.innerHTML = [ - '
', - '
' - ].join('') + fixtureEl.innerHTML = '
' const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl) - expect(offCanvas._config.backdrop).toEqual(true) - expect(offCanvas._backdrop._config.isVisible).toEqual(true) - expect(offCanvas._config.keyboard).toEqual(true) - expect(offCanvas._config.scroll).toEqual(false) + expect(offCanvas._config.backdrop).toBeTrue() + expect(offCanvas._backdrop._config.isVisible).toBeTrue() + expect(offCanvas._config.keyboard).toBeTrue() + expect(offCanvas._config.scroll).toBeFalse() }) it('should read data attributes and override default config', () => { - fixtureEl.innerHTML = [ - '
', - '
' - ].join('') + fixtureEl.innerHTML = '
' const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl) - expect(offCanvas._config.backdrop).toEqual(false) - expect(offCanvas._backdrop._config.isVisible).toEqual(false) - expect(offCanvas._config.keyboard).toEqual(false) - expect(offCanvas._config.scroll).toEqual(true) + expect(offCanvas._config.backdrop).toBeFalse() + expect(offCanvas._backdrop._config.isVisible).toBeFalse() + expect(offCanvas._config.keyboard).toBeFalse() + expect(offCanvas._config.scroll).toBeTrue() }) it('given a config object must override data attributes', () => { - fixtureEl.innerHTML = [ - '
', - '
' - ].join('') + fixtureEl.innerHTML = '
' const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl, { @@ -151,90 +213,120 @@ describe('Offcanvas', () => { keyboard: true, scroll: false }) - expect(offCanvas._config.backdrop).toEqual(true) - expect(offCanvas._config.keyboard).toEqual(true) - expect(offCanvas._config.scroll).toEqual(false) + expect(offCanvas._config.backdrop).toBeTrue() + expect(offCanvas._config.keyboard).toBeTrue() + expect(offCanvas._config.scroll).toBeFalse() }) }) - describe('options', () => { - it('if scroll is enabled, should allow body to scroll while offcanvas is open', done => { - fixtureEl.innerHTML = '
' - - spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() - spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl, { scroll: true }) - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(ScrollBarHelper.prototype.hide).not.toHaveBeenCalled() - offCanvas.hide() + describe('options', () => { + it('if scroll is enabled, should allow body to scroll while offcanvas is open', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' + + const spyHide = spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() + const spyReset = spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl, { scroll: true }) + + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(spyHide).not.toHaveBeenCalled() + offCanvas.hide() + }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(spyReset).not.toHaveBeenCalled() + resolve() + }) + offCanvas.show() }) - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(ScrollBarHelper.prototype.reset).not.toHaveBeenCalled() - done() + }) + + it('if scroll is disabled, should call ScrollBarHelper to handle scrollBar on body', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' + + const spyHide = spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() + const spyReset = spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl, { scroll: false }) + + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(spyHide).toHaveBeenCalled() + offCanvas.hide() + }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(spyReset).toHaveBeenCalled() + resolve() + }) + offCanvas.show() }) - offCanvas.show() }) - it('if scroll is disabled, should call ScrollBarHelper to handle scrollBar on body', done => { - fixtureEl.innerHTML = '
' + it('should hide a shown element if user click on backdrop', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - spyOn(ScrollBarHelper.prototype, 'hide').and.callThrough() - spyOn(ScrollBarHelper.prototype, 'reset').and.callThrough() - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl, { scroll: false }) + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl, { backdrop: true }) - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(ScrollBarHelper.prototype.hide).toHaveBeenCalled() - offCanvas.hide() - }) - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(ScrollBarHelper.prototype.reset).toHaveBeenCalled() - done() + const clickEvent = new Event('mousedown', { bubbles: true, cancelable: true }) + const spy = spyOn(offCanvas._backdrop._config, 'clickCallback').and.callThrough() + + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvas._backdrop._config.clickCallback).toEqual(jasmine.any(Function)) + + offCanvas._backdrop._getElement().dispatchEvent(clickEvent) + }) + + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) + + offCanvas.show() }) - offCanvas.show() }) - it('should hide a shown element if user click on backdrop', done => { - fixtureEl.innerHTML = '
' - - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl, { backdrop: true }) + it('should not trap focus if scroll is allowed', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const clickEvent = document.createEvent('MouseEvents') - clickEvent.initEvent('mousedown', true, true) - spyOn(offCanvas._backdrop._config, 'clickCallback').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl, { + scroll: true, + backdrop: false + }) - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(typeof offCanvas._backdrop._config.clickCallback).toBe('function') + const spy = spyOn(offCanvas._focustrap, 'activate').and.callThrough() - offCanvas._backdrop._getElement().dispatchEvent(clickEvent) - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(spy).not.toHaveBeenCalled() + resolve() + }) - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(offCanvas._backdrop._config.clickCallback).toHaveBeenCalled() - done() + offCanvas.show() }) - - offCanvas.show() }) - it('should not trap focus if scroll is allowed', done => { - fixtureEl.innerHTML = '
' + it('should trap focus if scroll is allowed OR backdrop is enabled', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl, { - scroll: true - }) + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl, { + scroll: true, + backdrop: true + }) - spyOn(offCanvas._focustrap, 'activate').and.callThrough() + const spy = spyOn(offCanvas._focustrap, 'activate').and.callThrough() - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvas._focustrap.activate).not.toHaveBeenCalled() - done() - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) - offCanvas.show() + offCanvas.show() + }) }) }) @@ -245,30 +337,57 @@ describe('Offcanvas', () => { const offCanvasEl = fixtureEl.querySelector('.offcanvas') const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas, 'show') + const spy = spyOn(offCanvas, 'show') offCanvas.toggle() - expect(offCanvas.show).toHaveBeenCalled() + expect(spy).toHaveBeenCalled() }) it('should call hide method if show class is present', () => { - fixtureEl.innerHTML = '
' + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl) - offCanvas.show() - expect(offCanvasEl.classList.contains('show')).toBe(true) + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas, 'hide') + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvasEl).toHaveClass('show') + const spy = spyOn(offCanvas, 'hide') - offCanvas.toggle() + offCanvas.toggle() + + expect(spy).toHaveBeenCalled() + resolve() + }) - expect(offCanvas.hide).toHaveBeenCalled() + offCanvas.show() + }) }) }) describe('show', () => { + it('should add `showing` class during opening and `show` class on end', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl) + + offCanvasEl.addEventListener('show.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('show') + }) + + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('showing') + expect(offCanvasEl).toHaveClass('show') + resolve() + }) + + offCanvas.show() + expect(offCanvasEl).toHaveClass('showing') + }) + }) + it('should do nothing if already shown', () => { fixtureEl.innerHTML = '
' @@ -276,166 +395,206 @@ describe('Offcanvas', () => { const offCanvas = new Offcanvas(offCanvasEl) offCanvas.show() - expect(offCanvasEl.classList.contains('show')).toBe(true) + expect(offCanvasEl).toHaveClass('show') - spyOn(offCanvas._backdrop, 'show').and.callThrough() - spyOn(EventHandler, 'trigger').and.callThrough() + const spyShow = spyOn(offCanvas._backdrop, 'show').and.callThrough() + const spyTrigger = spyOn(EventHandler, 'trigger').and.callThrough() offCanvas.show() - expect(EventHandler.trigger).not.toHaveBeenCalled() - expect(offCanvas._backdrop.show).not.toHaveBeenCalled() + expect(spyTrigger).not.toHaveBeenCalled() + expect(spyShow).not.toHaveBeenCalled() }) - it('should show a hidden element', done => { - fixtureEl.innerHTML = '
' + it('should show a hidden element', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._backdrop, 'show').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl) + const spy = spyOn(offCanvas._backdrop, 'show').and.callThrough() - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvasEl.classList.contains('show')).toEqual(true) - expect(offCanvas._backdrop.show).toHaveBeenCalled() - done() - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvasEl).toHaveClass('show') + expect(spy).toHaveBeenCalled() + resolve() + }) - offCanvas.show() + offCanvas.show() + }) }) - it('should not fire shown when show is prevented', done => { - fixtureEl.innerHTML = '
' + it('should not fire shown when show is prevented', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._backdrop, 'show').and.callThrough() - - const expectEnd = () => { - setTimeout(() => { - expect(offCanvas._backdrop.show).not.toHaveBeenCalled() - done() - }, 10) - } - - offCanvasEl.addEventListener('show.bs.offcanvas', event => { - event.preventDefault() - expectEnd() - }) + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl) + const spy = spyOn(offCanvas._backdrop, 'show').and.callThrough() - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - throw new Error('should not fire shown event') - }) + const expectEnd = () => { + setTimeout(() => { + expect(spy).not.toHaveBeenCalled() + resolve() + }, 10) + } - offCanvas.show() + offCanvasEl.addEventListener('show.bs.offcanvas', event => { + event.preventDefault() + expectEnd() + }) + + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + reject(new Error('should not fire shown event')) + }) + + offCanvas.show() + }) }) - it('on window load, should make visible an offcanvas element, if its markup contains class "show"', done => { - fixtureEl.innerHTML = '
' + it('on window load, should make visible an offcanvas element, if its markup contains class "show"', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - spyOn(Offcanvas.prototype, 'show').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('div') + const spy = spyOn(Offcanvas.prototype, 'show').and.callThrough() - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - done() - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + resolve() + }) - window.dispatchEvent(createEvent('load')) + window.dispatchEvent(createEvent('load')) - const instance = Offcanvas.getInstance(offCanvasEl) - expect(instance).not.toBeNull() - expect(Offcanvas.prototype.show).toHaveBeenCalled() + const instance = Offcanvas.getInstance(offCanvasEl) + expect(instance).not.toBeNull() + expect(spy).toHaveBeenCalled() + }) }) - it('should trap focus', done => { - fixtureEl.innerHTML = '
' + it('should trap focus', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('.offcanvas') - const offCanvas = new Offcanvas(offCanvasEl) + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._focustrap, 'activate').and.callThrough() + const spy = spyOn(offCanvas._focustrap, 'activate').and.callThrough() - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvas._focustrap.activate).toHaveBeenCalled() - done() - }) + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) - offCanvas.show() + offCanvas.show() + }) }) }) describe('hide', () => { + it('should add `hiding` class during closing and remover `show` & `hiding` classes on end', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' + const offCanvasEl = fixtureEl.querySelector('.offcanvas') + const offCanvas = new Offcanvas(offCanvasEl) + + offCanvasEl.addEventListener('hide.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('showing') + expect(offCanvasEl).toHaveClass('show') + }) + + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('hiding') + expect(offCanvasEl).not.toHaveClass('show') + resolve() + }) + + offCanvas.show() + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + offCanvas.hide() + expect(offCanvasEl).not.toHaveClass('showing') + expect(offCanvasEl).toHaveClass('hiding') + }) + }) + }) + it('should do nothing if already shown', () => { fixtureEl.innerHTML = '
' - spyOn(EventHandler, 'trigger').and.callThrough() + const spyTrigger = spyOn(EventHandler, 'trigger').and.callThrough() const offCanvasEl = fixtureEl.querySelector('div') const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._backdrop, 'hide').and.callThrough() + const spyHide = spyOn(offCanvas._backdrop, 'hide').and.callThrough() offCanvas.hide() - expect(offCanvas._backdrop.hide).not.toHaveBeenCalled() - expect(EventHandler.trigger).not.toHaveBeenCalled() + expect(spyHide).not.toHaveBeenCalled() + expect(spyTrigger).not.toHaveBeenCalled() }) - it('should hide a shown element', done => { - fixtureEl.innerHTML = '
' + it('should hide a shown element', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._backdrop, 'hide').and.callThrough() - offCanvas.show() + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl) + const spy = spyOn(offCanvas._backdrop, 'hide').and.callThrough() + offCanvas.show() - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(offCanvasEl.classList.contains('show')).toEqual(false) - expect(offCanvas._backdrop.hide).toHaveBeenCalled() - done() - }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(offCanvasEl).not.toHaveClass('show') + expect(spy).toHaveBeenCalled() + resolve() + }) - offCanvas.hide() + offCanvas.hide() + }) }) - it('should not fire hidden when hide is prevented', done => { - fixtureEl.innerHTML = '
' + it('should not fire hidden when hide is prevented', () => { + return new Promise((resolve, reject) => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._backdrop, 'hide').and.callThrough() + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl) + const spy = spyOn(offCanvas._backdrop, 'hide').and.callThrough() - offCanvas.show() + offCanvas.show() - const expectEnd = () => { - setTimeout(() => { - expect(offCanvas._backdrop.hide).not.toHaveBeenCalled() - done() - }, 10) - } + const expectEnd = () => { + setTimeout(() => { + expect(spy).not.toHaveBeenCalled() + resolve() + }, 10) + } - offCanvasEl.addEventListener('hide.bs.offcanvas', event => { - event.preventDefault() - expectEnd() - }) + offCanvasEl.addEventListener('hide.bs.offcanvas', event => { + event.preventDefault() + expectEnd() + }) - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - throw new Error('should not fire hidden event') - }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + reject(new Error('should not fire hidden event')) + }) - offCanvas.hide() + offCanvas.hide() + }) }) - it('should release focus trap', done => { - fixtureEl.innerHTML = '
' + it('should release focus trap', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = '
' - const offCanvasEl = fixtureEl.querySelector('div') - const offCanvas = new Offcanvas(offCanvasEl) - spyOn(offCanvas._focustrap, 'deactivate').and.callThrough() - offCanvas.show() + const offCanvasEl = fixtureEl.querySelector('div') + const offCanvas = new Offcanvas(offCanvasEl) + const spy = spyOn(offCanvas._focustrap, 'deactivate').and.callThrough() + offCanvas.show() - offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { - expect(offCanvas._focustrap.deactivate).toHaveBeenCalled() - done() - }) + offCanvasEl.addEventListener('hidden.bs.offcanvas', () => { + expect(spy).toHaveBeenCalled() + resolve() + }) - offCanvas.hide() + offCanvas.hide() + }) }) }) @@ -446,41 +605,41 @@ describe('Offcanvas', () => { const offCanvasEl = fixtureEl.querySelector('div') const offCanvas = new Offcanvas(offCanvasEl) const backdrop = offCanvas._backdrop - spyOn(backdrop, 'dispose').and.callThrough() + const spyDispose = spyOn(backdrop, 'dispose').and.callThrough() const focustrap = offCanvas._focustrap - spyOn(focustrap, 'deactivate').and.callThrough() + const spyDeactivate = spyOn(focustrap, 'deactivate').and.callThrough() expect(Offcanvas.getInstance(offCanvasEl)).toEqual(offCanvas) - spyOn(EventHandler, 'off') - offCanvas.dispose() - expect(backdrop.dispose).toHaveBeenCalled() + expect(spyDispose).toHaveBeenCalled() expect(offCanvas._backdrop).toBeNull() - expect(focustrap.deactivate).toHaveBeenCalled() + expect(spyDeactivate).toHaveBeenCalled() expect(offCanvas._focustrap).toBeNull() - expect(Offcanvas.getInstance(offCanvasEl)).toEqual(null) + expect(Offcanvas.getInstance(offCanvasEl)).toBeNull() }) }) describe('data-api', () => { - it('should not prevent event for input', done => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') - - const target = fixtureEl.querySelector('input') - const offCanvasEl = fixtureEl.querySelector('#offcanvasdiv1') - - offCanvasEl.addEventListener('shown.bs.offcanvas', () => { - expect(offCanvasEl.classList.contains('show')).toEqual(true) - expect(target.checked).toEqual(true) - done() + it('should not prevent event for input', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const target = fixtureEl.querySelector('input') + const offCanvasEl = fixtureEl.querySelector('#offcanvasdiv1') + + offCanvasEl.addEventListener('shown.bs.offcanvas', () => { + expect(offCanvasEl).toHaveClass('show') + expect(target.checked).toBeTrue() + resolve() + }) + + target.click() }) - - target.click() }) it('should not call toggle on disabled elements', () => { @@ -491,83 +650,89 @@ describe('Offcanvas', () => { const target = fixtureEl.querySelector('a') - spyOn(Offcanvas.prototype, 'toggle') + const spy = spyOn(Offcanvas.prototype, 'toggle') target.click() - expect(Offcanvas.prototype.toggle).not.toHaveBeenCalled() - }) - - it('should call hide first, if another offcanvas is open', done => { - fixtureEl.innerHTML = [ - '', - '
', - '
' - ].join('') - - const trigger2 = fixtureEl.querySelector('#btn2') - const offcanvasEl1 = document.querySelector('#offcanvas1') - const offcanvasEl2 = document.querySelector('#offcanvas2') - const offcanvas1 = new Offcanvas(offcanvasEl1) - - offcanvasEl1.addEventListener('shown.bs.offcanvas', () => { - trigger2.click() + expect(spy).not.toHaveBeenCalled() + }) + + it('should call hide first, if another offcanvas is open', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
', + '
' + ].join('') + + const trigger2 = fixtureEl.querySelector('#btn2') + const offcanvasEl1 = document.querySelector('#offcanvas1') + const offcanvasEl2 = document.querySelector('#offcanvas2') + const offcanvas1 = new Offcanvas(offcanvasEl1) + + offcanvasEl1.addEventListener('shown.bs.offcanvas', () => { + trigger2.click() + }) + offcanvasEl1.addEventListener('hidden.bs.offcanvas', () => { + expect(Offcanvas.getInstance(offcanvasEl2)).not.toBeNull() + resolve() + }) + offcanvas1.show() }) - offcanvasEl1.addEventListener('hidden.bs.offcanvas', () => { - expect(Offcanvas.getInstance(offcanvasEl2)).not.toBeNull() - done() - }) - offcanvas1.show() }) - it('should focus on trigger element after closing offcanvas', done => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') - - const trigger = fixtureEl.querySelector('#btn') - const offcanvasEl = fixtureEl.querySelector('#offcanvas') - const offcanvas = new Offcanvas(offcanvasEl) - spyOn(trigger, 'focus') - - offcanvasEl.addEventListener('shown.bs.offcanvas', () => { - offcanvas.hide() + it('should focus on trigger element after closing offcanvas', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const trigger = fixtureEl.querySelector('#btn') + const offcanvasEl = fixtureEl.querySelector('#offcanvas') + const offcanvas = new Offcanvas(offcanvasEl) + const spy = spyOn(trigger, 'focus') + + offcanvasEl.addEventListener('shown.bs.offcanvas', () => { + offcanvas.hide() + }) + offcanvasEl.addEventListener('hidden.bs.offcanvas', () => { + setTimeout(() => { + expect(spy).toHaveBeenCalled() + resolve() + }, 5) + }) + + trigger.click() }) - offcanvasEl.addEventListener('hidden.bs.offcanvas', () => { - setTimeout(() => { - expect(trigger.focus).toHaveBeenCalled() - done() - }, 5) - }) - - trigger.click() }) - it('should not focus on trigger element after closing offcanvas, if it is not visible', done => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') - - const trigger = fixtureEl.querySelector('#btn') - const offcanvasEl = fixtureEl.querySelector('#offcanvas') - const offcanvas = new Offcanvas(offcanvasEl) - spyOn(trigger, 'focus') - - offcanvasEl.addEventListener('shown.bs.offcanvas', () => { - trigger.style.display = 'none' - offcanvas.hide() - }) - offcanvasEl.addEventListener('hidden.bs.offcanvas', () => { - setTimeout(() => { - expect(isVisible(trigger)).toBe(false) - expect(trigger.focus).not.toHaveBeenCalled() - done() - }, 5) + it('should not focus on trigger element after closing offcanvas, if it is not visible', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const trigger = fixtureEl.querySelector('#btn') + const offcanvasEl = fixtureEl.querySelector('#offcanvas') + const offcanvas = new Offcanvas(offcanvasEl) + const spy = spyOn(trigger, 'focus') + + offcanvasEl.addEventListener('shown.bs.offcanvas', () => { + trigger.style.display = 'none' + offcanvas.hide() + }) + offcanvasEl.addEventListener('hidden.bs.offcanvas', () => { + setTimeout(() => { + expect(isVisible(trigger)).toBeFalse() + expect(spy).not.toHaveBeenCalled() + resolve() + }, 5) + }) + + trigger.click() }) - - trigger.click() }) }) @@ -646,13 +811,13 @@ describe('Offcanvas', () => { const div = fixtureEl.querySelector('div') - spyOn(Offcanvas.prototype, 'show') + const spy = spyOn(Offcanvas.prototype, 'show') jQueryMock.fn.offcanvas = Offcanvas.jQueryInterface jQueryMock.elements = [div] jQueryMock.fn.offcanvas.call(jQueryMock, 'show') - expect(Offcanvas.prototype.show).toHaveBeenCalled() + expect(spy).toHaveBeenCalled() }) it('should create a offcanvas with given config', () => { @@ -667,7 +832,7 @@ describe('Offcanvas', () => { const offcanvas = Offcanvas.getInstance(div) expect(offcanvas).not.toBeNull() - expect(offcanvas._config.scroll).toBe(true) + expect(offcanvas._config.scroll).toBeTrue() }) }) @@ -708,7 +873,7 @@ describe('Offcanvas', () => { const div = fixtureEl.querySelector('div') - expect(Offcanvas.getInstance(div)).toEqual(null) + expect(Offcanvas.getInstance(div)).toBeNull() expect(Offcanvas.getOrCreateInstance(div)).toBeInstanceOf(Offcanvas) }) @@ -717,13 +882,13 @@ describe('Offcanvas', () => { const div = fixtureEl.querySelector('div') - expect(Offcanvas.getInstance(div)).toEqual(null) + expect(Offcanvas.getInstance(div)).toBeNull() const offcanvas = Offcanvas.getOrCreateInstance(div, { scroll: true }) expect(offcanvas).toBeInstanceOf(Offcanvas) - expect(offcanvas._config.scroll).toEqual(true) + expect(offcanvas._config.scroll).toBeTrue() }) it('should return the instance when exists without given configuration', () => { @@ -741,7 +906,7 @@ describe('Offcanvas', () => { expect(offcanvas).toBeInstanceOf(Offcanvas) expect(offcanvas2).toEqual(offcanvas) - expect(offcanvas2._config.scroll).toEqual(true) + expect(offcanvas2._config.scroll).toBeTrue() }) }) }) diff --git a/app/vendor/twbs/bootstrap/js/tests/unit/popover.spec.js b/app/vendor/twbs/bootstrap/js/tests/unit/popover.spec.js index c54fc49ee..baf691cdc 100644 --- a/app/vendor/twbs/bootstrap/js/tests/unit/popover.spec.js +++ b/app/vendor/twbs/bootstrap/js/tests/unit/popover.spec.js @@ -1,6 +1,5 @@ import Popover from '../../src/popover' - -/** Test helpers */ +import EventHandler from '../../src/dom/event-handler' import { clearFixture, getFixture, jQueryMock } from '../helpers/fixture' describe('Popover', () => { @@ -15,9 +14,9 @@ describe('Popover', () => { const popoverList = document.querySelectorAll('.popover') - popoverList.forEach(popoverEl => { + for (const popoverEl of popoverList) { popoverEl.remove() - }) + } }) describe('VERSION', () => { @@ -44,12 +43,6 @@ describe('Popover', () => { }) }) - describe('Event', () => { - it('should return plugin events', () => { - expect(Popover.Event).toEqual(jasmine.any(Object)) - }) - }) - describe('EVENT_KEY', () => { it('should return plugin event key', () => { expect(Popover.EVENT_KEY).toEqual('.bs.popover') @@ -63,165 +56,210 @@ describe('Popover', () => { }) describe('show', () => { - it('should show a popover', done => { - fixtureEl.innerHTML = 'BS twitter' - - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl) + it('should show a popover', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'BS twitter' - popoverEl.addEventListener('shown.bs.popover', () => { - expect(document.querySelector('.popover')).not.toBeNull() - done() - }) - - popover.show() - }) - - it('should set title and content from functions', done => { - fixtureEl.innerHTML = 'BS twitter' - - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl, { - title: () => 'Bootstrap', - content: () => 'loves writing tests (╯°□°)╯︵ ┻━┻' - }) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl) - popoverEl.addEventListener('shown.bs.popover', () => { - const popoverDisplayed = document.querySelector('.popover') + popoverEl.addEventListener('shown.bs.popover', () => { + expect(document.querySelector('.popover')).not.toBeNull() + resolve() + }) - expect(popoverDisplayed).not.toBeNull() - expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Bootstrap') - expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('loves writing tests (╯°□°)╯︵ ┻━┻') - done() + popover.show() }) - - popover.show() }) - it('should show a popover with just content', done => { - fixtureEl.innerHTML = 'BS twitter' + it('should set title and content from functions', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'BS twitter' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl, { - content: 'Popover content' - }) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl, { + title: () => 'Bootstrap', + content: () => 'loves writing tests (╯°□°)╯︵ ┻━┻' + }) - popoverEl.addEventListener('shown.bs.popover', () => { - const popoverDisplayed = document.querySelector('.popover') + popoverEl.addEventListener('shown.bs.popover', () => { + const popoverDisplayed = document.querySelector('.popover') - expect(popoverDisplayed).not.toBeNull() - expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Popover content') - done() - }) + expect(popoverDisplayed).not.toBeNull() + expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Bootstrap') + expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('loves writing tests (╯°□°)╯︵ ┻━┻') + resolve() + }) - popover.show() + popover.show() + }) }) - it('should show a popover with just content without having header', done => { - fixtureEl.innerHTML = 'Nice link' + it('should show a popover with just content without having header', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'Nice link' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl, { - content: 'Some beautiful content :)' - }) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl, { + content: 'Some beautiful content :)' + }) - popoverEl.addEventListener('shown.bs.popover', () => { - const popoverDisplayed = document.querySelector('.popover') + popoverEl.addEventListener('shown.bs.popover', () => { + const popoverDisplayed = document.querySelector('.popover') - expect(popoverDisplayed).not.toBeNull() - expect(popoverDisplayed.querySelector('.popover-header')).toBeNull() - expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Some beautiful content :)') - done() - }) + expect(popoverDisplayed).not.toBeNull() + expect(popoverDisplayed.querySelector('.popover-header')).toBeNull() + expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Some beautiful content :)') + resolve() + }) - popover.show() + popover.show() + }) }) - it('should show a popover with just title without having body', done => { - fixtureEl.innerHTML = 'Nice link' + it('should show a popover with just title without having body', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'Nice link' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl, { - title: 'Title, which does not require content' - }) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl, { + title: 'Title which does not require content' + }) - popoverEl.addEventListener('shown.bs.popover', () => { - const popoverDisplayed = document.querySelector('.popover') + popoverEl.addEventListener('shown.bs.popover', () => { + const popoverDisplayed = document.querySelector('.popover') - expect(popoverDisplayed).not.toBeNull() - expect(popoverDisplayed.querySelector('.popover-body')).toBeNull() - expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Title, which does not require content') - done() - }) + expect(popoverDisplayed).not.toBeNull() + expect(popoverDisplayed.querySelector('.popover-body')).toBeNull() + expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Title which does not require content') + resolve() + }) - popover.show() + popover.show() + }) }) - it('should call setContent once', done => { - fixtureEl.innerHTML = 'BS twitter' + it('should show a popover with just title without having body using data-attribute to get config', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'Nice link' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl, { - content: 'Popover content' - }) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl) - const spy = spyOn(popover, 'setContent').and.callThrough() - let times = 1 + popoverEl.addEventListener('shown.bs.popover', () => { + const popoverDisplayed = document.querySelector('.popover') + + expect(popoverDisplayed).not.toBeNull() + expect(popoverDisplayed.querySelector('.popover-body')).toBeNull() + expect(popoverDisplayed.querySelector('.popover-header').textContent).toEqual('Title which does not require content') + resolve() + }) - popoverEl.addEventListener('hidden.bs.popover', () => { popover.show() }) + }) - popoverEl.addEventListener('shown.bs.popover', () => { - const popoverDisplayed = document.querySelector('.popover') + it('should NOT show a popover without `title` and `content`', () => { + fixtureEl.innerHTML = 'Nice link' - expect(popoverDisplayed).not.toBeNull() - expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Popover content') - expect(spy).toHaveBeenCalledTimes(1) - if (times > 1) { - done() - } + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl, { animation: false }) + const spy = spyOn(EventHandler, 'trigger').and.callThrough() - times++ - popover.hide() - }) popover.show() + + expect(spy).not.toHaveBeenCalledWith(popoverEl, Popover.eventName('show')) + expect(document.querySelector('.popover')).toBeNull() }) - it('should show a popover with provided custom class', done => { + it('"setContent" should keep the initial template', () => { fixtureEl.innerHTML = 'BS twitter' const popoverEl = fixtureEl.querySelector('a') const popover = new Popover(popoverEl) - popoverEl.addEventListener('shown.bs.popover', () => { - const tip = document.querySelector('.popover') - expect(tip).not.toBeNull() - expect(tip.classList.contains('custom-class')).toBeTrue() - done() + popover.setContent({ '.tooltip-inner': 'foo' }) + const tip = popover._getTipElement() + + expect(tip).toHaveClass('popover') + expect(tip).toHaveClass('bs-popover-auto') + expect(tip.querySelector('.popover-arrow')).not.toBeNull() + expect(tip.querySelector('.popover-header')).not.toBeNull() + expect(tip.querySelector('.popover-body')).not.toBeNull() + }) + + it('should call setContent once', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'BS twitter' + + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl, { + content: 'Popover content' + }) + expect(popover._templateFactory).toBeNull() + let spy = null + let times = 1 + + popoverEl.addEventListener('hidden.bs.popover', () => { + popover.show() + }) + + popoverEl.addEventListener('shown.bs.popover', () => { + spy = spy || spyOn(popover._templateFactory, 'constructor').and.callThrough() + const popoverDisplayed = document.querySelector('.popover') + + expect(popoverDisplayed).not.toBeNull() + expect(popoverDisplayed.querySelector('.popover-body').textContent).toEqual('Popover content') + expect(spy).toHaveBeenCalledTimes(0) + if (times > 1) { + resolve() + } + + times++ + popover.hide() + }) + popover.show() }) + }) - popover.show() + it('should show a popover with provided custom class', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'BS twitter' + + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl) + + popoverEl.addEventListener('shown.bs.popover', () => { + const tip = document.querySelector('.popover') + expect(tip).not.toBeNull() + expect(tip).toHaveClass('custom-class') + resolve() + }) + + popover.show() + }) }) }) describe('hide', () => { - it('should hide a popover', done => { - fixtureEl.innerHTML = 'BS twitter' + it('should hide a popover', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = 'BS twitter' - const popoverEl = fixtureEl.querySelector('a') - const popover = new Popover(popoverEl) + const popoverEl = fixtureEl.querySelector('a') + const popover = new Popover(popoverEl) - popoverEl.addEventListener('shown.bs.popover', () => { - popover.hide() - }) + popoverEl.addEventListener('shown.bs.popover', () => { + popover.hide() + }) - popoverEl.addEventListener('hidden.bs.popover', () => { - expect(document.querySelector('.popover')).toBeNull() - done() - }) + popoverEl.addEventListener('hidden.bs.popover', () => { + expect(document.querySelector('.popover')).toBeNull() + resolve() + }) - popover.show() + popover.show() + }) }) }) @@ -291,11 +329,11 @@ describe('Popover', () => { jQueryMock.fn.popover = Popover.jQueryInterface jQueryMock.elements = [popoverEl] - spyOn(popover, 'show') + const spy = spyOn(popover, 'show') jQueryMock.fn.popover.call(jQueryMock, 'show') - expect(popover.show).toHaveBeenCalled() + expect(spy).toHaveBeenCalled() }) }) @@ -315,7 +353,7 @@ describe('Popover', () => { const popoverEl = fixtureEl.querySelector('a') - expect(Popover.getInstance(popoverEl)).toEqual(null) + expect(Popover.getInstance(popoverEl)).toBeNull() }) }) @@ -336,7 +374,7 @@ describe('Popover', () => { const div = fixtureEl.querySelector('div') - expect(Popover.getInstance(div)).toEqual(null) + expect(Popover.getInstance(div)).toBeNull() expect(Popover.getOrCreateInstance(div)).toBeInstanceOf(Popover) }) @@ -345,7 +383,7 @@ describe('Popover', () => { const div = fixtureEl.querySelector('div') - expect(Popover.getInstance(div)).toEqual(null) + expect(Popover.getInstance(div)).toBeNull() const popover = Popover.getOrCreateInstance(div, { placement: 'top' }) diff --git a/app/vendor/twbs/bootstrap/js/tests/unit/scrollspy.spec.js b/app/vendor/twbs/bootstrap/js/tests/unit/scrollspy.spec.js index ad44d5b3c..c7951e6ff 100644 --- a/app/vendor/twbs/bootstrap/js/tests/unit/scrollspy.spec.js +++ b/app/vendor/twbs/bootstrap/js/tests/unit/scrollspy.spec.js @@ -1,30 +1,71 @@ import ScrollSpy from '../../src/scrollspy' -import Manipulator from '../../src/dom/manipulator' /** Test helpers */ -import { getFixture, clearFixture, createEvent, jQueryMock } from '../helpers/fixture' +import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture' +import EventHandler from '../../src/dom/event-handler' describe('ScrollSpy', () => { let fixtureEl - const testElementIsActiveAfterScroll = ({ elementSelector, targetSelector, contentEl, scrollSpy, spy, cb }) => { + const getElementScrollSpy = element => element.scrollTo ? + spyOn(element, 'scrollTo').and.callThrough() : + spyOnProperty(element, 'scrollTop', 'set').and.callThrough() + + const scrollTo = (el, height) => { + el.scrollTop = height + } + + const onScrollStop = (callback, element, timeout = 30) => { + let handle = null + const onScroll = function () { + if (handle) { + window.clearTimeout(handle) + } + + handle = setTimeout(() => { + element.removeEventListener('scroll', onScroll) + callback() + }, timeout + 1) + } + + element.addEventListener('scroll', onScroll) + } + + const getDummyFixture = () => { + return [ + '', + '
', + '
div 1
', + '
' + ].join('') + } + + const testElementIsActiveAfterScroll = ({ elementSelector, targetSelector, contentEl, scrollSpy, cb }) => { const element = fixtureEl.querySelector(elementSelector) const target = fixtureEl.querySelector(targetSelector) - // add top padding to fix Chrome on Android failures - const paddingTop = 5 - const scrollHeight = Math.ceil(contentEl.scrollTop + Manipulator.position(target).top) + paddingTop - - function listener() { - expect(element.classList.contains('active')).toEqual(true) - contentEl.removeEventListener('scroll', listener) - expect(scrollSpy._process).toHaveBeenCalled() - spy.calls.reset() + const paddingTop = 0 + const parentOffset = getComputedStyle(contentEl).getPropertyValue('position') === 'relative' ? 0 : contentEl.offsetTop + const scrollHeight = (target.offsetTop - parentOffset) + paddingTop + + contentEl.addEventListener('activate.bs.scrollspy', event => { + if (scrollSpy._activeTarget !== element) { + return + } + + expect(element).toHaveClass('active') + expect(scrollSpy._activeTarget).toEqual(element) + expect(event.relatedTarget).toEqual(element) cb() - } + }) - contentEl.addEventListener('scroll', listener) - contentEl.scrollTop = scrollHeight + setTimeout(() => { // in case we scroll something before the test + scrollTo(contentEl, scrollHeight) + }, 100) } beforeAll(() => { @@ -55,28 +96,25 @@ describe('ScrollSpy', () => { describe('constructor', () => { it('should take care of element either passed as a CSS selector or DOM element', () => { - fixtureEl.innerHTML = '
' + fixtureEl.innerHTML = getDummyFixture() - const sSpyEl = fixtureEl.querySelector('#navigation') - const sSpyBySelector = new ScrollSpy('#navigation') + const sSpyEl = fixtureEl.querySelector('.content') + const sSpyBySelector = new ScrollSpy('.content') const sSpyByElement = new ScrollSpy(sSpyEl) expect(sSpyBySelector._element).toEqual(sSpyEl) expect(sSpyByElement._element).toEqual(sSpyEl) }) - it('should not process element without target', () => { + it('should null, if element is not scrollable', () => { fixtureEl.innerHTML = [ '', - '
', - '
', - '
', + '
', + '
test
', '
' ].join('') @@ -84,533 +122,567 @@ describe('ScrollSpy', () => { target: '#navigation' }) - expect(scrollSpy._targets.length).toEqual(2) + expect(scrollSpy._observer.root).toBeNull() + expect(scrollSpy._rootElement).toBeNull() }) - it('should only switch "active" class on current target', done => { + it('should respect threshold option', () => { fixtureEl.innerHTML = [ - '
', - '
', - '
', - '
', - ' ', - '
', - '
', - '
', - '
', - '
', - '

Overview

', - '

', - '
', - '
', - '

Detail

', - '

', - '
', - '
', + '', + '
', + ' ', '
' ].join('') - const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example') - const rootEl = fixtureEl.querySelector('#root') - const scrollSpy = new ScrollSpy(scrollSpyEl, { - target: 'ss-target' - }) - - spyOn(scrollSpy, '_process').and.callThrough() - - scrollSpyEl.addEventListener('scroll', () => { - expect(rootEl.classList.contains('active')).toEqual(true) - expect(scrollSpy._process).toHaveBeenCalled() - done() + const scrollSpy = new ScrollSpy('#content', { + target: '#navigation', + threshold: [1] }) - scrollSpyEl.scrollTop = 350 + expect(scrollSpy._observer.thresholds).toEqual([1]) }) - it('should only switch "active" class on current target specified w element', done => { + it('should respect threshold option markup', () => { fixtureEl.innerHTML = [ - '
', - '
', - '
', - '
', - ' ', - '
', - '
', - '
', - '
', - '
', - '

Overview

', - '

', - '
', - '
', - '

Detail

', - '

', - '
', - '
', + '', + '
', + ' ', '
' ].join('') - const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example') - const rootEl = fixtureEl.querySelector('#root') - const scrollSpy = new ScrollSpy(scrollSpyEl, { - target: fixtureEl.querySelector('#ss-target') + const scrollSpy = new ScrollSpy('#content', { + target: '#navigation' }) - spyOn(scrollSpy, '_process').and.callThrough() - - scrollSpyEl.addEventListener('scroll', () => { - expect(rootEl.classList.contains('active')).toEqual(true) - expect(scrollSpy._process).toHaveBeenCalled() - done() - }) + // See https://stackoverflow.com/a/45592926 + const expectToBeCloseToArray = (actual, expected) => { + expect(actual.length).toBe(expected.length) + for (const x of actual) { + const i = actual.indexOf(x) + expect(x).withContext(`[${i}]`).toBeCloseTo(expected[i]) + } + } - scrollSpyEl.scrollTop = 350 + expectToBeCloseToArray(scrollSpy._observer.thresholds, [0, 0.2, 1]) }) - it('should correctly select middle navigation option when large offset is used', done => { + it('should not take count to not visible sections', () => { fixtureEl.innerHTML = [ - '', '', '
', - '
', - '
', - '
', + '
test
', + ' ', + ' ', '
' ].join('') - const contentEl = fixtureEl.querySelector('#content') - const scrollSpy = new ScrollSpy(contentEl, { - target: '#navigation', - offset: Manipulator.position(contentEl).top - }) - - spyOn(scrollSpy, '_process').and.callThrough() - - contentEl.addEventListener('scroll', () => { - expect(fixtureEl.querySelector('#one-link').classList.contains('active')).toEqual(false) - expect(fixtureEl.querySelector('#two-link').classList.contains('active')).toEqual(true) - expect(fixtureEl.querySelector('#three-link').classList.contains('active')).toEqual(false) - expect(scrollSpy._process).toHaveBeenCalled() - done() + const scrollSpy = new ScrollSpy(fixtureEl.querySelector('#content'), { + target: '#navigation' }) - contentEl.scrollTop = 550 + expect(scrollSpy._observableSections.size).toBe(1) + expect(scrollSpy._targetLinks.size).toBe(1) }) - it('should add the active class to the correct element', done => { + it('should not process element without target', () => { fixtureEl.innerHTML = [ - '
- - - - - - + diff --git a/app/vendor/twbs/bootstrap/js/tests/visual/dropdown.html b/app/vendor/twbs/bootstrap/js/tests/visual/dropdown.html index f1dd705f3..04cf06d7b 100644 --- a/app/vendor/twbs/bootstrap/js/tests/visual/dropdown.html +++ b/app/vendor/twbs/bootstrap/js/tests/visual/dropdown.html @@ -10,7 +10,7 @@

Dropdown Bootstrap Visual Test

-
-
+
Dropup split align end
-
+
Dropend split
- - -
+
Dropstart split
- - -{{< /example >}} - -{{< callout warning >}} -When an alert is dismissed, the element is completely removed from the page structure. If a keyboard user dismisses the alert using the close button, their focus will suddenly be lost and, depending on the browser, reset to the start of the page/document. For this reason, we recommend including additional JavaScript that listens for the `closed.bs.alert` event and programmatically sets `focus()` to the most appropriate location in the page. If you're planning to move focus to a non-interactive element that normally does not receive focus, make sure to add `tabindex="-1"` to the element. -{{< /callout >}} - -## Sass - -### Variables - -{{< scss-docs name="alert-variables" file="scss/_variables.scss" >}} - -### Variant mixin - -Used in combination with `$theme-colors` to create contextual modifier classes for our alerts. - -{{< scss-docs name="alert-variant-mixin" file="scss/mixins/_alert.scss" >}} - -### Loop - -Loop that generates the modifier classes with the `alert-variant()` mixin. - -{{< scss-docs name="alert-modifiers" file="scss/_alert.scss" >}} - -## JavaScript behavior - -### Initialize - -Initialize elements as alerts - -```js -var alertList = document.querySelectorAll('.alert') -var alerts = [].slice.call(alertList).map(function (element) { - return new bootstrap.Alert(element) -}) -``` - -{{< callout info >}} -For the sole purpose of dismissing an alert, it isn't necessary to initialize the component manually via the JS API. By making use of `data-bs-dismiss="alert"`, the component will be initialized automatically and properly dismissed. - -See the [triggers](#triggers) section for more details. -{{< /callout >}} - -### Triggers - -{{% js-dismiss "alert" %}} - -**Note that closing an alert will remove it from the DOM.** - -### Methods - - - - - - - - - - - - - - - - - - - - - - - - - - -
MethodDescription
- close - - Closes an alert by removing it from the DOM. If the .fade and .show classes are present on the element, the alert will fade out before it is removed. -
- dispose - - Destroys an element's alert. (Removes stored data on the DOM element) -
- getInstance - - Static method which allows you to get the alert instance associated to a DOM element, you can use it like this: bootstrap.Alert.getInstance(alert) -
- getOrCreateInstance - - Static method which returns an alert instance associated to a DOM element or create a new one in case it wasn't initialized. - You can use it like this: bootstrap.Alert.getOrCreateInstance(element) -
- -```js -var alertNode = document.querySelector('.alert') -var alert = bootstrap.Alert.getInstance(alertNode) -alert.close() -``` - -### Events - -Bootstrap's alert plugin exposes a few events for hooking into alert functionality. - - - - - - - - - - - - - - - - - - -
EventDescription
close.bs.alert - Fires immediately when the close instance method is called. -
closed.bs.alert - Fired when the alert has been closed and CSS transitions have completed. -
- -```js -var myAlert = document.getElementById('myAlert') -myAlert.addEventListener('closed.bs.alert', function () { - // do something, for instance, explicitly move focus to the most appropriate element, - // so it doesn't get lost/reset to the start of the page - // document.getElementById('...').focus() -}) -``` diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.1/components/badge.md b/app/vendor/twbs/bootstrap/site/content/docs/5.1/components/badge.md deleted file mode 100644 index de80d3b27..000000000 --- a/app/vendor/twbs/bootstrap/site/content/docs/5.1/components/badge.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -layout: docs -title: Badges -description: Documentation and examples for badges, our small count and labeling component. -group: components -toc: true ---- - -## Examples - -Badges scale to match the size of the immediate parent element by using relative font sizing and `em` units. As of v5, badges no longer have focus or hover styles for links. - -### Headings - -{{< example >}} -

Example heading New

-

Example heading New

-

Example heading New

-

Example heading New

-
Example heading New
-
Example heading New
-{{< /example >}} - -### Buttons - -Badges can be used as part of links or buttons to provide a counter. - -{{< example >}} - -{{< /example >}} - -Note that depending on how they are used, badges may be confusing for users of screen readers and similar assistive technologies. While the styling of badges provides a visual cue as to their purpose, these users will simply be presented with the content of the badge. Depending on the specific situation, these badges may seem like random additional words or numbers at the end of a sentence, link, or button. - -Unless the context is clear (as with the "Notifications" example, where it is understood that the "4" is the number of notifications), consider including additional context with a visually hidden piece of additional text. - -### Positioned - -Use utilities to modify a `.badge` and position it in the corner of a link or button. - -{{< example >}} - -{{< /example >}} - -You can also replace the `.badge` class with a few more utilities without a count for a more generic indicator. - -{{< example >}} - -{{< /example >}} - -## Background colors - -Use our background utility classes to quickly change the appearance of a badge. Please note that when using Bootstrap's default `.bg-light`, you'll likely need a text color utility like `.text-dark` for proper styling. This is because background utilities do not set anything but `background-color`. - -{{< example >}} -{{< badge.inline >}} -{{- range (index $.Site.Data "theme-colors") }} -{{ .name | title }}{{- end -}} -{{< /badge.inline >}} -{{< /example >}} - -{{< callout info >}} -{{< partial "callout-warning-color-assistive-technologies.md" >}} -{{< /callout >}} - -## Pill badges - -Use the `.rounded-pill` utility class to make badges more rounded with a larger `border-radius`. - -{{< example >}} -{{< badge.inline >}} -{{- range (index $.Site.Data "theme-colors") }} -{{ .name | title }}{{- end -}} -{{< /badge.inline >}} -{{< /example >}} - -## Sass - -### Variables - -{{< scss-docs name="badge-variables" file="scss/_variables.scss" >}} diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.1/components/breadcrumb.md b/app/vendor/twbs/bootstrap/site/content/docs/5.1/components/breadcrumb.md deleted file mode 100644 index 9143e7612..000000000 --- a/app/vendor/twbs/bootstrap/site/content/docs/5.1/components/breadcrumb.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -layout: docs -title: Breadcrumb -description: Indicate the current page's location within a navigational hierarchy that automatically adds separators via CSS. -group: components -toc: true ---- - -## Example - -Use an ordered or unordered list with linked list items to create a minimally styled breadcrumb. Use our utilities to add additional styles as desired. - -{{< example >}} - - - - - -{{< /example >}} - -## Dividers - -Dividers are automatically added in CSS through [`::before`](https://developer.mozilla.org/en-US/docs/Web/CSS/::before) and [`content`](https://developer.mozilla.org/en-US/docs/Web/CSS/content). They can be changed by modifying a local CSS custom property `--bs-breadcrumb-divider`, or through the `$breadcrumb-divider` Sass variable — and `$breadcrumb-divider-flipped` for its RTL counterpart, if needed. We default to our Sass variable, which is set as a fallback to the custom property. This way, you get a global divider that you can override without recompiling CSS at any time. - -{{< example >}} - -{{< /example >}} - -When modifying via Sass, the [quote](https://sass-lang.com/documentation/modules/string#quote) function is required to generate the quotes around a string. For example, using `>` as the divider, you can use this: - -```scss -$breadcrumb-divider: quote(">"); -``` - -It's also possible to use an **embedded SVG icon**. Apply it via our CSS custom property, or use the Sass variable. - -{{< example >}} - -{{< /example >}} - -```scss -$breadcrumb-divider: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath d='M2.5 0L1 1.5 3.5 4 1 6.5 2.5 8l4-4-4-4z' fill='currentColor'/%3E%3C/svg%3E"); -``` - -You can also remove the divider setting `--bs-breadcrumb-divider: '';` (empty strings in CSS custom properties counts as a value), or setting the Sass variable to `$breadcrumb-divider: none;`. - -{{< example >}} - -{{< /example >}} - - -```scss -$breadcrumb-divider: none; -``` - -## Accessibility - -Since breadcrumbs provide a navigation, it's a good idea to add a meaningful label such as `aria-label="breadcrumb"` to describe the type of navigation provided in the `
-{{< /example >}} - -### With indicators - -You can also add the indicators to the carousel, alongside the controls, too. - -{{< example >}} - -{{< /example >}} - -### With captions - -Add captions to your slides easily with the `.carousel-caption` element within any `.carousel-item`. They can be easily hidden on smaller viewports, as shown below, with optional [display utilities]({{< docsref "/utilities/display" >}}). We hide them initially with `.d-none` and bring them back on medium-sized devices with `.d-md-block`. - -{{< example >}} - -{{< /example >}} - -### Crossfade - -Add `.carousel-fade` to your carousel to animate slides with a fade transition instead of a slide. - -{{< example >}} - -{{< /example >}} - -### Individual `.carousel-item` interval - -Add `data-bs-interval=""` to a `.carousel-item` to change the amount of time to delay between automatically cycling to the next item. - -{{< example >}} - -{{< /example >}} - -### Disable touch swiping - -Carousels support swiping left/right on touchscreen devices to move between slides. This can be disabled using the `data-bs-touch` attribute. The example below also does not include the `data-bs-ride` attribute and has `data-bs-interval="false"` so it doesn't autoplay. - -{{< example >}} - -{{< /example >}} - -## Dark variant - -Add `.carousel-dark` to the `.carousel` for darker controls, indicators, and captions. Controls have been inverted from their default white fill with the `filter` CSS property. Captions and controls have additional Sass variables that customize the `color` and `background-color`. - -{{< example >}} - -{{< /example >}} - -## Custom transition - -The transition duration of `.carousel-item` can be changed with the `$carousel-transition-duration` Sass variable before compiling or custom styles if you're using the compiled CSS. If multiple transitions are applied, make sure the transform transition is defined first (eg. `transition: transform 2s ease, opacity .5s ease-out`). - -## Sass - -### Variables - -{{< scss-docs name="carousel-variables" file="scss/_variables.scss" >}} - -## Usage - -### Via data attributes - -Use data attributes to easily control the position of the carousel. `data-bs-slide` accepts the keywords `prev` or `next`, which alters the slide position relative to its current position. Alternatively, use `data-bs-slide-to` to pass a raw slide index to the carousel `data-bs-slide-to="2"`, which shifts the slide position to a particular index beginning with `0`. - -The `data-bs-ride="carousel"` attribute is used to mark a carousel as animating starting at page load. If you don't use `data-bs-ride="carousel"` to initialize your carousel, you have to initialize it yourself. **It cannot be used in combination with (redundant and unnecessary) explicit JavaScript initialization of the same carousel.** - -### Via JavaScript - -Call carousel manually with: - -```js -var myCarousel = document.querySelector('#myCarousel') -var carousel = new bootstrap.Carousel(myCarousel) -``` - -### Options - -Options can be passed via data attributes or JavaScript. For data attributes, append the option name to `data-bs-`, as in `data-bs-interval=""`. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
intervalnumber5000The amount of time to delay between automatically cycling an item. If false, carousel will not automatically cycle.
keyboardbooleantrueWhether the carousel should react to keyboard events.
pausestring | boolean'hover'

If set to 'hover', pauses the cycling of the carousel on mouseenter and resumes the cycling of the carousel on mouseleave. If set to false, hovering over the carousel won't pause it.

-

On touch-enabled devices, when set to 'hover', cycling will pause on touchend (once the user finished interacting with the carousel) for two intervals, before automatically resuming. Note that this is in addition to the above mouse behavior.

ridestring | booleanfalseAutoplays the carousel after the user manually cycles the first item. If set to 'carousel', autoplays the carousel on load.
wrapbooleantrueWhether the carousel should cycle continuously or have hard stops.
touchbooleantrueWhether the carousel should support left/right swipe interactions on touchscreen devices.
- -### Methods - -{{< callout danger >}} -{{< partial "callout-danger-async-methods.md" >}} -{{< /callout >}} - -You can create a carousel instance with the carousel constructor, for example, to initialize with additional options and start cycling through items: - -```js -var myCarousel = document.querySelector('#myCarousel') -var carousel = new bootstrap.Carousel(myCarousel, { - interval: 2000, - wrap: false -}) -``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MethodDescription
cycleCycles through the carousel items from left to right.
pauseStops the carousel from cycling through items.
prevCycles to the previous item. Returns to the caller before the previous item has been shown (e.g., before the slid.bs.carousel event occurs).
nextCycles to the next item. Returns to the caller before the next item has been shown (e.g., before the slid.bs.carousel event occurs).
nextWhenVisibleDon't cycle carousel to next when the page isn't visible or the carousel or its parent isn't visible. Returns to the caller before the target item has been shown -
toCycles the carousel to a particular frame (0 based, similar to an array). Returns to the caller before the target item has been shown (e.g., before the slid.bs.carousel event occurs).
disposeDestroys an element's carousel. (Removes stored data on the DOM element)
- getInstance - - Static method which allows you to get the carousel instance associated to a DOM element, you can use it like this: bootstrap.Carousel.getInstance(element) -
- getOrCreateInstance - - Static method which returns a carousel instance associated to a DOM element or create a new one in case it wasn't initialized. - You can use it like this: bootstrap.Carousel.getOrCreateInstance(element) -
- -### Events - -Bootstrap's carousel class exposes two events for hooking into carousel functionality. Both events have the following additional properties: - -- `direction`: The direction in which the carousel is sliding (either `"left"` or `"right"`). -- `relatedTarget`: The DOM element that is being slid into place as the active item. -- `from`: The index of the current item -- `to`: The index of the next item - -All carousel events are fired at the carousel itself (i.e. at the `
-{{< /example >}} - -You can also create non-interactive dropdown items with `.dropdown-item-text`. Feel free to style further with custom CSS or text utilities. - -{{< example >}} - -{{< /example >}} - -### Active - -Add `.active` to items in the dropdown to **style them as active**. To convey the active state to assistive technologies, use the `aria-current` attribute — using the `page` value for the current page, or `true` for the current item in a set. - -{{< example >}} - -{{< /example >}} - -### Disabled - -Add `.disabled` to items in the dropdown to **style them as disabled**. - -{{< example >}} - -{{< /example >}} - -## Menu alignment - -By default, a dropdown menu is automatically positioned 100% from the top and along the left side of its parent. You can change this with the directional `.drop*` classes, but you can also control them with additional modifier classes. - -Add `.dropdown-menu-end` to a `.dropdown-menu` to right align the dropdown menu. Directions are mirrored when using Bootstrap in RTL, meaning `.dropdown-menu-end` will appear on the left side. - -{{< callout info >}} -**Heads up!** Dropdowns are positioned thanks to Popper except when they are contained in a navbar. -{{< /callout >}} - -{{< example >}} -
- - -
-{{< /example >}} - -### Responsive alignment - -If you want to use responsive alignment, disable dynamic positioning by adding the `data-bs-display="static"` attribute and use the responsive variation classes. - -To align **right** the dropdown menu with the given breakpoint or larger, add `.dropdown-menu{-sm|-md|-lg|-xl|-xxl}-end`. - -{{< example >}} -
- - -
-{{< /example >}} - -To align **left** the dropdown menu with the given breakpoint or larger, add `.dropdown-menu-end` and `.dropdown-menu{-sm|-md|-lg|-xl|-xxl}-start`. - -{{< example >}} -
- - -
-{{< /example >}} - -Note that you don't need to add a `data-bs-display="static"` attribute to dropdown buttons in navbars, since Popper isn't used in navbars. - -### Alignment options - -Taking most of the options shown above, here's a small kitchen sink demo of various dropdown alignment options in one place. - -{{< example >}} -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
-{{< /example >}} - -## Menu content - -### Headers - -Add a header to label sections of actions in any dropdown menu. - -{{< example >}} - -{{< /example >}} - -### Dividers - -Separate groups of related menu items with a divider. - -{{< example >}} - -{{< /example >}} - -### Text - -Place any freeform text within a dropdown menu with text and use [spacing utilities]({{< docsref "/utilities/spacing" >}}). Note that you'll likely need additional sizing styles to constrain the menu width. - -{{< example >}} - -{{< /example >}} - -### Forms - -Put a form within a dropdown menu, or make it into a dropdown menu, and use [margin or padding utilities]({{< docsref "/utilities/spacing" >}}) to give it the negative space you require. - -{{< example >}} - -{{< /example >}} - -{{< example >}} - -{{< /example >}} - -## Dropdown options - -Use `data-bs-offset` or `data-bs-reference` to change the location of the dropdown. - -{{< example >}} -
- -
- - - -
-
-{{< /example >}} - -### Auto close behavior - -By default, the dropdown menu is closed when clicking inside or outside the dropdown menu. You can use the `autoClose` option to change this behavior of the dropdown. - -{{< example >}} -
- - -
- -
- - -
- -
- - -
- -
- - -
-{{< /example >}} - -## Sass - -### Variables - -Variables for all dropdowns: - -{{< scss-docs name="dropdown-variables" file="scss/_variables.scss" >}} - -Variables for the [dark dropdown](#dark-dropdowns): - -{{< scss-docs name="dropdown-dark-variables" file="scss/_variables.scss" >}} - -Variables for the CSS-based carets that indicate a dropdown's interactivity: - -{{< scss-docs name="caret-variables" file="scss/_variables.scss" >}} - -### Mixins - -Mixins are used to generate the CSS-based carets and can be found in `scss/mixins/_caret.scss`. - -{{< scss-docs name="caret-mixins" file="scss/mixins/_caret.scss" >}} - -## Usage - -Via data attributes or JavaScript, the dropdown plugin toggles hidden content (dropdown menus) by toggling the `.show` class on the parent `.dropdown-menu`. The `data-bs-toggle="dropdown"` attribute is relied on for closing dropdown menus at an application level, so it's a good idea to always use it. - -{{< callout info >}} -On touch-enabled devices, opening a dropdown adds empty `mouseover` handlers to the immediate children of the `` element. This admittedly ugly hack is necessary to work around a [quirk in iOS' event delegation](https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html), which would otherwise prevent a tap anywhere outside of the dropdown from triggering the code that closes the dropdown. Once the dropdown is closed, these additional empty `mouseover` handlers are removed. -{{< /callout >}} - -### Via data attributes - -Add `data-bs-toggle="dropdown"` to a link or button to toggle a dropdown. - -```html - -``` - -### Via JavaScript - -Call the dropdowns via JavaScript: - -```js -var dropdownElementList = [].slice.call(document.querySelectorAll('.dropdown-toggle')) -var dropdownList = dropdownElementList.map(function (dropdownToggleEl) { - return new bootstrap.Dropdown(dropdownToggleEl) -}) -``` - -{{< callout info >}} -##### `data-bs-toggle="dropdown"` still required - -Regardless of whether you call your dropdown via JavaScript or instead use the data-api, `data-bs-toggle="dropdown"` is always required to be present on the dropdown's trigger element. -{{< /callout >}} - -### Options - -Options can be passed via data attributes or JavaScript. For data attributes, append the option name to `data-bs-`, as in `data-bs-offset=""`. Make sure to change the case type of the option name from camelCase to kebab-case when passing the options via data attributes. For example, instead of using `data-bs-autoClose="false"`, use `data-bs-auto-close="false"`. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
boundarystring | element'clippingParents'Overflow constraint boundary of the dropdown menu (applies only to Popper's preventOverflow modifier). By default it's 'clippingParents' and can accept an HTMLElement reference (via JavaScript only). For more information refer to Popper's detectOverflow docs.
referencestring | element | object'toggle'Reference element of the dropdown menu. Accepts the values of 'toggle', 'parent', an HTMLElement reference or an object providing getBoundingClientRect. For more information refer to Popper's constructor docs and virtual element docs.
displaystring'dynamic'By default, we use Popper for dynamic positioning. Disable this with static.
offsetarray | string | function[0, 2] -

Offset of the dropdown relative to its target. You can pass a string in data attributes with comma separated values like: data-bs-offset="10,20"

-

When a function is used to determine the offset, it is called with an object containing the popper placement, the reference, and popper rects as its first argument. The triggering element DOM node is passed as the second argument. The function must return an array with two numbers: [skidding, distance].

-

For more information refer to Popper's offset docs.

-
autoCloseboolean | stringtrue -

Configure the auto close behavior of the dropdown:

-
    -
  • true - the dropdown will be closed by clicking outside or inside the dropdown menu.
  • -
  • false - the dropdown will be closed by clicking the toggle button and manually calling hide or toggle method. (Also will not be closed by pressing esc key)
  • -
  • 'inside' - the dropdown will be closed (only) by clicking inside the dropdown menu.
  • -
  • 'outside' - the dropdown will be closed (only) by clicking outside the dropdown menu.
  • -
-
popperConfignull | object | functionnull -

To change Bootstrap's default Popper config, see Popper's configuration.

-

When a function is used to create the Popper configuration, it's called with an object that contains the Bootstrap's default Popper configuration. It helps you use and merge the default with your own configuration. The function must return a configuration object for Popper.

-
- -#### Using function with `popperConfig` - -```js -var dropdown = new bootstrap.Dropdown(element, { - popperConfig: function (defaultBsPopperConfig) { - // var newPopperConfig = {...} - // use defaultBsPopperConfig if needed... - // return newPopperConfig - } -}) -``` - -### Methods - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MethodDescription
toggle - Toggles the dropdown menu of a given navbar or tabbed navigation. -
show - Shows the dropdown menu of a given navbar or tabbed navigation. -
hide - Hides the dropdown menu of a given navbar or tabbed navigation. -
update - Updates the position of an element's dropdown. -
dispose - Destroys an element's dropdown. (Removes stored data on the DOM element) -
- getInstance - - Static method which allows you to get the dropdown instance associated to a DOM element, you can use it like this: bootstrap.Dropdown.getInstance(element) -
- getOrCreateInstance - - Static method which returns a dropdown instance associated to a DOM element or create a new one in case it wasn't initialized. - You can use it like this: bootstrap.Dropdown.getOrCreateInstance(element) -
- -### Events - -All dropdown events are fired at the toggling element and then bubbled up. So you can also add event listeners on the `.dropdown-menu`'s parent element. `hide.bs.dropdown` and `hidden.bs.dropdown` events have a `clickEvent` property (only when the original Event type is `click`) that contains an Event Object for the click event. - - - - - - - - - - - - - - - - - - - - - - - - - - -
MethodDescription
- show.bs.dropdown - - Fires immediately when the show instance method is called. -
- shown.bs.dropdown - - Fired when the dropdown has been made visible to the user and CSS transitions have completed. -
- hide.bs.dropdown - - Fires immediately when the hide instance method has been called. -
- hidden.bs.dropdown - - Fired when the dropdown has finished being hidden from the user and CSS transitions have completed. -
- -```js -var myDropdown = document.getElementById('myDropdown') -myDropdown.addEventListener('show.bs.dropdown', function () { - // do something... -}) -``` diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.1/components/list-group.md b/app/vendor/twbs/bootstrap/site/content/docs/5.1/components/list-group.md deleted file mode 100644 index 71e45245c..000000000 --- a/app/vendor/twbs/bootstrap/site/content/docs/5.1/components/list-group.md +++ /dev/null @@ -1,542 +0,0 @@ ---- -layout: docs -title: List group -description: List groups are a flexible and powerful component for displaying a series of content. Modify and extend them to support just about any content within. -group: components -toc: true ---- - -## Basic example - -The most basic list group is an unordered list with list items and the proper classes. Build upon it with the options that follow, or with your own CSS as needed. - -{{< example >}} -
    -
  • An item
  • -
  • A second item
  • -
  • A third item
  • -
  • A fourth item
  • -
  • And a fifth one
  • -
-{{< /example >}} - -## Active items - -Add `.active` to a `.list-group-item` to indicate the current active selection. - -{{< example >}} -
    -
  • An active item
  • -
  • A second item
  • -
  • A third item
  • -
  • A fourth item
  • -
  • And a fifth one
  • -
-{{< /example >}} - -## Disabled items - -Add `.disabled` to a `.list-group-item` to make it _appear_ disabled. Note that some elements with `.disabled` will also require custom JavaScript to fully disable their click events (e.g., links). - -{{< example >}} -
    -
  • A disabled item
  • -
  • A second item
  • -
  • A third item
  • -
  • A fourth item
  • -
  • And a fifth one
  • -
-{{< /example >}} - -## Links and buttons - -Use ``s or ` - - - - -
-{{< /example >}} - -## Flush - -Add `.list-group-flush` to remove some borders and rounded corners to render list group items edge-to-edge in a parent container (e.g., cards). - -{{< example >}} -
    -
  • An item
  • -
  • A second item
  • -
  • A third item
  • -
  • A fourth item
  • -
  • And a fifth one
  • -
-{{< /example >}} - -## Numbered - -Add the `.list-group-numbered` modifier class (and optionally use an `
    ` element) to opt into numbered list group items. Numbers are generated via CSS (as opposed to a `
      `s default browser styling) for better placement inside list group items and to allow for better customization. - -Numbers are generated by `counter-reset` on the `
        `, and then styled and placed with a `::before` pseudo-element on the `
      1. ` with `counter-increment` and `content`. - -{{< example >}} -
          -
        1. A list item
        2. -
        3. A list item
        4. -
        5. A list item
        6. -
        -{{< /example >}} - -These work great with custom content as well. - -{{< example >}} -
          -
        1. -
          -
          Subheading
          - Content for list item -
          - 14 -
        2. -
        3. -
          -
          Subheading
          - Content for list item -
          - 14 -
        4. -
        5. -
          -
          Subheading
          - Content for list item -
          - 14 -
        6. -
        -{{< /example >}} - -## Horizontal - -Add `.list-group-horizontal` to change the layout of list group items from vertical to horizontal across all breakpoints. Alternatively, choose a responsive variant `.list-group-horizontal-{sm|md|lg|xl|xxl}` to make a list group horizontal starting at that breakpoint's `min-width`. Currently **horizontal list groups cannot be combined with flush list groups.** - -**ProTip:** Want equal-width list group items when horizontal? Add `.flex-fill` to each list group item. - -{{< example >}} -{{< list-group.inline >}} -{{- range $.Site.Data.breakpoints }} -
          -
        • An item
        • -
        • A second item
        • -
        • A third item
        • -
        -{{- end -}} -{{< /list-group.inline >}} -{{< /example >}} - -## Contextual classes - -Use contextual classes to style list items with a stateful background and color. - -{{< example >}} -
          -
        • A simple default list group item
        • -{{< list.inline >}} -{{- range (index $.Site.Data "theme-colors") }} -
        • A simple {{ .name }} list group item
        • -{{- end -}} -{{< /list.inline >}} -
        -{{< /example >}} - -Contextual classes also work with `.list-group-item-action`. Note the addition of the hover styles here not present in the previous example. Also supported is the `.active` state; apply it to indicate an active selection on a contextual list group item. - -{{< example >}} -
        - A simple default list group item -{{< list.inline >}} -{{- range (index $.Site.Data "theme-colors") }} - A simple {{ .name }} list group item -{{- end -}} -{{< /list.inline >}} -
        -{{< /example >}} - -{{< callout info >}} -{{< partial "callout-warning-color-assistive-technologies.md" >}} -{{< /callout >}} - -## With badges - -Add badges to any list group item to show unread counts, activity, and more with the help of some [utilities]({{< docsref "/utilities/flex" >}}). - -{{< example >}} -
          -
        • - A list item - 14 -
        • -
        • - A second list item - 2 -
        • -
        • - A third list item - 1 -
        • -
        -{{< /example >}} - -## Custom content - -Add nearly any HTML within, even for linked list groups like the one below, with the help of [flexbox utilities]({{< docsref "/utilities/flex" >}}). - -{{< example >}} - -{{< /example >}} - -## Checkboxes and radios - -Place Bootstrap's checkboxes and radios within list group items and customize as needed. You can use them without `
-{{< /example >}} - -To set a custom height on your ` - -
-{{< /example >}} - -## Selects - -Other than `.form-control`, floating labels are only available on `.form-select`s. They work in the same way, but unlike ``s, they'll always show the `
-{{< /example >}} - -## Sizing - -Set heights using classes like `.form-control-lg` and `.form-control-sm`. - -{{< example >}} - - - -{{< /example >}} - -## Disabled - -Add the `disabled` boolean attribute on an input to give it a grayed out appearance and remove pointer events. - -{{< example >}} - - -{{< /example >}} - -## Readonly - -Add the `readonly` boolean attribute on an input to prevent modification of the input's value. - -{{< example >}} - -{{< /example >}} - -## Readonly plain text - -If you want to have `` elements in your form styled as plain text, use the `.form-control-plaintext` class to remove the default form field styling and preserve the correct margin and padding. - -{{< example >}} -
- -
- -
-
-
- -
- -
-
-{{< /example >}} - -{{< example >}} -
-
- - -
-
- - -
-
- -
-
-{{< /example >}} - -## File input - -{{< example >}} -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-{{< /example >}} - -## Color - -{{< example >}} - - -{{< /example >}} - -## Datalists - -Datalists allow you to create a group of `
- - - - -{{< /example >}} - -## Segmented buttons - -{{< example >}} -
- - - - -
- -
- - - - -
-{{< /example >}} - -## Custom forms - -Input groups include support for custom selects and custom file inputs. Browser default versions of these are not supported. - -### Custom select - -{{< example >}} -
- - -
- -
- - -
- -
- - -
- -
- - -
-{{< /example >}} - -### Custom file input - -{{< example >}} -
- - -
- -
- - -
- -
- - -
- -
- - -
-{{< /example >}} - -## Sass - -### Variables - -{{< scss-docs name="input-group-variables" file="scss/_variables.scss" >}} diff --git a/app/vendor/twbs/bootstrap/site/content/docs/5.1/forms/layout.md b/app/vendor/twbs/bootstrap/site/content/docs/5.1/forms/layout.md deleted file mode 100644 index 47e2f8ab7..000000000 --- a/app/vendor/twbs/bootstrap/site/content/docs/5.1/forms/layout.md +++ /dev/null @@ -1,330 +0,0 @@ ---- -layout: docs -title: Layout -description: Give your forms some structure—from inline to horizontal to custom grid implementations—with our form layout options. -group: forms -toc: true ---- - -## Forms - -Every group of form fields should reside in a `
` element. Bootstrap provides no default styling for the `` element, but there are some powerful browser features that are provided by default. - -- New to browser forms? Consider reviewing [the MDN form docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) for an overview and complete list of available attributes. -- ` -
- -{{< /example >}} - -## Horizontal form - -Create horizontal forms with the grid by adding the `.row` class to form groups and using the `.col-*-*` classes to specify the width of your labels and controls. Be sure to add `.col-form-label` to your `