1
0
Fork 0
mirror of https://github.com/DanielnetoDotCom/YouPHPTube synced 2025-10-06 03:50:04 +02:00

Update composer

This commit is contained in:
Daniel Neto 2024-03-05 19:29:45 -03:00
parent 330cdbe615
commit 0c83c9a678
442 changed files with 9523 additions and 10793 deletions

View file

@ -6,7 +6,7 @@
"platform-check": false,
"vendor-dir": "vendor",
"platform": {
"php": "8.1.5"
"php": "8"
}
},
"require": {

391
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "482bbedbb5567f4d0aea3008c309ad66",
"content-hash": "03c93887788053985a400bb422d22871",
"packages": [
{
"name": "abraham/twitteroauth",
@ -479,26 +479,26 @@
},
{
"name": "carbonphp/carbon-doctrine-types",
"version": "3.2.0",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/CarbonPHP/carbon-doctrine-types.git",
"reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d"
"reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
"reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
"url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/99f76ffa36cce3b70a4a6abce41dba15ca2e84cb",
"reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb",
"shasum": ""
},
"require": {
"php": "^8.1"
"php": "^7.4 || ^8.0"
},
"conflict": {
"doctrine/dbal": "<4.0.0 || >=5.0.0"
"doctrine/dbal": "<3.7.0 || >=4.0.0"
},
"require-dev": {
"doctrine/dbal": "^4.0.0",
"doctrine/dbal": "^3.7.0",
"nesbot/carbon": "^2.71.0 || ^3.0.0",
"phpunit/phpunit": "^10.3"
},
@ -528,7 +528,7 @@
],
"support": {
"issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues",
"source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0"
"source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/2.1.0"
},
"funding": [
{
@ -544,7 +544,7 @@
"type": "tidelift"
}
],
"time": "2024-02-09T16:56:22+00:00"
"time": "2023-12-11T17:09:12+00:00"
},
{
"name": "cboden/ratchet",
@ -2813,27 +2813,22 @@
},
{
"name": "psr/container",
"version": "2.0.2",
"version": "1.1.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
"shasum": ""
},
"require": {
"php": ">=7.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
@ -2860,9 +2855,9 @@
],
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/2.0.2"
"source": "https://github.com/php-fig/container/tree/1.1.2"
},
"time": "2021-11-05T16:47:00+00:00"
"time": "2021-11-05T16:50:12+00:00"
},
{
"name": "psr/event-dispatcher",
@ -3170,20 +3165,21 @@
},
{
"name": "ramsey/collection",
"version": "2.0.0",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/ramsey/collection.git",
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5"
"reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
"url": "https://api.github.com/repos/ramsey/collection/zipball/ad7475d1c9e70b190ecffc58f2d989416af339b4",
"reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4",
"shasum": ""
},
"require": {
"php": "^8.1"
"php": "^7.4 || ^8.0",
"symfony/polyfill-php81": "^1.23"
},
"require-dev": {
"captainhook/plugin-composer": "^5.3",
@ -3243,7 +3239,7 @@
],
"support": {
"issues": "https://github.com/ramsey/collection/issues",
"source": "https://github.com/ramsey/collection/tree/2.0.0"
"source": "https://github.com/ramsey/collection/tree/1.3.0"
},
"funding": [
{
@ -3255,7 +3251,7 @@
"type": "tidelift"
}
],
"time": "2022-12-31T21:50:55+00:00"
"time": "2022-12-27T19:12:24+00:00"
},
{
"name": "ramsey/uuid",
@ -4118,47 +4114,52 @@
},
{
"name": "symfony/console",
"version": "v6.4.4",
"version": "v5.4.36",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "0d9e4eb5ad413075624378f474c4167ea202de78"
"reference": "39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/0d9e4eb5ad413075624378f474c4167ea202de78",
"reference": "0d9e4eb5ad413075624378f474c4167ea202de78",
"url": "https://api.github.com/repos/symfony/console/zipball/39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e",
"reference": "39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3",
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/service-contracts": "^2.5|^3",
"symfony/string": "^5.4|^6.0|^7.0"
"symfony/polyfill-php73": "^1.9",
"symfony/polyfill-php80": "^1.16",
"symfony/service-contracts": "^1.1|^2|^3",
"symfony/string": "^5.1|^6.0"
},
"conflict": {
"symfony/dependency-injection": "<5.4",
"symfony/dotenv": "<5.4",
"symfony/event-dispatcher": "<5.4",
"symfony/lock": "<5.4",
"symfony/process": "<5.4"
"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"
},
"provide": {
"psr/log-implementation": "1.0|2.0|3.0"
"psr/log-implementation": "1.0|2.0"
},
"require-dev": {
"psr/log": "^1|^2|^3",
"symfony/config": "^5.4|^6.0|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/event-dispatcher": "^5.4|^6.0|^7.0",
"symfony/http-foundation": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/lock": "^5.4|^6.0|^7.0",
"symfony/messenger": "^5.4|^6.0|^7.0",
"symfony/process": "^5.4|^6.0|^7.0",
"symfony/stopwatch": "^5.4|^6.0|^7.0",
"symfony/var-dumper": "^5.4|^6.0|^7.0"
"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"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
},
"type": "library",
"autoload": {
@ -4192,7 +4193,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.4.4"
"source": "https://github.com/symfony/console/tree/v5.4.36"
},
"funding": [
{
@ -4208,29 +4209,29 @@
"type": "tidelift"
}
],
"time": "2024-02-22T20:27:10+00:00"
"time": "2024-02-20T16:33:57+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.4.0",
"version": "v2.5.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"shasum": ""
},
"require": {
"php": ">=8.1"
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.4-dev"
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -4259,7 +4260,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2"
},
"funding": [
{
@ -4275,43 +4276,48 @@
"type": "tidelift"
}
],
"time": "2023-05-23T14:45:45+00:00"
"time": "2022-01-02T09:53:40+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v6.4.3",
"version": "v5.4.35",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "ae9d3a6f3003a6caf56acd7466d8d52378d44fef"
"reference": "7a69a85c7ea5bdd1e875806a99c51a87d3a74b38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ae9d3a6f3003a6caf56acd7466d8d52378d44fef",
"reference": "ae9d3a6f3003a6caf56acd7466d8d52378d44fef",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7a69a85c7ea5bdd1e875806a99c51a87d3a74b38",
"reference": "7a69a85c7ea5bdd1e875806a99c51a87d3a74b38",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/event-dispatcher-contracts": "^2.5|^3"
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/event-dispatcher-contracts": "^2|^3",
"symfony/polyfill-php80": "^1.16"
},
"conflict": {
"symfony/dependency-injection": "<5.4",
"symfony/service-contracts": "<2.5"
"symfony/dependency-injection": "<4.4"
},
"provide": {
"psr/event-dispatcher-implementation": "1.0",
"symfony/event-dispatcher-implementation": "2.0|3.0"
"symfony/event-dispatcher-implementation": "2.0"
},
"require-dev": {
"psr/log": "^1|^2|^3",
"symfony/config": "^5.4|^6.0|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/error-handler": "^5.4|^6.0|^7.0",
"symfony/expression-language": "^5.4|^6.0|^7.0",
"symfony/http-foundation": "^5.4|^6.0|^7.0",
"symfony/service-contracts": "^2.5|^3",
"symfony/stopwatch": "^5.4|^6.0|^7.0"
"symfony/config": "^4.4|^5.0|^6.0",
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/error-handler": "^4.4|^5.0|^6.0",
"symfony/expression-language": "^4.4|^5.0|^6.0",
"symfony/http-foundation": "^4.4|^5.0|^6.0",
"symfony/service-contracts": "^1.1|^2|^3",
"symfony/stopwatch": "^4.4|^5.0|^6.0"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"type": "library",
"autoload": {
@ -4339,7 +4345,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v6.4.3"
"source": "https://github.com/symfony/event-dispatcher/tree/v5.4.35"
},
"funding": [
{
@ -4355,30 +4361,33 @@
"type": "tidelift"
}
],
"time": "2024-01-23T14:51:35+00:00"
"time": "2024-01-23T13:51:25+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
"version": "v3.4.0",
"version": "v2.5.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
"reference": "a76aed96a42d2b521153fb382d418e30d18b59df"
"reference": "f98b54df6ad059855739db6fcbc2d36995283fe1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df",
"reference": "a76aed96a42d2b521153fb382d418e30d18b59df",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1",
"reference": "f98b54df6ad059855739db6fcbc2d36995283fe1",
"shasum": ""
},
"require": {
"php": ">=8.1",
"php": ">=7.2.5",
"psr/event-dispatcher": "^1"
},
"suggest": {
"symfony/event-dispatcher-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.4-dev"
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -4415,7 +4424,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.0"
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2"
},
"funding": [
{
@ -4431,7 +4440,7 @@
"type": "tidelift"
}
],
"time": "2023-05-23T14:45:45+00:00"
"time": "2022-01-02T09:53:40+00:00"
},
{
"name": "symfony/http-client",
@ -4604,36 +4613,35 @@
},
{
"name": "symfony/http-foundation",
"version": "v6.4.4",
"version": "v5.4.35",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304"
"reference": "f2ab692a22aef1cd54beb893aa0068bdfb093928"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/ebc713bc6e6f4b53f46539fc158be85dfcd77304",
"reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/f2ab692a22aef1cd54beb893aa0068bdfb093928",
"reference": "f2ab692a22aef1cd54beb893aa0068bdfb093928",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3",
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-mbstring": "~1.1",
"symfony/polyfill-php83": "^1.27"
},
"conflict": {
"symfony/cache": "<6.3"
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"doctrine/dbal": "^2.13.1|^3|^4",
"predis/predis": "^1.1|^2.0",
"symfony/cache": "^6.3|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/expression-language": "^5.4|^6.0|^7.0",
"symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0",
"symfony/mime": "^5.4|^6.0|^7.0",
"symfony/rate-limiter": "^5.4|^6.0|^7.0"
"predis/predis": "~1.0",
"symfony/cache": "^4.4|^5.0|^6.0",
"symfony/dependency-injection": "^5.4|^6.0",
"symfony/expression-language": "^4.4|^5.0|^6.0",
"symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4",
"symfony/mime": "^4.4|^5.0|^6.0",
"symfony/rate-limiter": "^5.2|^6.0"
},
"suggest": {
"symfony/mime": "To use the file extension guesser"
},
"type": "library",
"autoload": {
@ -4661,7 +4669,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v6.4.4"
"source": "https://github.com/symfony/http-foundation/tree/v5.4.35"
},
"funding": [
{
@ -4677,43 +4685,43 @@
"type": "tidelift"
}
],
"time": "2024-02-08T15:01:18+00:00"
"time": "2024-01-23T13:51:25+00:00"
},
{
"name": "symfony/mime",
"version": "v6.4.3",
"version": "v5.4.35",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "5017e0a9398c77090b7694be46f20eb796262a34"
"reference": "ee94d9b538f93abbbc1ee4ccff374593117b04a9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/5017e0a9398c77090b7694be46f20eb796262a34",
"reference": "5017e0a9398c77090b7694be46f20eb796262a34",
"url": "https://api.github.com/repos/symfony/mime/zipball/ee94d9b538f93abbbc1ee4ccff374593117b04a9",
"reference": "ee94d9b538f93abbbc1ee4ccff374593117b04a9",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3",
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-intl-idn": "^1.10",
"symfony/polyfill-mbstring": "^1.0"
"symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php80": "^1.16"
},
"conflict": {
"egulias/email-validator": "~3.0.0",
"phpdocumentor/reflection-docblock": "<3.2.2",
"phpdocumentor/type-resolver": "<1.4.0",
"symfony/mailer": "<5.4",
"symfony/serializer": "<6.3.2"
"symfony/mailer": "<4.4",
"symfony/serializer": "<5.4.35|>=6,<6.3.12|>=6.4,<6.4.3"
},
"require-dev": {
"egulias/email-validator": "^2.1.10|^3.1|^4",
"league/html-to-markdown": "^5.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/property-access": "^5.4|^6.0|^7.0",
"symfony/property-info": "^5.4|^6.0|^7.0",
"symfony/serializer": "^6.3.2|^7.0"
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/property-access": "^4.4|^5.1|^6.0",
"symfony/property-info": "^4.4|^5.1|^6.0",
"symfony/serializer": "^5.4.35|~6.3.12|^6.4.3"
},
"type": "library",
"autoload": {
@ -4745,7 +4753,7 @@
"mime-type"
],
"support": {
"source": "https://github.com/symfony/mime/tree/v6.4.3"
"source": "https://github.com/symfony/mime/tree/v5.4.35"
},
"funding": [
{
@ -4761,25 +4769,27 @@
"type": "tidelift"
}
],
"time": "2024-01-30T08:32:12+00:00"
"time": "2024-01-30T08:00:51+00:00"
},
{
"name": "symfony/options-resolver",
"version": "v6.4.0",
"version": "v5.4.21",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "22301f0e7fdeaacc14318928612dee79be99860e"
"reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/22301f0e7fdeaacc14318928612dee79be99860e",
"reference": "22301f0e7fdeaacc14318928612dee79be99860e",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9",
"reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3"
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-php73": "~1.0",
"symfony/polyfill-php80": "^1.16"
},
"type": "library",
"autoload": {
@ -4812,7 +4822,7 @@
"options"
],
"support": {
"source": "https://github.com/symfony/options-resolver/tree/v6.4.0"
"source": "https://github.com/symfony/options-resolver/tree/v5.4.21"
},
"funding": [
{
@ -4828,7 +4838,7 @@
"type": "tidelift"
}
],
"time": "2023-08-08T10:16:24+00:00"
"time": "2023-02-14T08:03:56+00:00"
},
{
"name": "symfony/polyfill-ctype",
@ -5462,22 +5472,21 @@
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-php83",
"name": "symfony/polyfill-php81",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php83.git",
"reference": "86fcae159633351e5fd145d1c47de6c528f8caff"
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "c565ad1e63f30e7477fc40738343c62b40bc672d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/86fcae159633351e5fd145d1c47de6c528f8caff",
"reference": "86fcae159633351e5fd145d1c47de6c528f8caff",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/c565ad1e63f30e7477fc40738343c62b40bc672d",
"reference": "c565ad1e63f30e7477fc40738343c62b40bc672d",
"shasum": ""
},
"require": {
"php": ">=7.1",
"symfony/polyfill-php80": "^1.14"
"php": ">=7.1"
},
"type": "library",
"extra": {
@ -5491,7 +5500,7 @@
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php83\\": ""
"Symfony\\Polyfill\\Php81\\": ""
},
"classmap": [
"Resources/stubs"
@ -5511,7 +5520,7 @@
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions",
"description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
@ -5520,7 +5529,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php83/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-php81/tree/v1.29.0"
},
"funding": [
{
@ -5540,36 +5549,43 @@
},
{
"name": "symfony/routing",
"version": "v6.4.5",
"version": "v5.4.37",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
"reference": "7fe30068e207d9c31c0138501ab40358eb2d49a4"
"reference": "48ae43e443693ddb4e574f7c12f0d17ce287694e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/routing/zipball/7fe30068e207d9c31c0138501ab40358eb2d49a4",
"reference": "7fe30068e207d9c31c0138501ab40358eb2d49a4",
"url": "https://api.github.com/repos/symfony/routing/zipball/48ae43e443693ddb4e574f7c12f0d17ce287694e",
"reference": "48ae43e443693ddb4e574f7c12f0d17ce287694e",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3"
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-php80": "^1.16"
},
"conflict": {
"doctrine/annotations": "<1.12",
"symfony/config": "<6.2",
"symfony/dependency-injection": "<5.4",
"symfony/yaml": "<5.4"
"symfony/config": "<5.3",
"symfony/dependency-injection": "<4.4",
"symfony/yaml": "<4.4"
},
"require-dev": {
"doctrine/annotations": "^1.12|^2",
"psr/log": "^1|^2|^3",
"symfony/config": "^6.2|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/expression-language": "^5.4|^6.0|^7.0",
"symfony/http-foundation": "^5.4|^6.0|^7.0",
"symfony/yaml": "^5.4|^6.0|^7.0"
"symfony/config": "^5.3|^6.0",
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/expression-language": "^4.4|^5.0|^6.0",
"symfony/http-foundation": "^4.4|^5.0|^6.0",
"symfony/yaml": "^4.4|^5.0|^6.0"
},
"suggest": {
"symfony/config": "For using the all-in-one router or any loader",
"symfony/expression-language": "For using expression matching",
"symfony/http-foundation": "For using a Symfony Request object",
"symfony/yaml": "For using the YAML loader"
},
"type": "library",
"autoload": {
@ -5603,7 +5619,7 @@
"url"
],
"support": {
"source": "https://github.com/symfony/routing/tree/v6.4.5"
"source": "https://github.com/symfony/routing/tree/v5.4.37"
},
"funding": [
{
@ -5619,33 +5635,37 @@
"type": "tidelift"
}
],
"time": "2024-02-27T12:33:30+00:00"
"time": "2024-02-27T09:52:32+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v3.4.1",
"version": "v2.5.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "fe07cbc8d837f60caf7018068e350cc5163681a0"
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0",
"reference": "fe07cbc8d837f60caf7018068e350cc5163681a0",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"shasum": ""
},
"require": {
"php": ">=8.1",
"psr/container": "^1.1|^2.0"
"php": ">=7.2.5",
"psr/container": "^1.1",
"symfony/deprecation-contracts": "^2.1|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
},
"suggest": {
"symfony/service-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.4-dev"
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -5655,10 +5675,7 @@
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -5685,7 +5702,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.4.1"
"source": "https://github.com/symfony/service-contracts/tree/v2.5.2"
},
"funding": [
{
@ -5701,38 +5718,38 @@
"type": "tidelift"
}
],
"time": "2023-12-26T14:02:43+00:00"
"time": "2022-05-30T19:17:29+00:00"
},
{
"name": "symfony/string",
"version": "v6.4.4",
"version": "v5.4.36",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9"
"reference": "4e232c83622bd8cd32b794216aa29d0d266d353b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9",
"reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9",
"url": "https://api.github.com/repos/symfony/string/zipball/4e232c83622bd8cd32b794216aa29d0d266d353b",
"reference": "4e232c83622bd8cd32b794216aa29d0d266d353b",
"shasum": ""
},
"require": {
"php": ">=8.1",
"php": ">=7.2.5",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-intl-grapheme": "~1.0",
"symfony/polyfill-intl-normalizer": "~1.0",
"symfony/polyfill-mbstring": "~1.0"
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php80": "~1.15"
},
"conflict": {
"symfony/translation-contracts": "<2.5"
"symfony/translation-contracts": ">=3.0"
},
"require-dev": {
"symfony/error-handler": "^5.4|^6.0|^7.0",
"symfony/http-client": "^5.4|^6.0|^7.0",
"symfony/intl": "^6.2|^7.0",
"symfony/translation-contracts": "^2.5|^3.0",
"symfony/var-exporter": "^5.4|^6.0|^7.0"
"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"
},
"type": "library",
"autoload": {
@ -5771,7 +5788,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v6.4.4"
"source": "https://github.com/symfony/string/tree/v5.4.36"
},
"funding": [
{
@ -5787,7 +5804,7 @@
"type": "tidelift"
}
],
"time": "2024-02-01T13:16:41+00:00"
"time": "2024-02-01T08:49:30+00:00"
},
{
"name": "symfony/translation",
@ -6031,7 +6048,7 @@
},
"platform-dev": [],
"platform-overrides": {
"php": "8.1.5"
"php": "8"
},
"plugin-api-version": "2.3.0"
}

View file

@ -10,15 +10,15 @@
"Doctrine"
],
"require": {
"php": "^8.1"
"php": "^7.4 || ^8.0"
},
"require-dev": {
"doctrine/dbal": "^4.0.0",
"doctrine/dbal": "^3.7.0",
"nesbot/carbon": "^2.71.0 || ^3.0.0",
"phpunit/phpunit": "^10.3"
},
"conflict": {
"doctrine/dbal": "<4.0.0 || >=5.0.0"
"doctrine/dbal": "<3.7.0 || >=4.0.0"
},
"license": "MIT",
"autoload": {

View file

@ -1,7 +1,5 @@
<?php
declare(strict_types=1);
namespace Carbon\Doctrine;
use Doctrine\DBAL\Platforms\AbstractPlatform;
@ -10,7 +8,7 @@ interface CarbonDoctrineType
{
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform);
public function convertToPHPValue(mixed $value, AbstractPlatform $platform);
public function convertToPHPValue($value, AbstractPlatform $platform);
public function convertToDatabaseValue($value, AbstractPlatform $platform);
}

View file

@ -1,7 +1,5 @@
<?php
declare(strict_types=1);
namespace Carbon\Doctrine;
class CarbonImmutableType extends DateTimeImmutableType implements CarbonDoctrineType

View file

@ -1,7 +1,5 @@
<?php
declare(strict_types=1);
namespace Carbon\Doctrine;
class CarbonType extends DateTimeType implements CarbonDoctrineType

View file

@ -1,7 +1,5 @@
<?php
declare(strict_types=1);
namespace Carbon\Doctrine;
use Carbon\Carbon;
@ -10,10 +8,9 @@ use DateTimeInterface;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\DB2Platform;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\DBAL\Types\Exception\InvalidType;
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
use Doctrine\DBAL\Types\ConversionException;
use Exception;
/**
@ -61,25 +58,10 @@ trait CarbonTypeConverter
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*
* @return T|null
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
{
if ($value === null) {
return $value;
}
if ($value instanceof DateTimeInterface) {
return $value->format('Y-m-d H:i:s.u');
}
throw InvalidType::new(
$value,
static::class,
['null', 'DateTime', 'Carbon']
);
}
private function doConvertToPHPValue(mixed $value)
public function convertToPHPValue($value, AbstractPlatform $platform)
{
$class = $this->getCarbonClassName();
@ -101,9 +83,9 @@ trait CarbonTypeConverter
}
if (!$date) {
throw ValueNotConvertible::new(
throw ConversionException::conversionFailedFormat(
$value,
static::class,
$this->getTypeName(),
'Y-m-d H:i:s.u or any format supported by '.$class.'::parse()',
$error
);
@ -112,6 +94,34 @@ trait CarbonTypeConverter
return $date;
}
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
{
if ($value === null) {
return $value;
}
if ($value instanceof DateTimeInterface) {
return $value->format('Y-m-d H:i:s.u');
}
throw ConversionException::conversionFailedInvalidType(
$value,
$this->getTypeName(),
['null', 'DateTime', 'Carbon']
);
}
private function getTypeName(): string
{
$chunks = explode('\\', static::class);
$type = preg_replace('/Type$/', '', end($chunks));
return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $type));
}
private function getMaximumPrecision(AbstractPlatform $platform): int
{
if ($platform instanceof DB2Platform) {
@ -122,7 +132,7 @@ trait CarbonTypeConverter
return 9;
}
if ($platform instanceof SQLServerPlatform || $platform instanceof SQLitePlatform) {
if ($platform instanceof SQLServerPlatform || $platform instanceof SqlitePlatform) {
return 3;
}

View file

@ -1,7 +1,5 @@
<?php
declare(strict_types=1);
namespace Carbon\Doctrine;
class DateTimeDefaultPrecision

View file

@ -1,12 +1,8 @@
<?php
declare(strict_types=1);
namespace Carbon\Doctrine;
use Carbon\CarbonImmutable;
use DateTimeImmutable;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\VarDateTimeImmutableType;
class DateTimeImmutableType extends VarDateTimeImmutableType implements CarbonDoctrineType
@ -14,14 +10,6 @@ class DateTimeImmutableType extends VarDateTimeImmutableType implements CarbonDo
/** @use CarbonTypeConverter<CarbonImmutable> */
use CarbonTypeConverter;
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?CarbonImmutable
{
return $this->doConvertToPHPValue($value);
}
/**
* @return class-string<CarbonImmutable>
*/

View file

@ -1,24 +1,12 @@
<?php
declare(strict_types=1);
namespace Carbon\Doctrine;
use Carbon\Carbon;
use DateTime;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\VarDateTimeType;
class DateTimeType extends VarDateTimeType implements CarbonDoctrineType
{
/** @use CarbonTypeConverter<Carbon> */
use CarbonTypeConverter;
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?Carbon
{
return $this->doConvertToPHPValue($value);
}
}

View file

@ -33,16 +33,8 @@ return array(
'AWS\\CRT\\OptionValue' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Options.php',
'AWS\\CRT\\Options' => $vendorDir . '/aws/aws-crt-php/src/AWS/CRT/Options.php',
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'CURLStringFile' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'DateError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
'DateException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
'DateInvalidOperationException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateInvalidOperationException.php',
'DateInvalidTimeZoneException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateInvalidTimeZoneException.php',
'DateMalformedIntervalStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedIntervalStringException.php',
'DateMalformedPeriodStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedPeriodStringException.php',
'DateMalformedStringException' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',
'DateObjectError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',
'DateRangeError' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',
'Google_AccessToken_Revoke' => $vendorDir . '/google/apiclient/src/aliases.php',
'Google_AccessToken_Verify' => $vendorDir . '/google/apiclient/src/aliases.php',
'Google_AuthHandler_AuthHandlerFactory' => $vendorDir . '/google/apiclient/src/aliases.php',
@ -116,10 +108,9 @@ return array(
'OpenPGP_UserAttributePacket' => $vendorDir . '/singpolyma/openpgp-php/lib/openpgp.php',
'OpenPGP_UserIDPacket' => $vendorDir . '/singpolyma/openpgp-php/lib/openpgp.php',
'OpenSSLWrapper' => $vendorDir . '/singpolyma/openpgp-php/lib/openpgp_openssl_wrapper.php',
'Override' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/Override.php',
'PHP_ICO' => $vendorDir . '/chrisjean/php-ico/class-php-ico.php',
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'SQLite3Exception' => $vendorDir . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',
'ReturnTypeWillChange' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',

View file

@ -7,16 +7,17 @@ $baseDir = dirname($vendorDir);
return array(
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'ad155f8f1cf0d418fe49e248db8c661b' => $vendorDir . '/react/promise/src/functions_include.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php',
'23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php',
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php',
@ -24,7 +25,6 @@ return array(
'e39a8b23c42d4e1452234d762b03835a' => $vendorDir . '/ramsey/uuid/src/functions.php',
'1f87db08236948d07391152dccb70f04' => $vendorDir . '/google/apiclient-services/autoload.php',
'b067bc7112e384b61c701452d53a14a8' => $vendorDir . '/mtdowling/jmespath.php/src/JmesPath.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'e8aa6e4b5a1db2f56ae794f1505391a8' => $vendorDir . '/amphp/amp/lib/functions.php',
'76cd0796156622033397994f25b0d8fc' => $vendorDir . '/amphp/amp/lib/Internal/functions.php',
'8a9dc1de0ca7e01f3e08231539562f61' => $vendorDir . '/aws/aws-sdk-php/src/functions.php',

View file

@ -9,7 +9,7 @@ return array(
'phpseclib3\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
'Vimeo\\' => array($vendorDir . '/vimeo/vimeo-api/src/Vimeo'),
'TusPhp\\' => array($vendorDir . '/ankitpokhrel/tus-php/src'),
'Symfony\\Polyfill\\Php83\\' => array($vendorDir . '/symfony/polyfill-php83'),
'Symfony\\Polyfill\\Php81\\' => array($vendorDir . '/symfony/polyfill-php81'),
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'),
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),

View file

@ -8,16 +8,17 @@ class ComposerStaticInitc3a61dba26daada128f5891f1a57c504
{
public static $files = array (
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'662a729f963d39afe703c9d9b7ab4a8c' => __DIR__ . '/..' . '/symfony/polyfill-php83/bootstrap.php',
'23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php',
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php',
@ -25,7 +26,6 @@ class ComposerStaticInitc3a61dba26daada128f5891f1a57c504
'e39a8b23c42d4e1452234d762b03835a' => __DIR__ . '/..' . '/ramsey/uuid/src/functions.php',
'1f87db08236948d07391152dccb70f04' => __DIR__ . '/..' . '/google/apiclient-services/autoload.php',
'b067bc7112e384b61c701452d53a14a8' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/JmesPath.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'e8aa6e4b5a1db2f56ae794f1505391a8' => __DIR__ . '/..' . '/amphp/amp/lib/functions.php',
'76cd0796156622033397994f25b0d8fc' => __DIR__ . '/..' . '/amphp/amp/lib/Internal/functions.php',
'8a9dc1de0ca7e01f3e08231539562f61' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/functions.php',
@ -49,7 +49,7 @@ class ComposerStaticInitc3a61dba26daada128f5891f1a57c504
),
'S' =>
array (
'Symfony\\Polyfill\\Php83\\' => 23,
'Symfony\\Polyfill\\Php81\\' => 23,
'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Polyfill\\Php73\\' => 23,
'Symfony\\Polyfill\\Php72\\' => 23,
@ -176,9 +176,9 @@ class ComposerStaticInitc3a61dba26daada128f5891f1a57c504
array (
0 => __DIR__ . '/..' . '/ankitpokhrel/tus-php/src',
),
'Symfony\\Polyfill\\Php83\\' =>
'Symfony\\Polyfill\\Php81\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php83',
0 => __DIR__ . '/..' . '/symfony/polyfill-php81',
),
'Symfony\\Polyfill\\Php80\\' =>
array (
@ -513,16 +513,8 @@ class ComposerStaticInitc3a61dba26daada128f5891f1a57c504
'AWS\\CRT\\OptionValue' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Options.php',
'AWS\\CRT\\Options' => __DIR__ . '/..' . '/aws/aws-crt-php/src/AWS/CRT/Options.php',
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'CURLStringFile' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'DateError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateError.php',
'DateException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateException.php',
'DateInvalidOperationException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateInvalidOperationException.php',
'DateInvalidTimeZoneException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateInvalidTimeZoneException.php',
'DateMalformedIntervalStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedIntervalStringException.php',
'DateMalformedPeriodStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedPeriodStringException.php',
'DateMalformedStringException' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateMalformedStringException.php',
'DateObjectError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateObjectError.php',
'DateRangeError' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/DateRangeError.php',
'Google_AccessToken_Revoke' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
'Google_AccessToken_Verify' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
'Google_AuthHandler_AuthHandlerFactory' => __DIR__ . '/..' . '/google/apiclient/src/aliases.php',
@ -596,10 +588,9 @@ class ComposerStaticInitc3a61dba26daada128f5891f1a57c504
'OpenPGP_UserAttributePacket' => __DIR__ . '/..' . '/singpolyma/openpgp-php/lib/openpgp.php',
'OpenPGP_UserIDPacket' => __DIR__ . '/..' . '/singpolyma/openpgp-php/lib/openpgp.php',
'OpenSSLWrapper' => __DIR__ . '/..' . '/singpolyma/openpgp-php/lib/openpgp_openssl_wrapper.php',
'Override' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/Override.php',
'PHP_ICO' => __DIR__ . '/..' . '/chrisjean/php-ico/class-php-ico.php',
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'SQLite3Exception' => __DIR__ . '/..' . '/symfony/polyfill-php83/Resources/stubs/SQLite3Exception.php',
'ReturnTypeWillChange' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',

View file

@ -494,31 +494,31 @@
},
{
"name": "carbonphp/carbon-doctrine-types",
"version": "3.2.0",
"version_normalized": "3.2.0.0",
"version": "2.1.0",
"version_normalized": "2.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/CarbonPHP/carbon-doctrine-types.git",
"reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d"
"reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
"reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
"url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/99f76ffa36cce3b70a4a6abce41dba15ca2e84cb",
"reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb",
"shasum": ""
},
"require": {
"php": "^8.1"
"php": "^7.4 || ^8.0"
},
"conflict": {
"doctrine/dbal": "<4.0.0 || >=5.0.0"
"doctrine/dbal": "<3.7.0 || >=4.0.0"
},
"require-dev": {
"doctrine/dbal": "^4.0.0",
"doctrine/dbal": "^3.7.0",
"nesbot/carbon": "^2.71.0 || ^3.0.0",
"phpunit/phpunit": "^10.3"
},
"time": "2024-02-09T16:56:22+00:00",
"time": "2023-12-11T17:09:12+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -546,7 +546,7 @@
],
"support": {
"issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues",
"source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0"
"source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/2.1.0"
},
"funding": [
{
@ -2931,29 +2931,24 @@
},
{
"name": "psr/container",
"version": "2.0.2",
"version_normalized": "2.0.2.0",
"version": "1.1.2",
"version_normalized": "1.1.2.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
"reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
"shasum": ""
},
"require": {
"php": ">=7.4.0"
},
"time": "2021-11-05T16:47:00+00:00",
"time": "2021-11-05T16:50:12+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
@ -2981,7 +2976,7 @@
],
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/2.0.2"
"source": "https://github.com/php-fig/container/tree/1.1.2"
},
"install-path": "../psr/container"
},
@ -3309,21 +3304,22 @@
},
{
"name": "ramsey/collection",
"version": "2.0.0",
"version_normalized": "2.0.0.0",
"version": "1.3.0",
"version_normalized": "1.3.0.0",
"source": {
"type": "git",
"url": "https://github.com/ramsey/collection.git",
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5"
"reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
"url": "https://api.github.com/repos/ramsey/collection/zipball/ad7475d1c9e70b190ecffc58f2d989416af339b4",
"reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4",
"shasum": ""
},
"require": {
"php": "^8.1"
"php": "^7.4 || ^8.0",
"symfony/polyfill-php81": "^1.23"
},
"require-dev": {
"captainhook/plugin-composer": "^5.3",
@ -3347,7 +3343,7 @@
"ramsey/conventional-commits": "^1.3",
"vimeo/psalm": "^5.4"
},
"time": "2022-12-31T21:50:55+00:00",
"time": "2022-12-27T19:12:24+00:00",
"type": "library",
"extra": {
"captainhook": {
@ -3385,7 +3381,7 @@
],
"support": {
"issues": "https://github.com/ramsey/collection/issues",
"source": "https://github.com/ramsey/collection/tree/2.0.0"
"source": "https://github.com/ramsey/collection/tree/1.3.0"
},
"funding": [
{
@ -4296,50 +4292,55 @@
},
{
"name": "symfony/console",
"version": "v6.4.4",
"version_normalized": "6.4.4.0",
"version": "v5.4.36",
"version_normalized": "5.4.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "0d9e4eb5ad413075624378f474c4167ea202de78"
"reference": "39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/0d9e4eb5ad413075624378f474c4167ea202de78",
"reference": "0d9e4eb5ad413075624378f474c4167ea202de78",
"url": "https://api.github.com/repos/symfony/console/zipball/39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e",
"reference": "39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3",
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/service-contracts": "^2.5|^3",
"symfony/string": "^5.4|^6.0|^7.0"
"symfony/polyfill-php73": "^1.9",
"symfony/polyfill-php80": "^1.16",
"symfony/service-contracts": "^1.1|^2|^3",
"symfony/string": "^5.1|^6.0"
},
"conflict": {
"symfony/dependency-injection": "<5.4",
"symfony/dotenv": "<5.4",
"symfony/event-dispatcher": "<5.4",
"symfony/lock": "<5.4",
"symfony/process": "<5.4"
"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"
},
"provide": {
"psr/log-implementation": "1.0|2.0|3.0"
"psr/log-implementation": "1.0|2.0"
},
"require-dev": {
"psr/log": "^1|^2|^3",
"symfony/config": "^5.4|^6.0|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/event-dispatcher": "^5.4|^6.0|^7.0",
"symfony/http-foundation": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/lock": "^5.4|^6.0|^7.0",
"symfony/messenger": "^5.4|^6.0|^7.0",
"symfony/process": "^5.4|^6.0|^7.0",
"symfony/stopwatch": "^5.4|^6.0|^7.0",
"symfony/var-dumper": "^5.4|^6.0|^7.0"
"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"
},
"time": "2024-02-22T20:27:10+00:00",
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
},
"time": "2024-02-20T16:33:57+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -4373,7 +4374,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.4.4"
"source": "https://github.com/symfony/console/tree/v5.4.36"
},
"funding": [
{
@ -4393,27 +4394,27 @@
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.4.0",
"version_normalized": "3.4.0.0",
"version": "v2.5.2",
"version_normalized": "2.5.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
"shasum": ""
},
"require": {
"php": ">=8.1"
"php": ">=7.1"
},
"time": "2023-05-23T14:45:45+00:00",
"time": "2022-01-02T09:53:40+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.4-dev"
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -4443,7 +4444,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2"
},
"funding": [
{
@ -4463,42 +4464,47 @@
},
{
"name": "symfony/event-dispatcher",
"version": "v6.4.3",
"version_normalized": "6.4.3.0",
"version": "v5.4.35",
"version_normalized": "5.4.35.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "ae9d3a6f3003a6caf56acd7466d8d52378d44fef"
"reference": "7a69a85c7ea5bdd1e875806a99c51a87d3a74b38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ae9d3a6f3003a6caf56acd7466d8d52378d44fef",
"reference": "ae9d3a6f3003a6caf56acd7466d8d52378d44fef",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7a69a85c7ea5bdd1e875806a99c51a87d3a74b38",
"reference": "7a69a85c7ea5bdd1e875806a99c51a87d3a74b38",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/event-dispatcher-contracts": "^2.5|^3"
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/event-dispatcher-contracts": "^2|^3",
"symfony/polyfill-php80": "^1.16"
},
"conflict": {
"symfony/dependency-injection": "<5.4",
"symfony/service-contracts": "<2.5"
"symfony/dependency-injection": "<4.4"
},
"provide": {
"psr/event-dispatcher-implementation": "1.0",
"symfony/event-dispatcher-implementation": "2.0|3.0"
"symfony/event-dispatcher-implementation": "2.0"
},
"require-dev": {
"psr/log": "^1|^2|^3",
"symfony/config": "^5.4|^6.0|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/error-handler": "^5.4|^6.0|^7.0",
"symfony/expression-language": "^5.4|^6.0|^7.0",
"symfony/http-foundation": "^5.4|^6.0|^7.0",
"symfony/service-contracts": "^2.5|^3",
"symfony/stopwatch": "^5.4|^6.0|^7.0"
"symfony/config": "^4.4|^5.0|^6.0",
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/error-handler": "^4.4|^5.0|^6.0",
"symfony/expression-language": "^4.4|^5.0|^6.0",
"symfony/http-foundation": "^4.4|^5.0|^6.0",
"symfony/service-contracts": "^1.1|^2|^3",
"symfony/stopwatch": "^4.4|^5.0|^6.0"
},
"time": "2024-01-23T14:51:35+00:00",
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"time": "2024-01-23T13:51:25+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -4526,7 +4532,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v6.4.3"
"source": "https://github.com/symfony/event-dispatcher/tree/v5.4.35"
},
"funding": [
{
@ -4546,28 +4552,31 @@
},
{
"name": "symfony/event-dispatcher-contracts",
"version": "v3.4.0",
"version_normalized": "3.4.0.0",
"version": "v2.5.2",
"version_normalized": "2.5.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
"reference": "a76aed96a42d2b521153fb382d418e30d18b59df"
"reference": "f98b54df6ad059855739db6fcbc2d36995283fe1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df",
"reference": "a76aed96a42d2b521153fb382d418e30d18b59df",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1",
"reference": "f98b54df6ad059855739db6fcbc2d36995283fe1",
"shasum": ""
},
"require": {
"php": ">=8.1",
"php": ">=7.2.5",
"psr/event-dispatcher": "^1"
},
"time": "2023-05-23T14:45:45+00:00",
"suggest": {
"symfony/event-dispatcher-implementation": ""
},
"time": "2022-01-02T09:53:40+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.4-dev"
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -4605,7 +4614,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.0"
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2"
},
"funding": [
{
@ -4800,39 +4809,38 @@
},
{
"name": "symfony/http-foundation",
"version": "v6.4.4",
"version_normalized": "6.4.4.0",
"version": "v5.4.35",
"version_normalized": "5.4.35.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304"
"reference": "f2ab692a22aef1cd54beb893aa0068bdfb093928"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/ebc713bc6e6f4b53f46539fc158be85dfcd77304",
"reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/f2ab692a22aef1cd54beb893aa0068bdfb093928",
"reference": "f2ab692a22aef1cd54beb893aa0068bdfb093928",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3",
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-mbstring": "~1.1",
"symfony/polyfill-php83": "^1.27"
},
"conflict": {
"symfony/cache": "<6.3"
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"doctrine/dbal": "^2.13.1|^3|^4",
"predis/predis": "^1.1|^2.0",
"symfony/cache": "^6.3|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/expression-language": "^5.4|^6.0|^7.0",
"symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0",
"symfony/mime": "^5.4|^6.0|^7.0",
"symfony/rate-limiter": "^5.4|^6.0|^7.0"
"predis/predis": "~1.0",
"symfony/cache": "^4.4|^5.0|^6.0",
"symfony/dependency-injection": "^5.4|^6.0",
"symfony/expression-language": "^4.4|^5.0|^6.0",
"symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4",
"symfony/mime": "^4.4|^5.0|^6.0",
"symfony/rate-limiter": "^5.2|^6.0"
},
"time": "2024-02-08T15:01:18+00:00",
"suggest": {
"symfony/mime": "To use the file extension guesser"
},
"time": "2024-01-23T13:51:25+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -4860,7 +4868,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v6.4.4"
"source": "https://github.com/symfony/http-foundation/tree/v5.4.35"
},
"funding": [
{
@ -4880,42 +4888,42 @@
},
{
"name": "symfony/mime",
"version": "v6.4.3",
"version_normalized": "6.4.3.0",
"version": "v5.4.35",
"version_normalized": "5.4.35.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "5017e0a9398c77090b7694be46f20eb796262a34"
"reference": "ee94d9b538f93abbbc1ee4ccff374593117b04a9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/5017e0a9398c77090b7694be46f20eb796262a34",
"reference": "5017e0a9398c77090b7694be46f20eb796262a34",
"url": "https://api.github.com/repos/symfony/mime/zipball/ee94d9b538f93abbbc1ee4ccff374593117b04a9",
"reference": "ee94d9b538f93abbbc1ee4ccff374593117b04a9",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3",
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-intl-idn": "^1.10",
"symfony/polyfill-mbstring": "^1.0"
"symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php80": "^1.16"
},
"conflict": {
"egulias/email-validator": "~3.0.0",
"phpdocumentor/reflection-docblock": "<3.2.2",
"phpdocumentor/type-resolver": "<1.4.0",
"symfony/mailer": "<5.4",
"symfony/serializer": "<6.3.2"
"symfony/mailer": "<4.4",
"symfony/serializer": "<5.4.35|>=6,<6.3.12|>=6.4,<6.4.3"
},
"require-dev": {
"egulias/email-validator": "^2.1.10|^3.1|^4",
"league/html-to-markdown": "^5.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/property-access": "^5.4|^6.0|^7.0",
"symfony/property-info": "^5.4|^6.0|^7.0",
"symfony/serializer": "^6.3.2|^7.0"
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/property-access": "^4.4|^5.1|^6.0",
"symfony/property-info": "^4.4|^5.1|^6.0",
"symfony/serializer": "^5.4.35|~6.3.12|^6.4.3"
},
"time": "2024-01-30T08:32:12+00:00",
"time": "2024-01-30T08:00:51+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -4947,7 +4955,7 @@
"mime-type"
],
"support": {
"source": "https://github.com/symfony/mime/tree/v6.4.3"
"source": "https://github.com/symfony/mime/tree/v5.4.35"
},
"funding": [
{
@ -4967,24 +4975,26 @@
},
{
"name": "symfony/options-resolver",
"version": "v6.4.0",
"version_normalized": "6.4.0.0",
"version": "v5.4.21",
"version_normalized": "5.4.21.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "22301f0e7fdeaacc14318928612dee79be99860e"
"reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/22301f0e7fdeaacc14318928612dee79be99860e",
"reference": "22301f0e7fdeaacc14318928612dee79be99860e",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9",
"reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3"
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-php73": "~1.0",
"symfony/polyfill-php80": "^1.16"
},
"time": "2023-08-08T10:16:24+00:00",
"time": "2023-02-14T08:03:56+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -5017,7 +5027,7 @@
"options"
],
"support": {
"source": "https://github.com/symfony/options-resolver/tree/v6.4.0"
"source": "https://github.com/symfony/options-resolver/tree/v5.4.21"
},
"funding": [
{
@ -5691,23 +5701,22 @@
"install-path": "../symfony/polyfill-php80"
},
{
"name": "symfony/polyfill-php83",
"name": "symfony/polyfill-php81",
"version": "v1.29.0",
"version_normalized": "1.29.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php83.git",
"reference": "86fcae159633351e5fd145d1c47de6c528f8caff"
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "c565ad1e63f30e7477fc40738343c62b40bc672d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/86fcae159633351e5fd145d1c47de6c528f8caff",
"reference": "86fcae159633351e5fd145d1c47de6c528f8caff",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/c565ad1e63f30e7477fc40738343c62b40bc672d",
"reference": "c565ad1e63f30e7477fc40738343c62b40bc672d",
"shasum": ""
},
"require": {
"php": ">=7.1",
"symfony/polyfill-php80": "^1.14"
"php": ">=7.1"
},
"time": "2024-01-29T20:11:03+00:00",
"type": "library",
@ -5723,7 +5732,7 @@
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php83\\": ""
"Symfony\\Polyfill\\Php81\\": ""
},
"classmap": [
"Resources/stubs"
@ -5743,7 +5752,7 @@
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions",
"description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
@ -5752,7 +5761,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php83/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-php81/tree/v1.29.0"
},
"funding": [
{
@ -5768,43 +5777,50 @@
"type": "tidelift"
}
],
"install-path": "../symfony/polyfill-php83"
"install-path": "../symfony/polyfill-php81"
},
{
"name": "symfony/routing",
"version": "v6.4.5",
"version_normalized": "6.4.5.0",
"version": "v5.4.37",
"version_normalized": "5.4.37.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
"reference": "7fe30068e207d9c31c0138501ab40358eb2d49a4"
"reference": "48ae43e443693ddb4e574f7c12f0d17ce287694e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/routing/zipball/7fe30068e207d9c31c0138501ab40358eb2d49a4",
"reference": "7fe30068e207d9c31c0138501ab40358eb2d49a4",
"url": "https://api.github.com/repos/symfony/routing/zipball/48ae43e443693ddb4e574f7c12f0d17ce287694e",
"reference": "48ae43e443693ddb4e574f7c12f0d17ce287694e",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3"
"php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-php80": "^1.16"
},
"conflict": {
"doctrine/annotations": "<1.12",
"symfony/config": "<6.2",
"symfony/dependency-injection": "<5.4",
"symfony/yaml": "<5.4"
"symfony/config": "<5.3",
"symfony/dependency-injection": "<4.4",
"symfony/yaml": "<4.4"
},
"require-dev": {
"doctrine/annotations": "^1.12|^2",
"psr/log": "^1|^2|^3",
"symfony/config": "^6.2|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/expression-language": "^5.4|^6.0|^7.0",
"symfony/http-foundation": "^5.4|^6.0|^7.0",
"symfony/yaml": "^5.4|^6.0|^7.0"
"symfony/config": "^5.3|^6.0",
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/expression-language": "^4.4|^5.0|^6.0",
"symfony/http-foundation": "^4.4|^5.0|^6.0",
"symfony/yaml": "^4.4|^5.0|^6.0"
},
"time": "2024-02-27T12:33:30+00:00",
"suggest": {
"symfony/config": "For using the all-in-one router or any loader",
"symfony/expression-language": "For using expression matching",
"symfony/http-foundation": "For using a Symfony Request object",
"symfony/yaml": "For using the YAML loader"
},
"time": "2024-02-27T09:52:32+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -5838,7 +5854,7 @@
"url"
],
"support": {
"source": "https://github.com/symfony/routing/tree/v6.4.5"
"source": "https://github.com/symfony/routing/tree/v5.4.37"
},
"funding": [
{
@ -5858,31 +5874,35 @@
},
{
"name": "symfony/service-contracts",
"version": "v3.4.1",
"version_normalized": "3.4.1.0",
"version": "v2.5.2",
"version_normalized": "2.5.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "fe07cbc8d837f60caf7018068e350cc5163681a0"
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0",
"reference": "fe07cbc8d837f60caf7018068e350cc5163681a0",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
"shasum": ""
},
"require": {
"php": ">=8.1",
"psr/container": "^1.1|^2.0"
"php": ">=7.2.5",
"psr/container": "^1.1",
"symfony/deprecation-contracts": "^2.1|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
},
"time": "2023-12-26T14:02:43+00:00",
"suggest": {
"symfony/service-implementation": ""
},
"time": "2022-05-30T19:17:29+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.4-dev"
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -5893,10 +5913,7 @@
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -5923,7 +5940,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.4.1"
"source": "https://github.com/symfony/service-contracts/tree/v2.5.2"
},
"funding": [
{
@ -5943,37 +5960,37 @@
},
{
"name": "symfony/string",
"version": "v6.4.4",
"version_normalized": "6.4.4.0",
"version": "v5.4.36",
"version_normalized": "5.4.36.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9"
"reference": "4e232c83622bd8cd32b794216aa29d0d266d353b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9",
"reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9",
"url": "https://api.github.com/repos/symfony/string/zipball/4e232c83622bd8cd32b794216aa29d0d266d353b",
"reference": "4e232c83622bd8cd32b794216aa29d0d266d353b",
"shasum": ""
},
"require": {
"php": ">=8.1",
"php": ">=7.2.5",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-intl-grapheme": "~1.0",
"symfony/polyfill-intl-normalizer": "~1.0",
"symfony/polyfill-mbstring": "~1.0"
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php80": "~1.15"
},
"conflict": {
"symfony/translation-contracts": "<2.5"
"symfony/translation-contracts": ">=3.0"
},
"require-dev": {
"symfony/error-handler": "^5.4|^6.0|^7.0",
"symfony/http-client": "^5.4|^6.0|^7.0",
"symfony/intl": "^6.2|^7.0",
"symfony/translation-contracts": "^2.5|^3.0",
"symfony/var-exporter": "^5.4|^6.0|^7.0"
"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"
},
"time": "2024-02-01T13:16:41+00:00",
"time": "2024-02-01T08:49:30+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -6012,7 +6029,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v6.4.4"
"source": "https://github.com/symfony/string/tree/v5.4.36"
},
"funding": [
{

View file

@ -5,7 +5,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '7673eda07e6599ae459b50f273eb6bed73ae1c26',
'reference' => '330cdbe615c93927cb99d0f1161f1c570506fbe1',
'name' => 'wwbn/avideo',
'dev' => true,
),
@ -74,12 +74,12 @@
'dev_requirement' => false,
),
'carbonphp/carbon-doctrine-types' => array(
'pretty_version' => '3.2.0',
'version' => '3.2.0.0',
'pretty_version' => '2.1.0',
'version' => '2.1.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../carbonphp/carbon-doctrine-types',
'aliases' => array(),
'reference' => '18ba5ddfec8976260ead6e866180bd5d2f71aa1d',
'reference' => '99f76ffa36cce3b70a4a6abce41dba15ca2e84cb',
'dev_requirement' => false,
),
'cboden/ratchet' => array(
@ -413,12 +413,12 @@
),
),
'psr/container' => array(
'pretty_version' => '2.0.2',
'version' => '2.0.2.0',
'pretty_version' => '1.1.2',
'version' => '1.1.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/container',
'aliases' => array(),
'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963',
'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea',
'dev_requirement' => false,
),
'psr/event-dispatcher' => array(
@ -494,7 +494,7 @@
'dev_requirement' => false,
'provided' => array(
0 => '1.0.0 || 2.0.0 || 3.0.0',
1 => '1.0|2.0|3.0',
1 => '1.0|2.0',
),
),
'ralouphie/getallheaders' => array(
@ -507,12 +507,12 @@
'dev_requirement' => false,
),
'ramsey/collection' => array(
'pretty_version' => '2.0.0',
'version' => '2.0.0.0',
'pretty_version' => '1.3.0',
'version' => '1.3.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../ramsey/collection',
'aliases' => array(),
'reference' => 'a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5',
'reference' => 'ad7475d1c9e70b190ecffc58f2d989416af339b4',
'dev_requirement' => false,
),
'ramsey/uuid' => array(
@ -630,45 +630,45 @@
'dev_requirement' => false,
),
'symfony/console' => array(
'pretty_version' => 'v6.4.4',
'version' => '6.4.4.0',
'pretty_version' => 'v5.4.36',
'version' => '5.4.36.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(),
'reference' => '0d9e4eb5ad413075624378f474c4167ea202de78',
'reference' => '39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e',
'dev_requirement' => false,
),
'symfony/deprecation-contracts' => array(
'pretty_version' => 'v3.4.0',
'version' => '3.4.0.0',
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
'aliases' => array(),
'reference' => '7c3aff79d10325257a001fcf92d991f24fc967cf',
'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66',
'dev_requirement' => false,
),
'symfony/event-dispatcher' => array(
'pretty_version' => 'v6.4.3',
'version' => '6.4.3.0',
'pretty_version' => 'v5.4.35',
'version' => '5.4.35.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/event-dispatcher',
'aliases' => array(),
'reference' => 'ae9d3a6f3003a6caf56acd7466d8d52378d44fef',
'reference' => '7a69a85c7ea5bdd1e875806a99c51a87d3a74b38',
'dev_requirement' => false,
),
'symfony/event-dispatcher-contracts' => array(
'pretty_version' => 'v3.4.0',
'version' => '3.4.0.0',
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts',
'aliases' => array(),
'reference' => 'a76aed96a42d2b521153fb382d418e30d18b59df',
'reference' => 'f98b54df6ad059855739db6fcbc2d36995283fe1',
'dev_requirement' => false,
),
'symfony/event-dispatcher-implementation' => array(
'dev_requirement' => false,
'provided' => array(
0 => '2.0|3.0',
0 => '2.0',
),
),
'symfony/http-client' => array(
@ -696,30 +696,30 @@
),
),
'symfony/http-foundation' => array(
'pretty_version' => 'v6.4.4',
'version' => '6.4.4.0',
'pretty_version' => 'v5.4.35',
'version' => '5.4.35.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-foundation',
'aliases' => array(),
'reference' => 'ebc713bc6e6f4b53f46539fc158be85dfcd77304',
'reference' => 'f2ab692a22aef1cd54beb893aa0068bdfb093928',
'dev_requirement' => false,
),
'symfony/mime' => array(
'pretty_version' => 'v6.4.3',
'version' => '6.4.3.0',
'pretty_version' => 'v5.4.35',
'version' => '5.4.35.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/mime',
'aliases' => array(),
'reference' => '5017e0a9398c77090b7694be46f20eb796262a34',
'reference' => 'ee94d9b538f93abbbc1ee4ccff374593117b04a9',
'dev_requirement' => false,
),
'symfony/options-resolver' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'pretty_version' => 'v5.4.21',
'version' => '5.4.21.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/options-resolver',
'aliases' => array(),
'reference' => '22301f0e7fdeaacc14318928612dee79be99860e',
'reference' => '4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9',
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
@ -794,40 +794,40 @@
'reference' => '87b68208d5c1188808dd7839ee1e6c8ec3b02f1b',
'dev_requirement' => false,
),
'symfony/polyfill-php83' => array(
'symfony/polyfill-php81' => array(
'pretty_version' => 'v1.29.0',
'version' => '1.29.0.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php83',
'install_path' => __DIR__ . '/../symfony/polyfill-php81',
'aliases' => array(),
'reference' => '86fcae159633351e5fd145d1c47de6c528f8caff',
'reference' => 'c565ad1e63f30e7477fc40738343c62b40bc672d',
'dev_requirement' => false,
),
'symfony/routing' => array(
'pretty_version' => 'v6.4.5',
'version' => '6.4.5.0',
'pretty_version' => 'v5.4.37',
'version' => '5.4.37.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/routing',
'aliases' => array(),
'reference' => '7fe30068e207d9c31c0138501ab40358eb2d49a4',
'reference' => '48ae43e443693ddb4e574f7c12f0d17ce287694e',
'dev_requirement' => false,
),
'symfony/service-contracts' => array(
'pretty_version' => 'v3.4.1',
'version' => '3.4.1.0',
'pretty_version' => 'v2.5.2',
'version' => '2.5.2.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/service-contracts',
'aliases' => array(),
'reference' => 'fe07cbc8d837f60caf7018068e350cc5163681a0',
'reference' => '4b426aac47d6427cc1a1d0f7e2ac724627f5966c',
'dev_requirement' => false,
),
'symfony/string' => array(
'pretty_version' => 'v6.4.4',
'version' => '6.4.4.0',
'pretty_version' => 'v5.4.36',
'version' => '5.4.36.0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/string',
'aliases' => array(),
'reference' => '4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9',
'reference' => '4e232c83622bd8cd32b794216aa29d0d266d353b',
'dev_requirement' => false,
),
'symfony/translation' => array(
@ -869,7 +869,7 @@
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '7673eda07e6599ae459b50f273eb6bed73ae1c26',
'reference' => '330cdbe615c93927cb99d0f1161f1c570506fbe1',
'dev_requirement' => false,
),
),

View file

@ -18,10 +18,5 @@
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
}
}

View file

@ -32,5 +32,5 @@ interface ContainerInterface
*
* @return bool
*/
public function has(string $id): bool;
public function has(string $id);
}

View file

@ -19,7 +19,8 @@
}
],
"require": {
"php": "^8.1"
"php": "^7.4 || ^8.0",
"symfony/polyfill-php81": "^1.23"
},
"require-dev": {
"captainhook/plugin-composer": "^5.3",

View file

@ -18,6 +18,8 @@ use ArrayIterator;
use Traversable;
use function count;
use function serialize;
use function unserialize;
/**
* This class provides a basic implementation of `ArrayInterface`, to minimize
@ -68,7 +70,7 @@ abstract class AbstractArray implements ArrayInterface
*
* @param array-key $offset The offset to check.
*/
public function offsetExists(mixed $offset): bool
public function offsetExists($offset): bool
{
return isset($this->data[$offset]);
}
@ -80,12 +82,13 @@ abstract class AbstractArray implements ArrayInterface
*
* @param array-key $offset The offset for which a value should be returned.
*
* @return T the value stored at the offset, or null if the offset
* @return T|null the value stored at the offset, or null if the offset
* does not exist.
*/
public function offsetGet(mixed $offset): mixed
#[\ReturnTypeWillChange] // phpcs:ignore
public function offsetGet($offset)
{
return $this->data[$offset];
return $this->data[$offset] ?? null;
}
/**
@ -93,11 +96,12 @@ abstract class AbstractArray implements ArrayInterface
*
* @link http://php.net/manual/en/arrayaccess.offsetset.php ArrayAccess::offsetSet()
*
* @param array-key | null $offset The offset to set. If `null`, the value
* may be set at a numerically-indexed offset.
* @param array-key|null $offset The offset to set. If `null`, the value may be
* set at a numerically-indexed offset.
* @param T $value The value to set at the given offset.
*/
public function offsetSet(mixed $offset, mixed $value): void
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function offsetSet($offset, $value): void
{
if ($offset === null) {
$this->data[] = $value;
@ -113,11 +117,25 @@ abstract class AbstractArray implements ArrayInterface
*
* @param array-key $offset The offset to remove from the array.
*/
public function offsetUnset(mixed $offset): void
public function offsetUnset($offset): void
{
unset($this->data[$offset]);
}
/**
* Returns a serialized string representation of this array object.
*
* @deprecated The Serializable interface will go away in PHP 9.
*
* @link http://php.net/manual/en/serializable.serialize.php Serializable::serialize()
*
* @return string a PHP serialized string.
*/
public function serialize(): string
{
return serialize($this->data);
}
/**
* Returns data suitable for PHP serialization.
*
@ -131,6 +149,25 @@ abstract class AbstractArray implements ArrayInterface
return $this->data;
}
/**
* Converts a serialized string representation into an instance object.
*
* @deprecated The Serializable interface will go away in PHP 9.
*
* @link http://php.net/manual/en/serializable.unserialize.php Serializable::unserialize()
*
* @param string $serialized A PHP serialized string to unserialize.
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
*/
public function unserialize($serialized): void
{
/** @var array<array-key, T> $data */
$data = unserialize($serialized, ['allowed_classes' => false]);
$this->data = $data;
}
/**
* Adds unserialized data to the object.
*
@ -166,6 +203,6 @@ abstract class AbstractArray implements ArrayInterface
public function isEmpty(): bool
{
return $this->data === [];
return count($this->data) === 0;
}
}

View file

@ -17,27 +17,27 @@ namespace Ramsey\Collection;
use Closure;
use Ramsey\Collection\Exception\CollectionMismatchException;
use Ramsey\Collection\Exception\InvalidArgumentException;
use Ramsey\Collection\Exception\InvalidPropertyOrMethod;
use Ramsey\Collection\Exception\NoSuchElementException;
use Ramsey\Collection\Exception\UnsupportedOperationException;
use Ramsey\Collection\Exception\InvalidSortOrderException;
use Ramsey\Collection\Exception\OutOfBoundsException;
use Ramsey\Collection\Tool\TypeTrait;
use Ramsey\Collection\Tool\ValueExtractorTrait;
use Ramsey\Collection\Tool\ValueToStringTrait;
use function array_filter;
use function array_key_first;
use function array_key_last;
use function array_map;
use function array_merge;
use function array_reduce;
use function array_search;
use function array_udiff;
use function array_uintersect;
use function current;
use function end;
use function in_array;
use function is_int;
use function is_object;
use function reset;
use function spl_object_id;
use function sprintf;
use function unserialize;
use function usort;
/**
@ -55,24 +55,27 @@ abstract class AbstractCollection extends AbstractArray implements CollectionInt
use ValueExtractorTrait;
/**
* @throws InvalidArgumentException if $element is of the wrong type.
* @inheritDoc
*/
public function add(mixed $element): bool
public function add($element): bool
{
$this[] = $element;
return true;
}
public function contains(mixed $element, bool $strict = true): bool
/**
* @inheritDoc
*/
public function contains($element, bool $strict = true): bool
{
return in_array($element, $this->data, $strict);
}
/**
* @throws InvalidArgumentException if $element is of the wrong type.
* @inheritDoc
*/
public function offsetSet(mixed $offset, mixed $value): void
public function offsetSet($offset, $value): void
{
if ($this->checkType($this->getType(), $value) === false) {
throw new InvalidArgumentException(
@ -88,7 +91,10 @@ abstract class AbstractCollection extends AbstractArray implements CollectionInt
}
}
public function remove(mixed $element): bool
/**
* @inheritDoc
*/
public function remove($element): bool
{
if (($position = array_search($element, $this->data, true)) !== false) {
unset($this[$position]);
@ -100,11 +106,6 @@ abstract class AbstractCollection extends AbstractArray implements CollectionInt
}
/**
* @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist
* on the elements in this collection.
* @throws UnsupportedOperationException if unable to call column() on this
* collection.
*
* @inheritDoc
*/
public function column(string $propertyOrMethod): array
@ -112,55 +113,55 @@ abstract class AbstractCollection extends AbstractArray implements CollectionInt
$temp = [];
foreach ($this->data as $item) {
/** @var mixed $value */
$value = $this->extractValue($item, $propertyOrMethod);
/** @psalm-suppress MixedAssignment */
$temp[] = $this->extractValue($item, $propertyOrMethod);
$temp[] = $value;
}
return $temp;
}
/**
* @return T
*
* @throws NoSuchElementException if this collection is empty.
* @inheritDoc
*/
public function first(): mixed
public function first()
{
$firstIndex = array_key_first($this->data);
if ($firstIndex === null) {
throw new NoSuchElementException('Can\'t determine first item. Collection is empty');
if ($this->isEmpty()) {
throw new OutOfBoundsException('Can\'t determine first item. Collection is empty');
}
return $this->data[$firstIndex];
reset($this->data);
/** @var T $first */
$first = current($this->data);
return $first;
}
/**
* @return T
*
* @throws NoSuchElementException if this collection is empty.
* @inheritDoc
*/
public function last(): mixed
public function last()
{
$lastIndex = array_key_last($this->data);
if ($lastIndex === null) {
throw new NoSuchElementException('Can\'t determine last item. Collection is empty');
if ($this->isEmpty()) {
throw new OutOfBoundsException('Can\'t determine last item. Collection is empty');
}
return $this->data[$lastIndex];
/** @var T $item */
$item = end($this->data);
reset($this->data);
return $item;
}
/**
* @return CollectionInterface<T>
*
* @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist
* on the elements in this collection.
* @throws UnsupportedOperationException if unable to call sort() on this
* collection.
*/
public function sort(?string $propertyOrMethod = null, Sort $order = Sort::Ascending): CollectionInterface
public function sort(string $propertyOrMethod, string $order = self::SORT_ASC): CollectionInterface
{
if (!in_array($order, [self::SORT_ASC, self::SORT_DESC], true)) {
throw new InvalidSortOrderException('Invalid sort order given: ' . $order);
}
$collection = clone $this;
usort(
@ -169,25 +170,20 @@ abstract class AbstractCollection extends AbstractArray implements CollectionInt
* @param T $a
* @param T $b
*/
function (mixed $a, mixed $b) use ($propertyOrMethod, $order): int {
function ($a, $b) use ($propertyOrMethod, $order): int {
/** @var mixed $aValue */
$aValue = $this->extractValue($a, $propertyOrMethod);
/** @var mixed $bValue */
$bValue = $this->extractValue($b, $propertyOrMethod);
return ($aValue <=> $bValue) * ($order === Sort::Descending ? -1 : 1);
return ($aValue <=> $bValue) * ($order === self::SORT_DESC ? -1 : 1);
},
);
return $collection;
}
/**
* @param callable(T): bool $callback A callable to use for filtering elements.
*
* @return CollectionInterface<T>
*/
public function filter(callable $callback): CollectionInterface
{
$collection = clone $this;
@ -197,66 +193,23 @@ abstract class AbstractCollection extends AbstractArray implements CollectionInt
}
/**
* @return CollectionInterface<T>
*
* @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist
* on the elements in this collection.
* @throws UnsupportedOperationException if unable to call where() on this
* collection.
* {@inheritdoc}
*/
public function where(?string $propertyOrMethod, mixed $value): CollectionInterface
public function where(string $propertyOrMethod, $value): CollectionInterface
{
return $this->filter(
/**
* @param T $item
*/
function (mixed $item) use ($propertyOrMethod, $value): bool {
return $this->filter(function ($item) use ($propertyOrMethod, $value) {
/** @var mixed $accessorValue */
$accessorValue = $this->extractValue($item, $propertyOrMethod);
return $accessorValue === $value;
},
);
});
}
/**
* @param callable(T): TCallbackReturn $callback A callable to apply to each
* item of the collection.
*
* @return CollectionInterface<TCallbackReturn>
*
* @template TCallbackReturn
*/
public function map(callable $callback): CollectionInterface
{
/** @var Collection<TCallbackReturn> */
return new Collection('mixed', array_map($callback, $this->data));
}
/**
* @param callable(TCarry, T): TCarry $callback A callable to apply to each
* item of the collection to reduce it to a single value.
* @param TCarry $initial This is the initial value provided to the callback.
*
* @return TCarry
*
* @template TCarry
*/
public function reduce(callable $callback, mixed $initial): mixed
{
/** @var TCarry */
return array_reduce($this->data, $callback, $initial);
}
/**
* @param CollectionInterface<T> $other The collection to check for divergent
* items.
*
* @return CollectionInterface<T>
*
* @throws CollectionMismatchException if the compared collections are of
* differing types.
*/
public function diff(CollectionInterface $other): CollectionInterface
{
$this->compareCollectionTypes($other);
@ -273,15 +226,6 @@ abstract class AbstractCollection extends AbstractArray implements CollectionInt
return $collection;
}
/**
* @param CollectionInterface<T> $other The collection to check for
* intersecting items.
*
* @return CollectionInterface<T>
*
* @throws CollectionMismatchException if the compared collections are of
* differing types.
*/
public function intersect(CollectionInterface $other): CollectionInterface
{
$this->compareCollectionTypes($other);
@ -295,15 +239,6 @@ abstract class AbstractCollection extends AbstractArray implements CollectionInt
return $collection;
}
/**
* @param CollectionInterface<T> ...$collections The collections to merge.
*
* @return CollectionInterface<T>
*
* @throws CollectionMismatchException if unable to merge any of the given
* collections or items within the given collections due to type
* mismatch errors.
*/
public function merge(CollectionInterface ...$collections): CollectionInterface
{
$mergedCollection = clone $this;
@ -339,10 +274,19 @@ abstract class AbstractCollection extends AbstractArray implements CollectionInt
return $mergedCollection;
}
/**
* @inheritDoc
*/
public function unserialize($serialized): void
{
/** @var array<array-key, T> $data */
$data = unserialize($serialized, ['allowed_classes' => [$this->getType()]]);
$this->data = $data;
}
/**
* @param CollectionInterface<T> $other
*
* @throws CollectionMismatchException
*/
private function compareCollectionTypes(CollectionInterface $other): void
{
@ -363,7 +307,7 @@ abstract class AbstractCollection extends AbstractArray implements CollectionInt
* @param T $a
* @param T $b
*/
function (mixed $a, mixed $b): int {
function ($a, $b): int {
// If the two values are object, we convert them to unique scalars.
// If the collection contains mixed values (unlikely) where some are objects
// and some are not, we leave them as they are.
@ -383,11 +327,15 @@ abstract class AbstractCollection extends AbstractArray implements CollectionInt
*/
private function getUniformType(CollectionInterface $collection): string
{
return match ($collection->getType()) {
'integer' => 'int',
'boolean' => 'bool',
'double' => 'float',
default => $collection->getType(),
};
switch ($collection->getType()) {
case 'integer':
return 'int';
case 'boolean':
return 'bool';
case 'double':
return 'float';
default:
return $collection->getType();
}
}
}

View file

@ -24,7 +24,10 @@ namespace Ramsey\Collection;
*/
abstract class AbstractSet extends AbstractCollection
{
public function add(mixed $element): bool
/**
* @inheritDoc
*/
public function add($element): bool
{
if ($this->contains($element)) {
return false;
@ -33,7 +36,10 @@ abstract class AbstractSet extends AbstractCollection
return parent::add($element);
}
public function offsetSet(mixed $offset, mixed $value): void
/**
* @inheritDoc
*/
public function offsetSet($offset, $value): void
{
if ($this->contains($value)) {
return;

View file

@ -17,6 +17,7 @@ namespace Ramsey\Collection;
use ArrayAccess;
use Countable;
use IteratorAggregate;
use Serializable;
/**
* `ArrayInterface` provides traversable array functionality to data types.
@ -28,7 +29,8 @@ use IteratorAggregate;
interface ArrayInterface extends
ArrayAccess,
Countable,
IteratorAggregate
IteratorAggregate,
Serializable
{
/**
* Removes all items from this array.

View file

@ -75,16 +75,25 @@ namespace Ramsey\Collection;
*/
class Collection extends AbstractCollection
{
/**
* The type of elements stored in this collection.
*
* A collection's type is immutable once it is set. For this reason, this
* property is set private.
*/
private string $collectionType;
/**
* Constructs a collection object of the specified type, optionally with the
* specified data.
*
* @param string $collectionType The type or class name associated with this
* @param string $collectionType The type (FQCN) associated with this
* collection.
* @param array<array-key, T> $data The initial items to store in the collection.
*/
public function __construct(private readonly string $collectionType, array $data = [])
public function __construct(string $collectionType, array $data = [])
{
$this->collectionType = $collectionType;
parent::__construct($data);
}

View file

@ -14,14 +14,8 @@ declare(strict_types=1);
namespace Ramsey\Collection;
use Ramsey\Collection\Exception\CollectionMismatchException;
use Ramsey\Collection\Exception\InvalidArgumentException;
use Ramsey\Collection\Exception\InvalidPropertyOrMethod;
use Ramsey\Collection\Exception\NoSuchElementException;
use Ramsey\Collection\Exception\UnsupportedOperationException;
/**
* A collection represents a group of values, known as its elements.
* A collection represents a group of objects, known as its elements.
*
* Some collections allow duplicate elements and others do not. Some are ordered
* and others unordered.
@ -31,6 +25,16 @@ use Ramsey\Collection\Exception\UnsupportedOperationException;
*/
interface CollectionInterface extends ArrayInterface
{
/**
* Ascending sort type.
*/
public const SORT_ASC = 'asc';
/**
* Descending sort type.
*/
public const SORT_DESC = 'desc';
/**
* Ensures that this collection contains the specified element (optional
* operation).
@ -54,11 +58,9 @@ interface CollectionInterface extends ArrayInterface
* @param T $element The element to add to the collection.
*
* @return bool `true` if this collection changed as a result of the call.
*
* @throws InvalidArgumentException if the collection refuses to add the
* $element for any reason other than that it already contains the element.
*/
public function add(mixed $element): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function add($element): bool;
/**
* Returns `true` if this collection contains the specified element.
@ -66,7 +68,8 @@ interface CollectionInterface extends ArrayInterface
* @param T $element The element to check whether the collection contains.
* @param bool $strict Whether to perform a strict type check on the value.
*/
public function contains(mixed $element, bool $strict = true): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function contains($element, bool $strict = true): bool;
/**
* Returns the type associated with this collection.
@ -81,20 +84,15 @@ interface CollectionInterface extends ArrayInterface
*
* @return bool `true` if an element was removed as a result of this call.
*/
public function remove(mixed $element): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function remove($element): bool;
/**
* Returns the values from the given property, method, or array key.
* Returns the values from the given property or method.
*
* @param string $propertyOrMethod The name of the property, method, or
* array key to evaluate and return.
* @param string $propertyOrMethod The property or method name to filter by.
*
* @return array<int, mixed>
*
* @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist
* on the elements in this collection.
* @throws UnsupportedOperationException if unable to call column() on this
* collection.
* @return list<mixed>
*/
public function column(string $propertyOrMethod): array;
@ -102,41 +100,29 @@ interface CollectionInterface extends ArrayInterface
* Returns the first item of the collection.
*
* @return T
*
* @throws NoSuchElementException if this collection is empty.
*/
public function first(): mixed;
public function first();
/**
* Returns the last item of the collection.
*
* @return T
*
* @throws NoSuchElementException if this collection is empty.
*/
public function last(): mixed;
public function last();
/**
* Sort the collection by a property, method, or array key with the given
* sort order.
*
* If $propertyOrMethod is `null`, this will sort by comparing each element.
* Sort the collection by a property or method with the given sort order.
*
* This will always leave the original collection untouched and will return
* a new one.
*
* @param string | null $propertyOrMethod The property, method, or array key
* to sort by.
* @param Sort $order The sort order for the resulting collection.
* @param string $propertyOrMethod The property or method to sort by.
* @param string $order The sort order for the resulting collection (one of
* this interface's `SORT_*` constants).
*
* @return CollectionInterface<T>
*
* @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist
* on the elements in this collection.
* @throws UnsupportedOperationException if unable to call sort() on this
* collection.
*/
public function sort(?string $propertyOrMethod = null, Sort $order = Sort::Ascending): self;
public function sort(string $propertyOrMethod, string $order = self::SORT_ASC): self;
/**
* Filter out items of the collection which don't match the criteria of
@ -148,31 +134,25 @@ interface CollectionInterface extends ArrayInterface
* See the {@link http://php.net/manual/en/function.array-filter.php PHP array_filter() documentation}
* for examples of how the `$callback` parameter works.
*
* @param callable(T): bool $callback A callable to use for filtering elements.
* @param callable(T):bool $callback A callable to use for filtering elements.
*
* @return CollectionInterface<T>
*/
public function filter(callable $callback): self;
/**
* Create a new collection where the result of the given property, method,
* or array key of each item in the collection equals the given value.
* Create a new collection where items match the criteria of given callback.
*
* This will always leave the original collection untouched and will return
* a new one.
*
* @param string | null $propertyOrMethod The property, method, or array key
* to evaluate. If `null`, the element itself is compared to $value.
* @param string $propertyOrMethod The property or method to evaluate.
* @param mixed $value The value to match.
*
* @return CollectionInterface<T>
*
* @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist
* on the elements in this collection.
* @throws UnsupportedOperationException if unable to call where() on this
* collection.
*/
public function where(?string $propertyOrMethod, mixed $value): self;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function where(string $propertyOrMethod, $value): self;
/**
* Apply a given callback method on each item of the collection.
@ -184,7 +164,7 @@ interface CollectionInterface extends ArrayInterface
* See the {@link http://php.net/manual/en/function.array-map.php PHP array_map() documentation}
* for examples of how the `$callback` parameter works.
*
* @param callable(T): TCallbackReturn $callback A callable to apply to each
* @param callable(T):TCallbackReturn $callback A callable to apply to each
* item of the collection.
*
* @return CollectionInterface<TCallbackReturn>
@ -193,23 +173,6 @@ interface CollectionInterface extends ArrayInterface
*/
public function map(callable $callback): self;
/**
* Apply a given callback method on each item of the collection
* to reduce it to a single value.
*
* See the {@link http://php.net/manual/en/function.array-reduce.php PHP array_reduce() documentation}
* for examples of how the `$callback` and `$initial` parameters work.
*
* @param callable(TCarry, T): TCarry $callback A callable to apply to each
* item of the collection to reduce it to a single value.
* @param TCarry $initial This is the initial value provided to the callback.
*
* @return TCarry
*
* @template TCarry
*/
public function reduce(callable $callback, mixed $initial): mixed;
/**
* Create a new collection with divergent items between current and given
* collection.
@ -218,9 +181,6 @@ interface CollectionInterface extends ArrayInterface
* items.
*
* @return CollectionInterface<T>
*
* @throws CollectionMismatchException if the compared collections are of
* differing types.
*/
public function diff(CollectionInterface $other): self;
@ -232,9 +192,6 @@ interface CollectionInterface extends ArrayInterface
* intersecting items.
*
* @return CollectionInterface<T>
*
* @throws CollectionMismatchException if the compared collections are of
* differing types.
*/
public function intersect(CollectionInterface $other): self;
@ -244,10 +201,6 @@ interface CollectionInterface extends ArrayInterface
* @param CollectionInterface<T> ...$collections The collections to merge.
*
* @return CollectionInterface<T>
*
* @throws CollectionMismatchException if unable to merge any of the given
* collections or items within the given collections due to type
* mismatch errors.
*/
public function merge(CollectionInterface ...$collections): self;
}

View file

@ -17,10 +17,6 @@ namespace Ramsey\Collection;
use Ramsey\Collection\Exception\InvalidArgumentException;
use Ramsey\Collection\Exception\NoSuchElementException;
use function array_key_last;
use function array_pop;
use function array_unshift;
/**
* This class provides a basic implementation of `DoubleEndedQueueInterface`, to
* minimize the effort required to implement this interface.
@ -32,21 +28,33 @@ use function array_unshift;
class DoubleEndedQueue extends Queue implements DoubleEndedQueueInterface
{
/**
* Constructs a double-ended queue (dequeue) object of the specified type,
* optionally with the specified data.
*
* @param string $queueType The type or class name associated with this dequeue.
* @param array<array-key, T> $data The initial items to store in the dequeue.
* Index of the last element in the queue.
*/
public function __construct(private readonly string $queueType, array $data = [])
private int $tail = -1;
/**
* @inheritDoc
*/
public function offsetSet($offset, $value): void
{
parent::__construct($this->queueType, $data);
if ($this->checkType($this->getType(), $value) === false) {
throw new InvalidArgumentException(
'Value must be of type ' . $this->getType() . '; value is '
. $this->toolValueToString($value),
);
}
$this->tail++;
$this->data[$this->tail] = $value;
}
/**
* @throws InvalidArgumentException if $element is of the wrong type
*
* @inheritDoc
*/
public function addFirst(mixed $element): bool
public function addFirst($element): bool
{
if ($this->checkType($this->getType(), $element) === false) {
throw new InvalidArgumentException(
@ -55,112 +63,125 @@ class DoubleEndedQueue extends Queue implements DoubleEndedQueueInterface
);
}
array_unshift($this->data, $element);
$this->index--;
$this->data[$this->index] = $element;
return true;
}
/**
* @throws InvalidArgumentException if $element is of the wrong type
* @inheritDoc
*/
public function addLast(mixed $element): bool
public function addLast($element): bool
{
return $this->add($element);
}
public function offerFirst(mixed $element): bool
/**
* @inheritDoc
*/
public function offerFirst($element): bool
{
try {
return $this->addFirst($element);
} catch (InvalidArgumentException) {
} catch (InvalidArgumentException $e) {
return false;
}
}
public function offerLast(mixed $element): bool
/**
* @inheritDoc
*/
public function offerLast($element): bool
{
return $this->offer($element);
}
/**
* @return T the first element in this queue.
*
* @throws NoSuchElementException if the queue is empty
* @inheritDoc
*/
public function removeFirst(): mixed
public function removeFirst()
{
return $this->remove();
}
/**
* @return T the last element in this queue.
*
* @throws NoSuchElementException if this queue is empty.
* @inheritDoc
*/
public function removeLast(): mixed
public function removeLast()
{
return $this->pollLast() ?? throw new NoSuchElementException(
'Can\'t return element from Queue. Queue is empty.',
);
$tail = $this->pollLast();
if ($tail === null) {
throw new NoSuchElementException('Can\'t return element from Queue. Queue is empty.');
}
return $tail;
}
/**
* @return T | null the head of this queue, or `null` if this queue is empty.
* @inheritDoc
*/
public function pollFirst(): mixed
public function pollFirst()
{
return $this->poll();
}
/**
* @return T | null the tail of this queue, or `null` if this queue is empty.
* @inheritDoc
*/
public function pollLast(): mixed
public function pollLast()
{
return array_pop($this->data);
if ($this->count() === 0) {
return null;
}
$tail = $this[$this->tail];
unset($this[$this->tail]);
$this->tail--;
return $tail;
}
/**
* @return T the head of this queue.
*
* @throws NoSuchElementException if this queue is empty.
* @inheritDoc
*/
public function firstElement(): mixed
public function firstElement()
{
return $this->element();
}
/**
* @return T the tail of this queue.
*
* @throws NoSuchElementException if this queue is empty.
* @inheritDoc
*/
public function lastElement(): mixed
public function lastElement()
{
return $this->peekLast() ?? throw new NoSuchElementException(
'Can\'t return element from Queue. Queue is empty.',
);
if ($this->count() === 0) {
throw new NoSuchElementException('Can\'t return element from Queue. Queue is empty.');
}
return $this->data[$this->tail];
}
/**
* @return T | null the head of this queue, or `null` if this queue is empty.
* @inheritDoc
*/
public function peekFirst(): mixed
public function peekFirst()
{
return $this->peek();
}
/**
* @return T | null the tail of this queue, or `null` if this queue is empty.
* @inheritDoc
*/
public function peekLast(): mixed
public function peekLast()
{
$lastIndex = array_key_last($this->data);
if ($lastIndex === null) {
if ($this->count() === 0) {
return null;
}
return $this->data[$lastIndex];
return $this->data[$this->tail];
}
}

View file

@ -181,7 +181,8 @@ interface DoubleEndedQueueInterface extends QueueInterface
* Implementations should use a more-specific exception that extends
* `\RuntimeException`.
*/
public function addFirst(mixed $element): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function addFirst($element): bool;
/**
* Inserts the specified element at the end of this queue if it is possible
@ -201,7 +202,8 @@ interface DoubleEndedQueueInterface extends QueueInterface
* Implementations should use a more-specific exception that extends
* `\RuntimeException`.
*/
public function addLast(mixed $element): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function addLast($element): bool;
/**
* Inserts the specified element at the front of this queue if it is
@ -215,7 +217,8 @@ interface DoubleEndedQueueInterface extends QueueInterface
*
* @return bool `true` if the element was added to this queue, else `false`.
*/
public function offerFirst(mixed $element): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function offerFirst($element): bool;
/**
* Inserts the specified element at the end of this queue if it is possible
@ -229,7 +232,8 @@ interface DoubleEndedQueueInterface extends QueueInterface
*
* @return bool `true` if the element was added to this queue, else `false`.
*/
public function offerLast(mixed $element): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function offerLast($element): bool;
/**
* Retrieves and removes the head of this queue.
@ -241,7 +245,7 @@ interface DoubleEndedQueueInterface extends QueueInterface
*
* @throws NoSuchElementException if this queue is empty.
*/
public function removeFirst(): mixed;
public function removeFirst();
/**
* Retrieves and removes the tail of this queue.
@ -253,23 +257,23 @@ interface DoubleEndedQueueInterface extends QueueInterface
*
* @throws NoSuchElementException if this queue is empty.
*/
public function removeLast(): mixed;
public function removeLast();
/**
* Retrieves and removes the head of this queue, or returns `null` if this
* queue is empty.
*
* @return T | null the head of this queue, or `null` if this queue is empty.
* @return T|null the head of this queue, or `null` if this queue is empty.
*/
public function pollFirst(): mixed;
public function pollFirst();
/**
* Retrieves and removes the tail of this queue, or returns `null` if this
* queue is empty.
*
* @return T | null the tail of this queue, or `null` if this queue is empty.
* @return T|null the tail of this queue, or `null` if this queue is empty.
*/
public function pollLast(): mixed;
public function pollLast();
/**
* Retrieves, but does not remove, the head of this queue.
@ -281,7 +285,7 @@ interface DoubleEndedQueueInterface extends QueueInterface
*
* @throws NoSuchElementException if this queue is empty.
*/
public function firstElement(): mixed;
public function firstElement();
/**
* Retrieves, but does not remove, the tail of this queue.
@ -293,21 +297,21 @@ interface DoubleEndedQueueInterface extends QueueInterface
*
* @throws NoSuchElementException if this queue is empty.
*/
public function lastElement(): mixed;
public function lastElement();
/**
* Retrieves, but does not remove, the head of this queue, or returns `null`
* if this queue is empty.
*
* @return T | null the head of this queue, or `null` if this queue is empty.
* @return T|null the head of this queue, or `null` if this queue is empty.
*/
public function peekFirst(): mixed;
public function peekFirst();
/**
* Retrieves, but does not remove, the tail of this queue, or returns `null`
* if this queue is empty.
*
* @return T | null the tail of this queue, or `null` if this queue is empty.
* @return T|null the tail of this queue, or `null` if this queue is empty.
*/
public function peekLast(): mixed;
public function peekLast();
}

View file

@ -19,6 +19,6 @@ use RuntimeException;
/**
* Thrown when attempting to operate on collections of differing types.
*/
class CollectionMismatchException extends RuntimeException implements CollectionException
class CollectionMismatchException extends RuntimeException
{
}

View file

@ -14,11 +14,9 @@ declare(strict_types=1);
namespace Ramsey\Collection\Exception;
use InvalidArgumentException as PhpInvalidArgumentException;
/**
* Thrown to indicate an argument is not of the expected type.
*/
class InvalidArgumentException extends PhpInvalidArgumentException implements CollectionException
class InvalidArgumentException extends \InvalidArgumentException
{
}

View file

@ -14,8 +14,11 @@ declare(strict_types=1);
namespace Ramsey\Collection\Exception;
use Throwable;
use RuntimeException;
interface CollectionException extends Throwable
/**
* Thrown when attempting to use a sort order that is not recognized.
*/
class InvalidSortOrderException extends RuntimeException
{
}

View file

@ -19,6 +19,6 @@ use RuntimeException;
/**
* Thrown when attempting to access an element that does not exist.
*/
class NoSuchElementException extends RuntimeException implements CollectionException
class NoSuchElementException extends RuntimeException
{
}

View file

@ -14,11 +14,9 @@ declare(strict_types=1);
namespace Ramsey\Collection\Exception;
use OutOfBoundsException as PhpOutOfBoundsException;
/**
* Thrown when attempting to access an element out of the range of the collection.
*/
class OutOfBoundsException extends PhpOutOfBoundsException implements CollectionException
class OutOfBoundsException extends \OutOfBoundsException
{
}

View file

@ -19,6 +19,6 @@ use RuntimeException;
/**
* Thrown to indicate that the requested operation is not supported.
*/
class UnsupportedOperationException extends RuntimeException implements CollectionException
class UnsupportedOperationException extends RuntimeException
{
}

View file

@ -17,10 +17,8 @@ namespace Ramsey\Collection\Exception;
use RuntimeException;
/**
* Thrown when attempting to evaluate a property, method, or array key
* that doesn't exist on an element or cannot otherwise be evaluated in the
* current context.
* Thrown when attempting to extract a value for a method or property that does not exist.
*/
class InvalidPropertyOrMethod extends RuntimeException implements CollectionException
class ValueExtractionException extends RuntimeException
{
}

View file

@ -16,7 +16,6 @@ namespace Ramsey\Collection\Map;
use Ramsey\Collection\AbstractArray;
use Ramsey\Collection\Exception\InvalidArgumentException;
use Traversable;
use function array_key_exists;
use function array_keys;
@ -27,37 +26,16 @@ use function var_export;
* This class provides a basic implementation of `MapInterface`, to minimize the
* effort required to implement this interface.
*
* @template K of array-key
* @template T
* @extends AbstractArray<T>
* @implements MapInterface<K, T>
* @implements MapInterface<T>
*/
abstract class AbstractMap extends AbstractArray implements MapInterface
{
/**
* @param array<K, T> $data The initial items to add to this map.
*/
public function __construct(array $data = [])
{
parent::__construct($data);
}
/**
* @return Traversable<K, T>
*/
public function getIterator(): Traversable
{
return parent::getIterator();
}
/**
* @param K $offset The offset to set
* @param T $value The value to set at the given offset.
*
* @inheritDoc
* @psalm-suppress MoreSpecificImplementedParamType,DocblockTypeContradiction
*/
public function offsetSet(mixed $offset, mixed $value): void
public function offsetSet($offset, $value): void
{
if ($offset === null) {
throw new InvalidArgumentException(
@ -69,12 +47,18 @@ abstract class AbstractMap extends AbstractArray implements MapInterface
$this->data[$offset] = $value;
}
public function containsKey(int | string $key): bool
/**
* @inheritDoc
*/
public function containsKey($key): bool
{
return array_key_exists($key, $this->data);
}
public function containsValue(mixed $value): bool
/**
* @inheritDoc
*/
public function containsValue($value): bool
{
return in_array($value, $this->data, true);
}
@ -88,24 +72,21 @@ abstract class AbstractMap extends AbstractArray implements MapInterface
}
/**
* @param K $key The key to return from the map.
* @param T | null $defaultValue The default value to use if `$key` is not found.
*
* @return T | null the value or `null` if the key could not be found.
* @inheritDoc
*/
public function get(int | string $key, mixed $defaultValue = null): mixed
public function get($key, $defaultValue = null)
{
return $this[$key] ?? $defaultValue;
if (!$this->containsKey($key)) {
return $defaultValue;
}
return $this[$key];
}
/**
* @param K $key The key to put or replace in the map.
* @param T $value The value to store at `$key`.
*
* @return T | null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
* @inheritDoc
*/
public function put(int | string $key, mixed $value): mixed
public function put($key, $value)
{
$previousValue = $this->get($key);
$this[$key] = $value;
@ -114,13 +95,9 @@ abstract class AbstractMap extends AbstractArray implements MapInterface
}
/**
* @param K $key The key to put in the map.
* @param T $value The value to store at `$key`.
*
* @return T | null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
* @inheritDoc
*/
public function putIfAbsent(int | string $key, mixed $value): mixed
public function putIfAbsent($key, $value)
{
$currentValue = $this->get($key);
@ -132,12 +109,9 @@ abstract class AbstractMap extends AbstractArray implements MapInterface
}
/**
* @param K $key The key to remove from the map.
*
* @return T | null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
* @inheritDoc
*/
public function remove(int | string $key): mixed
public function remove($key)
{
$previousValue = $this->get($key);
unset($this[$key]);
@ -145,7 +119,10 @@ abstract class AbstractMap extends AbstractArray implements MapInterface
return $previousValue;
}
public function removeIf(int | string $key, mixed $value): bool
/**
* @inheritDoc
*/
public function removeIf($key, $value): bool
{
if ($this->get($key) === $value) {
unset($this[$key]);
@ -157,13 +134,9 @@ abstract class AbstractMap extends AbstractArray implements MapInterface
}
/**
* @param K $key The key to replace.
* @param T $value The value to set at `$key`.
*
* @return T | null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
* @inheritDoc
*/
public function replace(int | string $key, mixed $value): mixed
public function replace($key, $value)
{
$currentValue = $this->get($key);
@ -174,7 +147,10 @@ abstract class AbstractMap extends AbstractArray implements MapInterface
return $currentValue;
}
public function replaceIf(int | string $key, mixed $oldValue, mixed $newValue): bool
/**
* @inheritDoc
*/
public function replaceIf($key, $oldValue, $newValue): bool
{
if ($this->get($key) === $oldValue) {
$this[$key] = $newValue;
@ -184,20 +160,4 @@ abstract class AbstractMap extends AbstractArray implements MapInterface
return false;
}
/**
* @return array<K, T>
*/
public function __serialize(): array
{
return parent::__serialize();
}
/**
* @return array<K, T>
*/
public function toArray(): array
{
return parent::toArray();
}
}

View file

@ -18,14 +18,16 @@ use Ramsey\Collection\Exception\InvalidArgumentException;
use Ramsey\Collection\Tool\TypeTrait;
use Ramsey\Collection\Tool\ValueToStringTrait;
use function var_export;
/**
* This class provides a basic implementation of `TypedMapInterface`, to
* minimize the effort required to implement this interface.
*
* @template K of array-key
* @template T
* @extends AbstractMap<K, T>
* @implements TypedMapInterface<K, T>
* @extends AbstractMap<T>
* @implements TypedMapInterface<T>
*/
abstract class AbstractTypedMap extends AbstractMap implements TypedMapInterface
{
@ -33,14 +35,20 @@ abstract class AbstractTypedMap extends AbstractMap implements TypedMapInterface
use ValueToStringTrait;
/**
* @param K $offset
* @param K|null $offset
* @param T $value
*
* @inheritDoc
* @psalm-suppress MoreSpecificImplementedParamType
*/
public function offsetSet(mixed $offset, mixed $value): void
public function offsetSet($offset, $value): void
{
if ($offset === null) {
throw new InvalidArgumentException(
'Map elements are key/value pairs; a key must be provided for '
. 'value ' . var_export($value, true),
);
}
if ($this->checkType($this->getKeyType(), $offset) === false) {
throw new InvalidArgumentException(
'Key must be of type ' . $this->getKeyType() . '; key is '

View file

@ -17,7 +17,8 @@ namespace Ramsey\Collection\Map;
/**
* `AssociativeArrayMap` represents a standard associative array object.
*
* @extends AbstractMap<string, mixed>
* @template T
* @extends AbstractMap<T>
*/
class AssociativeArrayMap extends AbstractMap
{

View file

@ -21,7 +21,6 @@ use Ramsey\Collection\ArrayInterface;
*
* A map cannot contain duplicate keys; each key can map to at most one value.
*
* @template K of array-key
* @template T
* @extends ArrayInterface<T>
*/
@ -30,9 +29,9 @@ interface MapInterface extends ArrayInterface
/**
* Returns `true` if this map contains a mapping for the specified key.
*
* @param K $key The key to check in the map.
* @param array-key $key The key to check in the map.
*/
public function containsKey(int | string $key): bool;
public function containsKey($key): bool;
/**
* Returns `true` if this map maps one or more keys to the specified value.
@ -41,12 +40,13 @@ interface MapInterface extends ArrayInterface
*
* @param T $value The value to check in the map.
*/
public function containsValue(mixed $value): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function containsValue($value): bool;
/**
* Return an array of the keys contained in this map.
*
* @return list<K>
* @return list<array-key>
*/
public function keys(): array;
@ -55,12 +55,13 @@ interface MapInterface extends ArrayInterface
* map contains no mapping for the key, or (optionally) `$defaultValue` if
* this map contains no mapping for the key.
*
* @param K $key The key to return from the map.
* @param T | null $defaultValue The default value to use if `$key` is not found.
* @param array-key $key The key to return from the map.
* @param T|null $defaultValue The default value to use if `$key` is not found.
*
* @return T | null the value or `null` if the key could not be found.
* @return T|null the value or `null` if the key could not be found.
*/
public function get(int | string $key, mixed $defaultValue = null): mixed;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function get($key, $defaultValue = null);
/**
* Associates the specified value with the specified key in this map.
@ -68,13 +69,14 @@ interface MapInterface extends ArrayInterface
* If the map previously contained a mapping for the key, the old value is
* replaced by the specified value.
*
* @param K $key The key to put or replace in the map.
* @param array-key $key The key to put or replace in the map.
* @param T $value The value to store at `$key`.
*
* @return T | null the previous value associated with key, or `null` if
* @return T|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function put(int | string $key, mixed $value): mixed;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function put($key, $value);
/**
* Associates the specified value with the specified key in this map only if
@ -83,23 +85,25 @@ interface MapInterface extends ArrayInterface
* If there is already a value associated with `$key`, this returns that
* value without replacing it.
*
* @param K $key The key to put in the map.
* @param array-key $key The key to put in the map.
* @param T $value The value to store at `$key`.
*
* @return T | null the previous value associated with key, or `null` if
* @return T|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function putIfAbsent(int | string $key, mixed $value): mixed;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function putIfAbsent($key, $value);
/**
* Removes the mapping for a key from this map if it is present.
*
* @param K $key The key to remove from the map.
* @param array-key $key The key to remove from the map.
*
* @return T | null the previous value associated with key, or `null` if
* @return T|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function remove(int | string $key): mixed;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function remove($key);
/**
* Removes the entry for the specified key only if it is currently mapped to
@ -107,24 +111,26 @@ interface MapInterface extends ArrayInterface
*
* This performs a strict type check on the value.
*
* @param K $key The key to remove from the map.
* @param array-key $key The key to remove from the map.
* @param T $value The value to match.
*
* @return bool true if the value was removed.
*/
public function removeIf(int | string $key, mixed $value): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function removeIf($key, $value): bool;
/**
* Replaces the entry for the specified key only if it is currently mapped
* to some value.
*
* @param K $key The key to replace.
* @param array-key $key The key to replace.
* @param T $value The value to set at `$key`.
*
* @return T | null the previous value associated with key, or `null` if
* @return T|null the previous value associated with key, or `null` if
* there was no mapping for `$key`.
*/
public function replace(int | string $key, mixed $value): mixed;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function replace($key, $value);
/**
* Replaces the entry for the specified key only if currently mapped to the
@ -132,11 +138,12 @@ interface MapInterface extends ArrayInterface
*
* This performs a strict type check on the value.
*
* @param K $key The key to remove from the map.
* @param array-key $key The key to remove from the map.
* @param T $oldValue The value to match.
* @param T $newValue The value to use as a replacement.
*
* @return bool true if the value was replaced.
*/
public function replaceIf(int | string $key, mixed $oldValue, mixed $newValue): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function replaceIf($key, $oldValue, $newValue): bool;
}

View file

@ -21,12 +21,13 @@ use Ramsey\Collection\Tool\ValueToStringTrait;
use function array_combine;
use function array_key_exists;
use function is_int;
use function var_export;
/**
* `NamedParameterMap` represents a mapping of values to a set of named keys
* that may optionally be typed
*
* @extends AbstractMap<string, mixed>
* @extends AbstractMap<mixed>
*/
class NamedParameterMap extends AbstractMap
{
@ -38,13 +39,13 @@ class NamedParameterMap extends AbstractMap
*
* @var array<string, string>
*/
private readonly array $namedParameters;
protected array $namedParameters;
/**
* Constructs a new `NamedParameterMap`.
*
* @param array<array-key, string> $namedParameters The named parameters defined for this map.
* @param array<string, mixed> $data An initial set of data to set on this map.
* @param array<array-key, mixed> $data An initial set of data to set on this map.
*/
public function __construct(array $namedParameters, array $data = [])
{
@ -62,12 +63,22 @@ class NamedParameterMap extends AbstractMap
return $this->namedParameters;
}
public function offsetSet(mixed $offset, mixed $value): void
/**
* @inheritDoc
*/
public function offsetSet($offset, $value): void
{
if ($offset === null) {
throw new InvalidArgumentException(
'Map elements are key/value pairs; a key must be provided for '
. 'value ' . var_export($value, true),
);
}
if (!array_key_exists($offset, $this->namedParameters)) {
throw new InvalidArgumentException(
'Attempting to set value for unconfigured parameter \''
. $this->toolValueToString($offset) . '\'',
. $offset . '\'',
);
}

View file

@ -14,6 +14,8 @@ declare(strict_types=1);
namespace Ramsey\Collection\Map;
use Ramsey\Collection\Tool\TypeTrait;
/**
* A `TypedMap` represents a map of elements where key and value are typed.
*
@ -84,6 +86,24 @@ namespace Ramsey\Collection\Map;
*/
class TypedMap extends AbstractTypedMap
{
use TypeTrait;
/**
* The data type of keys stored in this collection.
*
* A map key's type is immutable once it is set. For this reason, this
* property is set private.
*/
private string $keyType;
/**
* The data type of values stored in this collection.
*
* A map value's type is immutable once it is set. For this reason, this
* property is set private.
*/
private string $valueType;
/**
* Constructs a map object of the specified key and value types,
* optionally with the specified data.
@ -92,11 +112,11 @@ class TypedMap extends AbstractTypedMap
* @param string $valueType The data type of the map's values.
* @param array<K, T> $data The initial data to set for this map.
*/
public function __construct(
private readonly string $keyType,
private readonly string $valueType,
array $data = [],
) {
public function __construct(string $keyType, string $valueType, array $data = [])
{
$this->keyType = $keyType;
$this->valueType = $valueType;
parent::__construct($data);
}

View file

@ -18,9 +18,8 @@ namespace Ramsey\Collection\Map;
* A `TypedMapInterface` represents a map of elements where key and value are
* typed.
*
* @template K of array-key
* @template T
* @extends MapInterface<K, T>
* @extends MapInterface<T>
*/
interface TypedMapInterface extends MapInterface
{

View file

@ -19,8 +19,6 @@ use Ramsey\Collection\Exception\NoSuchElementException;
use Ramsey\Collection\Tool\TypeTrait;
use Ramsey\Collection\Tool\ValueToStringTrait;
use function array_key_first;
/**
* This class provides a basic implementation of `QueueInterface`, to minimize
* the effort required to implement this interface.
@ -34,15 +32,29 @@ class Queue extends AbstractArray implements QueueInterface
use TypeTrait;
use ValueToStringTrait;
/**
* The type of elements stored in this queue.
*
* A queue's type is immutable once it is set. For this reason, this
* property is set private.
*/
private string $queueType;
/**
* The index of the head of the queue.
*/
protected int $index = 0;
/**
* Constructs a queue object of the specified type, optionally with the
* specified data.
*
* @param string $queueType The type or class name associated with this queue.
* @param array<array-key, T> $data The initial items to store in the queue.
* @param string $queueType The type (FQCN) associated with this queue.
* @param array<array-key, T> $data The initial items to store in the collection.
*/
public function __construct(private readonly string $queueType, array $data = [])
public function __construct(string $queueType, array $data = [])
{
$this->queueType = $queueType;
parent::__construct($data);
}
@ -53,9 +65,9 @@ class Queue extends AbstractArray implements QueueInterface
* serves only to fulfill the `ArrayAccess` interface requirements. It is
* invoked by other operations when adding values to the queue.
*
* @throws InvalidArgumentException if $value is of the wrong type.
* @throws InvalidArgumentException if $value is of the wrong type
*/
public function offsetSet(mixed $offset, mixed $value): void
public function offsetSet($offset, $value): void
{
if ($this->checkType($this->getType(), $value) === false) {
throw new InvalidArgumentException(
@ -68,9 +80,11 @@ class Queue extends AbstractArray implements QueueInterface
}
/**
* @throws InvalidArgumentException if $value is of the wrong type.
* @throws InvalidArgumentException if $value is of the wrong type
*
* @inheritDoc
*/
public function add(mixed $element): bool
public function add($element): bool
{
$this[] = $element;
@ -78,67 +92,74 @@ class Queue extends AbstractArray implements QueueInterface
}
/**
* @return T
*
* @throws NoSuchElementException if this queue is empty.
* @inheritDoc
*/
public function element(): mixed
public function element()
{
return $this->peek() ?? throw new NoSuchElementException(
$element = $this->peek();
if ($element === null) {
throw new NoSuchElementException(
'Can\'t return element from Queue. Queue is empty.',
);
}
public function offer(mixed $element): bool
return $element;
}
/**
* @inheritDoc
*/
public function offer($element): bool
{
try {
return $this->add($element);
} catch (InvalidArgumentException) {
} catch (InvalidArgumentException $e) {
return false;
}
}
/**
* @return T | null
* @inheritDoc
*/
public function peek(): mixed
public function peek()
{
$index = array_key_first($this->data);
if ($index === null) {
if ($this->count() === 0) {
return null;
}
return $this[$index];
return $this[$this->index];
}
/**
* @return T | null
* @inheritDoc
*/
public function poll(): mixed
public function poll()
{
$index = array_key_first($this->data);
if ($index === null) {
if ($this->count() === 0) {
return null;
}
$head = $this[$index];
unset($this[$index]);
$head = $this[$this->index];
unset($this[$this->index]);
$this->index++;
return $head;
}
/**
* @return T
*
* @throws NoSuchElementException if this queue is empty.
* @inheritDoc
*/
public function remove(): mixed
public function remove()
{
return $this->poll() ?? throw new NoSuchElementException(
'Can\'t return element from Queue. Queue is empty.',
);
$head = $this->poll();
if ($head === null) {
throw new NoSuchElementException('Can\'t return element from Queue. Queue is empty.');
}
return $head;
}
public function getType(): string

View file

@ -129,7 +129,8 @@ interface QueueInterface extends ArrayInterface
* Implementations should use a more-specific exception that extends
* `\RuntimeException`.
*/
public function add(mixed $element): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function add($element): bool;
/**
* Retrieves, but does not remove, the head of this queue.
@ -143,7 +144,7 @@ interface QueueInterface extends ArrayInterface
*
* @throws NoSuchElementException if this queue is empty.
*/
public function element(): mixed;
public function element();
/**
* Inserts the specified element into this queue if it is possible to do so
@ -159,7 +160,8 @@ interface QueueInterface extends ArrayInterface
*
* @return bool `true` if the element was added to this queue, else `false`.
*/
public function offer(mixed $element): bool;
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
public function offer($element): bool;
/**
* Retrieves, but does not remove, the head of this queue, or returns `null`
@ -167,9 +169,9 @@ interface QueueInterface extends ArrayInterface
*
* @see self::element()
*
* @return T | null the head of this queue, or `null` if this queue is empty.
* @return T|null the head of this queue, or `null` if this queue is empty.
*/
public function peek(): mixed;
public function peek();
/**
* Retrieves and removes the head of this queue, or returns `null`
@ -177,9 +179,9 @@ interface QueueInterface extends ArrayInterface
*
* @see self::remove()
*
* @return T | null the head of this queue, or `null` if this queue is empty.
* @return T|null the head of this queue, or `null` if this queue is empty.
*/
public function poll(): mixed;
public function poll();
/**
* Retrieves and removes the head of this queue.
@ -193,7 +195,7 @@ interface QueueInterface extends ArrayInterface
*
* @throws NoSuchElementException if this queue is empty.
*/
public function remove(): mixed;
public function remove();
/**
* Returns the type associated with this queue.

View file

@ -28,7 +28,7 @@ namespace Ramsey\Collection;
* $foo = new \My\Foo();
* $set = new Set(\My\Foo::class);
*
* $set->add($foo); // returns TRUE, the element doesn't exist
* $set->add($foo); // returns TRUE, the element don't exists
* $set->add($foo); // returns FALSE, the element already exists
*
* $bar = new \My\Foo();
@ -40,15 +40,23 @@ namespace Ramsey\Collection;
*/
class Set extends AbstractSet
{
/**
* The type of elements stored in this set
*
* A set's type is immutable. For this reason, this property is private.
*/
private string $setType;
/**
* Constructs a set object of the specified type, optionally with the
* specified data.
*
* @param string $setType The type or class name associated with this set.
* @param string $setType The type (FQCN) associated with this set.
* @param array<array-key, T> $data The initial items to store in the set.
*/
public function __construct(private readonly string $setType, array $data = [])
public function __construct(string $setType, array $data = [])
{
$this->setType = $setType;
parent::__construct($data);
}

View file

@ -1,31 +0,0 @@
<?php
/**
* This file is part of the ramsey/collection library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
*/
declare(strict_types=1);
namespace Ramsey\Collection;
/**
* Collection sorting
*/
enum Sort: string
{
/**
* Sort items in a collection in ascending order.
*/
case Ascending = 'asc';
/**
* Sort items in a collection in descending order.
*/
case Descending = 'desc';
}

View file

@ -36,22 +36,39 @@ trait TypeTrait
* @param string $type The type to check the value against.
* @param mixed $value The value to check.
*/
protected function checkType(string $type, mixed $value): bool
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
protected function checkType(string $type, $value): bool
{
return match ($type) {
'array' => is_array($value),
'bool', 'boolean' => is_bool($value),
'callable' => is_callable($value),
'float', 'double' => is_float($value),
'int', 'integer' => is_int($value),
'null' => $value === null,
'numeric' => is_numeric($value),
'object' => is_object($value),
'resource' => is_resource($value),
'scalar' => is_scalar($value),
'string' => is_string($value),
'mixed' => true,
default => $value instanceof $type,
};
switch ($type) {
case 'array':
return is_array($value);
case 'bool':
case 'boolean':
return is_bool($value);
case 'callable':
return is_callable($value);
case 'float':
case 'double':
return is_float($value);
case 'int':
case 'integer':
return is_int($value);
case 'null':
return $value === null;
case 'numeric':
return is_numeric($value);
case 'object':
return is_object($value);
case 'resource':
return is_resource($value);
case 'scalar':
return is_scalar($value);
case 'string':
return is_string($value);
case 'mixed':
return true;
default:
return $value instanceof $type;
}
}
}

View file

@ -14,10 +14,9 @@ declare(strict_types=1);
namespace Ramsey\Collection\Tool;
use Ramsey\Collection\Exception\InvalidPropertyOrMethod;
use Ramsey\Collection\Exception\UnsupportedOperationException;
use Ramsey\Collection\Exception\ValueExtractionException;
use function is_array;
use function get_class;
use function is_object;
use function method_exists;
use function property_exists;
@ -29,53 +28,34 @@ use function sprintf;
trait ValueExtractorTrait
{
/**
* Extracts the value of the given property, method, or array key from the
* element.
* Extracts the value of the given property or method from the object.
*
* If `$propertyOrMethod` is `null`, we return the element as-is.
*
* @param mixed $element The element to extract the value from.
* @param string | null $propertyOrMethod The property or method for which the
* @param mixed $object The object to extract the value from.
* @param string $propertyOrMethod The property or method for which the
* value should be extracted.
*
* @return mixed the value extracted from the specified property, method,
* or array key, or the element itself.
* @return mixed the value extracted from the specified property or method.
*
* @throws InvalidPropertyOrMethod
* @throws UnsupportedOperationException
* @throws ValueExtractionException if the method or property is not defined.
*/
protected function extractValue(mixed $element, ?string $propertyOrMethod): mixed
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
protected function extractValue($object, string $propertyOrMethod)
{
if ($propertyOrMethod === null) {
return $element;
if (!is_object($object)) {
throw new ValueExtractionException('Unable to extract a value from a non-object');
}
if (!is_object($element) && !is_array($element)) {
throw new UnsupportedOperationException(sprintf(
'The collection type "%s" does not support the $propertyOrMethod parameter',
$this->getType(),
));
if (property_exists($object, $propertyOrMethod)) {
return $object->$propertyOrMethod;
}
if (is_array($element)) {
return $element[$propertyOrMethod] ?? throw new InvalidPropertyOrMethod(sprintf(
'Key or index "%s" not found in collection elements',
$propertyOrMethod,
));
if (method_exists($object, $propertyOrMethod)) {
return $object->{$propertyOrMethod}();
}
if (property_exists($element, $propertyOrMethod)) {
return $element->$propertyOrMethod;
}
if (method_exists($element, $propertyOrMethod)) {
return $element->{$propertyOrMethod}();
}
throw new InvalidPropertyOrMethod(sprintf(
'Method or property "%s" not defined in %s',
$propertyOrMethod,
$element::class,
));
throw new ValueExtractionException(
// phpcs:ignore SlevomatCodingStandard.Classes.ModernClassNameReference.ClassNameReferencedViaFunctionCall
sprintf('Method or property "%s" not defined in %s', $propertyOrMethod, get_class($object)),
);
}
}

View file

@ -16,7 +16,7 @@ namespace Ramsey\Collection\Tool;
use DateTimeInterface;
use function assert;
use function get_class;
use function get_resource_type;
use function is_array;
use function is_bool;
@ -24,6 +24,7 @@ use function is_callable;
use function is_object;
use function is_resource;
use function is_scalar;
use function var_export;
/**
* Provides functionality to express a value as string
@ -45,7 +46,8 @@ trait ValueToStringTrait
*
* @param mixed $value the value to return as a string.
*/
protected function toolValueToString(mixed $value): string
// phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
protected function toolValueToString($value): string
{
// null
if ($value === null) {
@ -72,8 +74,12 @@ trait ValueToStringTrait
return '(' . get_resource_type($value) . ' resource #' . (int) $value . ')';
}
// If we don't know what it is, use var_export().
if (!is_object($value)) {
return '(' . var_export($value, true) . ')';
}
// From here, $value should be an object.
assert(is_object($value));
// __toString() is implemented
if (is_callable([$value, '__toString'])) {
@ -86,6 +92,7 @@ trait ValueToStringTrait
}
// unknown type
return '(' . $value::class . ' Object)';
// phpcs:ignore SlevomatCodingStandard.Classes.ModernClassNameReference.ClassNameReferencedViaFunctionCall
return '(' . get_class($value) . ' Object)';
}
}

View file

@ -21,7 +21,6 @@ use Symfony\Component\Console\Command\SignalableCommandInterface;
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Suggestion;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
use Symfony\Component\Console\Event\ConsoleSignalEvent;
@ -33,7 +32,6 @@ use Symfony\Component\Console\Exception\NamespaceNotFoundException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\DebugFormatterHelper;
use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Helper\HelperSet;
@ -72,24 +70,23 @@ use Symfony\Contracts\Service\ResetInterface;
*/
class Application implements ResetInterface
{
private array $commands = [];
private bool $wantHelps = false;
private ?Command $runningCommand = null;
private string $name;
private string $version;
private ?CommandLoaderInterface $commandLoader = null;
private bool $catchExceptions = true;
private bool $catchErrors = false;
private bool $autoExit = true;
private InputDefinition $definition;
private HelperSet $helperSet;
private ?EventDispatcherInterface $dispatcher = null;
private Terminal $terminal;
private string $defaultCommand;
private bool $singleCommand = false;
private bool $initialized = false;
private ?SignalRegistry $signalRegistry = null;
private array $signalsToDispatchEvent = [];
private $commands = [];
private $wantHelps = false;
private $runningCommand;
private $name;
private $version;
private $commandLoader;
private $catchExceptions = true;
private $autoExit = true;
private $definition;
private $helperSet;
private $dispatcher;
private $terminal;
private $defaultCommand;
private $singleCommand = false;
private $initialized;
private $signalRegistry;
private $signalsToDispatchEvent = [];
public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
{
@ -106,14 +103,11 @@ class Application implements ResetInterface
/**
* @final
*/
public function setDispatcher(EventDispatcherInterface $dispatcher): void
public function setDispatcher(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}
/**
* @return void
*/
public function setCommandLoader(CommandLoaderInterface $commandLoader)
{
$this->commandLoader = $commandLoader;
@ -122,15 +116,12 @@ class Application implements ResetInterface
public function getSignalRegistry(): SignalRegistry
{
if (!$this->signalRegistry) {
throw new RuntimeException('Signals are not supported. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
throw new RuntimeException('Signals are not supported. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
}
return $this->signalRegistry;
}
/**
* @return void
*/
public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent)
{
$this->signalsToDispatchEvent = $signalsToDispatchEvent;
@ -143,15 +134,20 @@ class Application implements ResetInterface
*
* @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}.
*/
public function run(?InputInterface $input = null, ?OutputInterface $output = null): int
public function run(?InputInterface $input = null, ?OutputInterface $output = null)
{
if (\function_exists('putenv')) {
@putenv('LINES='.$this->terminal->getHeight());
@putenv('COLUMNS='.$this->terminal->getWidth());
}
$input ??= new ArgvInput();
$output ??= new ConsoleOutput();
if (null === $input) {
$input = new ArgvInput();
}
if (null === $output) {
$output = new ConsoleOutput();
}
$renderException = function (\Throwable $e) use ($output) {
if ($output instanceof ConsoleOutputInterface) {
@ -173,11 +169,8 @@ class Application implements ResetInterface
try {
$exitCode = $this->doRun($input, $output);
} catch (\Throwable $e) {
if ($e instanceof \Exception && !$this->catchExceptions) {
throw $e;
}
if (!$e instanceof \Exception && !$this->catchErrors) {
} catch (\Exception $e) {
if (!$this->catchExceptions) {
throw $e;
}
@ -235,7 +228,7 @@ class Application implements ResetInterface
try {
// Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument.
$input->bind($this->getDefinition());
} catch (ExceptionInterface) {
} catch (ExceptionInterface $e) {
// Errors must be ignored, full binding/validation happens later when the command is known.
}
@ -265,7 +258,21 @@ class Application implements ResetInterface
// the command name MUST be the first element of the input
$command = $this->find($name);
} catch (\Throwable $e) {
if (($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) && 1 === \count($alternatives = $e->getAlternatives()) && $input->isInteractive()) {
if (!($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) || 1 !== \count($alternatives = $e->getAlternatives()) || !$input->isInteractive()) {
if (null !== $this->dispatcher) {
$event = new ConsoleErrorEvent($input, $output, $e);
$this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
if (0 === $event->getExitCode()) {
return 0;
}
$e = $event->getError();
}
throw $e;
}
$alternative = $alternatives[0];
$style = new SymfonyStyle($input, $output);
@ -284,36 +291,6 @@ class Application implements ResetInterface
}
$command = $this->find($alternative);
} else {
if (null !== $this->dispatcher) {
$event = new ConsoleErrorEvent($input, $output, $e);
$this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
if (0 === $event->getExitCode()) {
return 0;
}
$e = $event->getError();
}
try {
if ($e instanceof CommandNotFoundException && $namespace = $this->findNamespace($name)) {
$helper = new DescriptorHelper();
$helper->describe($output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output, $this, [
'format' => 'txt',
'raw_text' => false,
'namespace' => $namespace,
'short' => false,
]);
return isset($event) ? $event->getExitCode() : 1;
}
throw $e;
} catch (NamespaceNotFoundException) {
throw $e;
}
}
}
if ($command instanceof LazyCommand) {
@ -328,15 +305,12 @@ class Application implements ResetInterface
}
/**
* @return void
* {@inheritdoc}
*/
public function reset()
{
}
/**
* @return void
*/
public function setHelperSet(HelperSet $helperSet)
{
$this->helperSet = $helperSet;
@ -344,15 +318,18 @@ class Application implements ResetInterface
/**
* Get the helper set associated with the command.
*
* @return HelperSet
*/
public function getHelperSet(): HelperSet
public function getHelperSet()
{
return $this->helperSet ??= $this->getDefaultHelperSet();
if (!$this->helperSet) {
$this->helperSet = $this->getDefaultHelperSet();
}
return $this->helperSet;
}
/**
* @return void
*/
public function setDefinition(InputDefinition $definition)
{
$this->definition = $definition;
@ -360,10 +337,14 @@ class Application implements ResetInterface
/**
* Gets the InputDefinition related to this Application.
*
* @return InputDefinition
*/
public function getDefinition(): InputDefinition
public function getDefinition()
{
$this->definition ??= $this->getDefaultInputDefinition();
if (!$this->definition) {
$this->definition = $this->getDefaultInputDefinition();
}
if ($this->singleCommand) {
$inputDefinition = $this->definition;
@ -384,16 +365,18 @@ class Application implements ResetInterface
CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType()
&& 'command' === $input->getCompletionName()
) {
$commandNames = [];
foreach ($this->all() as $name => $command) {
// skip hidden commands and aliased commands as they already get added below
if ($command->isHidden() || $command->getName() !== $name) {
continue;
}
$suggestions->suggestValue(new Suggestion($command->getName(), $command->getDescription()));
$commandNames[] = $command->getName();
foreach ($command->getAliases() as $name) {
$suggestions->suggestValue(new Suggestion($name, $command->getDescription()));
$commandNames[] = $name;
}
}
$suggestions->suggestValues(array_filter($commandNames));
return;
}
@ -407,50 +390,44 @@ class Application implements ResetInterface
/**
* Gets the help message.
*
* @return string
*/
public function getHelp(): string
public function getHelp()
{
return $this->getLongVersion();
}
/**
* Gets whether to catch exceptions or not during commands execution.
*
* @return bool
*/
public function areExceptionsCaught(): bool
public function areExceptionsCaught()
{
return $this->catchExceptions;
}
/**
* Sets whether to catch exceptions or not during commands execution.
*
* @return void
*/
public function setCatchExceptions(bool $boolean)
{
$this->catchExceptions = $boolean;
}
/**
* Sets whether to catch errors or not during commands execution.
*/
public function setCatchErrors(bool $catchErrors = true): void
{
$this->catchErrors = $catchErrors;
}
/**
* Gets whether to automatically exit after a command execution or not.
*
* @return bool
*/
public function isAutoExitEnabled(): bool
public function isAutoExitEnabled()
{
return $this->autoExit;
}
/**
* Sets whether to automatically exit after a command execution or not.
*
* @return void
*/
public function setAutoExit(bool $boolean)
{
@ -459,17 +436,17 @@ class Application implements ResetInterface
/**
* Gets the name of the application.
*
* @return string
*/
public function getName(): string
public function getName()
{
return $this->name;
}
/**
* Sets the application name.
*
* @return void
*/
**/
public function setName(string $name)
{
$this->name = $name;
@ -477,16 +454,16 @@ class Application implements ResetInterface
/**
* Gets the application version.
*
* @return string
*/
public function getVersion(): string
public function getVersion()
{
return $this->version;
}
/**
* Sets the application version.
*
* @return void
*/
public function setVersion(string $version)
{
@ -513,8 +490,10 @@ class Application implements ResetInterface
/**
* Registers a new command.
*
* @return Command
*/
public function register(string $name): Command
public function register(string $name)
{
return $this->add(new Command($name));
}
@ -525,8 +504,6 @@ class Application implements ResetInterface
* If a Command is not enabled it will not be added.
*
* @param Command[] $commands An array of commands
*
* @return void
*/
public function addCommands(array $commands)
{
@ -609,12 +586,14 @@ class Application implements ResetInterface
/**
* Returns true if the command exists, false otherwise.
*
* @return bool
*/
public function has(string $name): bool
public function has(string $name)
{
$this->init();
return isset($this->commands[$name]) || ($this->commandLoader?->has($name) && $this->add($this->commandLoader->get($name)));
return isset($this->commands[$name]) || ($this->commandLoader && $this->commandLoader->has($name) && $this->add($this->commandLoader->get($name)));
}
/**
@ -624,7 +603,7 @@ class Application implements ResetInterface
*
* @return string[]
*/
public function getNamespaces(): array
public function getNamespaces()
{
$namespaces = [];
foreach ($this->all() as $command) {
@ -645,9 +624,11 @@ class Application implements ResetInterface
/**
* Finds a registered namespace by a name or an abbreviation.
*
* @return string
*
* @throws NamespaceNotFoundException When namespace is incorrect or ambiguous
*/
public function findNamespace(string $namespace): string
public function findNamespace(string $namespace)
{
$allNamespaces = $this->getNamespaces();
$expr = implode('[^:]*:', array_map('preg_quote', explode(':', $namespace))).'[^:]*';
@ -724,7 +705,9 @@ class Application implements ResetInterface
if ($alternatives = $this->findAlternatives($name, $allCommands)) {
// remove hidden commands
$alternatives = array_filter($alternatives, fn ($name) => !$this->get($name)->isHidden());
$alternatives = array_filter($alternatives, function ($name) {
return !$this->get($name)->isHidden();
});
if (1 == \count($alternatives)) {
$message .= "\n\nDid you mean this?\n ";
@ -837,7 +820,7 @@ class Application implements ResetInterface
*
* @return string[][]
*/
public static function getAbbreviations(array $names): array
public static function getAbbreviations(array $names)
{
$abbrevs = [];
foreach ($names as $name) {
@ -875,7 +858,9 @@ class Application implements ResetInterface
}
if (str_contains($message, "@anonymous\0")) {
$message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $message);
$message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) {
return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0];
}, $message);
}
$width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX;
@ -936,8 +921,6 @@ class Application implements ResetInterface
/**
* Configures the input and output instances based on the user arguments and options.
*
* @return void
*/
protected function configureIO(InputInterface $input, OutputInterface $output)
{
@ -1012,65 +995,44 @@ class Application implements ResetInterface
}
}
if ($this->signalsToDispatchEvent) {
$commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : [];
if ($commandSignals || $this->dispatcher && $this->signalsToDispatchEvent) {
if ($commandSignals || null !== $this->dispatcher) {
if (!$this->signalRegistry) {
throw new RuntimeException('Unable to subscribe to signal events. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
}
if (Terminal::hasSttyAvailable()) {
$sttyMode = shell_exec('stty -g');
foreach ([\SIGINT, \SIGTERM] as $signal) {
$this->signalRegistry->register($signal, static fn () => shell_exec('stty '.$sttyMode));
$this->signalRegistry->register($signal, static function () use ($sttyMode) {
shell_exec('stty '.$sttyMode);
});
}
}
}
if ($this->dispatcher) {
// We register application signals, so that we can dispatch the event
if (null !== $this->dispatcher) {
foreach ($this->signalsToDispatchEvent as $signal) {
$event = new ConsoleSignalEvent($command, $input, $output, $signal);
$this->signalRegistry->register($signal, function ($signal) use ($event, $command, $commandSignals) {
$this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) {
$this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
$exitCode = $event->getExitCode();
// If the command is signalable, we call the handleSignal() method
if (\in_array($signal, $commandSignals, true)) {
$exitCode = $command->handleSignal($signal, $exitCode);
// BC layer for Symfony <= 5
if (null === $exitCode) {
trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command));
$exitCode = 0;
// No more handlers, we try to simulate PHP default behavior
if (!$hasNext) {
if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], true)) {
exit(0);
}
}
if (false !== $exitCode) {
$event = new ConsoleTerminateEvent($command, $event->getInput(), $event->getOutput(), $exitCode, $signal);
$this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);
exit($event->getExitCode());
}
});
}
// then we register command signals, but not if already handled after the dispatcher
$commandSignals = array_diff($commandSignals, $this->signalsToDispatchEvent);
}
foreach ($commandSignals as $signal) {
$this->signalRegistry->register($signal, function (int $signal) use ($command): void {
$exitCode = $command->handleSignal($signal);
// BC layer for Symfony <= 5
if (null === $exitCode) {
trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command));
$exitCode = 0;
}
if (false !== $exitCode) {
exit($exitCode);
}
});
$this->signalRegistry->register($signal, [$command, 'handleSignal']);
}
}
@ -1082,7 +1044,7 @@ class Application implements ResetInterface
try {
$command->mergeApplicationDefinition();
$input->bind($command->getDefinition());
} catch (ExceptionInterface) {
} catch (ExceptionInterface $e) {
// ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition
}
@ -1119,16 +1081,20 @@ class Application implements ResetInterface
/**
* Gets the name of the command based on input.
*
* @return string|null
*/
protected function getCommandName(InputInterface $input): ?string
protected function getCommandName(InputInterface $input)
{
return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument();
}
/**
* Gets the default input definition.
*
* @return InputDefinition
*/
protected function getDefaultInputDefinition(): InputDefinition
protected function getDefaultInputDefinition()
{
return new InputDefinition([
new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
@ -1146,15 +1112,17 @@ class Application implements ResetInterface
*
* @return Command[]
*/
protected function getDefaultCommands(): array
protected function getDefaultCommands()
{
return [new HelpCommand(), new ListCommand(), new CompleteCommand(), new DumpCompletionCommand()];
}
/**
* Gets the default helper set with the helpers that should always be available.
*
* @return HelperSet
*/
protected function getDefaultHelperSet(): HelperSet
protected function getDefaultHelperSet()
{
return new HelperSet([
new FormatterHelper(),
@ -1176,8 +1144,10 @@ class Application implements ResetInterface
* Returns the namespace part of the command name.
*
* This method is not part of public API and should not be used directly.
*
* @return string
*/
public function extractNamespace(string $name, ?int $limit = null): string
public function extractNamespace(string $name, ?int $limit = null)
{
$parts = explode(':', $name, -1);
@ -1226,7 +1196,7 @@ class Application implements ResetInterface
}
}
$alternatives = array_filter($alternatives, fn ($lev) => $lev < 2 * $threshold);
$alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; });
ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE);
return array_keys($alternatives);
@ -1237,7 +1207,7 @@ class Application implements ResetInterface
*
* @return $this
*/
public function setDefaultCommand(string $commandName, bool $isSingleCommand = false): static
public function setDefaultCommand(string $commandName, bool $isSingleCommand = false)
{
$this->defaultCommand = explode('|', ltrim($commandName, '|'))[0];
@ -1317,7 +1287,7 @@ class Application implements ResetInterface
return $namespaces;
}
private function init(): void
private function init()
{
if ($this->initialized) {
return;

View file

@ -1,50 +1,6 @@
CHANGELOG
=========
6.4
---
* Add `SignalMap` to map signal value to its name
* Multi-line text in vertical tables is aligned properly
* The application can also catch errors with `Application::setCatchErrors(true)`
* Add `RunCommandMessage` and `RunCommandMessageHandler`
* Dispatch `ConsoleTerminateEvent` after an exit on signal handling and add `ConsoleTerminateEvent::getInterruptingSignal()`
6.3
---
* Add support for choosing exit code while handling signal, or to not exit at all
* Add `ProgressBar::setPlaceholderFormatter` to set a placeholder attached to a instance, instead of being global.
* Add `ReStructuredTextDescriptor`
6.2
---
* Improve truecolor terminal detection in some cases
* Add support for 256 color terminals (conversion from Ansi24 to Ansi8 if terminal is capable of it)
* Deprecate calling `*Command::setApplication()`, `*FormatterStyle::setForeground/setBackground()`, `Helper::setHelpSet()`, `Input*::setDefault()`, `Question::setAutocompleterCallback/setValidator()`without any arguments
* Change the signature of `OutputFormatterStyleInterface::setForeground/setBackground()` to `setForeground/setBackground(?string)`
* Change the signature of `HelperInterface::setHelperSet()` to `setHelperSet(?HelperSet)`
6.1
---
* Add support to display table vertically when calling setVertical()
* Add method `__toString()` to `InputInterface`
* Added `OutputWrapper` to prevent truncated URL in `SymfonyStyle::createBlock`.
* Deprecate `Command::$defaultName` and `Command::$defaultDescription`, use the `AsCommand` attribute instead
* Add suggested values for arguments and options in input definition, for input completion
* Add `$resumeAt` parameter to `ProgressBar#start()`, so that one can easily 'resume' progress on longer tasks, and still get accurate `getEstimate()` and `getRemaining()` results.
6.0
---
* `Command::setHidden()` has a default value (`true`) for `$hidden` parameter and is final
* Remove `Helper::strlen()`, use `Helper::width()` instead
* Remove `Helper::strlenWithoutDecoration()`, use `Helper::removeDecoration()` instead
* `AddConsoleCommandPass` can not be configured anymore
* Remove `HelperSet::setCommand()` and `getCommand()` without replacement
5.4
---

View file

@ -20,7 +20,7 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class GithubActionReporter
{
private OutputInterface $output;
private $output;
/**
* @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L80-L85

View file

@ -49,9 +49,9 @@ final class Color
'conceal' => ['set' => 8, 'unset' => 28],
];
private string $foreground;
private string $background;
private array $options = [];
private $foreground;
private $background;
private $options = [];
public function __construct(string $foreground = '', string $background = '', array $options = [])
{
@ -117,7 +117,17 @@ final class Color
}
if ('#' === $color[0]) {
return ($background ? '4' : '3').Terminal::getColorMode()->convertFromHexToAnsiColorCode($color);
$color = substr($color, 1);
if (3 === \strlen($color)) {
$color = $color[0].$color[0].$color[1].$color[1].$color[2].$color[2];
}
if (6 !== \strlen($color)) {
throw new InvalidArgumentException(sprintf('Invalid "%s" color.', $color));
}
return ($background ? '4' : '3').$this->convertHexColorToAnsi(hexdec($color));
}
if (isset(self::COLORS[$color])) {
@ -130,4 +140,41 @@ final class Color
throw new InvalidArgumentException(sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS)))));
}
private function convertHexColorToAnsi(int $color): string
{
$r = ($color >> 16) & 255;
$g = ($color >> 8) & 255;
$b = $color & 255;
// see https://github.com/termstandard/colors/ for more information about true color support
if ('truecolor' !== getenv('COLORTERM')) {
return (string) $this->degradeHexColorToAnsi($r, $g, $b);
}
return sprintf('8;2;%d;%d;%d', $r, $g, $b);
}
private function degradeHexColorToAnsi(int $r, int $g, int $b): int
{
if (0 === round($this->getSaturation($r, $g, $b) / 50)) {
return 0;
}
return (round($b / 255) << 2) | (round($g / 255) << 1) | round($r / 255);
}
private function getSaturation(int $r, int $g, int $b): int
{
$r = $r / 255;
$g = $g / 255;
$b = $b / 255;
$v = max($r, $g, $b);
if (0 === $diff = $v - min($r, $g, $b)) {
return 0;
}
return (int) $diff * 100 / $v;
}
}

View file

@ -15,11 +15,9 @@ use Symfony\Component\Console\Application;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Suggestion;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Helper\HelperInterface;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
@ -41,69 +39,56 @@ class Command
/**
* @var string|null The default command name
*
* @deprecated since Symfony 6.1, use the AsCommand attribute instead
*/
protected static $defaultName;
/**
* @var string|null The default command description
*
* @deprecated since Symfony 6.1, use the AsCommand attribute instead
*/
protected static $defaultDescription;
private ?Application $application = null;
private ?string $name = null;
private ?string $processTitle = null;
private array $aliases = [];
private InputDefinition $definition;
private bool $hidden = false;
private string $help = '';
private string $description = '';
private ?InputDefinition $fullDefinition = null;
private bool $ignoreValidationErrors = false;
private ?\Closure $code = null;
private array $synopsis = [];
private array $usages = [];
private ?HelperSet $helperSet = null;
private $application;
private $name;
private $processTitle;
private $aliases = [];
private $definition;
private $hidden = false;
private $help = '';
private $description = '';
private $fullDefinition;
private $ignoreValidationErrors = false;
private $code;
private $synopsis = [];
private $usages = [];
private $helperSet;
public static function getDefaultName(): ?string
/**
* @return string|null
*/
public static function getDefaultName()
{
$class = static::class;
if ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) {
if (\PHP_VERSION_ID >= 80000 && $attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) {
return $attribute[0]->newInstance()->name;
}
$r = new \ReflectionProperty($class, 'defaultName');
if ($class !== $r->class || null === static::$defaultName) {
return null;
}
trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultName" for setting a command name is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class);
return static::$defaultName;
return $class === $r->class ? static::$defaultName : null;
}
public static function getDefaultDescription(): ?string
{
$class = static::class;
if ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) {
if (\PHP_VERSION_ID >= 80000 && $attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) {
return $attribute[0]->newInstance()->description;
}
$r = new \ReflectionProperty($class, 'defaultDescription');
if ($class !== $r->class || null === static::$defaultDescription) {
return null;
}
trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultDescription" for setting a command description is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class);
return static::$defaultDescription;
return $class === $r->class ? static::$defaultDescription : null;
}
/**
@ -141,22 +126,14 @@ class Command
* Ignores validation errors.
*
* This is mainly useful for the help command.
*
* @return void
*/
public function ignoreValidationErrors()
{
$this->ignoreValidationErrors = true;
}
/**
* @return void
*/
public function setApplication(?Application $application = null)
{
if (1 > \func_num_args()) {
trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
}
$this->application = $application;
if ($application) {
$this->setHelperSet($application->getHelperSet());
@ -167,9 +144,6 @@ class Command
$this->fullDefinition = null;
}
/**
* @return void
*/
public function setHelperSet(HelperSet $helperSet)
{
$this->helperSet = $helperSet;
@ -177,16 +151,20 @@ class Command
/**
* Gets the helper set.
*
* @return HelperSet|null
*/
public function getHelperSet(): ?HelperSet
public function getHelperSet()
{
return $this->helperSet;
}
/**
* Gets the application instance for this command.
*
* @return Application|null
*/
public function getApplication(): ?Application
public function getApplication()
{
return $this->application;
}
@ -206,8 +184,6 @@ class Command
/**
* Configures the current command.
*
* @return void
*/
protected function configure()
{
@ -238,8 +214,6 @@ class Command
* This method is executed before the InputDefinition is validated.
* This means that this is the only place where the command can
* interactively ask for values of missing required arguments.
*
* @return void
*/
protected function interact(InputInterface $input, OutputInterface $output)
{
@ -254,8 +228,6 @@ class Command
*
* @see InputInterface::bind()
* @see InputInterface::validate()
*
* @return void
*/
protected function initialize(InputInterface $input, OutputInterface $output)
{
@ -275,7 +247,7 @@ class Command
* @see setCode()
* @see execute()
*/
public function run(InputInterface $input, OutputInterface $output): int
public function run(InputInterface $input, OutputInterface $output)
{
// add the application arguments and options
$this->mergeApplicationDefinition();
@ -338,12 +310,6 @@ class Command
*/
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$definition = $this->getDefinition();
if (CompletionInput::TYPE_OPTION_VALUE === $input->getCompletionType() && $definition->hasOption($input->getCompletionName())) {
$definition->getOption($input->getCompletionName())->complete($input, $suggestions);
} elseif (CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && $definition->hasArgument($input->getCompletionName())) {
$definition->getArgument($input->getCompletionName())->complete($input, $suggestions);
}
}
/**
@ -360,7 +326,7 @@ class Command
*
* @see execute()
*/
public function setCode(callable $code): static
public function setCode(callable $code)
{
if ($code instanceof \Closure) {
$r = new \ReflectionFunction($code);
@ -374,8 +340,6 @@ class Command
restore_error_handler();
}
}
} else {
$code = $code(...);
}
$this->code = $code;
@ -392,7 +356,7 @@ class Command
*
* @internal
*/
public function mergeApplicationDefinition(bool $mergeArgs = true): void
public function mergeApplicationDefinition(bool $mergeArgs = true)
{
if (null === $this->application) {
return;
@ -413,9 +377,11 @@ class Command
/**
* Sets an array of argument and option instances.
*
* @param array|InputDefinition $definition An array of argument and option instances or a definition instance
*
* @return $this
*/
public function setDefinition(array|InputDefinition $definition): static
public function setDefinition($definition)
{
if ($definition instanceof InputDefinition) {
$this->definition = $definition;
@ -430,8 +396,10 @@ class Command
/**
* Gets the InputDefinition attached to this Command.
*
* @return InputDefinition
*/
public function getDefinition(): InputDefinition
public function getDefinition()
{
return $this->fullDefinition ?? $this->getNativeDefinition();
}
@ -443,31 +411,34 @@ class Command
* be changed by merging with the application InputDefinition.
*
* This method is not part of public API and should not be used directly.
*
* @return InputDefinition
*/
public function getNativeDefinition(): InputDefinition
public function getNativeDefinition()
{
return $this->definition ?? throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));
if (null === $this->definition) {
throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));
}
return $this->definition;
}
/**
* Adds an argument.
*
* @param $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
* @param $default The default value (for InputArgument::OPTIONAL mode only)
* @param array|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
* @param int|null $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
* @param mixed $default The default value (for InputArgument::OPTIONAL mode only)
*
* @return $this
*
* @throws InvalidArgumentException When argument mode is not valid
*/
public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = null */): static
public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null)
{
$suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : [];
if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) {
throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues)));
$this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
if (null !== $this->fullDefinition) {
$this->fullDefinition->addArgument(new InputArgument($name, $mode, $description, $default));
}
$this->definition->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues));
$this->fullDefinition?->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues));
return $this;
}
@ -475,23 +446,20 @@ class Command
/**
* Adds an option.
*
* @param $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
* @param $mode The option mode: One of the InputOption::VALUE_* constants
* @param $default The default value (must be null for InputOption::VALUE_NONE)
* @param array|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
* @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
* @param int|null $mode The option mode: One of the InputOption::VALUE_* constants
* @param mixed $default The default value (must be null for InputOption::VALUE_NONE)
*
* @return $this
*
* @throws InvalidArgumentException If option mode is invalid or incompatible
*/
public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static
public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null)
{
$suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : [];
if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) {
throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues)));
$this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
if (null !== $this->fullDefinition) {
$this->fullDefinition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
}
$this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues));
$this->fullDefinition?->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues));
return $this;
}
@ -508,7 +476,7 @@ class Command
*
* @throws InvalidArgumentException When the name is invalid
*/
public function setName(string $name): static
public function setName(string $name)
{
$this->validateName($name);
@ -525,7 +493,7 @@ class Command
*
* @return $this
*/
public function setProcessTitle(string $title): static
public function setProcessTitle(string $title)
{
$this->processTitle = $title;
@ -534,18 +502,23 @@ class Command
/**
* Returns the command name.
*
* @return string|null
*/
public function getName(): ?string
public function getName()
{
return $this->name;
}
/**
* @param bool $hidden Whether or not the command should be hidden from the list of commands
* The default value will be true in Symfony 6.0
*
* @return $this
*
* @final since Symfony 5.1
*/
public function setHidden(bool $hidden = true): static
public function setHidden(bool $hidden /* = true */)
{
$this->hidden = $hidden;
@ -555,7 +528,7 @@ class Command
/**
* @return bool whether the command should be publicly shown or not
*/
public function isHidden(): bool
public function isHidden()
{
return $this->hidden;
}
@ -565,7 +538,7 @@ class Command
*
* @return $this
*/
public function setDescription(string $description): static
public function setDescription(string $description)
{
$this->description = $description;
@ -574,8 +547,10 @@ class Command
/**
* Returns the description for the command.
*
* @return string
*/
public function getDescription(): string
public function getDescription()
{
return $this->description;
}
@ -585,7 +560,7 @@ class Command
*
* @return $this
*/
public function setHelp(string $help): static
public function setHelp(string $help)
{
$this->help = $help;
@ -594,8 +569,10 @@ class Command
/**
* Returns the help for the command.
*
* @return string
*/
public function getHelp(): string
public function getHelp()
{
return $this->help;
}
@ -603,11 +580,13 @@ class Command
/**
* Returns the processed help for the command replacing the %command.name% and
* %command.full_name% patterns with the real values dynamically.
*
* @return string
*/
public function getProcessedHelp(): string
public function getProcessedHelp()
{
$name = $this->name;
$isSingleCommand = $this->application?->isSingleCommand();
$isSingleCommand = $this->application && $this->application->isSingleCommand();
$placeholders = [
'%command.name%',
@ -630,7 +609,7 @@ class Command
*
* @throws InvalidArgumentException When an alias is invalid
*/
public function setAliases(iterable $aliases): static
public function setAliases(iterable $aliases)
{
$list = [];
@ -646,8 +625,10 @@ class Command
/**
* Returns the aliases for the command.
*
* @return array
*/
public function getAliases(): array
public function getAliases()
{
return $this->aliases;
}
@ -656,8 +637,10 @@ class Command
* Returns the synopsis for the command.
*
* @param bool $short Whether to show the short version of the synopsis (with options folded) or not
*
* @return string
*/
public function getSynopsis(bool $short = false): string
public function getSynopsis(bool $short = false)
{
$key = $short ? 'short' : 'long';
@ -673,7 +656,7 @@ class Command
*
* @return $this
*/
public function addUsage(string $usage): static
public function addUsage(string $usage)
{
if (!str_starts_with($usage, $this->name)) {
$usage = sprintf('%s %s', $this->name, $usage);
@ -686,8 +669,10 @@ class Command
/**
* Returns alternative usages of the command.
*
* @return array
*/
public function getUsages(): array
public function getUsages()
{
return $this->usages;
}
@ -695,12 +680,12 @@ class Command
/**
* Gets a helper instance by name.
*
* @return HelperInterface
* @return mixed
*
* @throws LogicException if no HelperSet is defined
* @throws InvalidArgumentException if the helper is not defined
*/
public function getHelper(string $name): mixed
public function getHelper(string $name)
{
if (null === $this->helperSet) {
throw new LogicException(sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name));
@ -716,7 +701,7 @@ class Command
*
* @throws InvalidArgumentException When the name is invalid
*/
private function validateName(string $name): void
private function validateName(string $name)
{
if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));

View file

@ -11,13 +11,10 @@
namespace Symfony\Component\Console\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Output\BashCompletionOutput;
use Symfony\Component\Console\Completion\Output\CompletionOutputInterface;
use Symfony\Component\Console\Completion\Output\FishCompletionOutput;
use Symfony\Component\Console\Completion\Output\ZshCompletionOutput;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Input\InputInterface;
@ -29,24 +26,14 @@ use Symfony\Component\Console\Output\OutputInterface;
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
#[AsCommand(name: '|_complete', description: 'Internal command to provide shell completion suggestions')]
final class CompleteCommand extends Command
{
public const COMPLETION_API_VERSION = '1';
/**
* @deprecated since Symfony 6.1
*/
protected static $defaultName = '|_complete';
/**
* @deprecated since Symfony 6.1
*/
protected static $defaultDescription = 'Internal command to provide shell completion suggestions';
private array $completionOutputs;
private $completionOutputs;
private bool $isDebug = false;
private $isDebug = false;
/**
* @param array<string, class-string<CompletionOutputInterface>> $completionOutputs A list of additional completion outputs, with shell name as key and FQCN as value
@ -54,11 +41,7 @@ final class CompleteCommand extends Command
public function __construct(array $completionOutputs = [])
{
// must be set before the parent constructor, as the property value is used in configure()
$this->completionOutputs = $completionOutputs + [
'bash' => BashCompletionOutput::class,
'fish' => FishCompletionOutput::class,
'zsh' => ZshCompletionOutput::class,
];
$this->completionOutputs = $completionOutputs + ['bash' => BashCompletionOutput::class];
parent::__construct();
}
@ -69,29 +52,28 @@ final class CompleteCommand extends Command
->addOption('shell', 's', InputOption::VALUE_REQUIRED, 'The shell type ("'.implode('", "', array_keys($this->completionOutputs)).'")')
->addOption('input', 'i', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'An array of input tokens (e.g. COMP_WORDS or argv)')
->addOption('current', 'c', InputOption::VALUE_REQUIRED, 'The index of the "input" array that the cursor is in (e.g. COMP_CWORD)')
->addOption('api-version', 'a', InputOption::VALUE_REQUIRED, 'The API version of the completion script')
->addOption('symfony', 'S', InputOption::VALUE_REQUIRED, 'deprecated')
->addOption('symfony', 'S', InputOption::VALUE_REQUIRED, 'The version of the completion script')
;
}
protected function initialize(InputInterface $input, OutputInterface $output): void
protected function initialize(InputInterface $input, OutputInterface $output)
{
$this->isDebug = filter_var(getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOL);
$this->isDebug = filter_var(getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOLEAN);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
try {
// "symfony" must be kept for compat with the shell scripts generated by Symfony Console 5.4 - 6.1
$version = $input->getOption('symfony') ? '1' : $input->getOption('api-version');
if ($version && version_compare($version, self::COMPLETION_API_VERSION, '<')) {
$message = sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION);
$this->log($message);
// uncomment when a bugfix or BC break has been introduced in the shell completion scripts
// $version = $input->getOption('symfony');
// if ($version && version_compare($version, 'x.y', '>=')) {
// $message = sprintf('Completion script version is not supported ("%s" given, ">=x.y" required).', $version);
// $this->log($message);
$output->writeln($message.' Install the Symfony completion script again by using the "completion" command.');
// $output->writeln($message.' Install the Symfony completion script again by using the "completion" command.');
return 126;
}
// return 126;
// }
$shell = $input->getOption('shell');
if (!$shell) {
@ -134,12 +116,12 @@ final class CompleteCommand extends Command
$completionInput->bind($command->getDefinition());
if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) {
$this->log(' Completing option names for the <comment>'.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.'</> command.');
$this->log(' Completing option names for the <comment>'.\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).'</> command.');
$suggestions->suggestOptions($command->getDefinition()->getOptions());
} else {
$this->log([
' Completing using the <comment>'.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.'</> class.',
' Completing using the <comment>'.\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).'</> class.',
' Completing <comment>'.$completionInput->getCompletionType().'</> for <comment>'.$completionInput->getCompletionName().'</>',
]);
if (null !== $compval = $completionInput->getCompletionValue()) {
@ -155,7 +137,7 @@ final class CompleteCommand extends Command
$this->log('<info>Suggestions:</>');
if ($options = $suggestions->getOptionSuggestions()) {
$this->log(' --'.implode(' --', array_map(fn ($o) => $o->getName(), $options)));
$this->log(' --'.implode(' --', array_map(function ($o) { return $o->getName(); }, $options)));
} elseif ($values = $suggestions->getValueSuggestions()) {
$this->log(' '.implode(' ', $values));
} else {
@ -190,7 +172,7 @@ final class CompleteCommand extends Command
try {
$completionInput->bind($this->getApplication()->getDefinition());
} catch (ExceptionInterface) {
} catch (ExceptionInterface $e) {
}
return $completionInput;
@ -205,7 +187,7 @@ final class CompleteCommand extends Command
}
return $this->getApplication()->find($inputName);
} catch (CommandNotFoundException) {
} catch (CommandNotFoundException $e) {
}
return null;

View file

@ -11,7 +11,8 @@
namespace Symfony\Component\Console\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@ -24,67 +25,55 @@ use Symfony\Component\Process\Process;
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
#[AsCommand(name: 'completion', description: 'Dump the shell completion script')]
final class DumpCompletionCommand extends Command
{
/**
* @deprecated since Symfony 6.1
*/
protected static $defaultName = 'completion';
/**
* @deprecated since Symfony 6.1
*/
protected static $defaultDescription = 'Dump the shell completion script';
private array $supportedShells;
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('shell')) {
$suggestions->suggestValues($this->getSupportedShells());
}
}
protected function configure(): void
protected function configure()
{
$fullCommand = $_SERVER['PHP_SELF'];
$commandName = basename($fullCommand);
$fullCommand = @realpath($fullCommand) ?: $fullCommand;
$shell = $this->guessShell();
[$rcFile, $completionFile] = match ($shell) {
'fish' => ['~/.config/fish/config.fish', "/etc/fish/completions/$commandName.fish"],
'zsh' => ['~/.zshrc', '$fpath[1]/_'.$commandName],
default => ['~/.bashrc', "/etc/bash_completion.d/$commandName"],
};
$supportedShells = implode(', ', $this->getSupportedShells());
$this
->setHelp(<<<EOH
The <info>%command.name%</> command dumps the shell completion script required
to use shell autocompletion (currently, {$supportedShells} completion are supported).
to use shell autocompletion (currently only bash completion is supported).
<comment>Static installation
-------------------</>
Dump the script to a global completion file and restart your shell:
<info>%command.full_name% {$shell} | sudo tee {$completionFile}</>
<info>%command.full_name% bash | sudo tee /etc/bash_completion.d/{$commandName}</>
Or dump the script to a local file and source it:
<info>%command.full_name% {$shell} > completion.sh</>
<info>%command.full_name% bash > completion.sh</>
<comment># source the file whenever you use the project</>
<info>source completion.sh</>
<comment># or add this line at the end of your "{$rcFile}" file:</>
<comment># or add this line at the end of your "~/.bashrc" file:</>
<info>source /path/to/completion.sh</>
<comment>Dynamic installation
--------------------</>
Add this to the end of your shell configuration file (e.g. <info>"{$rcFile}"</>):
Add this to the end of your shell configuration file (e.g. <info>"~/.bashrc"</>):
<info>eval "$({$fullCommand} completion {$shell})"</>
<info>eval "$({$fullCommand} completion bash)"</>
EOH
)
->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given', null, $this->getSupportedShells(...))
->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given')
->addOption('debug', null, InputOption::VALUE_NONE, 'Tail the completion debug log')
;
}
@ -116,7 +105,7 @@ EOH
return 2;
}
$output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, CompleteCommand::COMPLETION_API_VERSION], file_get_contents($completionFile)));
$output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, $this->getApplication()->getVersion()], file_get_contents($completionFile)));
return 0;
}
@ -143,10 +132,6 @@ EOH
*/
private function getSupportedShells(): array
{
if (isset($this->supportedShells)) {
return $this->supportedShells;
}
$shells = [];
foreach (new \DirectoryIterator(__DIR__.'/../Resources/') as $file) {
@ -154,8 +139,7 @@ EOH
$shells[] = $file->getExtension();
}
}
sort($shells);
return $this->supportedShells = $shells;
return $shells;
}
}

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Console\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Descriptor\ApplicationDescription;
use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
@ -25,10 +27,10 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class HelpCommand extends Command
{
private Command $command;
private $command;
/**
* @return void
* {@inheritdoc}
*/
protected function configure()
{
@ -37,8 +39,8 @@ class HelpCommand extends Command
$this
->setName('help')
->setDefinition([
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', fn () => array_keys((new ApplicationDescription($this->getApplication()))->getCommands())),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', fn () => (new DescriptorHelper())->getFormats()),
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
])
->setDescription('Display help for a command')
@ -57,17 +59,19 @@ EOF
;
}
/**
* @return void
*/
public function setCommand(Command $command)
{
$this->command = $command;
}
protected function execute(InputInterface $input, OutputInterface $output): int
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->command ??= $this->getApplication()->find($input->getArgument('command_name'));
if (null === $this->command) {
$this->command = $this->getApplication()->find($input->getArgument('command_name'));
}
$helper = new DescriptorHelper();
$helper->describe($output, $this->command, [
@ -75,8 +79,23 @@ EOF
'raw_text' => $input->getOption('raw'),
]);
unset($this->command);
$this->command = null;
return 0;
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('command_name')) {
$descriptor = new ApplicationDescription($this->getApplication());
$suggestions->suggestValues(array_keys($descriptor->getCommands()));
return;
}
if ($input->mustSuggestOptionValuesFor('format')) {
$helper = new DescriptorHelper();
$suggestions->suggestValues($helper->getFormats());
}
}
}

View file

@ -14,8 +14,6 @@ namespace Symfony\Component\Console\Command;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Completion\Suggestion;
use Symfony\Component\Console\Helper\HelperInterface;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
@ -26,8 +24,8 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
final class LazyCommand extends Command
{
private \Closure|Command $command;
private ?bool $isEnabled;
private $command;
private $isEnabled;
public function __construct(string $name, array $aliases, string $description, bool $isHidden, \Closure $commandFactory, ?bool $isEnabled = true)
{
@ -47,9 +45,6 @@ final class LazyCommand extends Command
public function setApplication(?Application $application = null): void
{
if (1 > \func_num_args()) {
trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
}
if ($this->command instanceof parent) {
$this->command->setApplication($application);
}
@ -81,7 +76,10 @@ final class LazyCommand extends Command
$this->getCommand()->complete($input, $suggestions);
}
public function setCode(callable $code): static
/**
* @return $this
*/
public function setCode(callable $code): self
{
$this->getCommand()->setCode($code);
@ -96,7 +94,10 @@ final class LazyCommand extends Command
$this->getCommand()->mergeApplicationDefinition($mergeArgs);
}
public function setDefinition(array|InputDefinition $definition): static
/**
* @return $this
*/
public function setDefinition($definition): self
{
$this->getCommand()->setDefinition($definition);
@ -114,35 +115,39 @@ final class LazyCommand extends Command
}
/**
* @param array|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
* @return $this
*/
public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static
public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null): self
{
$suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : [];
$this->getCommand()->addArgument($name, $mode, $description, $default, $suggestedValues);
$this->getCommand()->addArgument($name, $mode, $description, $default);
return $this;
}
/**
* @param array|\Closure(CompletionInput,CompletionSuggestions):list<string|Suggestion> $suggestedValues The values used for input completion
* @return $this
*/
public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static
public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null): self
{
$suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : [];
$this->getCommand()->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues);
$this->getCommand()->addOption($name, $shortcut, $mode, $description, $default);
return $this;
}
public function setProcessTitle(string $title): static
/**
* @return $this
*/
public function setProcessTitle(string $title): self
{
$this->getCommand()->setProcessTitle($title);
return $this;
}
public function setHelp(string $help): static
/**
* @return $this
*/
public function setHelp(string $help): self
{
$this->getCommand()->setHelp($help);
@ -164,7 +169,10 @@ final class LazyCommand extends Command
return $this->getCommand()->getSynopsis($short);
}
public function addUsage(string $usage): static
/**
* @return $this
*/
public function addUsage(string $usage): self
{
$this->getCommand()->addUsage($usage);
@ -176,7 +184,10 @@ final class LazyCommand extends Command
return $this->getCommand()->getUsages();
}
public function getHelper(string $name): HelperInterface
/**
* @return mixed
*/
public function getHelper(string $name)
{
return $this->getCommand()->getHelper($name);
}

View file

@ -11,6 +11,8 @@
namespace Symfony\Component\Console\Command;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Descriptor\ApplicationDescription;
use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
@ -26,16 +28,16 @@ use Symfony\Component\Console\Output\OutputInterface;
class ListCommand extends Command
{
/**
* @return void
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('list')
->setDefinition([
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, fn () => array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces())),
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', fn () => (new DescriptorHelper())->getFormats()),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments'),
])
->setDescription('List commands')
@ -60,7 +62,10 @@ EOF
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$helper = new DescriptorHelper();
$helper->describe($output, $this->getApplication(), [
@ -72,4 +77,19 @@ EOF
return 0;
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
if ($input->mustSuggestArgumentValuesFor('namespace')) {
$descriptor = new ApplicationDescription($this->getApplication());
$suggestions->suggestValues(array_keys($descriptor->getNamespaces()));
return;
}
if ($input->mustSuggestOptionValuesFor('format')) {
$helper = new DescriptorHelper();
$suggestions->suggestValues($helper->getFormats());
}
}
}

View file

@ -24,7 +24,8 @@ use Symfony\Component\Lock\Store\SemaphoreStore;
*/
trait LockableTrait
{
private ?LockInterface $lock = null;
/** @var LockInterface|null */
private $lock;
/**
* Locks a command.
@ -32,7 +33,7 @@ trait LockableTrait
private function lock(?string $name = null, bool $blocking = false): bool
{
if (!class_exists(SemaphoreStore::class)) {
throw new LogicException('To enable the locking feature you must install the symfony/lock component. Try running "composer require symfony/lock".');
throw new LogicException('To enable the locking feature you must install the symfony/lock component.');
}
if (null !== $this->lock) {
@ -58,7 +59,7 @@ trait LockableTrait
/**
* Releases the command lock if there is one.
*/
private function release(): void
private function release()
{
if ($this->lock) {
$this->lock->release();

View file

@ -25,10 +25,6 @@ interface SignalableCommandInterface
/**
* The method will be called when the application is signaled.
*
* @param int|false $previousExitCode
*
* @return int|false The exit code to return or false to continue the normal execution
*/
public function handleSignal(int $signal, /* int|false $previousExitCode = 0 */);
public function handleSignal(int $signal): void;
}

View file

@ -1,356 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Command;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Completion\CompletionInput;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Helper\HelperInterface;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Stopwatch\Stopwatch;
/**
* @internal
*
* @author Jules Pietri <jules@heahprod.com>
*/
final class TraceableCommand extends Command implements SignalableCommandInterface
{
public readonly Command $command;
public int $exitCode;
public ?int $interruptedBySignal = null;
public bool $ignoreValidation;
public bool $isInteractive = false;
public string $duration = 'n/a';
public string $maxMemoryUsage = 'n/a';
public InputInterface $input;
public OutputInterface $output;
/** @var array<string, mixed> */
public array $arguments;
/** @var array<string, mixed> */
public array $options;
/** @var array<string, mixed> */
public array $interactiveInputs = [];
public array $handledSignals = [];
public function __construct(
Command $command,
private readonly Stopwatch $stopwatch,
) {
if ($command instanceof LazyCommand) {
$command = $command->getCommand();
}
$this->command = $command;
// prevent call to self::getDefaultDescription()
$this->setDescription($command->getDescription());
parent::__construct($command->getName());
// init below enables calling {@see parent::run()}
[$code, $processTitle, $ignoreValidationErrors] = \Closure::bind(function () {
return [$this->code, $this->processTitle, $this->ignoreValidationErrors];
}, $command, Command::class)();
if (\is_callable($code)) {
$this->setCode($code);
}
if ($processTitle) {
parent::setProcessTitle($processTitle);
}
if ($ignoreValidationErrors) {
parent::ignoreValidationErrors();
}
$this->ignoreValidation = $ignoreValidationErrors;
}
public function __call(string $name, array $arguments): mixed
{
return $this->command->{$name}(...$arguments);
}
public function getSubscribedSignals(): array
{
return $this->command instanceof SignalableCommandInterface ? $this->command->getSubscribedSignals() : [];
}
public function handleSignal(int $signal, int|false $previousExitCode = 0): int|false
{
if (!$this->command instanceof SignalableCommandInterface) {
return false;
}
$event = $this->stopwatch->start($this->getName().'.handle_signal');
$exit = $this->command->handleSignal($signal, $previousExitCode);
$event->stop();
if (!isset($this->handledSignals[$signal])) {
$this->handledSignals[$signal] = [
'handled' => 0,
'duration' => 0,
'memory' => 0,
];
}
++$this->handledSignals[$signal]['handled'];
$this->handledSignals[$signal]['duration'] += $event->getDuration();
$this->handledSignals[$signal]['memory'] = max(
$this->handledSignals[$signal]['memory'],
$event->getMemory() >> 20
);
return $exit;
}
/**
* {@inheritdoc}
*
* Calling parent method is required to be used in {@see parent::run()}.
*/
public function ignoreValidationErrors(): void
{
$this->ignoreValidation = true;
$this->command->ignoreValidationErrors();
parent::ignoreValidationErrors();
}
public function setApplication(?Application $application = null): void
{
$this->command->setApplication($application);
}
public function getApplication(): ?Application
{
return $this->command->getApplication();
}
public function setHelperSet(HelperSet $helperSet): void
{
$this->command->setHelperSet($helperSet);
}
public function getHelperSet(): ?HelperSet
{
return $this->command->getHelperSet();
}
public function isEnabled(): bool
{
return $this->command->isEnabled();
}
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
$this->command->complete($input, $suggestions);
}
/**
* {@inheritdoc}
*
* Calling parent method is required to be used in {@see parent::run()}.
*/
public function setCode(callable $code): static
{
$this->command->setCode($code);
return parent::setCode(function (InputInterface $input, OutputInterface $output) use ($code): int {
$event = $this->stopwatch->start($this->getName().'.code');
$this->exitCode = $code($input, $output);
$event->stop();
return $this->exitCode;
});
}
/**
* @internal
*/
public function mergeApplicationDefinition(bool $mergeArgs = true): void
{
$this->command->mergeApplicationDefinition($mergeArgs);
}
public function setDefinition(array|InputDefinition $definition): static
{
$this->command->setDefinition($definition);
return $this;
}
public function getDefinition(): InputDefinition
{
return $this->command->getDefinition();
}
public function getNativeDefinition(): InputDefinition
{
return $this->command->getNativeDefinition();
}
public function addArgument(string $name, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
{
$this->command->addArgument($name, $mode, $description, $default, $suggestedValues);
return $this;
}
public function addOption(string $name, string|array|null $shortcut = null, ?int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static
{
$this->command->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues);
return $this;
}
/**
* {@inheritdoc}
*
* Calling parent method is required to be used in {@see parent::run()}.
*/
public function setProcessTitle(string $title): static
{
$this->command->setProcessTitle($title);
return parent::setProcessTitle($title);
}
public function setHelp(string $help): static
{
$this->command->setHelp($help);
return $this;
}
public function getHelp(): string
{
return $this->command->getHelp();
}
public function getProcessedHelp(): string
{
return $this->command->getProcessedHelp();
}
public function getSynopsis(bool $short = false): string
{
return $this->command->getSynopsis($short);
}
public function addUsage(string $usage): static
{
$this->command->addUsage($usage);
return $this;
}
public function getUsages(): array
{
return $this->command->getUsages();
}
public function getHelper(string $name): HelperInterface
{
return $this->command->getHelper($name);
}
public function run(InputInterface $input, OutputInterface $output): int
{
$this->input = $input;
$this->output = $output;
$this->arguments = $input->getArguments();
$this->options = $input->getOptions();
$event = $this->stopwatch->start($this->getName(), 'command');
try {
$this->exitCode = parent::run($input, $output);
} finally {
$event->stop();
if ($output instanceof ConsoleOutputInterface && $output->isDebug()) {
$output->getErrorOutput()->writeln((string) $event);
}
$this->duration = $event->getDuration().' ms';
$this->maxMemoryUsage = ($event->getMemory() >> 20).' MiB';
if ($this->isInteractive) {
$this->extractInteractiveInputs($input->getArguments(), $input->getOptions());
}
}
return $this->exitCode;
}
protected function initialize(InputInterface $input, OutputInterface $output): void
{
$event = $this->stopwatch->start($this->getName().'.init', 'command');
$this->command->initialize($input, $output);
$event->stop();
}
protected function interact(InputInterface $input, OutputInterface $output): void
{
if (!$this->isInteractive = Command::class !== (new \ReflectionMethod($this->command, 'interact'))->getDeclaringClass()->getName()) {
return;
}
$event = $this->stopwatch->start($this->getName().'.interact', 'command');
$this->command->interact($input, $output);
$event->stop();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$event = $this->stopwatch->start($this->getName().'.execute', 'command');
$exitCode = $this->command->execute($input, $output);
$event->stop();
return $exitCode;
}
private function extractInteractiveInputs(array $arguments, array $options): void
{
foreach ($arguments as $argName => $argValue) {
if (\array_key_exists($argName, $this->arguments) && $this->arguments[$argName] === $argValue) {
continue;
}
$this->interactiveInputs[$argName] = $argValue;
}
foreach ($options as $optName => $optValue) {
if (\array_key_exists($optName, $this->options) && $this->options[$optName] === $optValue) {
continue;
}
$this->interactiveInputs['--'.$optName] = $optValue;
}
}
}

View file

@ -22,17 +22,21 @@ interface CommandLoaderInterface
/**
* Loads a command.
*
* @return Command
*
* @throws CommandNotFoundException
*/
public function get(string $name): Command;
public function get(string $name);
/**
* Checks if a command exists.
*
* @return bool
*/
public function has(string $name): bool;
public function has(string $name);
/**
* @return string[]
*/
public function getNames(): array;
public function getNames();
}

View file

@ -12,7 +12,6 @@
namespace Symfony\Component\Console\CommandLoader;
use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\CommandNotFoundException;
/**
@ -22,8 +21,8 @@ use Symfony\Component\Console\Exception\CommandNotFoundException;
*/
class ContainerCommandLoader implements CommandLoaderInterface
{
private ContainerInterface $container;
private array $commandMap;
private $container;
private $commandMap;
/**
* @param array $commandMap An array with command names as keys and service ids as values
@ -34,7 +33,10 @@ class ContainerCommandLoader implements CommandLoaderInterface
$this->commandMap = $commandMap;
}
public function get(string $name): Command
/**
* {@inheritdoc}
*/
public function get(string $name)
{
if (!$this->has($name)) {
throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
@ -43,12 +45,18 @@ class ContainerCommandLoader implements CommandLoaderInterface
return $this->container->get($this->commandMap[$name]);
}
public function has(string $name): bool
/**
* {@inheritdoc}
*/
public function has(string $name)
{
return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]);
}
public function getNames(): array
/**
* {@inheritdoc}
*/
public function getNames()
{
return array_keys($this->commandMap);
}

View file

@ -11,7 +11,6 @@
namespace Symfony\Component\Console\CommandLoader;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\CommandNotFoundException;
/**
@ -21,7 +20,7 @@ use Symfony\Component\Console\Exception\CommandNotFoundException;
*/
class FactoryCommandLoader implements CommandLoaderInterface
{
private array $factories;
private $factories;
/**
* @param callable[] $factories Indexed by command names
@ -31,12 +30,18 @@ class FactoryCommandLoader implements CommandLoaderInterface
$this->factories = $factories;
}
public function has(string $name): bool
/**
* {@inheritdoc}
*/
public function has(string $name)
{
return isset($this->factories[$name]);
}
public function get(string $name): Command
/**
* {@inheritdoc}
*/
public function get(string $name)
{
if (!isset($this->factories[$name])) {
throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
@ -47,7 +52,10 @@ class FactoryCommandLoader implements CommandLoaderInterface
return $factory();
}
public function getNames(): array
/**
* {@inheritdoc}
*/
public function getNames()
{
return array_keys($this->factories);
}

View file

@ -31,11 +31,11 @@ final class CompletionInput extends ArgvInput
public const TYPE_OPTION_NAME = 'option_name';
public const TYPE_NONE = 'none';
private array $tokens;
private int $currentIndex;
private string $completionType;
private ?string $completionName = null;
private string $completionValue = '';
private $tokens;
private $currentIndex;
private $completionType;
private $completionName = null;
private $completionValue = '';
/**
* Converts a terminal string into tokens.
@ -64,6 +64,9 @@ final class CompletionInput extends ArgvInput
return $input;
}
/**
* {@inheritdoc}
*/
public function bind(InputDefinition $definition): void
{
parent::bind($definition);
@ -81,7 +84,7 @@ final class CompletionInput extends ArgvInput
return;
}
if ($option?->acceptValue()) {
if (null !== $option && $option->acceptValue()) {
$this->completionType = self::TYPE_OPTION_VALUE;
$this->completionName = $option->getName();
$this->completionValue = $optionValue ?: (!str_starts_with($optionToken, '--') ? substr($optionToken, 2) : '');
@ -94,7 +97,7 @@ final class CompletionInput extends ArgvInput
if ('-' === $previousToken[0] && '' !== trim($previousToken, '-')) {
// check if previous option accepted a value
$previousOption = $this->getOptionFromToken($previousToken);
if ($previousOption?->acceptValue()) {
if (null !== $previousOption && $previousOption->acceptValue()) {
$this->completionType = self::TYPE_OPTION_VALUE;
$this->completionName = $previousOption->getName();
$this->completionValue = $relevantToken;
@ -141,9 +144,7 @@ final class CompletionInput extends ArgvInput
* TYPE_OPTION_NAME when completing the name of an input option
* TYPE_NONE when nothing should be completed
*
* TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component.
*
* @return self::TYPE_*
* @return string One of self::TYPE_* constants. TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component
*/
public function getCompletionType(): string
{
@ -182,7 +183,7 @@ final class CompletionInput extends ArgvInput
{
try {
return parent::parseToken($token, $parseOptions);
} catch (RuntimeException) {
} catch (RuntimeException $e) {
// suppress errors, completed input is almost never valid
}

View file

@ -20,15 +20,17 @@ use Symfony\Component\Console\Input\InputOption;
*/
final class CompletionSuggestions
{
private array $valueSuggestions = [];
private array $optionSuggestions = [];
private $valueSuggestions = [];
private $optionSuggestions = [];
/**
* Add a suggested value for an input option or argument.
*
* @param string|Suggestion $value
*
* @return $this
*/
public function suggestValue(string|Suggestion $value): static
public function suggestValue($value): self
{
$this->valueSuggestions[] = !$value instanceof Suggestion ? new Suggestion($value) : $value;
@ -42,7 +44,7 @@ final class CompletionSuggestions
*
* @return $this
*/
public function suggestValues(array $values): static
public function suggestValues(array $values): self
{
foreach ($values as $value) {
$this->suggestValue($value);
@ -56,7 +58,7 @@ final class CompletionSuggestions
*
* @return $this
*/
public function suggestOption(InputOption $option): static
public function suggestOption(InputOption $option): self
{
$this->optionSuggestions[] = $option;
@ -70,7 +72,7 @@ final class CompletionSuggestions
*
* @return $this
*/
public function suggestOptions(array $options): static
public function suggestOptions(array $options): self
{
foreach ($options as $option) {
$this->suggestOption($option);

View file

@ -1,33 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Completion\Output;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Guillaume Aveline <guillaume.aveline@pm.me>
*/
class FishCompletionOutput implements CompletionOutputInterface
{
public function write(CompletionSuggestions $suggestions, OutputInterface $output): void
{
$values = $suggestions->getValueSuggestions();
foreach ($suggestions->getOptionSuggestions() as $option) {
$values[] = '--'.$option->getName();
if ($option->isNegatable()) {
$values[] = '--no-'.$option->getName();
}
}
$output->write(implode("\n", $values));
}
}

View file

@ -1,36 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Completion\Output;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Jitendra A <adhocore@gmail.com>
*/
class ZshCompletionOutput implements CompletionOutputInterface
{
public function write(CompletionSuggestions $suggestions, OutputInterface $output): void
{
$values = [];
foreach ($suggestions->getValueSuggestions() as $value) {
$values[] = $value->getValue().($value->getDescription() ? "\t".$value->getDescription() : '');
}
foreach ($suggestions->getOptionSuggestions() as $option) {
$values[] = '--'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : '');
if ($option->isNegatable()) {
$values[] = '--no-'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : '');
}
}
$output->write(implode("\n", $values)."\n");
}
}

View file

@ -16,12 +16,13 @@ namespace Symfony\Component\Console\Completion;
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
class Suggestion implements \Stringable
class Suggestion
{
public function __construct(
private readonly string $value,
private readonly string $description = ''
) {
private $value;
public function __construct(string $value)
{
$this->value = $value;
}
public function getValue(): string
@ -29,11 +30,6 @@ class Suggestion implements \Stringable
return $this->value;
}
public function getDescription(): string
{
return $this->description;
}
public function __toString(): string
{
return $this->getValue();

View file

@ -18,8 +18,7 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
final class Cursor
{
private OutputInterface $output;
/** @var resource */
private $output;
private $input;
/**
@ -34,7 +33,7 @@ final class Cursor
/**
* @return $this
*/
public function moveUp(int $lines = 1): static
public function moveUp(int $lines = 1): self
{
$this->output->write(sprintf("\x1b[%dA", $lines));
@ -44,7 +43,7 @@ final class Cursor
/**
* @return $this
*/
public function moveDown(int $lines = 1): static
public function moveDown(int $lines = 1): self
{
$this->output->write(sprintf("\x1b[%dB", $lines));
@ -54,7 +53,7 @@ final class Cursor
/**
* @return $this
*/
public function moveRight(int $columns = 1): static
public function moveRight(int $columns = 1): self
{
$this->output->write(sprintf("\x1b[%dC", $columns));
@ -64,7 +63,7 @@ final class Cursor
/**
* @return $this
*/
public function moveLeft(int $columns = 1): static
public function moveLeft(int $columns = 1): self
{
$this->output->write(sprintf("\x1b[%dD", $columns));
@ -74,7 +73,7 @@ final class Cursor
/**
* @return $this
*/
public function moveToColumn(int $column): static
public function moveToColumn(int $column): self
{
$this->output->write(sprintf("\x1b[%dG", $column));
@ -84,7 +83,7 @@ final class Cursor
/**
* @return $this
*/
public function moveToPosition(int $column, int $row): static
public function moveToPosition(int $column, int $row): self
{
$this->output->write(sprintf("\x1b[%d;%dH", $row + 1, $column));
@ -94,7 +93,7 @@ final class Cursor
/**
* @return $this
*/
public function savePosition(): static
public function savePosition(): self
{
$this->output->write("\x1b7");
@ -104,7 +103,7 @@ final class Cursor
/**
* @return $this
*/
public function restorePosition(): static
public function restorePosition(): self
{
$this->output->write("\x1b8");
@ -114,7 +113,7 @@ final class Cursor
/**
* @return $this
*/
public function hide(): static
public function hide(): self
{
$this->output->write("\x1b[?25l");
@ -124,7 +123,7 @@ final class Cursor
/**
* @return $this
*/
public function show(): static
public function show(): self
{
$this->output->write("\x1b[?25h\x1b[?0c");
@ -136,7 +135,7 @@ final class Cursor
*
* @return $this
*/
public function clearLine(): static
public function clearLine(): self
{
$this->output->write("\x1b[2K");
@ -158,7 +157,7 @@ final class Cursor
*
* @return $this
*/
public function clearOutput(): static
public function clearOutput(): self
{
$this->output->write("\x1b[0J");
@ -170,7 +169,7 @@ final class Cursor
*
* @return $this
*/
public function clearScreen(): static
public function clearScreen(): self
{
$this->output->write("\x1b[2J");
@ -184,7 +183,11 @@ final class Cursor
{
static $isTtySupported;
if (!$isTtySupported ??= '/' === \DIRECTORY_SEPARATOR && stream_isatty(\STDOUT)) {
if (null === $isTtySupported && \function_exists('proc_open')) {
$isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
}
if (!$isTtySupported) {
return [1, 1];
}

View file

@ -1,234 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\DataCollector;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Debug\CliRequest;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\SignalRegistry\SignalMap;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
use Symfony\Component\VarDumper\Cloner\Data;
/**
* @internal
*
* @author Jules Pietri <jules@heahprod.com>
*/
final class CommandDataCollector extends DataCollector
{
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
if (!$request instanceof CliRequest) {
return;
}
$command = $request->command;
$application = $command->getApplication();
$this->data = [
'command' => $this->cloneVar($command->command),
'exit_code' => $command->exitCode,
'interrupted_by_signal' => $command->interruptedBySignal,
'duration' => $command->duration,
'max_memory_usage' => $command->maxMemoryUsage,
'verbosity_level' => match ($command->output->getVerbosity()) {
OutputInterface::VERBOSITY_QUIET => 'quiet',
OutputInterface::VERBOSITY_NORMAL => 'normal',
OutputInterface::VERBOSITY_VERBOSE => 'verbose',
OutputInterface::VERBOSITY_VERY_VERBOSE => 'very verbose',
OutputInterface::VERBOSITY_DEBUG => 'debug',
},
'interactive' => $command->isInteractive,
'validate_input' => !$command->ignoreValidation,
'enabled' => $command->isEnabled(),
'visible' => !$command->isHidden(),
'input' => $this->cloneVar($command->input),
'output' => $this->cloneVar($command->output),
'interactive_inputs' => array_map($this->cloneVar(...), $command->interactiveInputs),
'signalable' => $command->getSubscribedSignals(),
'handled_signals' => $command->handledSignals,
'helper_set' => array_map($this->cloneVar(...), iterator_to_array($command->getHelperSet())),
];
$baseDefinition = $application->getDefinition();
foreach ($command->arguments as $argName => $argValue) {
if ($baseDefinition->hasArgument($argName)) {
$this->data['application_inputs'][$argName] = $this->cloneVar($argValue);
} else {
$this->data['arguments'][$argName] = $this->cloneVar($argValue);
}
}
foreach ($command->options as $optName => $optValue) {
if ($baseDefinition->hasOption($optName)) {
$this->data['application_inputs']['--'.$optName] = $this->cloneVar($optValue);
} else {
$this->data['options'][$optName] = $this->cloneVar($optValue);
}
}
}
public function getName(): string
{
return 'command';
}
/**
* @return array{
* class?: class-string,
* executor?: string,
* file: string,
* line: int,
* }
*/
public function getCommand(): array
{
$class = $this->data['command']->getType();
$r = new \ReflectionMethod($class, 'execute');
if (Command::class !== $r->getDeclaringClass()) {
return [
'executor' => $class.'::'.$r->name,
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
];
}
$r = new \ReflectionClass($class);
return [
'class' => $class,
'file' => $r->getFileName(),
'line' => $r->getStartLine(),
];
}
public function getInterruptedBySignal(): ?string
{
if (isset($this->data['interrupted_by_signal'])) {
return sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']);
}
return null;
}
public function getDuration(): string
{
return $this->data['duration'];
}
public function getMaxMemoryUsage(): string
{
return $this->data['max_memory_usage'];
}
public function getVerbosityLevel(): string
{
return $this->data['verbosity_level'];
}
public function getInteractive(): bool
{
return $this->data['interactive'];
}
public function getValidateInput(): bool
{
return $this->data['validate_input'];
}
public function getEnabled(): bool
{
return $this->data['enabled'];
}
public function getVisible(): bool
{
return $this->data['visible'];
}
public function getInput(): Data
{
return $this->data['input'];
}
public function getOutput(): Data
{
return $this->data['output'];
}
/**
* @return Data[]
*/
public function getArguments(): array
{
return $this->data['arguments'] ?? [];
}
/**
* @return Data[]
*/
public function getOptions(): array
{
return $this->data['options'] ?? [];
}
/**
* @return Data[]
*/
public function getApplicationInputs(): array
{
return $this->data['application_inputs'] ?? [];
}
/**
* @return Data[]
*/
public function getInteractiveInputs(): array
{
return $this->data['interactive_inputs'] ?? [];
}
public function getSignalable(): array
{
return array_map(
static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal),
$this->data['signalable']
);
}
public function getHandledSignals(): array
{
$keys = array_map(
static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal),
array_keys($this->data['handled_signals'])
);
return array_combine($keys, array_values($this->data['handled_signals']));
}
/**
* @return Data[]
*/
public function getHelperSet(): array
{
return $this->data['helper_set'] ?? [];
}
public function reset(): void
{
$this->data = [];
}
}

View file

@ -1,70 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Debug;
use Symfony\Component\Console\Command\TraceableCommand;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* @internal
*/
final class CliRequest extends Request
{
public function __construct(
public readonly TraceableCommand $command,
) {
parent::__construct(
attributes: ['_controller' => \get_class($command->command), '_virtual_type' => 'command'],
server: $_SERVER,
);
}
// Methods below allow to populate a profile, thus enable search and filtering
public function getUri(): string
{
if ($this->server->has('SYMFONY_CLI_BINARY_NAME')) {
$binary = $this->server->get('SYMFONY_CLI_BINARY_NAME').' console';
} else {
$binary = $this->server->get('argv')[0];
}
return $binary.' '.$this->command->input;
}
public function getMethod(): string
{
return $this->command->isInteractive ? 'INTERACTIVE' : 'BATCH';
}
public function getResponse(): Response
{
return new class($this->command->exitCode) extends Response {
public function __construct(private readonly int $exitCode)
{
parent::__construct();
}
public function getStatusCode(): int
{
return $this->exitCode;
}
};
}
public function getClientIp(): string
{
$application = $this->command->getApplication();
return $application->getName().' '.$application->getVersion();
}
}

View file

@ -29,19 +29,33 @@ use Symfony\Component\DependencyInjection\TypedReference;
*/
class AddConsoleCommandPass implements CompilerPassInterface
{
/**
* @return void
*/
private $commandLoaderServiceId;
private $commandTag;
private $noPreloadTag;
private $privateTagName;
public function __construct(string $commandLoaderServiceId = 'console.command_loader', string $commandTag = 'console.command', string $noPreloadTag = 'container.no_preload', string $privateTagName = 'container.private')
{
if (0 < \func_num_args()) {
trigger_deprecation('symfony/console', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
}
$this->commandLoaderServiceId = $commandLoaderServiceId;
$this->commandTag = $commandTag;
$this->noPreloadTag = $noPreloadTag;
$this->privateTagName = $privateTagName;
}
public function process(ContainerBuilder $container)
{
$commandServices = $container->findTaggedServiceIds('console.command', true);
$commandServices = $container->findTaggedServiceIds($this->commandTag, true);
$lazyCommandMap = [];
$lazyCommandRefs = [];
$serviceIds = [];
foreach ($commandServices as $id => $tags) {
$definition = $container->getDefinition($id);
$definition->addTag('container.no_preload');
$definition->addTag($this->noPreloadTag);
$class = $container->getParameterBag()->resolveValue($definition->getClass());
if (isset($tags[0]['command'])) {
@ -51,7 +65,7 @@ class AddConsoleCommandPass implements CompilerPassInterface
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
}
if (!$r->isSubclassOf(Command::class)) {
throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class));
throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class));
}
$aliases = str_replace('%', '%%', $class::getDefaultName() ?? '');
}
@ -64,7 +78,7 @@ class AddConsoleCommandPass implements CompilerPassInterface
}
if (null === $commandName) {
if (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag('container.private')) {
if (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag($this->privateTagName)) {
$commandId = 'console.command.public_alias.'.$id;
$container->setAlias($commandId, $id)->setPublic(true);
$id = $commandId;
@ -90,7 +104,7 @@ class AddConsoleCommandPass implements CompilerPassInterface
$lazyCommandMap[$tag['command']] = $id;
}
$description ??= $tag['description'] ?? null;
$description = $description ?? $tag['description'] ?? null;
}
$definition->addMethodCall('setName', [$commandName]);
@ -108,7 +122,7 @@ class AddConsoleCommandPass implements CompilerPassInterface
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
}
if (!$r->isSubclassOf(Command::class)) {
throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class));
throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class));
}
$description = str_replace('%', '%%', $class::getDefaultDescription() ?? '');
}
@ -124,9 +138,9 @@ class AddConsoleCommandPass implements CompilerPassInterface
}
$container
->register('console.command_loader', ContainerCommandLoader::class)
->register($this->commandLoaderServiceId, ContainerCommandLoader::class)
->setPublic(true)
->addTag('container.no_preload')
->addTag($this->noPreloadTag)
->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]);
$container->setParameter('console.command.ids', $serviceIds);

View file

@ -24,20 +24,24 @@ class ApplicationDescription
{
public const GLOBAL_NAMESPACE = '_global';
private Application $application;
private ?string $namespace;
private bool $showHidden;
private array $namespaces;
private $application;
private $namespace;
private $showHidden;
/**
* @var array
*/
private $namespaces;
/**
* @var array<string, Command>
*/
private array $commands;
private $commands;
/**
* @var array<string, Command>
*/
private array $aliases = [];
private $aliases;
public function __construct(Application $application, ?string $namespace = null, bool $showHidden = false)
{
@ -48,7 +52,7 @@ class ApplicationDescription
public function getNamespaces(): array
{
if (!isset($this->namespaces)) {
if (null === $this->namespaces) {
$this->inspectApplication();
}
@ -60,7 +64,7 @@ class ApplicationDescription
*/
public function getCommands(): array
{
if (!isset($this->commands)) {
if (null === $this->commands) {
$this->inspectApplication();
}
@ -79,7 +83,7 @@ class ApplicationDescription
return $this->commands[$name] ?? $this->aliases[$name];
}
private function inspectApplication(): void
private function inspectApplication()
{
$this->commands = [];
$this->namespaces = [];

View file

@ -26,23 +26,43 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
abstract class Descriptor implements DescriptorInterface
{
protected OutputInterface $output;
/**
* @var OutputInterface
*/
protected $output;
public function describe(OutputInterface $output, object $object, array $options = []): void
/**
* {@inheritdoc}
*/
public function describe(OutputInterface $output, object $object, array $options = [])
{
$this->output = $output;
match (true) {
$object instanceof InputArgument => $this->describeInputArgument($object, $options),
$object instanceof InputOption => $this->describeInputOption($object, $options),
$object instanceof InputDefinition => $this->describeInputDefinition($object, $options),
$object instanceof Command => $this->describeCommand($object, $options),
$object instanceof Application => $this->describeApplication($object, $options),
default => throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object))),
};
switch (true) {
case $object instanceof InputArgument:
$this->describeInputArgument($object, $options);
break;
case $object instanceof InputOption:
$this->describeInputOption($object, $options);
break;
case $object instanceof InputDefinition:
$this->describeInputDefinition($object, $options);
break;
case $object instanceof Command:
$this->describeCommand($object, $options);
break;
case $object instanceof Application:
$this->describeApplication($object, $options);
break;
default:
throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object)));
}
}
protected function write(string $content, bool $decorated = false): void
/**
* Writes content to output.
*/
protected function write(string $content, bool $decorated = false)
{
$this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
}
@ -50,25 +70,25 @@ abstract class Descriptor implements DescriptorInterface
/**
* Describes an InputArgument instance.
*/
abstract protected function describeInputArgument(InputArgument $argument, array $options = []): void;
abstract protected function describeInputArgument(InputArgument $argument, array $options = []);
/**
* Describes an InputOption instance.
*/
abstract protected function describeInputOption(InputOption $option, array $options = []): void;
abstract protected function describeInputOption(InputOption $option, array $options = []);
/**
* Describes an InputDefinition instance.
*/
abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []): void;
abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []);
/**
* Describes a Command instance.
*/
abstract protected function describeCommand(Command $command, array $options = []): void;
abstract protected function describeCommand(Command $command, array $options = []);
/**
* Describes an Application instance.
*/
abstract protected function describeApplication(Application $application, array $options = []): void;
abstract protected function describeApplication(Application $application, array $options = []);
}

View file

@ -20,8 +20,5 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
interface DescriptorInterface
{
/**
* @return void
*/
public function describe(OutputInterface $output, object $object, array $options = []);
}

View file

@ -26,12 +26,18 @@ use Symfony\Component\Console\Input\InputOption;
*/
class JsonDescriptor extends Descriptor
{
protected function describeInputArgument(InputArgument $argument, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputArgument(InputArgument $argument, array $options = [])
{
$this->writeData($this->getInputArgumentData($argument), $options);
}
protected function describeInputOption(InputOption $option, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputOption(InputOption $option, array $options = [])
{
$this->writeData($this->getInputOptionData($option), $options);
if ($option->isNegatable()) {
@ -39,17 +45,26 @@ class JsonDescriptor extends Descriptor
}
}
protected function describeInputDefinition(InputDefinition $definition, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputDefinition(InputDefinition $definition, array $options = [])
{
$this->writeData($this->getInputDefinitionData($definition), $options);
}
protected function describeCommand(Command $command, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeCommand(Command $command, array $options = [])
{
$this->writeData($this->getCommandData($command, $options['short'] ?? false), $options);
}
protected function describeApplication(Application $application, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeApplication(Application $application, array $options = [])
{
$describedNamespace = $options['namespace'] ?? null;
$description = new ApplicationDescription($application, $describedNamespace, true);
@ -81,7 +96,7 @@ class JsonDescriptor extends Descriptor
/**
* Writes data as json.
*/
private function writeData(array $data, array $options): void
private function writeData(array $data, array $options)
{
$flags = $options['json_encoding'] ?? 0;

View file

@ -28,7 +28,10 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class MarkdownDescriptor extends Descriptor
{
public function describe(OutputInterface $output, object $object, array $options = []): void
/**
* {@inheritdoc}
*/
public function describe(OutputInterface $output, object $object, array $options = [])
{
$decorated = $output->isDecorated();
$output->setDecorated(false);
@ -38,12 +41,18 @@ class MarkdownDescriptor extends Descriptor
$output->setDecorated($decorated);
}
protected function write(string $content, bool $decorated = true): void
/**
* {@inheritdoc}
*/
protected function write(string $content, bool $decorated = true)
{
parent::write($content, $decorated);
}
protected function describeInputArgument(InputArgument $argument, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputArgument(InputArgument $argument, array $options = [])
{
$this->write(
'#### `'.($argument->getName() ?: '<none>')."`\n\n"
@ -54,7 +63,10 @@ class MarkdownDescriptor extends Descriptor
);
}
protected function describeInputOption(InputOption $option, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputOption(InputOption $option, array $options = [])
{
$name = '--'.$option->getName();
if ($option->isNegatable()) {
@ -75,13 +87,18 @@ class MarkdownDescriptor extends Descriptor
);
}
protected function describeInputDefinition(InputDefinition $definition, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputDefinition(InputDefinition $definition, array $options = [])
{
if ($showArguments = \count($definition->getArguments()) > 0) {
$this->write('### Arguments');
foreach ($definition->getArguments() as $argument) {
$this->write("\n\n");
$this->describeInputArgument($argument);
if (null !== $describeInputArgument = $this->describeInputArgument($argument)) {
$this->write($describeInputArgument);
}
}
}
@ -93,12 +110,17 @@ class MarkdownDescriptor extends Descriptor
$this->write('### Options');
foreach ($definition->getOptions() as $option) {
$this->write("\n\n");
$this->describeInputOption($option);
if (null !== $describeInputOption = $this->describeInputOption($option)) {
$this->write($describeInputOption);
}
}
}
}
protected function describeCommand(Command $command, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeCommand(Command $command, array $options = [])
{
if ($options['short'] ?? false) {
$this->write(
@ -106,7 +128,9 @@ class MarkdownDescriptor extends Descriptor
.str_repeat('-', Helper::width($command->getName()) + 2)."\n\n"
.($command->getDescription() ? $command->getDescription()."\n\n" : '')
.'### Usage'."\n\n"
.array_reduce($command->getAliases(), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n")
.array_reduce($command->getAliases(), function ($carry, $usage) {
return $carry.'* `'.$usage.'`'."\n";
})
);
return;
@ -119,7 +143,9 @@ class MarkdownDescriptor extends Descriptor
.str_repeat('-', Helper::width($command->getName()) + 2)."\n\n"
.($command->getDescription() ? $command->getDescription()."\n\n" : '')
.'### Usage'."\n\n"
.array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n")
.array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) {
return $carry.'* `'.$usage.'`'."\n";
})
);
if ($help = $command->getProcessedHelp()) {
@ -134,7 +160,10 @@ class MarkdownDescriptor extends Descriptor
}
}
protected function describeApplication(Application $application, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeApplication(Application $application, array $options = [])
{
$describedNamespace = $options['namespace'] ?? null;
$description = new ApplicationDescription($application, $describedNamespace);
@ -149,12 +178,16 @@ class MarkdownDescriptor extends Descriptor
}
$this->write("\n\n");
$this->write(implode("\n", array_map(fn ($commandName) => sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands'])));
$this->write(implode("\n", array_map(function ($commandName) use ($description) {
return sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName()));
}, $namespace['commands'])));
}
foreach ($description->getCommands() as $command) {
$this->write("\n\n");
$this->describeCommand($command, $options);
if (null !== $describeCommand = $this->describeCommand($command, $options)) {
$this->write($describeCommand);
}
}
}

View file

@ -1,272 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Descriptor;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\String\UnicodeString;
class ReStructuredTextDescriptor extends Descriptor
{
// <h1>
private string $partChar = '=';
// <h2>
private string $chapterChar = '-';
// <h3>
private string $sectionChar = '~';
// <h4>
private string $subsectionChar = '.';
// <h5>
private string $subsubsectionChar = '^';
// <h6>
private string $paragraphsChar = '"';
private array $visibleNamespaces = [];
public function describe(OutputInterface $output, object $object, array $options = []): void
{
$decorated = $output->isDecorated();
$output->setDecorated(false);
parent::describe($output, $object, $options);
$output->setDecorated($decorated);
}
/**
* Override parent method to set $decorated = true.
*/
protected function write(string $content, bool $decorated = true): void
{
parent::write($content, $decorated);
}
protected function describeInputArgument(InputArgument $argument, array $options = []): void
{
$this->write(
$argument->getName() ?: '<none>'."\n".str_repeat($this->paragraphsChar, Helper::width($argument->getName()))."\n\n"
.($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '')
.'- **Is required**: '.($argument->isRequired() ? 'yes' : 'no')."\n"
.'- **Is array**: '.($argument->isArray() ? 'yes' : 'no')."\n"
.'- **Default**: ``'.str_replace("\n", '', var_export($argument->getDefault(), true)).'``'
);
}
protected function describeInputOption(InputOption $option, array $options = []): void
{
$name = '\-\-'.$option->getName();
if ($option->isNegatable()) {
$name .= '|\-\-no-'.$option->getName();
}
if ($option->getShortcut()) {
$name .= '|-'.str_replace('|', '|-', $option->getShortcut());
}
$optionDescription = $option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n\n", $option->getDescription())."\n\n" : '';
$optionDescription = (new UnicodeString($optionDescription))->ascii();
$this->write(
$name."\n".str_repeat($this->paragraphsChar, Helper::width($name))."\n\n"
.$optionDescription
.'- **Accept value**: '.($option->acceptValue() ? 'yes' : 'no')."\n"
.'- **Is value required**: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
.'- **Is multiple**: '.($option->isArray() ? 'yes' : 'no')."\n"
.'- **Is negatable**: '.($option->isNegatable() ? 'yes' : 'no')."\n"
.'- **Default**: ``'.str_replace("\n", '', var_export($option->getDefault(), true)).'``'."\n"
);
}
protected function describeInputDefinition(InputDefinition $definition, array $options = []): void
{
if ($showArguments = ((bool) $definition->getArguments())) {
$this->write("Arguments\n".str_repeat($this->subsubsectionChar, 9))."\n\n";
foreach ($definition->getArguments() as $argument) {
$this->write("\n\n");
$this->describeInputArgument($argument);
}
}
if ($nonDefaultOptions = $this->getNonDefaultOptions($definition)) {
if ($showArguments) {
$this->write("\n\n");
}
$this->write("Options\n".str_repeat($this->subsubsectionChar, 7)."\n\n");
foreach ($nonDefaultOptions as $option) {
$this->describeInputOption($option);
$this->write("\n");
}
}
}
protected function describeCommand(Command $command, array $options = []): void
{
if ($options['short'] ?? false) {
$this->write(
'``'.$command->getName()."``\n"
.str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n"
.($command->getDescription() ? $command->getDescription()."\n\n" : '')
."Usage\n".str_repeat($this->paragraphsChar, 5)."\n\n"
.array_reduce($command->getAliases(), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n")
);
return;
}
$command->mergeApplicationDefinition(false);
foreach ($command->getAliases() as $alias) {
$this->write('.. _'.$alias.":\n\n");
}
$this->write(
$command->getName()."\n"
.str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n"
.($command->getDescription() ? $command->getDescription()."\n\n" : '')
."Usage\n".str_repeat($this->subsubsectionChar, 5)."\n\n"
.array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n")
);
if ($help = $command->getProcessedHelp()) {
$this->write("\n");
$this->write($help);
}
$definition = $command->getDefinition();
if ($definition->getOptions() || $definition->getArguments()) {
$this->write("\n\n");
$this->describeInputDefinition($definition);
}
}
protected function describeApplication(Application $application, array $options = []): void
{
$description = new ApplicationDescription($application, $options['namespace'] ?? null);
$title = $this->getApplicationTitle($application);
$this->write($title."\n".str_repeat($this->partChar, Helper::width($title)));
$this->createTableOfContents($description, $application);
$this->describeCommands($application, $options);
}
private function getApplicationTitle(Application $application): string
{
if ('UNKNOWN' === $application->getName()) {
return 'Console Tool';
}
if ('UNKNOWN' !== $application->getVersion()) {
return sprintf('%s %s', $application->getName(), $application->getVersion());
}
return $application->getName();
}
private function describeCommands($application, array $options): void
{
$title = 'Commands';
$this->write("\n\n$title\n".str_repeat($this->chapterChar, Helper::width($title))."\n\n");
foreach ($this->visibleNamespaces as $namespace) {
if ('_global' === $namespace) {
$commands = $application->all('');
$this->write('Global'."\n".str_repeat($this->sectionChar, Helper::width('Global'))."\n\n");
} else {
$commands = $application->all($namespace);
$this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n");
}
foreach ($this->removeAliasesAndHiddenCommands($commands) as $command) {
$this->describeCommand($command, $options);
$this->write("\n\n");
}
}
}
private function createTableOfContents(ApplicationDescription $description, Application $application): void
{
$this->setVisibleNamespaces($description);
$chapterTitle = 'Table of Contents';
$this->write("\n\n$chapterTitle\n".str_repeat($this->chapterChar, Helper::width($chapterTitle))."\n\n");
foreach ($this->visibleNamespaces as $namespace) {
if ('_global' === $namespace) {
$commands = $application->all('');
} else {
$commands = $application->all($namespace);
$this->write("\n\n");
$this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n");
}
$commands = $this->removeAliasesAndHiddenCommands($commands);
$this->write("\n\n");
$this->write(implode("\n", array_map(static fn ($commandName) => sprintf('- `%s`_', $commandName), array_keys($commands))));
}
}
private function getNonDefaultOptions(InputDefinition $definition): array
{
$globalOptions = [
'help',
'quiet',
'verbose',
'version',
'ansi',
'no-interaction',
];
$nonDefaultOptions = [];
foreach ($definition->getOptions() as $option) {
// Skip global options.
if (!\in_array($option->getName(), $globalOptions)) {
$nonDefaultOptions[] = $option;
}
}
return $nonDefaultOptions;
}
private function setVisibleNamespaces(ApplicationDescription $description): void
{
$commands = $description->getCommands();
foreach ($description->getNamespaces() as $namespace) {
try {
$namespaceCommands = $namespace['commands'];
foreach ($namespaceCommands as $key => $commandName) {
if (!\array_key_exists($commandName, $commands)) {
// If the array key does not exist, then this is an alias.
unset($namespaceCommands[$key]);
} elseif ($commands[$commandName]->isHidden()) {
unset($namespaceCommands[$key]);
}
}
if (!$namespaceCommands) {
// If the namespace contained only aliases or hidden commands, skip the namespace.
continue;
}
} catch (\Exception) {
}
$this->visibleNamespaces[] = $namespace['id'];
}
}
private function removeAliasesAndHiddenCommands(array $commands): array
{
foreach ($commands as $key => $command) {
if ($command->isHidden() || \in_array($key, $command->getAliases(), true)) {
unset($commands[$key]);
}
}
unset($commands['completion']);
return $commands;
}
}

View file

@ -28,7 +28,10 @@ use Symfony\Component\Console\Input\InputOption;
*/
class TextDescriptor extends Descriptor
{
protected function describeInputArgument(InputArgument $argument, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputArgument(InputArgument $argument, array $options = [])
{
if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) {
$default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
@ -48,7 +51,10 @@ class TextDescriptor extends Descriptor
), $options);
}
protected function describeInputOption(InputOption $option, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputOption(InputOption $option, array $options = [])
{
if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) {
$default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));
@ -83,7 +89,10 @@ class TextDescriptor extends Descriptor
), $options);
}
protected function describeInputDefinition(InputDefinition $definition, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputDefinition(InputDefinition $definition, array $options = [])
{
$totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
foreach ($definition->getArguments() as $argument) {
@ -122,7 +131,10 @@ class TextDescriptor extends Descriptor
}
}
protected function describeCommand(Command $command, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeCommand(Command $command, array $options = [])
{
$command->mergeApplicationDefinition(false);
@ -157,7 +169,10 @@ class TextDescriptor extends Descriptor
}
}
protected function describeApplication(Application $application, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeApplication(Application $application, array $options = [])
{
$describedNamespace = $options['namespace'] ?? null;
$description = new ApplicationDescription($application, $describedNamespace);
@ -193,7 +208,9 @@ class TextDescriptor extends Descriptor
}
// calculate max. width based on available commands per namespace
$width = $this->getColumnWidth(array_merge(...array_values(array_map(fn ($namespace) => array_intersect($namespace['commands'], array_keys($commands)), array_values($namespaces)))));
$width = $this->getColumnWidth(array_merge(...array_values(array_map(function ($namespace) use ($commands) {
return array_intersect($namespace['commands'], array_keys($commands));
}, array_values($namespaces)))));
if ($describedNamespace) {
$this->writeText(sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
@ -202,7 +219,9 @@ class TextDescriptor extends Descriptor
}
foreach ($namespaces as $namespace) {
$namespace['commands'] = array_filter($namespace['commands'], fn ($name) => isset($commands[$name]));
$namespace['commands'] = array_filter($namespace['commands'], function ($name) use ($commands) {
return isset($commands[$name]);
});
if (!$namespace['commands']) {
continue;
@ -226,7 +245,10 @@ class TextDescriptor extends Descriptor
}
}
private function writeText(string $content, array $options = []): void
/**
* {@inheritdoc}
*/
private function writeText(string $content, array $options = [])
{
$this->write(
isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
@ -251,8 +273,10 @@ class TextDescriptor extends Descriptor
/**
* Formats input option/argument default value.
*
* @param mixed $default
*/
private function formatDefaultValue(mixed $default): string
private function formatDefaultValue($default): string
{
if (\INF === $default) {
return 'INF';

View file

@ -120,27 +120,42 @@ class XmlDescriptor extends Descriptor
return $dom;
}
protected function describeInputArgument(InputArgument $argument, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputArgument(InputArgument $argument, array $options = [])
{
$this->writeDocument($this->getInputArgumentDocument($argument));
}
protected function describeInputOption(InputOption $option, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputOption(InputOption $option, array $options = [])
{
$this->writeDocument($this->getInputOptionDocument($option));
}
protected function describeInputDefinition(InputDefinition $definition, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeInputDefinition(InputDefinition $definition, array $options = [])
{
$this->writeDocument($this->getInputDefinitionDocument($definition));
}
protected function describeCommand(Command $command, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeCommand(Command $command, array $options = [])
{
$this->writeDocument($this->getCommandDocument($command, $options['short'] ?? false));
}
protected function describeApplication(Application $application, array $options = []): void
/**
* {@inheritdoc}
*/
protected function describeApplication(Application $application, array $options = [])
{
$this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? false));
}
@ -148,7 +163,7 @@ class XmlDescriptor extends Descriptor
/**
* Appends document children to parent node.
*/
private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent): void
private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent)
{
foreach ($importedParent->childNodes as $childNode) {
$parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true));
@ -158,7 +173,7 @@ class XmlDescriptor extends Descriptor
/**
* Writes DOM document.
*/
private function writeDocument(\DOMDocument $dom): void
private function writeDocument(\DOMDocument $dom)
{
$dom->formatOutput = true;
$this->write($dom->saveXML());

View file

@ -29,7 +29,7 @@ final class ConsoleCommandEvent extends ConsoleEvent
/**
* Indicates if the command should be run or skipped.
*/
private bool $commandShouldRun = true;
private $commandShouldRun = true;
/**
* Disables the command, so it won't be run.

View file

@ -22,8 +22,8 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
final class ConsoleErrorEvent extends ConsoleEvent
{
private \Throwable $error;
private int $exitCode;
private $error;
private $exitCode;
public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, ?Command $command = null)
{
@ -47,6 +47,7 @@ final class ConsoleErrorEvent extends ConsoleEvent
$this->exitCode = $exitCode;
$r = new \ReflectionProperty($this->error, 'code');
$r->setAccessible(true);
$r->setValue($this->error, $this->exitCode);
}

View file

@ -25,8 +25,8 @@ class ConsoleEvent extends Event
{
protected $command;
private InputInterface $input;
private OutputInterface $output;
private $input;
private $output;
public function __construct(?Command $command, InputInterface $input, OutputInterface $output)
{
@ -37,24 +37,30 @@ class ConsoleEvent extends Event
/**
* Gets the command that is executed.
*
* @return Command|null
*/
public function getCommand(): ?Command
public function getCommand()
{
return $this->command;
}
/**
* Gets the input instance.
*
* @return InputInterface
*/
public function getInput(): InputInterface
public function getInput()
{
return $this->input;
}
/**
* Gets the output instance.
*
* @return OutputInterface
*/
public function getOutput(): OutputInterface
public function getOutput()
{
return $this->output;
}

View file

@ -20,37 +20,16 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
final class ConsoleSignalEvent extends ConsoleEvent
{
private int $handlingSignal;
private int|false $exitCode;
private $handlingSignal;
public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal, int|false $exitCode = 0)
public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal)
{
parent::__construct($command, $input, $output);
$this->handlingSignal = $handlingSignal;
$this->exitCode = $exitCode;
}
public function getHandlingSignal(): int
{
return $this->handlingSignal;
}
public function setExitCode(int $exitCode): void
{
if ($exitCode < 0 || $exitCode > 255) {
throw new \InvalidArgumentException('Exit code must be between 0 and 255.');
}
$this->exitCode = $exitCode;
}
public function abortExit(): void
{
$this->exitCode = false;
}
public function getExitCode(): int|false
{
return $this->exitCode;
}
}

View file

@ -19,18 +19,16 @@ use Symfony\Component\Console\Output\OutputInterface;
* Allows to manipulate the exit code of a command after its execution.
*
* @author Francesco Levorato <git@flevour.net>
* @author Jules Pietri <jules@heahprod.com>
*/
final class ConsoleTerminateEvent extends ConsoleEvent
{
public function __construct(
Command $command,
InputInterface $input,
OutputInterface $output,
private int $exitCode,
private readonly ?int $interruptingSignal = null,
) {
private $exitCode;
public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $exitCode)
{
parent::__construct($command, $input, $output);
$this->setExitCode($exitCode);
}
public function setExitCode(int $exitCode): void
@ -42,9 +40,4 @@ final class ConsoleTerminateEvent extends ConsoleEvent
{
return $this->exitCode;
}
public function getInterruptingSignal(): ?int
{
return $this->interruptingSignal;
}
}

View file

@ -24,16 +24,13 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
*/
class ErrorListener implements EventSubscriberInterface
{
private ?LoggerInterface $logger;
private $logger;
public function __construct(?LoggerInterface $logger = null)
{
$this->logger = $logger;
}
/**
* @return void
*/
public function onConsoleError(ConsoleErrorEvent $event)
{
if (null === $this->logger) {
@ -51,9 +48,6 @@ class ErrorListener implements EventSubscriberInterface
$this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]);
}
/**
* @return void
*/
public function onConsoleTerminate(ConsoleTerminateEvent $event)
{
if (null === $this->logger) {
@ -75,7 +69,7 @@ class ErrorListener implements EventSubscriberInterface
$this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]);
}
public static function getSubscribedEvents(): array
public static function getSubscribedEvents()
{
return [
ConsoleEvents::ERROR => ['onConsoleError', -128],
@ -85,10 +79,10 @@ class ErrorListener implements EventSubscriberInterface
private static function getInputString(ConsoleEvent $event): ?string
{
$commandName = $event->getCommand()?->getName();
$commandName = $event->getCommand() ? $event->getCommand()->getName() : null;
$input = $event->getInput();
if ($input instanceof \Stringable) {
if (method_exists($input, '__toString')) {
if ($commandName) {
return str_replace(["'$commandName'", "\"$commandName\""], $commandName, (string) $input);
}

View file

@ -18,7 +18,7 @@ namespace Symfony\Component\Console\Exception;
*/
class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
{
private array $alternatives;
private $alternatives;
/**
* @param string $message Exception message to throw
@ -36,7 +36,7 @@ class CommandNotFoundException extends \InvalidArgumentException implements Exce
/**
* @return string[]
*/
public function getAlternatives(): array
public function getAlternatives()
{
return $this->alternatives;
}

View file

@ -1,29 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Exception;
use Symfony\Component\Console\Messenger\RunCommandContext;
/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
final class RunCommandFailedException extends RuntimeException
{
public function __construct(\Throwable|string $exception, public readonly RunCommandContext $context)
{
parent::__construct(
$exception instanceof \Throwable ? $exception->getMessage() : $exception,
$exception instanceof \Throwable ? $exception->getCode() : 0,
$exception instanceof \Throwable ? $exception : null,
);
}
}

View file

@ -16,34 +16,52 @@ namespace Symfony\Component\Console\Formatter;
*/
final class NullOutputFormatter implements OutputFormatterInterface
{
private NullOutputFormatterStyle $style;
private $style;
/**
* {@inheritdoc}
*/
public function format(?string $message): ?string
{
return null;
}
/**
* {@inheritdoc}
*/
public function getStyle(string $name): OutputFormatterStyleInterface
{
// to comply with the interface we must return a OutputFormatterStyleInterface
return $this->style ??= new NullOutputFormatterStyle();
return $this->style ?? $this->style = new NullOutputFormatterStyle();
}
/**
* {@inheritdoc}
*/
public function hasStyle(string $name): bool
{
return false;
}
/**
* {@inheritdoc}
*/
public function isDecorated(): bool
{
return false;
}
/**
* {@inheritdoc}
*/
public function setDecorated(bool $decorated): void
{
// do nothing
}
/**
* {@inheritdoc}
*/
public function setStyle(string $name, OutputFormatterStyleInterface $style): void
{
// do nothing

View file

@ -16,37 +16,49 @@ namespace Symfony\Component\Console\Formatter;
*/
final class NullOutputFormatterStyle implements OutputFormatterStyleInterface
{
/**
* {@inheritdoc}
*/
public function apply(string $text): string
{
return $text;
}
/**
* {@inheritdoc}
*/
public function setBackground(?string $color = null): void
{
if (1 > \func_num_args()) {
trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
}
// do nothing
}
/**
* {@inheritdoc}
*/
public function setForeground(?string $color = null): void
{
if (1 > \func_num_args()) {
trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
}
// do nothing
}
/**
* {@inheritdoc}
*/
public function setOption(string $option): void
{
// do nothing
}
/**
* {@inheritdoc}
*/
public function setOptions(array $options): void
{
// do nothing
}
/**
* {@inheritdoc}
*/
public function unsetOption(string $option): void
{
// do nothing

View file

@ -23,9 +23,9 @@ use function Symfony\Component\String\b;
*/
class OutputFormatter implements WrappableOutputFormatterInterface
{
private bool $decorated;
private array $styles = [];
private OutputFormatterStyleStack $styleStack;
private $decorated;
private $styles = [];
private $styleStack;
public function __clone()
{
@ -37,8 +37,10 @@ class OutputFormatter implements WrappableOutputFormatterInterface
/**
* Escapes "<" and ">" special chars in given text.
*
* @return string
*/
public static function escape(string $text): string
public static function escape(string $text)
{
$text = preg_replace('/([^\\\\]|^)([<>])/', '$1\\\\$2', $text);
@ -84,32 +86,41 @@ class OutputFormatter implements WrappableOutputFormatterInterface
}
/**
* @return void
* {@inheritdoc}
*/
public function setDecorated(bool $decorated)
{
$this->decorated = $decorated;
}
public function isDecorated(): bool
/**
* {@inheritdoc}
*/
public function isDecorated()
{
return $this->decorated;
}
/**
* @return void
* {@inheritdoc}
*/
public function setStyle(string $name, OutputFormatterStyleInterface $style)
{
$this->styles[strtolower($name)] = $style;
}
public function hasStyle(string $name): bool
/**
* {@inheritdoc}
*/
public function hasStyle(string $name)
{
return isset($this->styles[strtolower($name)]);
}
public function getStyle(string $name): OutputFormatterStyleInterface
/**
* {@inheritdoc}
*/
public function getStyle(string $name)
{
if (!$this->hasStyle($name)) {
throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name));
@ -118,13 +129,16 @@ class OutputFormatter implements WrappableOutputFormatterInterface
return $this->styles[strtolower($name)];
}
public function format(?string $message): ?string
/**
* {@inheritdoc}
*/
public function format(?string $message)
{
return $this->formatAndWrap($message, 0);
}
/**
* @return string
* {@inheritdoc}
*/
public function formatAndWrap(?string $message, int $width)
{
@ -151,7 +165,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
$offset = $pos + \strlen($text);
// opening tag?
if ($open = '/' !== $text[1]) {
if ($open = '/' != $text[1]) {
$tag = $matches[1][$i][0];
} else {
$tag = $matches[3][$i][0] ?? '';
@ -174,7 +188,10 @@ class OutputFormatter implements WrappableOutputFormatterInterface
return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']);
}
public function getStyleStack(): OutputFormatterStyleStack
/**
* @return OutputFormatterStyleStack
*/
public function getStyleStack()
{
return $this->styleStack;
}
@ -246,7 +263,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
$text = $prefix.$this->addLineBreaks($text, $width);
$text = rtrim($text, "\n").($matches[1] ?? '');
if (!$currentLineLength && '' !== $current && !str_ends_with($current, "\n")) {
if (!$currentLineLength && '' !== $current && "\n" !== substr($current, -1)) {
$text = "\n".$text;
}

View file

@ -20,37 +20,41 @@ interface OutputFormatterInterface
{
/**
* Sets the decorated flag.
*
* @return void
*/
public function setDecorated(bool $decorated);
/**
* Whether the output will decorate messages.
*
* @return bool
*/
public function isDecorated(): bool;
public function isDecorated();
/**
* Sets a new style.
*
* @return void
*/
public function setStyle(string $name, OutputFormatterStyleInterface $style);
/**
* Checks if output formatter has style with specified name.
*
* @return bool
*/
public function hasStyle(string $name): bool;
public function hasStyle(string $name);
/**
* Gets style options from style with specified name.
*
* @return OutputFormatterStyleInterface
*
* @throws \InvalidArgumentException When style isn't defined
*/
public function getStyle(string $name): OutputFormatterStyleInterface;
public function getStyle(string $name);
/**
* Formats a message according to the given styles.
*
* @return string|null
*/
public function format(?string $message): ?string;
public function format(?string $message);
}

View file

@ -20,12 +20,12 @@ use Symfony\Component\Console\Color;
*/
class OutputFormatterStyle implements OutputFormatterStyleInterface
{
private Color $color;
private string $foreground;
private string $background;
private array $options;
private ?string $href = null;
private bool $handlesHrefGracefully;
private $color;
private $foreground;
private $background;
private $options;
private $href;
private $handlesHrefGracefully;
/**
* Initializes output formatter style.
@ -39,24 +39,18 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
}
/**
* @return void
* {@inheritdoc}
*/
public function setForeground(?string $color = null)
{
if (1 > \func_num_args()) {
trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
}
$this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options);
}
/**
* @return void
* {@inheritdoc}
*/
public function setBackground(?string $color = null)
{
if (1 > \func_num_args()) {
trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__);
}
$this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options);
}
@ -66,7 +60,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
}
/**
* @return void
* {@inheritdoc}
*/
public function setOption(string $option)
{
@ -75,7 +69,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
}
/**
* @return void
* {@inheritdoc}
*/
public function unsetOption(string $option)
{
@ -88,18 +82,23 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
}
/**
* @return void
* {@inheritdoc}
*/
public function setOptions(array $options)
{
$this->color = new Color($this->foreground, $this->background, $this->options = $options);
}
public function apply(string $text): string
/**
* {@inheritdoc}
*/
public function apply(string $text)
{
$this->handlesHrefGracefully ??= 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR')
if (null === $this->handlesHrefGracefully) {
$this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR')
&& (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100)
&& !isset($_SERVER['IDEA_INITIAL_DIRECTORY']);
}
if (null !== $this->href && $this->handlesHrefGracefully) {
$text = "\033]8;;$this->href\033\\$text\033]8;;\033\\";

View file

@ -20,41 +20,33 @@ interface OutputFormatterStyleInterface
{
/**
* Sets style foreground color.
*
* @return void
*/
public function setForeground(?string $color);
public function setForeground(?string $color = null);
/**
* Sets style background color.
*
* @return void
*/
public function setBackground(?string $color);
public function setBackground(?string $color = null);
/**
* Sets some specific style option.
*
* @return void
*/
public function setOption(string $option);
/**
* Unsets some specific style option.
*
* @return void
*/
public function unsetOption(string $option);
/**
* Sets multiple style options at once.
*
* @return void
*/
public function setOptions(array $options);
/**
* Applies the style to a given text.
*
* @return string
*/
public function apply(string $text): string;
public function apply(string $text);
}

View file

@ -22,9 +22,9 @@ class OutputFormatterStyleStack implements ResetInterface
/**
* @var OutputFormatterStyleInterface[]
*/
private array $styles = [];
private $styles;
private OutputFormatterStyleInterface $emptyStyle;
private $emptyStyle;
public function __construct(?OutputFormatterStyleInterface $emptyStyle = null)
{
@ -34,8 +34,6 @@ class OutputFormatterStyleStack implements ResetInterface
/**
* Resets stack (ie. empty internal arrays).
*
* @return void
*/
public function reset()
{
@ -44,8 +42,6 @@ class OutputFormatterStyleStack implements ResetInterface
/**
* Pushes a style in the stack.
*
* @return void
*/
public function push(OutputFormatterStyleInterface $style)
{
@ -55,11 +51,13 @@ class OutputFormatterStyleStack implements ResetInterface
/**
* Pops a style from the stack.
*
* @return OutputFormatterStyleInterface
*
* @throws InvalidArgumentException When style tags incorrectly nested
*/
public function pop(?OutputFormatterStyleInterface $style = null): OutputFormatterStyleInterface
public function pop(?OutputFormatterStyleInterface $style = null)
{
if (!$this->styles) {
if (empty($this->styles)) {
return $this->emptyStyle;
}
@ -80,10 +78,12 @@ class OutputFormatterStyleStack implements ResetInterface
/**
* Computes current style with stacks top codes.
*
* @return OutputFormatterStyle
*/
public function getCurrent(): OutputFormatterStyleInterface
public function getCurrent()
{
if (!$this->styles) {
if (empty($this->styles)) {
return $this->emptyStyle;
}
@ -93,14 +93,17 @@ class OutputFormatterStyleStack implements ResetInterface
/**
* @return $this
*/
public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle): static
public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)
{
$this->emptyStyle = $emptyStyle;
return $this;
}
public function getEmptyStyle(): OutputFormatterStyleInterface
/**
* @return OutputFormatterStyleInterface
*/
public function getEmptyStyle()
{
return $this->emptyStyle;
}

View file

@ -20,8 +20,6 @@ interface WrappableOutputFormatterInterface extends OutputFormatterInterface
{
/**
* Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping).
*
* @return string
*/
public function formatAndWrap(?string $message, int $width);
}

View file

@ -21,13 +21,15 @@ namespace Symfony\Component\Console\Helper;
class DebugFormatterHelper extends Helper
{
private const COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];
private array $started = [];
private int $count = -1;
private $started = [];
private $count = -1;
/**
* Starts a debug formatting session.
*
* @return string
*/
public function start(string $id, string $message, string $prefix = 'RUN'): string
public function start(string $id, string $message, string $prefix = 'RUN')
{
$this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)];
@ -36,8 +38,10 @@ class DebugFormatterHelper extends Helper
/**
* Adds progress to a formatting session.
*
* @return string
*/
public function progress(string $id, string $buffer, bool $error = false, string $prefix = 'OUT', string $errorPrefix = 'ERR'): string
public function progress(string $id, string $buffer, bool $error = false, string $prefix = 'OUT', string $errorPrefix = 'ERR')
{
$message = '';
@ -70,8 +74,10 @@ class DebugFormatterHelper extends Helper
/**
* Stops a formatting session.
*
* @return string
*/
public function stop(string $id, string $message, bool $successful, string $prefix = 'RES'): string
public function stop(string $id, string $message, bool $successful, string $prefix = 'RES')
{
$trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';
@ -91,7 +97,10 @@ class DebugFormatterHelper extends Helper
return sprintf('<bg=%s> </>', self::COLORS[$this->started[$id]['border']]);
}
public function getName(): string
/**
* {@inheritdoc}
*/
public function getName()
{
return 'debug_formatter';
}

View file

@ -14,7 +14,6 @@ namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Descriptor\DescriptorInterface;
use Symfony\Component\Console\Descriptor\JsonDescriptor;
use Symfony\Component\Console\Descriptor\MarkdownDescriptor;
use Symfony\Component\Console\Descriptor\ReStructuredTextDescriptor;
use Symfony\Component\Console\Descriptor\TextDescriptor;
use Symfony\Component\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Exception\InvalidArgumentException;
@ -30,7 +29,7 @@ class DescriptorHelper extends Helper
/**
* @var DescriptorInterface[]
*/
private array $descriptors = [];
private $descriptors = [];
public function __construct()
{
@ -39,7 +38,6 @@ class DescriptorHelper extends Helper
->register('xml', new XmlDescriptor())
->register('json', new JsonDescriptor())
->register('md', new MarkdownDescriptor())
->register('rst', new ReStructuredTextDescriptor())
;
}
@ -50,8 +48,6 @@ class DescriptorHelper extends Helper
* * format: string, the output format name
* * raw_text: boolean, sets output type as raw
*
* @return void
*
* @throws InvalidArgumentException when the given format is not supported
*/
public function describe(OutputInterface $output, ?object $object, array $options = [])
@ -74,14 +70,17 @@ class DescriptorHelper extends Helper
*
* @return $this
*/
public function register(string $format, DescriptorInterface $descriptor): static
public function register(string $format, DescriptorInterface $descriptor)
{
$this->descriptors[$format] = $descriptor;
return $this;
}
public function getName(): string
/**
* {@inheritdoc}
*/
public function getName()
{
return 'descriptor';
}

View file

@ -21,10 +21,10 @@ use Symfony\Component\VarDumper\Dumper\CliDumper;
*/
final class Dumper
{
private OutputInterface $output;
private ?CliDumper $dumper;
private ?ClonerInterface $cloner;
private \Closure $handler;
private $output;
private $dumper;
private $cloner;
private $handler;
public function __construct(OutputInterface $output, ?CliDumper $dumper = null, ?ClonerInterface $cloner = null)
{
@ -34,23 +34,30 @@ final class Dumper
if (class_exists(CliDumper::class)) {
$this->handler = function ($var): string {
$dumper = $this->dumper ??= new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);
$dumper = $this->dumper ?? $this->dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);
$dumper->setColors($this->output->isDecorated());
return rtrim($dumper->dump(($this->cloner ??= new VarCloner())->cloneVar($var)->withRefHandles(false), true));
return rtrim($dumper->dump(($this->cloner ?? $this->cloner = new VarCloner())->cloneVar($var)->withRefHandles(false), true));
};
} else {
$this->handler = fn ($var): string => match (true) {
null === $var => 'null',
true === $var => 'true',
false === $var => 'false',
\is_string($var) => '"'.$var.'"',
default => rtrim(print_r($var, true)),
$this->handler = function ($var): string {
switch (true) {
case null === $var:
return 'null';
case true === $var:
return 'true';
case false === $var:
return 'false';
case \is_string($var):
return '"'.$var.'"';
default:
return rtrim(print_r($var, true));
}
};
}
}
public function __invoke(mixed $var): string
public function __invoke($var): string
{
return ($this->handler)($var);
}

Some files were not shown because too many files have changed in this diff Show more