diff --git a/composer.json b/composer.json index 9e96667e3..8a577fcce 100644 --- a/composer.json +++ b/composer.json @@ -50,15 +50,15 @@ "sabre/dav": "^4.7.0", "scssphp/scssphp": "^1.12", "stecman/symfony-console-completion": "^0.13.0", - "symfony/console": "^6.4.17", - "symfony/event-dispatcher": "^6.4.13", - "symfony/http-foundation": "^6.4.29", + "symfony/console": "^6.4.30", + "symfony/event-dispatcher": "^6.4.25", + "symfony/http-foundation": "^6.4.30", "symfony/mailer": "^6.4", "symfony/polyfill-intl-grapheme": "^1.31.0", "symfony/polyfill-intl-normalizer": "^1.31.0", - "symfony/process": "^6.4.15", - "symfony/routing": "^6.4.18", - "symfony/translation": "^6.4.13", + "symfony/process": "^6.4.26", + "symfony/routing": "^6.4.30", + "symfony/translation": "^6.4.30", "wapmorgan/mp3info": "^0.1.0", "web-auth/webauthn-lib": "^4.9.1" }, diff --git a/composer.lock b/composer.lock index 0a5327463..1b5783f3e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6149407f04b4be7debe07503c8defe5d", + "content-hash": "8110f8f87497db7a91ff9663391fa167", "packages": [ { "name": "aws/aws-crt-php", @@ -549,26 +549,29 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9" + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/31610dbb31faa98e6b5447b62340826f54fbc4e9", - "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=13" + }, "require-dev": { - "doctrine/coding-standard": "^9 || ^12", - "phpstan/phpstan": "1.4.10 || 2.0.3", + "doctrine/coding-standard": "^9 || ^12 || ^13", + "phpstan/phpstan": "1.4.10 || 2.1.11", "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", "psr/log": "^1 || ^2 || ^3" }, "suggest": { @@ -588,9 +591,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.4" + "source": "https://github.com/doctrine/deprecations/tree/1.1.5" }, - "time": "2024-12-07T21:18:45+00:00" + "time": "2025-04-07T20:06:18+00:00" }, { "name": "doctrine/event-manager", @@ -762,16 +765,16 @@ }, { "name": "egulias/email-validator", - "version": "4.0.3", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "b115554301161fa21467629f1e1391c1936de517" + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b115554301161fa21467629f1e1391c1936de517", - "reference": "b115554301161fa21467629f1e1391c1936de517", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", "shasum": "" }, "require": { @@ -817,7 +820,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.3" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" }, "funding": [ { @@ -825,7 +828,7 @@ "type": "github" } ], - "time": "2024-12-27T00:36:43+00:00" + "time": "2025-03-06T22:45:56+00:00" }, { "name": "fusonic/opengraph", @@ -4152,16 +4155,16 @@ }, { "name": "symfony/console", - "version": "v6.4.17", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04" + "reference": "1b2813049506b39eb3d7e64aff033fd5ca26c97e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04", + "url": "https://api.github.com/repos/symfony/console/zipball/1b2813049506b39eb3d7e64aff033fd5ca26c97e", + "reference": "1b2813049506b39eb3d7e64aff033fd5ca26c97e", "shasum": "" }, "require": { @@ -4226,7 +4229,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.17" + "source": "https://github.com/symfony/console/tree/v6.4.30" }, "funding": [ { @@ -4237,12 +4240,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-07T12:07:30+00:00" + "time": "2025-12-05T13:47:41+00:00" }, { "name": "symfony/css-selector", @@ -4445,16 +4452,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v6.4.13", + "version": "v6.4.25", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e" + "reference": "b0cf3162020603587363f0551cd3be43958611ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e", - "reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff", + "reference": "b0cf3162020603587363f0551cd3be43958611ff", "shasum": "" }, "require": { @@ -4505,7 +4512,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.13" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.25" }, "funding": [ { @@ -4516,25 +4523,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:18:03+00:00" + "time": "2025-08-13T09:41:44+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", "shasum": "" }, "require": { @@ -4548,7 +4559,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -4581,7 +4592,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" }, "funding": [ { @@ -4597,20 +4608,20 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.4.29", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "b03d11e015552a315714c127d8d1e0f9e970ec88" + "reference": "0384c62b79d96e9b22d77bc1272c9e83342ba3a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/b03d11e015552a315714c127d8d1e0f9e970ec88", - "reference": "b03d11e015552a315714c127d8d1e0f9e970ec88", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0384c62b79d96e9b22d77bc1272c9e83342ba3a6", + "reference": "0384c62b79d96e9b22d77bc1272c9e83342ba3a6", "shasum": "" }, "require": { @@ -4658,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.29" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.30" }, "funding": [ { @@ -4678,20 +4689,20 @@ "type": "tidelift" } ], - "time": "2025-11-08T16:40:12+00:00" + "time": "2025-12-01T20:07:31+00:00" }, { "name": "symfony/mailer", - "version": "v6.4.18", + "version": "v6.4.27", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "e93a6ae2767d7f7578c2b7961d9d8e27580b2b11" + "reference": "2f096718ed718996551f66e3a24e12b2ed027f95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/e93a6ae2767d7f7578c2b7961d9d8e27580b2b11", - "reference": "e93a6ae2767d7f7578c2b7961d9d8e27580b2b11", + "url": "https://api.github.com/repos/symfony/mailer/zipball/2f096718ed718996551f66e3a24e12b2ed027f95", + "reference": "2f096718ed718996551f66e3a24e12b2ed027f95", "shasum": "" }, "require": { @@ -4742,7 +4753,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.4.18" + "source": "https://github.com/symfony/mailer/tree/v6.4.27" }, "funding": [ { @@ -4753,25 +4764,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-01-24T15:27:15+00:00" + "time": "2025-10-24T13:29:09+00:00" }, { "name": "symfony/mime", - "version": "v6.4.18", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "917d77981eb1ea963608d5cda4d9c0cf72eaa68e" + "reference": "69aeef5d2692bb7c18ce133b09f67b27260b7acf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/917d77981eb1ea963608d5cda4d9c0cf72eaa68e", - "reference": "917d77981eb1ea963608d5cda4d9c0cf72eaa68e", + "url": "https://api.github.com/repos/symfony/mime/zipball/69aeef5d2692bb7c18ce133b09f67b27260b7acf", + "reference": "69aeef5d2692bb7c18ce133b09f67b27260b7acf", "shasum": "" }, "require": { @@ -4827,7 +4842,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.18" + "source": "https://github.com/symfony/mime/tree/v6.4.30" }, "funding": [ { @@ -4838,16 +4853,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-01-23T13:10:52+00:00" + "time": "2025-11-16T09:57:53+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -4906,7 +4925,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -4917,6 +4936,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -4926,16 +4949,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { @@ -4984,7 +5007,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -4995,25 +5018,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-06-27T09:58:17+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", "shasum": "" }, "require": { @@ -5067,7 +5094,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" }, "funding": [ { @@ -5078,16 +5105,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-09-10T14:38:51+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -5148,7 +5179,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -5159,6 +5190,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5168,19 +5203,20 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { + "ext-iconv": "*", "php": ">=7.2" }, "provide": { @@ -5228,7 +5264,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -5239,25 +5275,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { @@ -5308,7 +5348,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -5319,25 +5359,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-01-02T08:10:11+00:00" }, { "name": "symfony/polyfill-php83", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { @@ -5384,7 +5428,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -5395,12 +5439,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-07-08T02:45:35+00:00" }, { "name": "symfony/polyfill-uuid", @@ -5483,16 +5531,16 @@ }, { "name": "symfony/process", - "version": "v6.4.15", + "version": "v6.4.26", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3cb242f059c14ae08591c5c4087d1fe443564392" + "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3cb242f059c14ae08591c5c4087d1fe443564392", - "reference": "3cb242f059c14ae08591c5c4087d1fe443564392", + "url": "https://api.github.com/repos/symfony/process/zipball/48bad913268c8cafabbf7034b39c8bb24fbc5ab8", + "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8", "shasum": "" }, "require": { @@ -5524,7 +5572,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.15" + "source": "https://github.com/symfony/process/tree/v6.4.26" }, "funding": [ { @@ -5535,25 +5583,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-06T14:19:14+00:00" + "time": "2025-09-11T09:57:09+00:00" }, { "name": "symfony/routing", - "version": "v6.4.18", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "e9bfc94953019089acdfb9be51c1b9142c4afa68" + "reference": "ea50a13c2711eebcbb66b38ef6382e62e3262859" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/e9bfc94953019089acdfb9be51c1b9142c4afa68", - "reference": "e9bfc94953019089acdfb9be51c1b9142c4afa68", + "url": "https://api.github.com/repos/symfony/routing/zipball/ea50a13c2711eebcbb66b38ef6382e62e3262859", + "reference": "ea50a13c2711eebcbb66b38ef6382e62e3262859", "shasum": "" }, "require": { @@ -5607,7 +5659,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.18" + "source": "https://github.com/symfony/routing/tree/v6.4.30" }, "funding": [ { @@ -5618,25 +5670,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-01-09T08:51:02+00:00" + "time": "2025-11-22T09:51:35+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.5.1", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -5654,7 +5710,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -5690,7 +5746,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -5701,25 +5757,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "symfony/string", - "version": "v6.4.15", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f" + "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", - "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", + "url": "https://api.github.com/repos/symfony/string/zipball/50590a057841fa6bf69d12eceffce3465b9e32cb", + "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb", "shasum": "" }, "require": { @@ -5733,7 +5793,6 @@ "symfony/translation-contracts": "<2.5" }, "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", @@ -5776,7 +5835,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.15" + "source": "https://github.com/symfony/string/tree/v6.4.30" }, "funding": [ { @@ -5787,25 +5846,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-13T13:31:12+00:00" + "time": "2025-11-21T18:03:05+00:00" }, { "name": "symfony/translation", - "version": "v6.4.13", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66" + "reference": "d1fdeefd0707d15eb150c04e8837bf0b15ebea39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/bee9bfabfa8b4045a66bf82520e492cddbaffa66", - "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66", + "url": "https://api.github.com/repos/symfony/translation/zipball/d1fdeefd0707d15eb150c04e8837bf0b15ebea39", + "reference": "d1fdeefd0707d15eb150c04e8837bf0b15ebea39", "shasum": "" }, "require": { @@ -5871,7 +5934,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.4.13" + "source": "https://github.com/symfony/translation/tree/v6.4.30" }, "funding": [ { @@ -5882,25 +5945,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-27T18:14:25+00:00" + "time": "2025-11-24T13:57:00+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.5.1", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + "reference": "65a8bc82080447fae78373aa10f8d13b38338977" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", + "reference": "65a8bc82080447fae78373aa10f8d13b38338977", "shasum": "" }, "require": { @@ -5913,7 +5980,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -5949,7 +6016,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1" }, "funding": [ { @@ -5960,12 +6027,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/uid", diff --git a/composer/autoload_classmap.php b/composer/autoload_classmap.php index 88930c59d..feeba4ee7 100644 --- a/composer/autoload_classmap.php +++ b/composer/autoload_classmap.php @@ -3068,6 +3068,7 @@ 'Symfony\\Component\\Console\\Helper\\TableRows' => $vendorDir . '/symfony/console/Helper/TableRows.php', 'Symfony\\Component\\Console\\Helper\\TableSeparator' => $vendorDir . '/symfony/console/Helper/TableSeparator.php', 'Symfony\\Component\\Console\\Helper\\TableStyle' => $vendorDir . '/symfony/console/Helper/TableStyle.php', + 'Symfony\\Component\\Console\\Helper\\TerminalInputHelper' => $vendorDir . '/symfony/console/Helper/TerminalInputHelper.php', 'Symfony\\Component\\Console\\Input\\ArgvInput' => $vendorDir . '/symfony/console/Input/ArgvInput.php', 'Symfony\\Component\\Console\\Input\\ArrayInput' => $vendorDir . '/symfony/console/Input/ArrayInput.php', 'Symfony\\Component\\Console\\Input\\Input' => $vendorDir . '/symfony/console/Input/Input.php', diff --git a/composer/autoload_static.php b/composer/autoload_static.php index 1f8e12488..b18d2dd18 100644 --- a/composer/autoload_static.php +++ b/composer/autoload_static.php @@ -3596,6 +3596,7 @@ class ComposerStaticInit2f23f73bc0cc116b4b1eee1521aa8652 'Symfony\\Component\\Console\\Helper\\TableRows' => __DIR__ . '/..' . '/symfony/console/Helper/TableRows.php', 'Symfony\\Component\\Console\\Helper\\TableSeparator' => __DIR__ . '/..' . '/symfony/console/Helper/TableSeparator.php', 'Symfony\\Component\\Console\\Helper\\TableStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableStyle.php', + 'Symfony\\Component\\Console\\Helper\\TerminalInputHelper' => __DIR__ . '/..' . '/symfony/console/Helper/TerminalInputHelper.php', 'Symfony\\Component\\Console\\Input\\ArgvInput' => __DIR__ . '/..' . '/symfony/console/Input/ArgvInput.php', 'Symfony\\Component\\Console\\Input\\ArrayInput' => __DIR__ . '/..' . '/symfony/console/Input/ArrayInput.php', 'Symfony\\Component\\Console\\Input\\Input' => __DIR__ . '/..' . '/symfony/console/Input/Input.php', diff --git a/composer/installed.json b/composer/installed.json index aa433c228..50a6a3225 100644 --- a/composer/installed.json +++ b/composer/installed.json @@ -567,33 +567,36 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.4", - "version_normalized": "1.1.4.0", + "version": "1.1.5", + "version_normalized": "1.1.5.0", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9" + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/31610dbb31faa98e6b5447b62340826f54fbc4e9", - "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=13" + }, "require-dev": { - "doctrine/coding-standard": "^9 || ^12", - "phpstan/phpstan": "1.4.10 || 2.0.3", + "doctrine/coding-standard": "^9 || ^12 || ^13", + "phpstan/phpstan": "1.4.10 || 2.1.11", "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", "psr/log": "^1 || ^2 || ^3" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" }, - "time": "2024-12-07T21:18:45+00:00", + "time": "2025-04-07T20:06:18+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -609,7 +612,7 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.4" + "source": "https://github.com/doctrine/deprecations/tree/1.1.5" }, "install-path": "../doctrine/deprecations" }, @@ -789,17 +792,17 @@ }, { "name": "egulias/email-validator", - "version": "4.0.3", - "version_normalized": "4.0.3.0", + "version": "4.0.4", + "version_normalized": "4.0.4.0", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "b115554301161fa21467629f1e1391c1936de517" + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b115554301161fa21467629f1e1391c1936de517", - "reference": "b115554301161fa21467629f1e1391c1936de517", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", "shasum": "" }, "require": { @@ -814,7 +817,7 @@ "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" }, - "time": "2024-12-27T00:36:43+00:00", + "time": "2025-03-06T22:45:56+00:00", "type": "library", "extra": { "branch-alias": { @@ -847,7 +850,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.3" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" }, "funding": [ { @@ -4332,17 +4335,17 @@ }, { "name": "symfony/console", - "version": "v6.4.17", - "version_normalized": "6.4.17.0", + "version": "v6.4.30", + "version_normalized": "6.4.30.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04" + "reference": "1b2813049506b39eb3d7e64aff033fd5ca26c97e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04", + "url": "https://api.github.com/repos/symfony/console/zipball/1b2813049506b39eb3d7e64aff033fd5ca26c97e", + "reference": "1b2813049506b39eb3d7e64aff033fd5ca26c97e", "shasum": "" }, "require": { @@ -4375,7 +4378,7 @@ "symfony/stopwatch": "^5.4|^6.0|^7.0", "symfony/var-dumper": "^5.4|^6.0|^7.0" }, - "time": "2024-12-07T12:07:30+00:00", + "time": "2025-12-05T13:47:41+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -4409,7 +4412,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.17" + "source": "https://github.com/symfony/console/tree/v6.4.30" }, "funding": [ { @@ -4420,6 +4423,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -4637,17 +4644,17 @@ }, { "name": "symfony/event-dispatcher", - "version": "v6.4.13", - "version_normalized": "6.4.13.0", + "version": "v6.4.25", + "version_normalized": "6.4.25.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e" + "reference": "b0cf3162020603587363f0551cd3be43958611ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e", - "reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff", + "reference": "b0cf3162020603587363f0551cd3be43958611ff", "shasum": "" }, "require": { @@ -4672,7 +4679,7 @@ "symfony/service-contracts": "^2.5|^3", "symfony/stopwatch": "^5.4|^6.0|^7.0" }, - "time": "2024-09-25T14:18:03+00:00", + "time": "2025-08-13T09:41:44+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -4700,7 +4707,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.13" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.25" }, "funding": [ { @@ -4711,6 +4718,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -4720,24 +4731,24 @@ }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.5.1", - "version_normalized": "3.5.1.0", + "version": "v3.6.0", + "version_normalized": "3.6.0.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", - "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", "shasum": "" }, "require": { "php": ">=8.1", "psr/event-dispatcher": "^1" }, - "time": "2024-09-25T14:20:29+00:00", + "time": "2024-09-25T14:21:43+00:00", "type": "library", "extra": { "thanks": { @@ -4745,7 +4756,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "installation-source": "dist", @@ -4779,7 +4790,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" }, "funding": [ { @@ -4799,17 +4810,17 @@ }, { "name": "symfony/http-foundation", - "version": "v6.4.29", - "version_normalized": "6.4.29.0", + "version": "v6.4.30", + "version_normalized": "6.4.30.0", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "b03d11e015552a315714c127d8d1e0f9e970ec88" + "reference": "0384c62b79d96e9b22d77bc1272c9e83342ba3a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/b03d11e015552a315714c127d8d1e0f9e970ec88", - "reference": "b03d11e015552a315714c127d8d1e0f9e970ec88", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0384c62b79d96e9b22d77bc1272c9e83342ba3a6", + "reference": "0384c62b79d96e9b22d77bc1272c9e83342ba3a6", "shasum": "" }, "require": { @@ -4831,7 +4842,7 @@ "symfony/mime": "^5.4|^6.0|^7.0", "symfony/rate-limiter": "^5.4|^6.0|^7.0" }, - "time": "2025-11-08T16:40:12+00:00", + "time": "2025-12-01T20:07:31+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -4859,7 +4870,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.29" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.30" }, "funding": [ { @@ -4883,17 +4894,17 @@ }, { "name": "symfony/mailer", - "version": "v6.4.18", - "version_normalized": "6.4.18.0", + "version": "v6.4.27", + "version_normalized": "6.4.27.0", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "e93a6ae2767d7f7578c2b7961d9d8e27580b2b11" + "reference": "2f096718ed718996551f66e3a24e12b2ed027f95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/e93a6ae2767d7f7578c2b7961d9d8e27580b2b11", - "reference": "e93a6ae2767d7f7578c2b7961d9d8e27580b2b11", + "url": "https://api.github.com/repos/symfony/mailer/zipball/2f096718ed718996551f66e3a24e12b2ed027f95", + "reference": "2f096718ed718996551f66e3a24e12b2ed027f95", "shasum": "" }, "require": { @@ -4918,7 +4929,7 @@ "symfony/messenger": "^6.2|^7.0", "symfony/twig-bridge": "^6.2|^7.0" }, - "time": "2025-01-24T15:27:15+00:00", + "time": "2025-10-24T13:29:09+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -4946,7 +4957,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.4.18" + "source": "https://github.com/symfony/mailer/tree/v6.4.27" }, "funding": [ { @@ -4957,6 +4968,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -4966,17 +4981,17 @@ }, { "name": "symfony/mime", - "version": "v6.4.18", - "version_normalized": "6.4.18.0", + "version": "v6.4.30", + "version_normalized": "6.4.30.0", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "917d77981eb1ea963608d5cda4d9c0cf72eaa68e" + "reference": "69aeef5d2692bb7c18ce133b09f67b27260b7acf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/917d77981eb1ea963608d5cda4d9c0cf72eaa68e", - "reference": "917d77981eb1ea963608d5cda4d9c0cf72eaa68e", + "url": "https://api.github.com/repos/symfony/mime/zipball/69aeef5d2692bb7c18ce133b09f67b27260b7acf", + "reference": "69aeef5d2692bb7c18ce133b09f67b27260b7acf", "shasum": "" }, "require": { @@ -5002,7 +5017,7 @@ "symfony/property-info": "^5.4|^6.0|^7.0", "symfony/serializer": "^6.4.3|^7.0.3" }, - "time": "2025-01-23T13:10:52+00:00", + "time": "2025-11-16T09:57:53+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -5034,7 +5049,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.18" + "source": "https://github.com/symfony/mime/tree/v6.4.30" }, "funding": [ { @@ -5045,6 +5060,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5054,8 +5073,8 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -5116,7 +5135,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -5127,6 +5146,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5136,17 +5159,17 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { @@ -5155,7 +5178,7 @@ "suggest": { "ext-intl": "For best performance" }, - "time": "2024-09-09T11:45:10+00:00", + "time": "2025-06-27T09:58:17+00:00", "type": "library", "extra": { "thanks": { @@ -5197,7 +5220,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -5208,6 +5231,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5217,17 +5244,17 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", "shasum": "" }, "require": { @@ -5237,7 +5264,7 @@ "suggest": { "ext-intl": "For best performance" }, - "time": "2024-09-09T11:45:10+00:00", + "time": "2024-09-10T14:38:51+00:00", "type": "library", "extra": { "thanks": { @@ -5283,7 +5310,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" }, "funding": [ { @@ -5294,6 +5321,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5303,8 +5334,8 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -5367,7 +5398,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -5378,6 +5409,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5387,20 +5422,21 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { + "ext-iconv": "*", "php": ">=7.2" }, "provide": { @@ -5409,7 +5445,7 @@ "suggest": { "ext-mbstring": "For best performance" }, - "time": "2024-09-09T11:45:10+00:00", + "time": "2024-12-23T08:48:59+00:00", "type": "library", "extra": { "thanks": { @@ -5450,7 +5486,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -5461,6 +5497,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5470,23 +5510,23 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { "php": ">=7.2" }, - "time": "2024-09-09T11:45:10+00:00", + "time": "2025-01-02T08:10:11+00:00", "type": "library", "extra": { "thanks": { @@ -5533,7 +5573,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -5544,6 +5584,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5553,23 +5597,23 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { "php": ">=7.2" }, - "time": "2024-09-09T11:45:10+00:00", + "time": "2025-07-08T02:45:35+00:00", "type": "library", "extra": { "thanks": { @@ -5612,7 +5656,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -5623,6 +5667,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5714,23 +5762,23 @@ }, { "name": "symfony/process", - "version": "v6.4.15", - "version_normalized": "6.4.15.0", + "version": "v6.4.26", + "version_normalized": "6.4.26.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3cb242f059c14ae08591c5c4087d1fe443564392" + "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3cb242f059c14ae08591c5c4087d1fe443564392", - "reference": "3cb242f059c14ae08591c5c4087d1fe443564392", + "url": "https://api.github.com/repos/symfony/process/zipball/48bad913268c8cafabbf7034b39c8bb24fbc5ab8", + "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8", "shasum": "" }, "require": { "php": ">=8.1" }, - "time": "2024-11-06T14:19:14+00:00", + "time": "2025-09-11T09:57:09+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -5758,7 +5806,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.15" + "source": "https://github.com/symfony/process/tree/v6.4.26" }, "funding": [ { @@ -5769,6 +5817,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5778,17 +5830,17 @@ }, { "name": "symfony/routing", - "version": "v6.4.18", - "version_normalized": "6.4.18.0", + "version": "v6.4.30", + "version_normalized": "6.4.30.0", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "e9bfc94953019089acdfb9be51c1b9142c4afa68" + "reference": "ea50a13c2711eebcbb66b38ef6382e62e3262859" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/e9bfc94953019089acdfb9be51c1b9142c4afa68", - "reference": "e9bfc94953019089acdfb9be51c1b9142c4afa68", + "url": "https://api.github.com/repos/symfony/routing/zipball/ea50a13c2711eebcbb66b38ef6382e62e3262859", + "reference": "ea50a13c2711eebcbb66b38ef6382e62e3262859", "shasum": "" }, "require": { @@ -5810,7 +5862,7 @@ "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/yaml": "^5.4|^6.0|^7.0" }, - "time": "2025-01-09T08:51:02+00:00", + "time": "2025-11-22T09:51:35+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -5844,7 +5896,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.18" + "source": "https://github.com/symfony/routing/tree/v6.4.30" }, "funding": [ { @@ -5855,6 +5907,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5864,17 +5920,17 @@ }, { "name": "symfony/service-contracts", - "version": "v3.5.1", - "version_normalized": "3.5.1.0", + "version": "v3.6.1", + "version_normalized": "3.6.1.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -5885,7 +5941,7 @@ "conflict": { "ext-psr": "<1.1|>=2" }, - "time": "2024-09-25T14:20:29+00:00", + "time": "2025-07-15T11:30:57+00:00", "type": "library", "extra": { "thanks": { @@ -5893,7 +5949,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "installation-source": "dist", @@ -5930,7 +5986,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -5941,6 +5997,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5950,17 +6010,17 @@ }, { "name": "symfony/string", - "version": "v6.4.15", - "version_normalized": "6.4.15.0", + "version": "v6.4.30", + "version_normalized": "6.4.30.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f" + "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", - "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", + "url": "https://api.github.com/repos/symfony/string/zipball/50590a057841fa6bf69d12eceffce3465b9e32cb", + "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb", "shasum": "" }, "require": { @@ -5974,13 +6034,12 @@ "symfony/translation-contracts": "<2.5" }, "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" }, - "time": "2024-11-13T13:31:12+00:00", + "time": "2025-11-21T18:03:05+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -6019,7 +6078,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.15" + "source": "https://github.com/symfony/string/tree/v6.4.30" }, "funding": [ { @@ -6030,6 +6089,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -6039,17 +6102,17 @@ }, { "name": "symfony/translation", - "version": "v6.4.13", - "version_normalized": "6.4.13.0", + "version": "v6.4.30", + "version_normalized": "6.4.30.0", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66" + "reference": "d1fdeefd0707d15eb150c04e8837bf0b15ebea39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/bee9bfabfa8b4045a66bf82520e492cddbaffa66", - "reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66", + "url": "https://api.github.com/repos/symfony/translation/zipball/d1fdeefd0707d15eb150c04e8837bf0b15ebea39", + "reference": "d1fdeefd0707d15eb150c04e8837bf0b15ebea39", "shasum": "" }, "require": { @@ -6086,7 +6149,7 @@ "symfony/service-contracts": "^2.5|^3", "symfony/yaml": "^5.4|^6.0|^7.0" }, - "time": "2024-09-27T18:14:25+00:00", + "time": "2025-11-24T13:57:00+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -6117,7 +6180,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.4.13" + "source": "https://github.com/symfony/translation/tree/v6.4.30" }, "funding": [ { @@ -6128,6 +6191,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -6137,23 +6204,23 @@ }, { "name": "symfony/translation-contracts", - "version": "v3.5.1", - "version_normalized": "3.5.1.0", + "version": "v3.6.1", + "version_normalized": "3.6.1.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + "reference": "65a8bc82080447fae78373aa10f8d13b38338977" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", - "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", + "reference": "65a8bc82080447fae78373aa10f8d13b38338977", "shasum": "" }, "require": { "php": ">=8.1" }, - "time": "2024-09-25T14:20:29+00:00", + "time": "2025-07-15T13:41:35+00:00", "type": "library", "extra": { "thanks": { @@ -6161,7 +6228,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "installation-source": "dist", @@ -6198,7 +6265,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1" }, "funding": [ { @@ -6209,6 +6276,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" diff --git a/composer/installed.php b/composer/installed.php index e0b145055..89266720e 100644 --- a/composer/installed.php +++ b/composer/installed.php @@ -83,9 +83,9 @@ 'dev_requirement' => false, ), 'doctrine/deprecations' => array( - 'pretty_version' => '1.1.4', - 'version' => '1.1.4.0', - 'reference' => '31610dbb31faa98e6b5447b62340826f54fbc4e9', + 'pretty_version' => '1.1.5', + 'version' => '1.1.5.0', + 'reference' => '459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/deprecations', 'aliases' => array(), @@ -110,9 +110,9 @@ 'dev_requirement' => false, ), 'egulias/email-validator' => array( - 'pretty_version' => '4.0.3', - 'version' => '4.0.3.0', - 'reference' => 'b115554301161fa21467629f1e1391c1936de517', + 'pretty_version' => '4.0.4', + 'version' => '4.0.4.0', + 'reference' => 'd42c8731f0624ad6bdc8d3e5e9a4524f68801cfa', 'type' => 'library', 'install_path' => __DIR__ . '/../egulias/email-validator', 'aliases' => array(), @@ -644,9 +644,9 @@ 'dev_requirement' => false, ), 'symfony/console' => array( - 'pretty_version' => 'v6.4.17', - 'version' => '6.4.17.0', - 'reference' => '799445db3f15768ecc382ac5699e6da0520a0a04', + 'pretty_version' => 'v6.4.30', + 'version' => '6.4.30.0', + 'reference' => '1b2813049506b39eb3d7e64aff033fd5ca26c97e', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), @@ -680,18 +680,18 @@ 'dev_requirement' => false, ), 'symfony/event-dispatcher' => array( - 'pretty_version' => 'v6.4.13', - 'version' => '6.4.13.0', - 'reference' => '0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e', + 'pretty_version' => 'v6.4.25', + 'version' => '6.4.25.0', + 'reference' => 'b0cf3162020603587363f0551cd3be43958611ff', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/event-dispatcher', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/event-dispatcher-contracts' => array( - 'pretty_version' => 'v3.5.1', - 'version' => '3.5.1.0', - 'reference' => '7642f5e970b672283b7823222ae8ef8bbc160b9f', + 'pretty_version' => 'v3.6.0', + 'version' => '3.6.0.0', + 'reference' => '59eb412e93815df44f05f342958efa9f46b1e586', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts', 'aliases' => array(), @@ -704,35 +704,35 @@ ), ), 'symfony/http-foundation' => array( - 'pretty_version' => 'v6.4.29', - 'version' => '6.4.29.0', - 'reference' => 'b03d11e015552a315714c127d8d1e0f9e970ec88', + 'pretty_version' => 'v6.4.30', + 'version' => '6.4.30.0', + 'reference' => '0384c62b79d96e9b22d77bc1272c9e83342ba3a6', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-foundation', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/mailer' => array( - 'pretty_version' => 'v6.4.18', - 'version' => '6.4.18.0', - 'reference' => 'e93a6ae2767d7f7578c2b7961d9d8e27580b2b11', + 'pretty_version' => 'v6.4.27', + 'version' => '6.4.27.0', + 'reference' => '2f096718ed718996551f66e3a24e12b2ed027f95', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/mailer', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/mime' => array( - 'pretty_version' => 'v6.4.18', - 'version' => '6.4.18.0', - 'reference' => '917d77981eb1ea963608d5cda4d9c0cf72eaa68e', + 'pretty_version' => 'v6.4.30', + 'version' => '6.4.30.0', + 'reference' => '69aeef5d2692bb7c18ce133b09f67b27260b7acf', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/mime', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-ctype' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', 'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', @@ -740,26 +740,26 @@ 'dev_requirement' => false, ), 'symfony/polyfill-intl-grapheme' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', - 'reference' => 'b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '380872130d3a5dd3ace2f4010d95125fde5d5c70', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-intl-idn' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', - 'reference' => 'c36586dcf89a12315939e00ec9b4474adcb1d773', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '9614ac4d8061dc257ecc64cba1b140873dce8ad3', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-intl-normalizer' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', 'reference' => '3833d7255cc303546435cb650316bff708a1c75c', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', @@ -767,27 +767,27 @@ 'dev_requirement' => false, ), 'symfony/polyfill-mbstring' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', - 'reference' => '85181ba99b2345b0ef10ce42ecac37612d9fd341', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-php80' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', - 'reference' => '60328e362d4c2c802a54fcbf04f9d3fb892b4cf8', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '0cc9dd0f17f61d8131e7df6b84bd344899fe2608', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-php83' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', - 'reference' => '2fb86d65e2d424369ad2905e83b236a8805ba491', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '17f6f9a6b1735c0f163024d959f700cfbc5155e5', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php83', 'aliases' => array(), @@ -803,54 +803,54 @@ 'dev_requirement' => false, ), 'symfony/process' => array( - 'pretty_version' => 'v6.4.15', - 'version' => '6.4.15.0', - 'reference' => '3cb242f059c14ae08591c5c4087d1fe443564392', + 'pretty_version' => 'v6.4.26', + 'version' => '6.4.26.0', + 'reference' => '48bad913268c8cafabbf7034b39c8bb24fbc5ab8', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/process', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/routing' => array( - 'pretty_version' => 'v6.4.18', - 'version' => '6.4.18.0', - 'reference' => 'e9bfc94953019089acdfb9be51c1b9142c4afa68', + 'pretty_version' => 'v6.4.30', + 'version' => '6.4.30.0', + 'reference' => 'ea50a13c2711eebcbb66b38ef6382e62e3262859', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/routing', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/service-contracts' => array( - 'pretty_version' => 'v3.5.1', - 'version' => '3.5.1.0', - 'reference' => 'e53260aabf78fb3d63f8d79d69ece59f80d5eda0', + 'pretty_version' => 'v3.6.1', + 'version' => '3.6.1.0', + 'reference' => '45112560a3ba2d715666a509a0bc9521d10b6c43', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/service-contracts', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/string' => array( - 'pretty_version' => 'v6.4.15', - 'version' => '6.4.15.0', - 'reference' => '73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f', + 'pretty_version' => 'v6.4.30', + 'version' => '6.4.30.0', + 'reference' => '50590a057841fa6bf69d12eceffce3465b9e32cb', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/string', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/translation' => array( - 'pretty_version' => 'v6.4.13', - 'version' => '6.4.13.0', - 'reference' => 'bee9bfabfa8b4045a66bf82520e492cddbaffa66', + 'pretty_version' => 'v6.4.30', + 'version' => '6.4.30.0', + 'reference' => 'd1fdeefd0707d15eb150c04e8837bf0b15ebea39', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/translation', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/translation-contracts' => array( - 'pretty_version' => 'v3.5.1', - 'version' => '3.5.1.0', - 'reference' => '4667ff3bd513750603a09c8dedbea942487fb07c', + 'pretty_version' => 'v3.6.1', + 'version' => '3.6.1.0', + 'reference' => '65a8bc82080447fae78373aa10f8d13b38338977', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/translation-contracts', 'aliases' => array(), diff --git a/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php b/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php index 8b322b755..a6c7ad6fb 100644 --- a/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php +++ b/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php @@ -5,6 +5,8 @@ namespace Doctrine\Deprecations\PHPUnit; use Doctrine\Deprecations\Deprecation; +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\Before; use function sprintf; @@ -27,12 +29,14 @@ public function expectNoDeprecationWithIdentifier(string $identifier): void } /** @before */ + #[Before] public function enableDeprecationTracking(): void { Deprecation::enableTrackingDeprecations(); } /** @after */ + #[After] public function verifyDeprecationsAreTriggered(): void { foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) { diff --git a/egulias/email-validator/src/Parser/LocalPart.php b/egulias/email-validator/src/Parser/LocalPart.php index 5ed29d606..10f956546 100644 --- a/egulias/email-validator/src/Parser/LocalPart.php +++ b/egulias/email-validator/src/Parser/LocalPart.php @@ -34,6 +34,7 @@ class LocalPart extends PartParser public function parse(): Result { + $this->lexer->clearRecorded(); $this->lexer->startRecording(); while (!$this->lexer->current->isA(EmailLexer::S_AT) && !$this->lexer->current->isA(EmailLexer::S_EMPTY)) { diff --git a/egulias/email-validator/src/Result/Reason/NoDNSRecord.php b/egulias/email-validator/src/Result/Reason/NoDNSRecord.php index 2c966c280..0ea056dfc 100644 --- a/egulias/email-validator/src/Result/Reason/NoDNSRecord.php +++ b/egulias/email-validator/src/Result/Reason/NoDNSRecord.php @@ -11,6 +11,6 @@ public function code() : int public function description() : string { - return 'No MX or A DSN record was found for this email'; + return 'No MX or A DNS record was found for this email'; } } diff --git a/egulias/email-validator/src/Result/Result.php b/egulias/email-validator/src/Result/Result.php index fd13e6c68..0e50fc51c 100644 --- a/egulias/email-validator/src/Result/Result.php +++ b/egulias/email-validator/src/Result/Result.php @@ -6,22 +6,26 @@ interface Result { /** * Is validation result valid? + * */ - public function isValid() : bool; + public function isValid(): bool; /** * Is validation result invalid? * Usually the inverse of isValid() + * */ - public function isInvalid() : bool; + public function isInvalid(): bool; /** * Short description of the result, human readable. + * */ - public function description() : string; + public function description(): string; /** * Code for user land to act upon. + * */ - public function code() : int; + public function code(): int; } diff --git a/symfony/console/Application.php b/symfony/console/Application.php index dc710e8cc..f61761df5 100644 --- a/symfony/console/Application.php +++ b/symfony/console/Application.php @@ -270,9 +270,9 @@ public function doRun(InputInterface $input, OutputInterface $output) $style = new SymfonyStyle($input, $output); $output->writeln(''); - $formattedBlock = (new FormatterHelper())->formatBlock(sprintf('Command "%s" is not defined.', $name), 'error', true); + $formattedBlock = (new FormatterHelper())->formatBlock(\sprintf('Command "%s" is not defined.', $name), 'error', true); $output->writeln($formattedBlock); - if (!$style->confirm(sprintf('Do you want to run "%s" instead? ', $alternative), false)) { + if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), false)) { if (null !== $this->dispatcher) { $event = new ConsoleErrorEvent($input, $output, $e); $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); @@ -403,6 +403,15 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti return; } + + if ( + CompletionInput::TYPE_OPTION_VALUE === $input->getCompletionType() + && ($definition = $this->getDefinition())->hasOption($input->getCompletionName()) + ) { + $definition->getOption($input->getCompletionName())->complete($input, $suggestions); + + return; + } } /** @@ -502,7 +511,7 @@ public function getLongVersion() { if ('UNKNOWN' !== $this->getName()) { if ('UNKNOWN' !== $this->getVersion()) { - return sprintf('%s %s', $this->getName(), $this->getVersion()); + return \sprintf('%s %s', $this->getName(), $this->getVersion()); } return $this->getName(); @@ -561,7 +570,7 @@ public function add(Command $command) } if (!$command->getName()) { - throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command))); + throw new LogicException(\sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command))); } $this->commands[$command->getName()] = $command; @@ -585,12 +594,12 @@ public function get(string $name) $this->init(); if (!$this->has($name)) { - throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); } // When the command has a different name than the one used at the command loader level if (!isset($this->commands[$name])) { - throw new CommandNotFoundException(sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); + throw new CommandNotFoundException(\sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); } $command = $this->commands[$name]; @@ -654,7 +663,7 @@ public function findNamespace(string $namespace): string $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces); if (empty($namespaces)) { - $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); + $message = \sprintf('There are no commands defined in the "%s" namespace.', $namespace); if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { if (1 == \count($alternatives)) { @@ -671,7 +680,7 @@ public function findNamespace(string $namespace): string $exact = \in_array($namespace, $namespaces, true); if (\count($namespaces) > 1 && !$exact) { - throw new NamespaceNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); + throw new NamespaceNotFoundException(\sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); } return $exact ? $namespace : reset($namespaces); @@ -720,18 +729,17 @@ public function find(string $name) $this->findNamespace(substr($name, 0, $pos)); } - $message = sprintf('Command "%s" is not defined.', $name); + $message = \sprintf('Command "%s" is not defined.', $name); if ($alternatives = $this->findAlternatives($name, $allCommands)) { - // remove hidden commands - $alternatives = array_filter($alternatives, fn ($name) => !$this->get($name)->isHidden()); + $wantHelps = $this->wantHelps; + $this->wantHelps = false; - if (1 == \count($alternatives)) { - $message .= "\n\nDid you mean this?\n "; - } else { - $message .= "\n\nDid you mean one of these?\n "; + // remove hidden commands + if ($alternatives = array_filter($alternatives, fn ($name) => !$this->get($name)->isHidden())) { + $message .= \sprintf("\n\nDid you mean %s?\n %s", 1 === \count($alternatives) ? 'this' : 'one of these', implode("\n ", $alternatives)); } - $message .= implode("\n ", $alternatives); + $this->wantHelps = $wantHelps; } throw new CommandNotFoundException($message, array_values($alternatives)); @@ -775,14 +783,14 @@ public function find(string $name) if (\count($commands) > 1) { $suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs)); - throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands)); + throw new CommandNotFoundException(\sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands)); } } - $command = $this->get(reset($commands)); + $command = $commands ? $this->get(reset($commands)) : null; - if ($command->isHidden()) { - throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); + if (!$command || $command->isHidden()) { + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); } return $command; @@ -857,7 +865,7 @@ public function renderThrowable(\Throwable $e, OutputInterface $output): void $this->doRenderThrowable($e, $output); if (null !== $this->runningCommand) { - $output->writeln(sprintf('%s', OutputFormatter::escape(sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); + $output->writeln(\sprintf('%s', OutputFormatter::escape(\sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); $output->writeln('', OutputInterface::VERBOSITY_QUIET); } } @@ -868,7 +876,7 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $message = trim($e->getMessage()); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $class = get_debug_type($e); - $title = sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : ''); + $title = \sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : ''); $len = Helper::width($title); } else { $len = 0; @@ -892,14 +900,14 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $messages = []; if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { - $messages[] = sprintf('%s', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); + $messages[] = \sprintf('%s', OutputFormatter::escape(\sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); } - $messages[] = $emptyLine = sprintf('%s', str_repeat(' ', $len)); + $messages[] = $emptyLine = \sprintf('%s', str_repeat(' ', $len)); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { - $messages[] = sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::width($title)))); + $messages[] = \sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::width($title)))); } foreach ($lines as $line) { - $messages[] = sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); + $messages[] = \sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); } $messages[] = $emptyLine; $messages[] = ''; @@ -926,7 +934,7 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $file = $trace[$i]['file'] ?? 'n/a'; $line = $trace[$i]['line'] ?? 'n/a'; - $output->writeln(sprintf(' %s%s at %s:%s', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); + $output->writeln(\sprintf(' %s%s at %s:%s', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); } $output->writeln('', OutputInterface::VERBOSITY_QUIET); @@ -1012,19 +1020,15 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI } } + $registeredSignals = false; $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : []; if ($commandSignals || $this->dispatcher && $this->signalsToDispatchEvent) { 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.'); } - if (Terminal::hasSttyAvailable()) { - $sttyMode = shell_exec('stty -g'); - - foreach ([\SIGINT, \SIGTERM] as $signal) { - $this->signalRegistry->register($signal, static fn () => shell_exec('stty '.$sttyMode)); - } - } + $registeredSignals = true; + $this->getSignalRegistry()->pushCurrentHandlers(); if ($this->dispatcher) { // We register application signals, so that we can dispatch the event @@ -1075,7 +1079,13 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI } if (null === $this->dispatcher) { - return $command->run($input, $output); + try { + return $command->run($input, $output); + } finally { + if ($registeredSignals) { + $this->getSignalRegistry()->popPreviousHandlers(); + } + } } // bind before the console.command event, so the listeners have access to input options/arguments @@ -1105,6 +1115,10 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI if (0 === $exitCode = $event->getExitCode()) { $e = null; } + } finally { + if ($registeredSignals) { + $this->getSignalRegistry()->popPreviousHandlers(); + } } $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode); @@ -1278,7 +1292,7 @@ private function splitStringByWidth(string $string, int $width): array foreach (preg_split('//u', $m[0]) as $char) { // test if $char could be appended to current line - if (mb_strwidth($line.$char, 'utf8') <= $width) { + if (Helper::width($line.$char) <= $width) { $line .= $char; continue; } diff --git a/symfony/console/CI/GithubActionReporter.php b/symfony/console/CI/GithubActionReporter.php index 2cae6fd8b..28112c2a2 100644 --- a/symfony/console/CI/GithubActionReporter.php +++ b/symfony/console/CI/GithubActionReporter.php @@ -89,11 +89,11 @@ private function log(string $type, string $message, ?string $file = null, ?int $ if (!$file) { // No file provided, output the message solely: - $this->output->writeln(sprintf('::%s::%s', $type, $message)); + $this->output->writeln(\sprintf('::%s::%s', $type, $message)); return; } - $this->output->writeln(sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); + $this->output->writeln(\sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); } } diff --git a/symfony/console/Color.php b/symfony/console/Color.php index 60ed046a6..b1914c19a 100644 --- a/symfony/console/Color.php +++ b/symfony/console/Color.php @@ -60,7 +60,7 @@ public function __construct(string $foreground = '', string $background = '', ar foreach ($options as $option) { if (!isset(self::AVAILABLE_OPTIONS[$option])) { - throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS)))); + throw new InvalidArgumentException(\sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS)))); } $this->options[$option] = self::AVAILABLE_OPTIONS[$option]; @@ -88,7 +88,7 @@ public function set(): string return ''; } - return sprintf("\033[%sm", implode(';', $setCodes)); + return \sprintf("\033[%sm", implode(';', $setCodes)); } public function unset(): string @@ -107,7 +107,7 @@ public function unset(): string return ''; } - return sprintf("\033[%sm", implode(';', $unsetCodes)); + return \sprintf("\033[%sm", implode(';', $unsetCodes)); } private function parseColor(string $color, bool $background = false): string @@ -128,6 +128,6 @@ private function parseColor(string $color, bool $background = false): string return ($background ? '10' : '9').self::BRIGHT_COLORS[$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))))); + throw new InvalidArgumentException(\sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS))))); } } diff --git a/symfony/console/Command/Command.php b/symfony/console/Command/Command.php index 9f9cb2f53..3ede6ca6b 100644 --- a/symfony/console/Command/Command.php +++ b/symfony/console/Command/Command.php @@ -326,7 +326,7 @@ public function run(InputInterface $input, OutputInterface $output): int $statusCode = $this->execute($input, $output); if (!\is_int($statusCode)) { - throw new \TypeError(sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode))); + throw new \TypeError(\sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode))); } } @@ -446,7 +446,7 @@ public function getDefinition(): InputDefinition */ public function getNativeDefinition(): InputDefinition { - return $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 ?? throw new LogicException(\sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); } /** @@ -464,7 +464,7 @@ public function addArgument(string $name, ?int $mode = null, string $description { $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))); + 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, $suggestedValues)); $this->fullDefinition?->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); @@ -488,7 +488,7 @@ public function addOption(string $name, string|array|null $shortcut = null, ?int { $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))); + 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, $suggestedValues)); $this->fullDefinition?->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); @@ -662,7 +662,7 @@ public function getSynopsis(bool $short = false): string $key = $short ? 'short' : 'long'; if (!isset($this->synopsis[$key])) { - $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); + $this->synopsis[$key] = trim(\sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); } return $this->synopsis[$key]; @@ -676,7 +676,7 @@ public function getSynopsis(bool $short = false): string public function addUsage(string $usage): static { if (!str_starts_with($usage, $this->name)) { - $usage = sprintf('%s %s', $this->name, $usage); + $usage = \sprintf('%s %s', $this->name, $usage); } $this->usages[] = $usage; @@ -703,7 +703,7 @@ public function getUsages(): array public function getHelper(string $name): mixed { 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)); + 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)); } return $this->helperSet->get($name); @@ -719,7 +719,7 @@ public function getHelper(string $name): mixed private function validateName(string $name): void { if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) { - throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name)); + throw new InvalidArgumentException(\sprintf('Command name "%s" is invalid.', $name)); } } } diff --git a/symfony/console/Command/CompleteCommand.php b/symfony/console/Command/CompleteCommand.php index 23be5577b..33f7f93c8 100644 --- a/symfony/console/Command/CompleteCommand.php +++ b/symfony/console/Command/CompleteCommand.php @@ -85,7 +85,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int // "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); + $message = \sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION); $this->log($message); $output->writeln($message.' Install the Symfony completion script again by using the "completion" command.'); @@ -99,7 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } if (!$completionOutput = $this->completionOutputs[$shell] ?? false) { - throw new \RuntimeException(sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs)))); + throw new \RuntimeException(\sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs)))); } $completionInput = $this->createCompletionInput($input); diff --git a/symfony/console/Command/DumpCompletionCommand.php b/symfony/console/Command/DumpCompletionCommand.php index 51b613a14..571425b88 100644 --- a/symfony/console/Command/DumpCompletionCommand.php +++ b/symfony/console/Command/DumpCompletionCommand.php @@ -108,9 +108,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output = $output->getErrorOutput(); } if ($shell) { - $output->writeln(sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, implode('", "', $supportedShells))); + $output->writeln(\sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, implode('", "', $supportedShells))); } else { - $output->writeln(sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); + $output->writeln(\sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); } return 2; diff --git a/symfony/console/Command/SignalableCommandInterface.php b/symfony/console/Command/SignalableCommandInterface.php index f8eb8e522..74d59b086 100644 --- a/symfony/console/Command/SignalableCommandInterface.php +++ b/symfony/console/Command/SignalableCommandInterface.php @@ -30,5 +30,5 @@ public function getSubscribedSignals(): array; * * @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/* , int|false $previousExitCode = 0 */); } diff --git a/symfony/console/Command/TraceableCommand.php b/symfony/console/Command/TraceableCommand.php index 9ffb68da3..9df467b0d 100644 --- a/symfony/console/Command/TraceableCommand.php +++ b/symfony/console/Command/TraceableCommand.php @@ -283,7 +283,7 @@ public function run(InputInterface $input, OutputInterface $output): int $event = $this->stopwatch->start($this->getName(), 'command'); try { - $this->exitCode = parent::run($input, $output); + $this->exitCode = $this->command->run($input, $output); } finally { $event->stop(); diff --git a/symfony/console/CommandLoader/ContainerCommandLoader.php b/symfony/console/CommandLoader/ContainerCommandLoader.php index bfa0ac467..1638f2fd0 100644 --- a/symfony/console/CommandLoader/ContainerCommandLoader.php +++ b/symfony/console/CommandLoader/ContainerCommandLoader.php @@ -37,7 +37,7 @@ public function __construct(ContainerInterface $container, array $commandMap) public function get(string $name): Command { if (!$this->has($name)) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } return $this->container->get($this->commandMap[$name]); diff --git a/symfony/console/CommandLoader/FactoryCommandLoader.php b/symfony/console/CommandLoader/FactoryCommandLoader.php index 9ced75aeb..ffe1b520c 100644 --- a/symfony/console/CommandLoader/FactoryCommandLoader.php +++ b/symfony/console/CommandLoader/FactoryCommandLoader.php @@ -39,7 +39,7 @@ public function has(string $name): bool public function get(string $name): Command { if (!isset($this->factories[$name])) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } $factory = $this->factories[$name]; diff --git a/symfony/console/Completion/Suggestion.php b/symfony/console/Completion/Suggestion.php index 7392965a2..3251b079f 100644 --- a/symfony/console/Completion/Suggestion.php +++ b/symfony/console/Completion/Suggestion.php @@ -20,7 +20,7 @@ class Suggestion implements \Stringable { public function __construct( private readonly string $value, - private readonly string $description = '' + private readonly string $description = '', ) { } diff --git a/symfony/console/Cursor.php b/symfony/console/Cursor.php index 69fd3821c..45243c796 100644 --- a/symfony/console/Cursor.php +++ b/symfony/console/Cursor.php @@ -36,7 +36,7 @@ public function __construct(OutputInterface $output, $input = null) */ public function moveUp(int $lines = 1): static { - $this->output->write(sprintf("\x1b[%dA", $lines)); + $this->output->write(\sprintf("\x1b[%dA", $lines)); return $this; } @@ -46,7 +46,7 @@ public function moveUp(int $lines = 1): static */ public function moveDown(int $lines = 1): static { - $this->output->write(sprintf("\x1b[%dB", $lines)); + $this->output->write(\sprintf("\x1b[%dB", $lines)); return $this; } @@ -56,7 +56,7 @@ public function moveDown(int $lines = 1): static */ public function moveRight(int $columns = 1): static { - $this->output->write(sprintf("\x1b[%dC", $columns)); + $this->output->write(\sprintf("\x1b[%dC", $columns)); return $this; } @@ -66,7 +66,7 @@ public function moveRight(int $columns = 1): static */ public function moveLeft(int $columns = 1): static { - $this->output->write(sprintf("\x1b[%dD", $columns)); + $this->output->write(\sprintf("\x1b[%dD", $columns)); return $this; } @@ -76,7 +76,7 @@ public function moveLeft(int $columns = 1): static */ public function moveToColumn(int $column): static { - $this->output->write(sprintf("\x1b[%dG", $column)); + $this->output->write(\sprintf("\x1b[%dG", $column)); return $this; } @@ -86,7 +86,7 @@ public function moveToColumn(int $column): static */ public function moveToPosition(int $column, int $row): static { - $this->output->write(sprintf("\x1b[%d;%dH", $row + 1, $column)); + $this->output->write(\sprintf("\x1b[%d;%dH", $row + 1, $column)); return $this; } @@ -195,7 +195,7 @@ public function getCurrentPosition(): array $code = trim(fread($this->input, 1024)); - shell_exec(sprintf('stty %s', $sttyMode)); + shell_exec(\sprintf('stty %s', $sttyMode)); sscanf($code, "\033[%d;%dR", $row, $col); diff --git a/symfony/console/DataCollector/CommandDataCollector.php b/symfony/console/DataCollector/CommandDataCollector.php index 45138c7dc..3cbe72b59 100644 --- a/symfony/console/DataCollector/CommandDataCollector.php +++ b/symfony/console/DataCollector/CommandDataCollector.php @@ -118,7 +118,7 @@ public function getCommand(): array 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 \sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']); } return null; @@ -204,7 +204,7 @@ public function getInteractiveInputs(): array public function getSignalable(): array { return array_map( - static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), $this->data['signalable'] ); } @@ -212,7 +212,7 @@ public function getSignalable(): array public function getHandledSignals(): array { $keys = array_map( - static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), array_keys($this->data['handled_signals']) ); diff --git a/symfony/console/DependencyInjection/AddConsoleCommandPass.php b/symfony/console/DependencyInjection/AddConsoleCommandPass.php index 27705ddb6..3cf05734b 100644 --- a/symfony/console/DependencyInjection/AddConsoleCommandPass.php +++ b/symfony/console/DependencyInjection/AddConsoleCommandPass.php @@ -48,10 +48,10 @@ public function process(ContainerBuilder $container) $aliases = $tags[0]['command']; } else { if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + 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, 'console.command', Command::class)); } $aliases = str_replace('%', '%%', $class::getDefaultName() ?? ''); } @@ -105,10 +105,10 @@ public function process(ContainerBuilder $container) if (!$description) { if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + 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, 'console.command', Command::class)); } $description = str_replace('%', '%%', $class::getDefaultDescription() ?? ''); } diff --git a/symfony/console/Descriptor/ApplicationDescription.php b/symfony/console/Descriptor/ApplicationDescription.php index ef9e8a63b..3f38379c9 100644 --- a/symfony/console/Descriptor/ApplicationDescription.php +++ b/symfony/console/Descriptor/ApplicationDescription.php @@ -73,7 +73,7 @@ public function getCommands(): array public function getCommand(string $name): Command { if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } return $this->commands[$name] ?? $this->aliases[$name]; diff --git a/symfony/console/Descriptor/Descriptor.php b/symfony/console/Descriptor/Descriptor.php index 7b2509c60..2143a17c3 100644 --- a/symfony/console/Descriptor/Descriptor.php +++ b/symfony/console/Descriptor/Descriptor.php @@ -38,7 +38,7 @@ public function describe(OutputInterface $output, object $object, array $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))), + default => throw new InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', get_debug_type($object))), }; } diff --git a/symfony/console/Descriptor/JsonDescriptor.php b/symfony/console/Descriptor/JsonDescriptor.php index 956303709..9a8e696cd 100644 --- a/symfony/console/Descriptor/JsonDescriptor.php +++ b/symfony/console/Descriptor/JsonDescriptor.php @@ -108,7 +108,7 @@ private function getInputOptionData(InputOption $option, bool $negated = false): 'is_value_required' => false, 'is_multiple' => false, 'description' => 'Negate the "--'.$option->getName().'" option', - 'default' => false, + 'default' => null === $option->getDefault() ? null : !$option->getDefault(), ] : [ 'name' => '--'.$option->getName(), 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '', diff --git a/symfony/console/Descriptor/MarkdownDescriptor.php b/symfony/console/Descriptor/MarkdownDescriptor.php index b3f16ee90..8b7075943 100644 --- a/symfony/console/Descriptor/MarkdownDescriptor.php +++ b/symfony/console/Descriptor/MarkdownDescriptor.php @@ -149,7 +149,7 @@ protected function describeApplication(Application $application, array $options } $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(fn ($commandName) => \sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands']))); } foreach ($description->getCommands() as $command) { @@ -162,7 +162,7 @@ private function getApplicationTitle(Application $application): string { if ('UNKNOWN' !== $application->getName()) { if ('UNKNOWN' !== $application->getVersion()) { - return sprintf('%s %s', $application->getName(), $application->getVersion()); + return \sprintf('%s %s', $application->getName(), $application->getVersion()); } return $application->getName(); diff --git a/symfony/console/Descriptor/ReStructuredTextDescriptor.php b/symfony/console/Descriptor/ReStructuredTextDescriptor.php index d4423fd34..a2b754276 100644 --- a/symfony/console/Descriptor/ReStructuredTextDescriptor.php +++ b/symfony/console/Descriptor/ReStructuredTextDescriptor.php @@ -167,7 +167,7 @@ private function getApplicationTitle(Application $application): string return 'Console Tool'; } if ('UNKNOWN' !== $application->getVersion()) { - return sprintf('%s %s', $application->getName(), $application->getVersion()); + return \sprintf('%s %s', $application->getName(), $application->getVersion()); } return $application->getName(); @@ -209,7 +209,7 @@ private function createTableOfContents(ApplicationDescription $description, Appl $commands = $this->removeAliasesAndHiddenCommands($commands); $this->write("\n\n"); - $this->write(implode("\n", array_map(static fn ($commandName) => sprintf('- `%s`_', $commandName), array_keys($commands)))); + $this->write(implode("\n", array_map(static fn ($commandName) => \sprintf('- `%s`_', $commandName), array_keys($commands)))); } } diff --git a/symfony/console/Descriptor/TextDescriptor.php b/symfony/console/Descriptor/TextDescriptor.php index d04d10238..51c411f46 100644 --- a/symfony/console/Descriptor/TextDescriptor.php +++ b/symfony/console/Descriptor/TextDescriptor.php @@ -31,7 +31,7 @@ class TextDescriptor extends Descriptor protected function describeInputArgument(InputArgument $argument, array $options = []): void { if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) { - $default = sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); } else { $default = ''; } @@ -39,7 +39,7 @@ protected function describeInputArgument(InputArgument $argument, array $options $totalWidth = $options['total_width'] ?? Helper::width($argument->getName()); $spacingWidth = $totalWidth - \strlen($argument->getName()); - $this->writeText(sprintf(' %s %s%s%s', + $this->writeText(\sprintf(' %s %s%s%s', $argument->getName(), str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after @@ -51,7 +51,7 @@ protected function describeInputArgument(InputArgument $argument, array $options protected function describeInputOption(InputOption $option, array $options = []): void { if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) { - $default = sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); } else { $default = ''; } @@ -66,14 +66,14 @@ protected function describeInputOption(InputOption $option, array $options = []) } $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]); - $synopsis = sprintf('%s%s', - $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ', - sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value) + $synopsis = \sprintf('%s%s', + $option->getShortcut() ? \sprintf('-%s, ', $option->getShortcut()) : ' ', + \sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value) ); $spacingWidth = $totalWidth - Helper::width($synopsis); - $this->writeText(sprintf(' %s %s%s%s%s', + $this->writeText(\sprintf(' %s %s%s%s%s', $synopsis, str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after @@ -166,7 +166,7 @@ protected function describeApplication(Application $application, array $options $width = $this->getColumnWidth($description->getCommands()); foreach ($description->getCommands() as $command) { - $this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); + $this->writeText(\sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); $this->writeText("\n"); } } else { @@ -196,7 +196,7 @@ protected function describeApplication(Application $application, array $options $width = $this->getColumnWidth(array_merge(...array_values(array_map(fn ($namespace) => array_intersect($namespace['commands'], array_keys($commands)), array_values($namespaces))))); if ($describedNamespace) { - $this->writeText(sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); + $this->writeText(\sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); } else { $this->writeText('Available commands:', $options); } @@ -218,7 +218,7 @@ protected function describeApplication(Application $application, array $options $spacingWidth = $width - Helper::width($name); $command = $commands[$name]; $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : ''; - $this->writeText(sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options); + $this->writeText(\sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options); } } diff --git a/symfony/console/Formatter/OutputFormatter.php b/symfony/console/Formatter/OutputFormatter.php index 3e4897c33..a30e44d84 100644 --- a/symfony/console/Formatter/OutputFormatter.php +++ b/symfony/console/Formatter/OutputFormatter.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Console\Formatter; use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Helper\Helper; use function Symfony\Component\String\b; @@ -112,7 +113,7 @@ public function hasStyle(string $name): bool public function getStyle(string $name): OutputFormatterStyleInterface { if (!$this->hasStyle($name)) { - throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name)); + throw new InvalidArgumentException(\sprintf('Undefined style: "%s".', $name)); } return $this->styles[strtolower($name)]; @@ -146,9 +147,11 @@ public function formatAndWrap(?string $message, int $width) continue; } + // convert byte position to character position. + $pos = Helper::length(substr($message, 0, $pos)); // add the text up to the next tag - $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); - $offset = $pos + \strlen($text); + $output .= $this->applyCurrentStyle(Helper::substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); + $offset = $pos + Helper::length($text); // opening tag? if ($open = '/' !== $text[1]) { @@ -169,7 +172,7 @@ public function formatAndWrap(?string $message, int $width) } } - $output .= $this->applyCurrentStyle(substr($message, $offset), $output, $width, $currentLineLength); + $output .= $this->applyCurrentStyle(Helper::substr($message, $offset), $output, $width, $currentLineLength); return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']); } @@ -236,8 +239,18 @@ private function applyCurrentStyle(string $text, string $current, int $width, in } if ($currentLineLength) { - $prefix = substr($text, 0, $i = $width - $currentLineLength)."\n"; - $text = substr($text, $i); + $lines = explode("\n", $text, 2); + $prefix = Helper::substr($lines[0], 0, $i = $width - $currentLineLength)."\n"; + $text = Helper::substr($lines[0], $i); + + if (isset($lines[1])) { + // $prefix may contain the full first line in which the \n is already a part of $prefix. + if ('' !== $text) { + $text .= "\n"; + } + + $text .= $lines[1]; + } } else { $prefix = ''; } @@ -252,8 +265,8 @@ private function applyCurrentStyle(string $text, string $current, int $width, in $lines = explode("\n", $text); - foreach ($lines as $line) { - $currentLineLength += \strlen($line); + foreach ($lines as $i => $line) { + $currentLineLength = 0 === $i ? $currentLineLength + Helper::length($line) : Helper::length($line); if ($width <= $currentLineLength) { $currentLineLength = 0; } @@ -272,6 +285,6 @@ private function addLineBreaks(string $text, int $width): string { $encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8'; - return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding); + return b($text)->toUnicodeString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding); } } diff --git a/symfony/console/Helper/DebugFormatterHelper.php b/symfony/console/Helper/DebugFormatterHelper.php index 9ea7fb914..dfdb8a82c 100644 --- a/symfony/console/Helper/DebugFormatterHelper.php +++ b/symfony/console/Helper/DebugFormatterHelper.php @@ -31,7 +31,7 @@ public function start(string $id, string $message, string $prefix = 'RUN'): stri { $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)]; - return sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); + return \sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); } /** @@ -47,22 +47,22 @@ public function progress(string $id, string $buffer, bool $error = false, string unset($this->started[$id]['out']); } if (!isset($this->started[$id]['err'])) { - $message .= sprintf('%s %s ', $this->getBorder($id), $errorPrefix); + $message .= \sprintf('%s %s ', $this->getBorder($id), $errorPrefix); $this->started[$id]['err'] = true; } - $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); + $message .= str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); } else { if (isset($this->started[$id]['err'])) { $message .= "\n"; unset($this->started[$id]['err']); } if (!isset($this->started[$id]['out'])) { - $message .= sprintf('%s %s ', $this->getBorder($id), $prefix); + $message .= \sprintf('%s %s ', $this->getBorder($id), $prefix); $this->started[$id]['out'] = true; } - $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); + $message .= str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); } return $message; @@ -76,10 +76,10 @@ public function stop(string $id, string $message, bool $successful, string $pref $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : ''; if ($successful) { - return sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + return \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); } - $message = sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + $message = \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); unset($this->started[$id]['out'], $this->started[$id]['err']); @@ -88,7 +88,7 @@ public function stop(string $id, string $message, bool $successful, string $pref private function getBorder(string $id): string { - return sprintf(' ', self::COLORS[$this->started[$id]['border']]); + return \sprintf(' ', self::COLORS[$this->started[$id]['border']]); } public function getName(): string diff --git a/symfony/console/Helper/DescriptorHelper.php b/symfony/console/Helper/DescriptorHelper.php index eb32bce8f..fda6779b9 100644 --- a/symfony/console/Helper/DescriptorHelper.php +++ b/symfony/console/Helper/DescriptorHelper.php @@ -62,7 +62,7 @@ public function describe(OutputInterface $output, ?object $object, array $option ], $options); if (!isset($this->descriptors[$options['format']])) { - throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format'])); + throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $options['format'])); } $descriptor = $this->descriptors[$options['format']]; diff --git a/symfony/console/Helper/FormatterHelper.php b/symfony/console/Helper/FormatterHelper.php index 279e4c799..3646b3d6f 100644 --- a/symfony/console/Helper/FormatterHelper.php +++ b/symfony/console/Helper/FormatterHelper.php @@ -25,7 +25,7 @@ class FormatterHelper extends Helper */ public function formatSection(string $section, string $message, string $style = 'info'): string { - return sprintf('<%s>[%s] %s', $style, $section, $style, $message); + return \sprintf('<%s>[%s] %s', $style, $section, $style, $message); } /** @@ -41,7 +41,7 @@ public function formatBlock(string|array $messages, string $style, bool $large = $lines = []; foreach ($messages as $message) { $message = OutputFormatter::escape($message); - $lines[] = sprintf($large ? ' %s ' : ' %s ', $message); + $lines[] = \sprintf($large ? ' %s ' : ' %s ', $message); $len = max(self::width($message) + ($large ? 4 : 2), $len); } @@ -54,7 +54,7 @@ public function formatBlock(string|array $messages, string $style, bool $large = } for ($i = 0; isset($messages[$i]); ++$i) { - $messages[$i] = sprintf('<%s>%s', $style, $messages[$i], $style); + $messages[$i] = \sprintf('<%s>%s', $style, $messages[$i], $style); } return implode("\n", $messages); diff --git a/symfony/console/Helper/Helper.php b/symfony/console/Helper/Helper.php index 05be64787..468d06689 100644 --- a/symfony/console/Helper/Helper.php +++ b/symfony/console/Helper/Helper.php @@ -48,7 +48,9 @@ public static function width(?string $string): int $string ??= ''; if (preg_match('//u', $string)) { - return (new UnicodeString($string))->width(false); + $string = preg_replace('/[\p{Cc}\x7F]++/u', '', $string, -1, $count); + + return (new UnicodeString($string))->width(false) + $count; } if (false === $encoding = mb_detect_encoding($string, null, true)) { @@ -84,6 +86,10 @@ public static function substr(?string $string, int $from, ?int $length = null): { $string ??= ''; + if (preg_match('//u', $string)) { + return (new UnicodeString($string))->slice($from, $length); + } + if (false === $encoding = mb_detect_encoding($string, null, true)) { return substr($string, $from, $length); } @@ -140,18 +146,18 @@ public static function formatTime(int|float $secs, int $precision = 1) public static function formatMemory(int $memory) { if ($memory >= 1024 * 1024 * 1024) { - return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); + return \sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); } if ($memory >= 1024 * 1024) { - return sprintf('%.1f MiB', $memory / 1024 / 1024); + return \sprintf('%.1f MiB', $memory / 1024 / 1024); } if ($memory >= 1024) { - return sprintf('%d KiB', $memory / 1024); + return \sprintf('%d KiB', $memory / 1024); } - return sprintf('%d B', $memory); + return \sprintf('%d B', $memory); } /** diff --git a/symfony/console/Helper/HelperSet.php b/symfony/console/Helper/HelperSet.php index f8c74ca2c..8deb22ee7 100644 --- a/symfony/console/Helper/HelperSet.php +++ b/symfony/console/Helper/HelperSet.php @@ -64,7 +64,7 @@ public function has(string $name): bool public function get(string $name): HelperInterface { if (!$this->has($name)) { - throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name)); + throw new InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name)); } return $this->helpers[$name]; diff --git a/symfony/console/Helper/OutputWrapper.php b/symfony/console/Helper/OutputWrapper.php index 2ec819c74..a615ed2f9 100644 --- a/symfony/console/Helper/OutputWrapper.php +++ b/symfony/console/Helper/OutputWrapper.php @@ -49,7 +49,7 @@ final class OutputWrapper private const URL_PATTERN = 'https?://\S+'; public function __construct( - private bool $allowCutUrls = false + private bool $allowCutUrls = false, ) { } @@ -59,7 +59,7 @@ public function wrap(string $text, int $width, string $break = "\n"): string return $text; } - $tagPattern = sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT); + $tagPattern = \sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT); $limitPattern = "{1,$width}"; $patternBlocks = [$tagPattern]; if (!$this->allowCutUrls) { @@ -68,7 +68,7 @@ public function wrap(string $text, int $width, string $break = "\n"): string $patternBlocks[] = '.'; $blocks = implode('|', $patternBlocks); $rowPattern = "(?:$blocks)$limitPattern"; - $pattern = sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern); + $pattern = \sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern); $output = rtrim(preg_replace($pattern, '\\1'.$break, $text), $break); return str_replace(' '.$break, $break, $output); diff --git a/symfony/console/Helper/ProcessHelper.php b/symfony/console/Helper/ProcessHelper.php index 3ef6f71f7..ae55a83c2 100644 --- a/symfony/console/Helper/ProcessHelper.php +++ b/symfony/console/Helper/ProcessHelper.php @@ -55,7 +55,7 @@ public function run(OutputInterface $output, array|Process $cmd, ?string $error $process = $cmd[0]; unset($cmd[0]); } else { - throw new \InvalidArgumentException(sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); + throw new \InvalidArgumentException(\sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); } if ($verbosity <= $output->getVerbosity()) { @@ -69,12 +69,12 @@ public function run(OutputInterface $output, array|Process $cmd, ?string $error $process->run($callback, $cmd); if ($verbosity <= $output->getVerbosity()) { - $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode()); + $message = $process->isSuccessful() ? 'Command ran successfully' : \sprintf('%s Command did not run successfully', $process->getExitCode()); $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful())); } if (!$process->isSuccessful() && null !== $error) { - $output->writeln(sprintf('%s', $this->escapeString($error))); + $output->writeln(\sprintf('%s', $this->escapeString($error))); } return $process; diff --git a/symfony/console/Helper/ProgressBar.php b/symfony/console/Helper/ProgressBar.php index 23157e3c7..8143acaff 100644 --- a/symfony/console/Helper/ProgressBar.php +++ b/symfony/console/Helper/ProgressBar.php @@ -486,12 +486,21 @@ private function overwrite(string $message): void if ($this->output instanceof ConsoleSectionOutput) { $messageLines = explode("\n", $this->previousMessage); $lineCount = \count($messageLines); + + $lastLineWithoutDecoration = Helper::removeDecoration($this->output->getFormatter(), end($messageLines) ?? ''); + + // When the last previous line is empty (without formatting) it is already cleared by the section output, so we don't need to clear it again + if ('' === $lastLineWithoutDecoration) { + --$lineCount; + } + foreach ($messageLines as $messageLine) { $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine)); if ($messageLineLength > $this->terminal->getWidth()) { $lineCount += floor($messageLineLength / $this->terminal->getWidth()); } } + $this->output->clear($lineCount); } else { $lineCount = substr_count($this->previousMessage, "\n"); @@ -594,7 +603,7 @@ private function buildLine(): string } if (isset($matches[2])) { - $text = sprintf('%'.$matches[2], $text); + $text = \sprintf('%'.$matches[2], $text); } return $text; diff --git a/symfony/console/Helper/QuestionHelper.php b/symfony/console/Helper/QuestionHelper.php index b40b13191..23d8522ad 100644 --- a/symfony/console/Helper/QuestionHelper.php +++ b/symfony/console/Helper/QuestionHelper.php @@ -220,7 +220,7 @@ protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string foreach ($choices as $key => $value) { $padding = str_repeat(' ', $maxWidth - self::width($key)); - $messages[] = sprintf(" [<$tag>%s$padding] %s", $key, $value); + $messages[] = \sprintf(" [<$tag>%s$padding] %s", $key, $value); } return $messages; @@ -258,11 +258,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu $ofs = -1; $matches = $autocomplete($ret); $numMatches = \count($matches); - - $sttyMode = shell_exec('stty -g'); - $isStdin = 'php://stdin' === (stream_get_meta_data($inputStream)['uri'] ?? null); - $r = [$inputStream]; - $w = []; + $inputHelper = new TerminalInputHelper($inputStream); // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) shell_exec('stty -icanon -echo'); @@ -272,15 +268,13 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu // Read a keypress while (!feof($inputStream)) { - while ($isStdin && 0 === @stream_select($r, $w, $w, 0, 100)) { - // Give signal handlers a chance to run - $r = [$inputStream]; - } + $inputHelper->waitForInput(); $c = fread($inputStream, 1); // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false. if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) { - shell_exec('stty '.$sttyMode); + // Restore the terminal so it behaves normally again + $inputHelper->finish(); throw new MissingInputException('Aborted.'); } elseif ("\177" === $c) { // Backspace Character if (0 === $numMatches && 0 !== $i) { @@ -317,7 +311,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu $ofs += ('A' === $c[2]) ? -1 : 1; $ofs = ($numMatches + $ofs) % $numMatches; } - } elseif (\ord($c) < 32) { + } elseif ('' === $c || \ord($c) < 32) { if ("\t" === $c || "\n" === $c) { if ($numMatches > 0 && -1 !== $ofs) { $ret = (string) $matches[$ofs]; @@ -382,8 +376,8 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu } } - // Reset stty so it behaves normally again - shell_exec('stty '.$sttyMode); + // Restore the terminal so it behaves normally again + $inputHelper->finish(); return $fullChoice; } @@ -434,27 +428,25 @@ private function getHiddenResponse(OutputInterface $output, $inputStream, bool $ return $value; } + $inputHelper = null; + if (self::$stty && Terminal::hasSttyAvailable()) { - $sttyMode = shell_exec('stty -g'); + $inputHelper = new TerminalInputHelper($inputStream); shell_exec('stty -echo'); } elseif ($this->isInteractiveInput($inputStream)) { throw new RuntimeException('Unable to hide the response.'); } - $value = fgets($inputStream, 4096); + $value = $this->doReadInput($inputStream, helper: $inputHelper); if (4095 === \strlen($value)) { $errOutput = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output; $errOutput->warning('The value was possibly truncated by your shell or terminal emulator'); } - if (self::$stty && Terminal::hasSttyAvailable()) { - shell_exec('stty '.$sttyMode); - } + // Restore the terminal so it behaves normally again + $inputHelper?->finish(); - if (false === $value) { - throw new MissingInputException('Aborted.'); - } if ($trimmable) { $value = trim($value); } @@ -514,7 +506,7 @@ private function readInput($inputStream, Question $question): string|false { if (!$question->isMultiline()) { $cp = $this->setIOCodepage(); - $ret = fgets($inputStream, 4096); + $ret = $this->doReadInput($inputStream); return $this->resetIOCodepage($cp, $ret); } @@ -524,13 +516,11 @@ private function readInput($inputStream, Question $question): string|false return false; } - $ret = ''; $cp = $this->setIOCodepage(); - while (false !== ($char = fgetc($multiLineStreamReader))) { - if (\PHP_EOL === "{$ret}{$char}") { - break; - } - $ret .= $char; + $ret = $this->doReadInput($multiLineStreamReader, "\x4"); + + if (stream_get_meta_data($inputStream)['seekable']) { + fseek($inputStream, ftell($multiLineStreamReader)); } return $this->resetIOCodepage($cp, $ret); @@ -597,4 +587,35 @@ private function cloneInputStream($inputStream) return $cloneStream; } + + /** + * @param resource $inputStream + */ + private function doReadInput($inputStream, ?string $exitChar = null, ?TerminalInputHelper $helper = null): string + { + $ret = ''; + $helper ??= new TerminalInputHelper($inputStream, false); + + while (!feof($inputStream)) { + $helper->waitForInput(); + $char = fread($inputStream, 1); + + // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false. + if (false === $char || ('' === $ret && '' === $char)) { + throw new MissingInputException('Aborted.'); + } + + if (\PHP_EOL === "{$ret}{$char}" || $exitChar === $char) { + break; + } + + $ret .= $char; + + if (null === $exitChar && "\n" === $char) { + break; + } + } + + return $ret; + } } diff --git a/symfony/console/Helper/SymfonyQuestionHelper.php b/symfony/console/Helper/SymfonyQuestionHelper.php index 8ebc84376..11b4e4238 100644 --- a/symfony/console/Helper/SymfonyQuestionHelper.php +++ b/symfony/console/Helper/SymfonyQuestionHelper.php @@ -34,17 +34,17 @@ protected function writePrompt(OutputInterface $output, Question $question) $default = $question->getDefault(); if ($question->isMultiline()) { - $text .= sprintf(' (press %s to continue)', $this->getEofShortcut()); + $text .= \sprintf(' (press %s to continue)', $this->getEofShortcut()); } switch (true) { case null === $default: - $text = sprintf(' %s:', $text); + $text = \sprintf(' %s:', $text); break; case $question instanceof ConfirmationQuestion: - $text = sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); + $text = \sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); break; @@ -56,18 +56,18 @@ protected function writePrompt(OutputInterface $output, Question $question) $default[$key] = $choices[trim($value)]; } - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); break; case $question instanceof ChoiceQuestion: $choices = $question->getChoices(); - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); break; default: - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); } $output->writeln($text); diff --git a/symfony/console/Helper/Table.php b/symfony/console/Helper/Table.php index 1f026dc50..469d228d6 100644 --- a/symfony/console/Helper/Table.php +++ b/symfony/console/Helper/Table.php @@ -83,7 +83,7 @@ public static function getStyleDefinition(string $name): TableStyle { self::$styles ??= self::initStyles(); - return self::$styles[$name] ?? throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); } /** @@ -168,7 +168,7 @@ public function setColumnWidths(array $widths): static public function setColumnMaxWidth(int $columnIndex, int $width): static { if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) { - throw new \LogicException(sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter()))); + throw new \LogicException(\sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter()))); } $this->columnMaxWidths[$columnIndex] = $width; @@ -237,7 +237,7 @@ public function addRow(TableSeparator|array $row): static public function appendRow(TableSeparator|array $row): static { if (!$this->output instanceof ConsoleSectionOutput) { - throw new RuntimeException(sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); + throw new RuntimeException(\sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); } if ($this->rendered) { @@ -370,14 +370,14 @@ public function render() foreach ($parts as $idx => $part) { if ($headers && !$containsColspan) { if (0 === $idx) { - $rows[] = [sprintf( + $rows[] = [\sprintf( '%s%s: %s', str_repeat(' ', $maxHeaderLength - Helper::width(Helper::removeDecoration($formatter, $headers[$i] ?? ''))), $headers[$i] ?? '', $part )]; } else { - $rows[] = [sprintf( + $rows[] = [\sprintf( '%s %s', str_pad('', $maxHeaderLength, ' ', \STR_PAD_LEFT), $part @@ -497,12 +497,12 @@ private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $ti } if (null !== $title) { - $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title))); + $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = \sprintf($titleFormat, $title))); $markupLength = Helper::width($markup); if ($titleLength > $limit = $markupLength - 4) { $titleLength = $limit; - $formatLength = Helper::width(Helper::removeDecoration($formatter, sprintf($titleFormat, ''))); - $formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); + $formatLength = Helper::width(Helper::removeDecoration($formatter, \sprintf($titleFormat, ''))); + $formattedTitle = \sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); } $titleStart = intdiv($markupLength - $titleLength, 2); @@ -513,7 +513,7 @@ private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $ti } } - $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup)); + $this->output->writeln(\sprintf($this->style->getBorderFormat(), $markup)); } /** @@ -523,7 +523,7 @@ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string { $borders = $this->style->getBorderChars(); - return sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); + return \sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); } /** @@ -564,18 +564,15 @@ private function renderCell(array $row, int $column, string $cellFormat): string } // str_pad won't work properly with multi-byte strings, we need to fix the padding - if (false !== $encoding = mb_detect_encoding($cell, null, true)) { - $width += \strlen($cell) - mb_strwidth($cell, $encoding); - } - + $width += \strlen($cell) - Helper::width($cell) - substr_count($cell, "\0"); $style = $this->getColumnStyle($column); if ($cell instanceof TableSeparator) { - return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); + return \sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); } $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell)); - $content = sprintf($style->getCellRowContentFormat(), $cell); + $content = \sprintf($style->getCellRowContentFormat(), $cell); $padType = $style->getPadType(); if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) { @@ -600,7 +597,7 @@ private function renderCell(array $row, int $column, string $cellFormat): string $padType = $cell->getStyle()->getPadByAlign(); } - return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType)); + return \sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType)); } /** @@ -632,8 +629,48 @@ private function buildTableRows(array $rows): TableRows foreach ($rows[$rowKey] as $column => $cell) { $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1; - if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) { - $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan); + $minWrappedWidth = 0; + $widthApplied = []; + $lengthColumnBorder = $this->getColumnSeparatorWidth() + Helper::width($this->style->getCellRowContentFormat()) - 2; + for ($i = $column; $i < ($column + $colspan); ++$i) { + if (isset($this->columnMaxWidths[$i])) { + $minWrappedWidth += $this->columnMaxWidths[$i]; + $widthApplied[] = ['type' => 'max', 'column' => $i]; + } elseif (($this->columnWidths[$i] ?? 0) > 0 && $colspan > 1) { + $minWrappedWidth += $this->columnWidths[$i]; + $widthApplied[] = ['type' => 'min', 'column' => $i]; + } + } + if (1 === \count($widthApplied)) { + if ($colspan > 1) { + $minWrappedWidth *= $colspan; // previous logic + } + } elseif (\count($widthApplied) > 1) { + $minWrappedWidth += (\count($widthApplied) - 1) * $lengthColumnBorder; + } + + $cellWidth = Helper::width(Helper::removeDecoration($formatter, $cell)); + if ($minWrappedWidth && $cellWidth > $minWrappedWidth) { + $cell = $formatter->formatAndWrap($cell, $minWrappedWidth); + } + // update minimal columnWidths for spanned columns + if ($colspan > 1 && $minWrappedWidth > 0) { + $columnsMinWidthProcessed = []; + $cellWidth = min($cellWidth, $minWrappedWidth); + foreach ($widthApplied as $item) { + if ('max' === $item['type'] && $cellWidth >= $this->columnMaxWidths[$item['column']]) { + $minWidthColumn = $this->columnMaxWidths[$item['column']]; + $this->columnWidths[$item['column']] = $minWidthColumn; + $columnsMinWidthProcessed[$item['column']] = true; + $cellWidth -= $minWidthColumn + $lengthColumnBorder; + } + } + for ($i = $column; $i < ($column + $colspan); ++$i) { + if (isset($columnsMinWidthProcessed[$i])) { + continue; + } + $this->columnWidths[$i] = $cellWidth + $lengthColumnBorder; + } } if (!str_contains($cell ?? '', "\n")) { continue; @@ -697,7 +734,7 @@ private function fillNextRows(array $rows, int $line): array $unmergedRows = []; foreach ($rows[$line] as $column => $cell) { if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !$cell instanceof \Stringable) { - throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell))); + throw new InvalidArgumentException(\sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell))); } if ($cell instanceof TableCell && $cell->getRowspan() > 1) { $nbLines = $cell->getRowspan() - 1; @@ -842,7 +879,7 @@ private function calculateColumnsWidth(iterable $groups): void private function getColumnSeparatorWidth(): int { - return Helper::width(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); + return Helper::width(\sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); } private function getCellWidth(array $row, int $column): int @@ -925,6 +962,6 @@ private function resolveStyle(TableStyle|string $name): TableStyle return $name; } - return self::$styles[$name] ?? throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); } } diff --git a/symfony/console/Helper/TableCell.php b/symfony/console/Helper/TableCell.php index 394b2bc95..ead32f283 100644 --- a/symfony/console/Helper/TableCell.php +++ b/symfony/console/Helper/TableCell.php @@ -31,7 +31,7 @@ public function __construct(string $value = '', array $options = []) // check option names if ($diff = array_diff(array_keys($options), array_keys($this->options))) { - throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); + throw new InvalidArgumentException(\sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); } if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) { diff --git a/symfony/console/Helper/TableCellStyle.php b/symfony/console/Helper/TableCellStyle.php index 9419dcb40..1b1ef276e 100644 --- a/symfony/console/Helper/TableCellStyle.php +++ b/symfony/console/Helper/TableCellStyle.php @@ -43,11 +43,11 @@ class TableCellStyle public function __construct(array $options = []) { if ($diff = array_diff(array_keys($options), array_keys($this->options))) { - throw new InvalidArgumentException(sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff))); + throw new InvalidArgumentException(\sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff))); } if (isset($options['align']) && !\array_key_exists($options['align'], self::ALIGN_MAP)) { - throw new InvalidArgumentException(sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP)))); + throw new InvalidArgumentException(\sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP)))); } $this->options = array_merge($this->options, $options); diff --git a/symfony/console/Helper/TerminalInputHelper.php b/symfony/console/Helper/TerminalInputHelper.php new file mode 100644 index 000000000..d6f07db8b --- /dev/null +++ b/symfony/console/Helper/TerminalInputHelper.php @@ -0,0 +1,156 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +/** + * TerminalInputHelper stops Ctrl-C and similar signals from leaving the terminal in + * an unusable state if its settings have been modified when reading user input. + * This can be an issue on non-Windows platforms. + * + * Usage: + * + * $inputHelper = new TerminalInputHelper($inputStream); + * + * ...change terminal settings + * + * // Wait for input before all input reads + * $inputHelper->waitForInput(); + * + * ...read input + * + * // Call finish to restore terminal settings and signal handlers + * $inputHelper->finish() + * + * @internal + */ +final class TerminalInputHelper +{ + /** @var resource */ + private $inputStream; + private bool $isStdin; + private string $initialState = ''; + private int $signalToKill = 0; + private array $signalHandlers = []; + private array $targetSignals = []; + private bool $withStty; + + /** + * @param resource $inputStream + * + * @throws \RuntimeException If unable to read terminal settings + */ + public function __construct($inputStream, bool $withStty = true) + { + $this->inputStream = $inputStream; + $this->isStdin = 'php://stdin' === stream_get_meta_data($inputStream)['uri']; + $this->withStty = $withStty; + + if ($withStty) { + if (!\is_string($state = shell_exec('stty -g'))) { + throw new \RuntimeException('Unable to read the terminal settings.'); + } + + $this->initialState = $state; + + $this->createSignalHandlers(); + } + } + + /** + * Waits for input. + */ + public function waitForInput(): void + { + if ($this->isStdin) { + $r = [$this->inputStream]; + $w = []; + + // Allow signal handlers to run + while (0 === @stream_select($r, $w, $w, 0, 100)) { + $r = [$this->inputStream]; + } + } + + if ($this->withStty) { + $this->checkForKillSignal(); + } + } + + /** + * Restores terminal state and signal handlers. + */ + public function finish(): void + { + if (!$this->withStty) { + return; + } + + // Safeguard in case an unhandled kill signal exists + $this->checkForKillSignal(); + shell_exec('stty '.$this->initialState); + $this->signalToKill = 0; + + foreach ($this->signalHandlers as $signal => $originalHandler) { + pcntl_signal($signal, $originalHandler); + } + $this->signalHandlers = []; + $this->targetSignals = []; + } + + private function createSignalHandlers(): void + { + if (!\function_exists('pcntl_async_signals') || !\function_exists('pcntl_signal')) { + return; + } + + pcntl_async_signals(true); + $this->targetSignals = [\SIGINT, \SIGQUIT, \SIGTERM]; + + foreach ($this->targetSignals as $signal) { + $this->signalHandlers[$signal] = pcntl_signal_get_handler($signal); + + pcntl_signal($signal, function ($signal) { + // Save current state, then restore to initial state + $currentState = shell_exec('stty -g'); + shell_exec('stty '.$this->initialState); + $originalHandler = $this->signalHandlers[$signal]; + + if (\is_callable($originalHandler)) { + $originalHandler($signal); + // Handler did not exit, so restore to current state + shell_exec('stty '.$currentState); + + return; + } + + // Not a callable, so SIG_DFL or SIG_IGN + if (\SIG_DFL === $originalHandler) { + $this->signalToKill = $signal; + } + }); + } + } + + private function checkForKillSignal(): void + { + if (\in_array($this->signalToKill, $this->targetSignals, true)) { + // Try posix_kill + if (\function_exists('posix_kill')) { + pcntl_signal($this->signalToKill, \SIG_DFL); + posix_kill(getmypid(), $this->signalToKill); + } + + // Best attempt fallback + exit(128 + $this->signalToKill); + } + } +} diff --git a/symfony/console/Input/ArgvInput.php b/symfony/console/Input/ArgvInput.php index ab9f28c54..b5f866689 100644 --- a/symfony/console/Input/ArgvInput.php +++ b/symfony/console/Input/ArgvInput.php @@ -122,7 +122,7 @@ private function parseShortOptionSet(string $name): void for ($i = 0; $i < $len; ++$i) { if (!$this->definition->hasShortcut($name[$i])) { $encoding = mb_detect_encoding($name, null, true); - throw new RuntimeException(sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding))); + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding))); } $option = $this->definition->getOptionForShortcut($name[$i]); @@ -176,21 +176,21 @@ private function parseArgument(string $token): void } else { $all = $this->definition->getArguments(); $symfonyCommandName = null; - if (($inputArgument = $all[$key = array_key_first($all)] ?? null) && 'command' === $inputArgument->getName()) { + if (($inputArgument = $all[$key = array_key_first($all) ?? ''] ?? null) && 'command' === $inputArgument->getName()) { $symfonyCommandName = $this->arguments['command'] ?? null; unset($all[$key]); } if (\count($all)) { if ($symfonyCommandName) { - $message = sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all))); + $message = \sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all))); } else { - $message = sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))); + $message = \sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))); } } elseif ($symfonyCommandName) { - $message = sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); + $message = \sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); } else { - $message = sprintf('No arguments expected, got "%s".', $token); + $message = \sprintf('No arguments expected, got "%s".', $token); } throw new RuntimeException($message); @@ -205,7 +205,7 @@ private function parseArgument(string $token): void private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { - throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); @@ -220,12 +220,12 @@ private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { - throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); if (null !== $value) { - throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); } $this->options[$optionName] = false; @@ -235,7 +235,7 @@ private function addLongOption(string $name, mixed $value): void $option = $this->definition->getOption($name); if (null !== $value && !$option->acceptValue()) { - throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); } if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) { @@ -251,7 +251,7 @@ private function addLongOption(string $name, mixed $value): void if (null === $value) { if ($option->isValueRequired()) { - throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isArray() && !$option->isValueOptional()) { diff --git a/symfony/console/Input/ArrayInput.php b/symfony/console/Input/ArrayInput.php index c1bc914ca..b9f753394 100644 --- a/symfony/console/Input/ArrayInput.php +++ b/symfony/console/Input/ArrayInput.php @@ -140,7 +140,7 @@ protected function parse() private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { - throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new InvalidOptionException(\sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); @@ -156,7 +156,7 @@ private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { - throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name)); + throw new InvalidOptionException(\sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); @@ -169,7 +169,7 @@ private function addLongOption(string $name, mixed $value): void if (null === $value) { if ($option->isValueRequired()) { - throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name)); + throw new InvalidOptionException(\sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isValueOptional()) { @@ -188,7 +188,7 @@ private function addLongOption(string $name, mixed $value): void private function addArgument(string|int $name, mixed $value): void { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; diff --git a/symfony/console/Input/Input.php b/symfony/console/Input/Input.php index 1c21573bc..d3a3c7fd2 100644 --- a/symfony/console/Input/Input.php +++ b/symfony/console/Input/Input.php @@ -74,7 +74,7 @@ public function validate() $missingArguments = array_filter(array_keys($definition->getArguments()), fn ($argument) => !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired()); if (\count($missingArguments) > 0) { - throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); + throw new RuntimeException(\sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); } } @@ -99,7 +99,7 @@ public function getArguments(): array public function getArgument(string $name): mixed { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault(); @@ -111,7 +111,7 @@ public function getArgument(string $name): mixed public function setArgument(string $name, mixed $value) { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; @@ -138,7 +138,7 @@ public function getOption(string $name): mixed } if (!$this->definition->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); } return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); @@ -154,7 +154,7 @@ public function setOption(string $name, mixed $value) return; } elseif (!$this->definition->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); } $this->options[$name] = $value; diff --git a/symfony/console/Input/InputArgument.php b/symfony/console/Input/InputArgument.php index 4ef79feb7..fd203919f 100644 --- a/symfony/console/Input/InputArgument.php +++ b/symfony/console/Input/InputArgument.php @@ -31,7 +31,7 @@ class InputArgument private string $name; private int $mode; - private string|int|bool|array|null|float $default; + private string|int|bool|array|float|null $default; private array|\Closure $suggestedValues; private string $description; @@ -49,7 +49,7 @@ public function __construct(string $name, ?int $mode = null, string $description if (null === $mode) { $mode = self::OPTIONAL; } elseif ($mode > 7 || $mode < 1) { - throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode)); + throw new InvalidArgumentException(\sprintf('Argument mode "%s" is not valid.', $mode)); } $this->name = $name; @@ -137,7 +137,7 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti { $values = $this->suggestedValues; if ($values instanceof \Closure && !\is_array($values = $values($input))) { - throw new LogicException(sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); + throw new LogicException(\sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); } if ($values) { $suggestions->suggestValues($values); diff --git a/symfony/console/Input/InputDefinition.php b/symfony/console/Input/InputDefinition.php index b7162d770..b5c202838 100644 --- a/symfony/console/Input/InputDefinition.php +++ b/symfony/console/Input/InputDefinition.php @@ -105,15 +105,15 @@ public function addArguments(?array $arguments = []) public function addArgument(InputArgument $argument) { if (isset($this->arguments[$argument->getName()])) { - throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName())); + throw new LogicException(\sprintf('An argument with name "%s" already exists.', $argument->getName())); } if (null !== $this->lastArrayArgument) { - throw new LogicException(sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); } if ($argument->isRequired() && null !== $this->lastOptionalArgument) { - throw new LogicException(sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); } if ($argument->isArray()) { @@ -137,7 +137,7 @@ public function addArgument(InputArgument $argument) public function getArgument(string|int $name): InputArgument { if (!$this->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments; @@ -231,16 +231,16 @@ public function addOptions(array $options = []) public function addOption(InputOption $option) { if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); } if (isset($this->negations[$option->getName()])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); } if ($option->getShortcut()) { foreach (explode('|', $option->getShortcut()) as $shortcut) { if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) { - throw new LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut)); + throw new LogicException(\sprintf('An option with shortcut "%s" already exists.', $shortcut)); } } } @@ -255,7 +255,7 @@ public function addOption(InputOption $option) if ($option->isNegatable()) { $negatedName = 'no-'.$option->getName(); if (isset($this->options[$negatedName])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $negatedName)); + throw new LogicException(\sprintf('An option named "%s" already exists.', $negatedName)); } $this->negations[$negatedName] = $option->getName(); } @@ -269,7 +269,7 @@ public function addOption(InputOption $option) public function getOption(string $name): InputOption { if (!$this->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $name)); } return $this->options[$name]; @@ -343,7 +343,7 @@ public function getOptionDefaults(): array public function shortcutToName(string $shortcut): string { if (!isset($this->shortcuts[$shortcut])) { - throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new InvalidArgumentException(\sprintf('The "-%s" option does not exist.', $shortcut)); } return $this->shortcuts[$shortcut]; @@ -359,7 +359,7 @@ public function shortcutToName(string $shortcut): string public function negationToName(string $negation): string { if (!isset($this->negations[$negation])) { - throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $negation)); + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $negation)); } return $this->negations[$negation]; @@ -378,7 +378,7 @@ public function getSynopsis(bool $short = false): string foreach ($this->getOptions() as $option) { $value = ''; if ($option->acceptValue()) { - $value = sprintf( + $value = \sprintf( ' %s%s%s', $option->isValueOptional() ? '[' : '', strtoupper($option->getName()), @@ -386,9 +386,9 @@ public function getSynopsis(bool $short = false): string ); } - $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : ''; - $negation = $option->isNegatable() ? sprintf('|--no-%s', $option->getName()) : ''; - $elements[] = sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); + $shortcut = $option->getShortcut() ? \sprintf('-%s|', $option->getShortcut()) : ''; + $negation = $option->isNegatable() ? \sprintf('|--no-%s', $option->getName()) : ''; + $elements[] = \sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); } } diff --git a/symfony/console/Input/InputOption.php b/symfony/console/Input/InputOption.php index bb533801f..3adc8c424 100644 --- a/symfony/console/Input/InputOption.php +++ b/symfony/console/Input/InputOption.php @@ -53,7 +53,7 @@ class InputOption private string $name; private string|array|null $shortcut; private int $mode; - private string|int|bool|array|null|float $default; + private string|int|bool|array|float|null $default; private array|\Closure $suggestedValues; private string $description; @@ -95,7 +95,7 @@ public function __construct(string $name, string|array|null $shortcut = null, ?i if (null === $mode) { $mode = self::VALUE_NONE; } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) { - throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode)); + throw new InvalidArgumentException(\sprintf('Option mode "%s" is not valid.', $mode)); } $this->name = $name; @@ -231,7 +231,7 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti { $values = $this->suggestedValues; if ($values instanceof \Closure && !\is_array($values = $values($input))) { - throw new LogicException(sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); + throw new LogicException(\sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); } if ($values) { $suggestions->suggestValues($values); diff --git a/symfony/console/Input/StringInput.php b/symfony/console/Input/StringInput.php index 82bd21440..9b94784af 100644 --- a/symfony/console/Input/StringInput.php +++ b/symfony/console/Input/StringInput.php @@ -72,7 +72,7 @@ private function tokenize(string $input): array $token .= $match[1]; } else { // should never happen - throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10))); + throw new InvalidArgumentException(\sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10))); } $cursor += \strlen($match[0]); diff --git a/symfony/console/Logger/ConsoleLogger.php b/symfony/console/Logger/ConsoleLogger.php index fddef50cd..70432b7de 100644 --- a/symfony/console/Logger/ConsoleLogger.php +++ b/symfony/console/Logger/ConsoleLogger.php @@ -62,7 +62,7 @@ public function __construct(OutputInterface $output, array $verbosityLevelMap = public function log($level, $message, array $context = []): void { if (!isset($this->verbosityLevelMap[$level])) { - throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level)); + throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level)); } $output = $this->output; @@ -78,7 +78,7 @@ public function log($level, $message, array $context = []): void // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. // We only do it for efficiency here as the message formatting is relatively expensive. if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { - $output->writeln(sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); + $output->writeln(\sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); } } diff --git a/symfony/console/Messenger/RunCommandMessageHandler.php b/symfony/console/Messenger/RunCommandMessageHandler.php index 14f9c1764..3f4286542 100644 --- a/symfony/console/Messenger/RunCommandMessageHandler.php +++ b/symfony/console/Messenger/RunCommandMessageHandler.php @@ -16,6 +16,8 @@ use Symfony\Component\Console\Exception\RunCommandFailedException; use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\BufferedOutput; +use Symfony\Component\Messenger\Exception\RecoverableExceptionInterface; +use Symfony\Component\Messenger\Exception\UnrecoverableExceptionInterface; /** * @author Kevin Bond @@ -35,12 +37,14 @@ public function __invoke(RunCommandMessage $message): RunCommandContext try { $exitCode = $this->application->run($input, $output); + } catch (UnrecoverableExceptionInterface|RecoverableExceptionInterface $e) { + throw $e; } catch (\Throwable $e) { throw new RunCommandFailedException($e, new RunCommandContext($message, Command::FAILURE, $output->fetch())); } if ($message->throwOnFailure && Command::SUCCESS !== $exitCode) { - throw new RunCommandFailedException(sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); + throw new RunCommandFailedException(\sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); } return new RunCommandContext($message, $exitCode, $output->fetch()); diff --git a/symfony/console/Output/AnsiColorMode.php b/symfony/console/Output/AnsiColorMode.php index 5f9f744fe..dcdd1d5c4 100644 --- a/symfony/console/Output/AnsiColorMode.php +++ b/symfony/console/Output/AnsiColorMode.php @@ -51,7 +51,7 @@ public function convertFromHexToAnsiColorCode(string $hexColor): string } if (6 !== \strlen($hexColor)) { - throw new InvalidArgumentException(sprintf('Invalid "#%s" color.', $hexColor)); + throw new InvalidArgumentException(\sprintf('Invalid "#%s" color.', $hexColor)); } $color = hexdec($hexColor); @@ -63,7 +63,7 @@ public function convertFromHexToAnsiColorCode(string $hexColor): string return match ($this) { self::Ansi4 => (string) $this->convertFromRGB($r, $g, $b), self::Ansi8 => '8;5;'.((string) $this->convertFromRGB($r, $g, $b)), - self::Ansi24 => sprintf('8;2;%d;%d;%d', $r, $g, $b) + self::Ansi24 => \sprintf('8;2;%d;%d;%d', $r, $g, $b), }; } @@ -72,7 +72,7 @@ private function convertFromRGB(int $r, int $g, int $b): int return match ($this) { self::Ansi4 => $this->degradeHexColorToAnsi4($r, $g, $b), self::Ansi8 => $this->degradeHexColorToAnsi8($r, $g, $b), - default => throw new InvalidArgumentException("RGB cannot be converted to {$this->name}.") + default => throw new InvalidArgumentException("RGB cannot be converted to {$this->name}."), }; } diff --git a/symfony/console/Output/ConsoleSectionOutput.php b/symfony/console/Output/ConsoleSectionOutput.php index f2d7933bb..04d587cf2 100644 --- a/symfony/console/Output/ConsoleSectionOutput.php +++ b/symfony/console/Output/ConsoleSectionOutput.php @@ -229,7 +229,7 @@ private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFr if ($numberOfLinesToClear > 0) { // move cursor up n lines - parent::doWrite(sprintf("\x1b[%dA", $numberOfLinesToClear), false); + parent::doWrite(\sprintf("\x1b[%dA", $numberOfLinesToClear), false); // erase to end of screen parent::doWrite("\x1b[0J", false); } diff --git a/symfony/console/Output/TrimmedBufferOutput.php b/symfony/console/Output/TrimmedBufferOutput.php index 23a2be8c3..90ee45aae 100644 --- a/symfony/console/Output/TrimmedBufferOutput.php +++ b/symfony/console/Output/TrimmedBufferOutput.php @@ -27,7 +27,7 @@ class TrimmedBufferOutput extends Output public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null) { if ($maxLength <= 0) { - throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); + throw new InvalidArgumentException(\sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); } parent::__construct($verbosity, $decorated, $formatter); diff --git a/symfony/console/Question/ChoiceQuestion.php b/symfony/console/Question/ChoiceQuestion.php index 465f3184f..bcfe4dc45 100644 --- a/symfony/console/Question/ChoiceQuestion.php +++ b/symfony/console/Question/ChoiceQuestion.php @@ -26,9 +26,9 @@ class ChoiceQuestion extends Question private string $errorMessage = 'Value "%s" is invalid'; /** - * @param string $question The question to ask to the user - * @param array $choices The list of available choices - * @param string|bool|int|float|null $default The default answer to return + * @param string $question The question to ask to the user + * @param array $choices The list of available choices + * @param string|bool|int|float|null $default The default answer to return */ public function __construct(string $question, array $choices, string|bool|int|float|null $default = null) { @@ -44,7 +44,7 @@ public function __construct(string $question, array $choices, string|bool|int|fl } /** - * Returns available choices. + * @return array */ public function getChoices(): array { @@ -120,7 +120,7 @@ private function getDefaultValidator(): callable if ($multiselect) { // Check for a separated comma values if (!preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) { - throw new InvalidArgumentException(sprintf($errorMessage, $selected)); + throw new InvalidArgumentException(\sprintf($errorMessage, $selected)); } $selectedChoices = explode(',', (string) $selected); @@ -144,7 +144,7 @@ private function getDefaultValidator(): callable } if (\count($results) > 1) { - throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results))); + throw new InvalidArgumentException(\sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results))); } $result = array_search($value, $choices); @@ -160,7 +160,7 @@ private function getDefaultValidator(): callable } if (false === $result) { - throw new InvalidArgumentException(sprintf($errorMessage, $value)); + throw new InvalidArgumentException(\sprintf($errorMessage, $value)); } // For associative choices, consistently return the key as string: diff --git a/symfony/console/Question/Question.php b/symfony/console/Question/Question.php index 94c688fa8..ecbde56d5 100644 --- a/symfony/console/Question/Question.php +++ b/symfony/console/Question/Question.php @@ -27,7 +27,7 @@ class Question private bool $hiddenFallback = true; private ?\Closure $autocompleterCallback = null; private ?\Closure $validator = null; - private string|int|bool|null|float $default; + private string|int|bool|float|null $default; private ?\Closure $normalizer = null; private bool $trimmable = true; private bool $multiline = false; diff --git a/symfony/console/Resources/completion.bash b/symfony/console/Resources/completion.bash index 64c6a338f..2befe76cb 100644 --- a/symfony/console/Resources/completion.bash +++ b/symfony/console/Resources/completion.bash @@ -37,7 +37,7 @@ _sf_{{ COMMAND_NAME }}() { local completecmd=("$sf_cmd" "_complete" "--no-interaction" "-sbash" "-c$cword" "-a{{ VERSION }}") for w in ${words[@]}; do - w=$(printf -- '%b' "$w") + w="${w//\\\\/\\}" # remove quotes from typed values quote="${w:0:1}" if [ "$quote" == \' ]; then diff --git a/symfony/console/SignalRegistry/SignalMap.php b/symfony/console/SignalRegistry/SignalMap.php index de419bda7..2f9aa67c1 100644 --- a/symfony/console/SignalRegistry/SignalMap.php +++ b/symfony/console/SignalRegistry/SignalMap.php @@ -27,7 +27,7 @@ public static function getSignalName(int $signal): ?string if (!isset(self::$map)) { $r = new \ReflectionExtension('pcntl'); $c = $r->getConstants(); - $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_'), \ARRAY_FILTER_USE_KEY); + $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_') && 'SIGBABY' !== $k, \ARRAY_FILTER_USE_KEY); self::$map = array_flip($map); } diff --git a/symfony/console/SignalRegistry/SignalRegistry.php b/symfony/console/SignalRegistry/SignalRegistry.php index ef2e5f04e..ac8851b06 100644 --- a/symfony/console/SignalRegistry/SignalRegistry.php +++ b/symfony/console/SignalRegistry/SignalRegistry.php @@ -13,8 +13,21 @@ final class SignalRegistry { + /** + * @var array> + */ private array $signalHandlers = []; + /** + * @var array>> + */ + private array $stack = []; + + /** + * @var array + */ + private array $originalHandlers = []; + public function __construct() { if (\function_exists('pcntl_async_signals')) { @@ -24,17 +37,21 @@ public function __construct() public function register(int $signal, callable $signalHandler): void { - if (!isset($this->signalHandlers[$signal])) { - $previousCallback = pcntl_signal_get_handler($signal); + $previous = pcntl_signal_get_handler($signal); + + if (!isset($this->originalHandlers[$signal])) { + $this->originalHandlers[$signal] = $previous; + } - if (\is_callable($previousCallback)) { - $this->signalHandlers[$signal][] = $previousCallback; + if (!isset($this->signalHandlers[$signal])) { + if (\is_callable($previous) && [$this, 'handle'] !== $previous) { + $this->signalHandlers[$signal][] = $previous; } } $this->signalHandlers[$signal][] = $signalHandler; - pcntl_signal($signal, $this->handle(...)); + pcntl_signal($signal, [$this, 'handle']); } public static function isSupported(): bool @@ -54,4 +71,38 @@ public function handle(int $signal): void $signalHandler($signal, $hasNext); } } + + /** + * Pushes the current active handlers onto the stack and clears the active list. + * + * This prepares the registry for a new set of handlers within a specific scope. + * + * @internal + */ + public function pushCurrentHandlers(): void + { + $this->stack[] = $this->signalHandlers; + $this->signalHandlers = []; + } + + /** + * Restores the previous handlers from the stack, making them active. + * + * This also restores the original OS-level signal handler if no + * more handlers are registered for a signal that was just popped. + * + * @internal + */ + public function popPreviousHandlers(): void + { + $popped = $this->signalHandlers; + $this->signalHandlers = array_pop($this->stack) ?? []; + + // Restore OS handler if no more Symfony handlers for this signal + foreach ($popped as $signal => $handlers) { + if (!($this->signalHandlers[$signal] ?? false) && isset($this->originalHandlers[$signal])) { + pcntl_signal($signal, $this->originalHandlers[$signal]); + } + } + } } diff --git a/symfony/console/Style/SymfonyStyle.php b/symfony/console/Style/SymfonyStyle.php index 03bda8784..135f4fd0e 100644 --- a/symfony/console/Style/SymfonyStyle.php +++ b/symfony/console/Style/SymfonyStyle.php @@ -79,8 +79,8 @@ public function title(string $message) { $this->autoPrependBlock(); $this->writeln([ - sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), - sprintf('%s', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), + \sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), + \sprintf('%s', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), ]); $this->newLine(); } @@ -92,8 +92,8 @@ public function section(string $message) { $this->autoPrependBlock(); $this->writeln([ - sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), - sprintf('%s', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), + \sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), + \sprintf('%s', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), ]); $this->newLine(); } @@ -104,7 +104,7 @@ public function section(string $message) public function listing(array $elements) { $this->autoPrependText(); - $elements = array_map(fn ($element) => sprintf(' * %s', $element), $elements); + $elements = array_map(fn ($element) => \sprintf(' * %s', $element), $elements); $this->writeln($elements); $this->newLine(); @@ -119,7 +119,7 @@ public function text(string|array $message) $messages = \is_array($message) ? array_values($message) : [$message]; foreach ($messages as $message) { - $this->writeln(sprintf(' %s', $message)); + $this->writeln(\sprintf(' %s', $message)); } } @@ -463,7 +463,7 @@ private function createBlock(iterable $messages, ?string $type = null, ?string $ $lines = []; if (null !== $type) { - $type = sprintf('[%s] ', $type); + $type = \sprintf('[%s] ', $type); $indentLength = Helper::width($type); $lineIndentation = str_repeat(' ', $indentLength); } @@ -505,7 +505,7 @@ private function createBlock(iterable $messages, ?string $type = null, ?string $ $line .= str_repeat(' ', max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0)); if ($style) { - $line = sprintf('<%s>%s', $style, $line); + $line = \sprintf('<%s>%s', $style, $line); } } diff --git a/symfony/console/Tester/Constraint/CommandIsSuccessful.php b/symfony/console/Tester/Constraint/CommandIsSuccessful.php index 09c6194b9..d677c27aa 100644 --- a/symfony/console/Tester/Constraint/CommandIsSuccessful.php +++ b/symfony/console/Tester/Constraint/CommandIsSuccessful.php @@ -38,6 +38,6 @@ protected function additionalFailureDescription($other): string Command::INVALID => 'Command was invalid.', ]; - return $mapping[$other] ?? sprintf('Command returned exit status %d.', $other); + return $mapping[$other] ?? \sprintf('Command returned exit status %d.', $other); } } diff --git a/symfony/console/Tester/TesterTrait.php b/symfony/console/Tester/TesterTrait.php index 1ab7a70aa..238c7b7eb 100644 --- a/symfony/console/Tester/TesterTrait.php +++ b/symfony/console/Tester/TesterTrait.php @@ -168,7 +168,11 @@ private static function createStream(array $inputs) $stream = fopen('php://memory', 'r+', false); foreach ($inputs as $input) { - fwrite($stream, $input.\PHP_EOL); + fwrite($stream, $input); + + if (!str_ends_with($input, "\x4")) { + fwrite($stream, \PHP_EOL); + } } rewind($stream); diff --git a/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php b/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php index 5ba83dad4..2faea0463 100644 --- a/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php +++ b/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php @@ -127,7 +127,7 @@ public function dispatch(object $event, ?string $eventName = null): object $currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : ''; if (null !== $this->logger && $event instanceof StoppableEventInterface && $event->isPropagationStopped()) { - $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName)); + $this->logger->debug(\sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName)); } $this->preProcess($eventName); @@ -279,7 +279,7 @@ private function preProcess(string $eventName): void $this->wrappedListeners[$eventName][] = $wrappedListener; $this->dispatcher->removeListener($eventName, $listener); $this->dispatcher->addListener($eventName, $wrappedListener, $priority); - $this->callStack->attach($wrappedListener, [$eventName, $this->currentRequestHash]); + $this->callStack[$wrappedListener] = [$eventName, $this->currentRequestHash]; } } @@ -303,7 +303,7 @@ private function postProcess(string $eventName): void if ($listener->wasCalled()) { $this->logger?->debug('Notified event "{event}" to listener "{listener}".', $context); } else { - $this->callStack->detach($listener); + unset($this->callStack[$listener]); } if (null !== $this->logger && $skipped) { diff --git a/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php b/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php index 866f4e64f..db119bb2f 100644 --- a/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php +++ b/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php @@ -91,7 +91,7 @@ public function process(ContainerBuilder $container) if (null !== ($class = $container->getDefinition($id)->getClass()) && ($r = $container->getReflectionClass($class, false)) && !$r->hasMethod($event['method'])) { if (!$r->hasMethod('__invoke')) { - throw new InvalidArgumentException(sprintf('None of the "%s" or "__invoke" methods exist for the service "%s". Please define the "method" attribute on "kernel.event_listener" tags.', $event['method'], $id)); + throw new InvalidArgumentException(\sprintf('None of the "%s" or "__invoke" methods exist for the service "%s". Please define the "method" attribute on "kernel.event_listener" tags.', $event['method'], $id)); } $event['method'] = '__invoke'; @@ -126,10 +126,10 @@ public function process(ContainerBuilder $container) $class = $def->getClass(); if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(EventSubscriberInterface::class)) { - throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EventSubscriberInterface::class)); + throw new InvalidArgumentException(\sprintf('Service "%s" must implement interface "%s".', $id, EventSubscriberInterface::class)); } $class = $r->name; @@ -181,7 +181,7 @@ private function getEventFromTypeDeclaration(ContainerBuilder $container, string || $type->isBuiltin() || Event::class === ($name = $type->getName()) ) { - throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "kernel.event_listener" tags.', $id)); + throw new InvalidArgumentException(\sprintf('Service "%s" must define the "event" attribute on "kernel.event_listener" tags.', $id)); } return $name; diff --git a/symfony/event-dispatcher/GenericEvent.php b/symfony/event-dispatcher/GenericEvent.php index 0ccbbd810..3bfeca045 100644 --- a/symfony/event-dispatcher/GenericEvent.php +++ b/symfony/event-dispatcher/GenericEvent.php @@ -59,7 +59,7 @@ public function getArgument(string $key): mixed return $this->arguments[$key]; } - throw new \InvalidArgumentException(sprintf('Argument "%s" not found.', $key)); + throw new \InvalidArgumentException(\sprintf('Argument "%s" not found.', $key)); } /** diff --git a/symfony/http-foundation/AcceptHeader.php b/symfony/http-foundation/AcceptHeader.php index 853c000e0..e735c7564 100644 --- a/symfony/http-foundation/AcceptHeader.php +++ b/symfony/http-foundation/AcceptHeader.php @@ -25,7 +25,7 @@ class_exists(AcceptHeaderItem::class); class AcceptHeader { /** - * @var AcceptHeaderItem[] + * @var array */ private array $items = []; @@ -46,18 +46,15 @@ public function __construct(array $items) */ public static function fromString(?string $headerValue): self { - $parts = HeaderUtils::split($headerValue ?? '', ',;='); + $items = []; + foreach (HeaderUtils::split($headerValue ?? '', ',;=') as $i => $parts) { + $part = array_shift($parts); + $item = new AcceptHeaderItem($part[0], HeaderUtils::combine($parts)); - return new self(array_map(function ($subParts) { - static $index = 0; - $part = array_shift($subParts); - $attributes = HeaderUtils::combine($subParts); - - $item = new AcceptHeaderItem($part[0], $attributes); - $item->setIndex($index++); + $items[] = $item->setIndex($i); + } - return $item; - }, $parts)); + return new self($items); } /** @@ -73,7 +70,9 @@ public function __toString(): string */ public function has(string $value): bool { - return isset($this->items[$value]); + $canonicalKey = $this->getCanonicalKey(AcceptHeaderItem::fromString($value)); + + return isset($this->items[$canonicalKey]); } /** @@ -81,7 +80,26 @@ public function has(string $value): bool */ public function get(string $value): ?AcceptHeaderItem { - return $this->items[$value] ?? $this->items[explode('/', $value)[0].'/*'] ?? $this->items['*/*'] ?? $this->items['*'] ?? null; + $queryItem = AcceptHeaderItem::fromString($value.';q=1'); + $canonicalKey = $this->getCanonicalKey($queryItem); + + if (isset($this->items[$canonicalKey])) { + return $this->items[$canonicalKey]; + } + + // Collect and filter matching candidates + if (!$candidates = array_filter($this->items, fn (AcceptHeaderItem $item) => $this->matches($item, $queryItem))) { + return null; + } + + usort( + $candidates, + fn ($a, $b) => $this->getSpecificity($b, $queryItem) <=> $this->getSpecificity($a, $queryItem) // Descending specificity + ?: $b->getQuality() <=> $a->getQuality() // Descending quality + ?: $a->getIndex() <=> $b->getIndex() // Ascending index (stability) + ); + + return reset($candidates); } /** @@ -91,7 +109,7 @@ public function get(string $value): ?AcceptHeaderItem */ public function add(AcceptHeaderItem $item): static { - $this->items[$item->getValue()] = $item; + $this->items[$this->getCanonicalKey($item)] = $item; $this->sorted = false; return $this; @@ -114,7 +132,7 @@ public function all(): array */ public function filter(string $pattern): self { - return new self(array_filter($this->items, fn (AcceptHeaderItem $item) => preg_match($pattern, $item->getValue()))); + return new self(array_filter($this->items, static fn ($item) => preg_match($pattern, $item->getValue()))); } /** @@ -133,18 +151,154 @@ public function first(): ?AcceptHeaderItem private function sort(): void { if (!$this->sorted) { - uasort($this->items, function (AcceptHeaderItem $a, AcceptHeaderItem $b) { - $qA = $a->getQuality(); - $qB = $b->getQuality(); + uasort($this->items, static fn ($a, $b) => $b->getQuality() <=> $a->getQuality() ?: $a->getIndex() <=> $b->getIndex()); - if ($qA === $qB) { - return $a->getIndex() > $b->getIndex() ? 1 : -1; - } + $this->sorted = true; + } + } - return $qA > $qB ? -1 : 1; - }); + /** + * Generates the canonical key for storing/retrieving an item. + */ + private function getCanonicalKey(AcceptHeaderItem $item): string + { + $parts = []; - $this->sorted = true; + // Normalize and sort attributes for consistent key generation + $attributes = $this->getMediaParams($item); + ksort($attributes); + + foreach ($attributes as $name => $value) { + if (null === $value) { + $parts[] = $name; // Flag parameter (e.g., "flowed") + continue; + } + + // Quote values containing spaces, commas, semicolons, or equals per RFC 9110 + // This handles cases like 'format="value with space"' or similar. + $quotedValue = \is_string($value) && preg_match('/[\s;,=]/', $value) ? '"'.addcslashes($value, '"\\').'"' : $value; + + $parts[] = $name.'='.$quotedValue; + } + + return $item->getValue().($parts ? ';'.implode(';', $parts) : ''); + } + + /** + * Checks if a given header item (range) matches a queried item (value). + * + * @param AcceptHeaderItem $rangeItem The item from the Accept header (e.g., text/*;format=flowed) + * @param AcceptHeaderItem $queryItem The item being queried (e.g., text/plain;format=flowed;charset=utf-8) + */ + private function matches(AcceptHeaderItem $rangeItem, AcceptHeaderItem $queryItem): bool + { + $rangeValue = strtolower($rangeItem->getValue()); + $queryValue = strtolower($queryItem->getValue()); + + // Handle universal wildcard ranges + if ('*' === $rangeValue || '*/*' === $rangeValue) { + return $this->rangeParametersMatch($rangeItem, $queryItem); + } + + // Queries for '*' only match wildcard ranges (handled above) + if ('*' === $queryValue) { + return false; } + + // Ensure media vs. non-media consistency + $isQueryMedia = str_contains($queryValue, '/'); + $isRangeMedia = str_contains($rangeValue, '/'); + + if ($isQueryMedia !== $isRangeMedia) { + return false; + } + + // Non-media: exact match only (wildcards handled above) + if (!$isQueryMedia) { + return $rangeValue === $queryValue && $this->rangeParametersMatch($rangeItem, $queryItem); + } + + // Media type: type/subtype with wildcards + [$queryType, $querySubtype] = explode('/', $queryValue, 2); + [$rangeType, $rangeSubtype] = explode('/', $rangeValue, 2) + [1 => '*']; + + if ('*' !== $rangeType && $rangeType !== $queryType) { + return false; + } + + if ('*' !== $rangeSubtype && $rangeSubtype !== $querySubtype) { + return false; + } + + // Parameters must match + return $this->rangeParametersMatch($rangeItem, $queryItem); + } + + /** + * Checks if the parameters of a range item are satisfied by the query item. + * + * Parameters are case-insensitive; range params must be a subset of query params. + */ + private function rangeParametersMatch(AcceptHeaderItem $rangeItem, AcceptHeaderItem $queryItem): bool + { + $queryAttributes = $this->getMediaParams($queryItem); + $rangeAttributes = $this->getMediaParams($rangeItem); + + foreach ($rangeAttributes as $name => $rangeValue) { + if (!\array_key_exists($name, $queryAttributes)) { + return false; // Missing required param + } + + $queryValue = $queryAttributes[$name]; + + if (null === $rangeValue) { + return null === $queryValue; // Both flags or neither + } + + if (null === $queryValue || strtolower($queryValue) !== strtolower($rangeValue)) { + return false; + } + } + + return true; + } + + /** + * Calculates a specificity score for sorting: media precision + param count. + */ + private function getSpecificity(AcceptHeaderItem $item, AcceptHeaderItem $queryItem): int + { + $rangeValue = strtolower($item->getValue()); + $queryValue = strtolower($queryItem->getValue()); + + $paramCount = \count($this->getMediaParams($item)); + + $isQueryMedia = str_contains($queryValue, '/'); + $isRangeMedia = str_contains($rangeValue, '/'); + + if (!$isQueryMedia && !$isRangeMedia) { + return ('*' !== $rangeValue ? 2000 : 1000) + $paramCount; + } + + [$rangeType, $rangeSubtype] = explode('/', $rangeValue, 2) + [1 => '*']; + + $specificity = match (true) { + '*' !== $rangeSubtype => 3000, // Exact subtype (text/plain) + '*' !== $rangeType => 2000, // Type wildcard (text/*) + default => 1000, // Full wildcard (*/* or *) + }; + + return $specificity + $paramCount; + } + + /** + * Returns normalized attributes: keys lowercased, excluding 'q'. + */ + private function getMediaParams(AcceptHeaderItem $item): array + { + $attributes = array_change_key_case($item->getAttributes(), \CASE_LOWER); + unset($attributes['q']); + + return $attributes; } } diff --git a/symfony/http-foundation/Request.php b/symfony/http-foundation/Request.php index a66312c8e..8a497a77c 100644 --- a/symfony/http-foundation/Request.php +++ b/symfony/http-foundation/Request.php @@ -857,7 +857,7 @@ public function getScriptName(): string * * Suppose this request is instantiated from /mysite on localhost: * - * * http://localhost/mysite returns an empty string + * * http://localhost/mysite returns '/' * * http://localhost/mysite/about returns '/about' * * http://localhost/mysite/enco%20ded returns '/enco%20ded' * * http://localhost/mysite/about?var=1 returns '/about' diff --git a/symfony/mailer/Command/MailerTestCommand.php b/symfony/mailer/Command/MailerTestCommand.php index bfc2779e3..8e00f6298 100644 --- a/symfony/mailer/Command/MailerTestCommand.php +++ b/symfony/mailer/Command/MailerTestCommand.php @@ -28,8 +28,6 @@ final class MailerTestCommand extends Command { public function __construct(private TransportInterface $transport) { - $this->transport = $transport; - parent::__construct(); } @@ -37,10 +35,10 @@ protected function configure(): void { $this ->addArgument('to', InputArgument::REQUIRED, 'The recipient of the message') - ->addOption('from', null, InputOption::VALUE_OPTIONAL, 'The sender of the message', 'from@example.org') - ->addOption('subject', null, InputOption::VALUE_OPTIONAL, 'The subject of the message', 'Testing transport') - ->addOption('body', null, InputOption::VALUE_OPTIONAL, 'The body of the message', 'Testing body') - ->addOption('transport', null, InputOption::VALUE_OPTIONAL, 'The transport to be used') + ->addOption('from', null, InputOption::VALUE_REQUIRED, 'The sender of the message', 'from@example.org') + ->addOption('subject', null, InputOption::VALUE_REQUIRED, 'The subject of the message', 'Testing transport') + ->addOption('body', null, InputOption::VALUE_REQUIRED, 'The body of the message', 'Testing body') + ->addOption('transport', null, InputOption::VALUE_REQUIRED, 'The transport to be used') ->setHelp(<<<'EOF' The %command.name% command tests a Mailer transport by sending a simple email message: diff --git a/symfony/mailer/Envelope.php b/symfony/mailer/Envelope.php index 0a4af2eda..45e1db363 100644 --- a/symfony/mailer/Envelope.php +++ b/symfony/mailer/Envelope.php @@ -46,7 +46,7 @@ public function setSender(Address $sender): void { // to ensure deliverability of bounce emails independent of UTF-8 capabilities of SMTP servers if (!preg_match('/^[^@\x80-\xFF]++@/', $sender->getAddress())) { - throw new InvalidArgumentException(sprintf('Invalid sender "%s": non-ASCII characters not supported in local-part of email.', $sender->getAddress())); + throw new InvalidArgumentException(\sprintf('Invalid sender "%s": non-ASCII characters not supported in local-part of email.', $sender->getAddress())); } $this->sender = $sender; } @@ -72,7 +72,7 @@ public function setRecipients(array $recipients): void $this->recipients = []; foreach ($recipients as $recipient) { if (!$recipient instanceof Address) { - throw new InvalidArgumentException(sprintf('A recipient must be an instance of "%s" (got "%s").', Address::class, get_debug_type($recipient))); + throw new InvalidArgumentException(\sprintf('A recipient must be an instance of "%s" (got "%s").', Address::class, get_debug_type($recipient))); } $this->recipients[] = new Address($recipient->getAddress()); } diff --git a/symfony/mailer/Event/MessageEvent.php b/symfony/mailer/Event/MessageEvent.php index f00fdd52c..7f466451a 100644 --- a/symfony/mailer/Event/MessageEvent.php +++ b/symfony/mailer/Event/MessageEvent.php @@ -85,7 +85,7 @@ public function reject(): void public function addStamp(StampInterface $stamp): void { if (!$this->queued) { - throw new LogicException(sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__)); + throw new LogicException(\sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__)); } $this->stamps[] = $stamp; @@ -97,7 +97,7 @@ public function addStamp(StampInterface $stamp): void public function getStamps(): array { if (!$this->queued) { - throw new LogicException(sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__)); + throw new LogicException(\sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__)); } return $this->stamps; diff --git a/symfony/mailer/EventListener/MessageListener.php b/symfony/mailer/EventListener/MessageListener.php index ec822d9c6..2d370b7e9 100644 --- a/symfony/mailer/EventListener/MessageListener.php +++ b/symfony/mailer/EventListener/MessageListener.php @@ -55,7 +55,7 @@ public function __construct(?Headers $headers = null, ?BodyRendererInterface $re public function addHeaderRule(string $headerName, int $rule): void { if ($rule < 1 || $rule > 3) { - throw new InvalidArgumentException(sprintf('The "%d" rule is not supported.', $rule)); + throw new InvalidArgumentException(\sprintf('The "%d" rule is not supported.', $rule)); } $this->headerRules[strtolower($headerName)] = $rule; @@ -105,7 +105,7 @@ private function setHeaders(Message $message): void $h = $headers->get($name); if (!$h instanceof MailboxListHeader) { - throw new RuntimeException(sprintf('Unable to set header "%s".', $name)); + throw new RuntimeException(\sprintf('Unable to set header "%s".', $name)); } Headers::checkHeaderClass($header); diff --git a/symfony/mailer/Exception/UnsupportedSchemeException.php b/symfony/mailer/Exception/UnsupportedSchemeException.php index 257fd47db..eacad1010 100644 --- a/symfony/mailer/Exception/UnsupportedSchemeException.php +++ b/symfony/mailer/Exception/UnsupportedSchemeException.php @@ -86,14 +86,14 @@ public function __construct(Dsn $dsn, ?string $name = null, array $supported = [ } $package = self::SCHEME_TO_PACKAGE_MAP[$provider] ?? null; if ($package && !class_exists($package['class'])) { - parent::__construct(sprintf('Unable to send emails via "%s" as the bridge is not installed. Try running "composer require %s".', $provider, $package['package'])); + parent::__construct(\sprintf('Unable to send emails via "%s" as the bridge is not installed. Try running "composer require %s".', $provider, $package['package'])); return; } - $message = sprintf('The "%s" scheme is not supported', $dsn->getScheme()); + $message = \sprintf('The "%s" scheme is not supported', $dsn->getScheme()); if ($name && $supported) { - $message .= sprintf('; supported schemes for mailer "%s" are: "%s"', $name, implode('", "', $supported)); + $message .= \sprintf('; supported schemes for mailer "%s" are: "%s"', $name, implode('", "', $supported)); } parent::__construct($message.'.'); diff --git a/symfony/mailer/Transport.php b/symfony/mailer/Transport.php index 599f4fbce..945b70db0 100644 --- a/symfony/mailer/Transport.php +++ b/symfony/mailer/Transport.php @@ -144,7 +144,7 @@ private function parseDsn(#[\SensitiveParameter] string $dsn, int $offset = 0): } if (preg_match('{(\w+)\(}A', $dsn, $matches, 0, $offset)) { - throw new InvalidArgumentException(sprintf('The "%s" keyword is not valid (valid ones are "%s"), ', $matches[1], implode('", "', array_keys($keywords)))); + throw new InvalidArgumentException(\sprintf('The "%s" keyword is not valid (valid ones are "%s"), ', $matches[1], implode('", "', array_keys($keywords)))); } if ($pos = strcspn($dsn, ' )', $offset)) { diff --git a/symfony/mailer/Transport/AbstractApiTransport.php b/symfony/mailer/Transport/AbstractApiTransport.php index 040745eed..6bd49e124 100644 --- a/symfony/mailer/Transport/AbstractApiTransport.php +++ b/symfony/mailer/Transport/AbstractApiTransport.php @@ -31,7 +31,7 @@ protected function doSendHttp(SentMessage $message): ResponseInterface try { $email = MessageConverter::toEmail($message->getOriginalMessage()); } catch (\Exception $e) { - throw new RuntimeException(sprintf('Unable to send message with the "%s" transport: ', __CLASS__).$e->getMessage(), 0, $e); + throw new RuntimeException(\sprintf('Unable to send message with the "%s" transport: ', __CLASS__).$e->getMessage(), 0, $e); } return $this->doSendApi($message, $email, $message->getEnvelope()); diff --git a/symfony/mailer/Transport/AbstractHttpTransport.php b/symfony/mailer/Transport/AbstractHttpTransport.php index 96b7ec009..ce0feecf0 100644 --- a/symfony/mailer/Transport/AbstractHttpTransport.php +++ b/symfony/mailer/Transport/AbstractHttpTransport.php @@ -33,7 +33,7 @@ public function __construct(?HttpClientInterface $client = null, ?EventDispatche $this->client = $client; if (null === $client) { if (!class_exists(HttpClient::class)) { - throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); + throw new \LogicException(\sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); } $this->client = HttpClient::create(); diff --git a/symfony/mailer/Transport/AbstractTransport.php b/symfony/mailer/Transport/AbstractTransport.php index 9a1cd6859..cff690623 100644 --- a/symfony/mailer/Transport/AbstractTransport.php +++ b/symfony/mailer/Transport/AbstractTransport.php @@ -81,7 +81,7 @@ public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMess $message = $event->getMessage(); if ($message instanceof TemplatedEmail && !$message->isRendered()) { - throw new LogicException(sprintf('You must configure a "%s" when a "%s" instance has a text or HTML template set.', BodyRendererInterface::class, get_debug_type($message))); + throw new LogicException(\sprintf('You must configure a "%s" when a "%s" instance has a text or HTML template set.', BodyRendererInterface::class, get_debug_type($message))); } $sentMessage = new SentMessage($message, $envelope); @@ -128,7 +128,7 @@ private function checkThrottling(): void $sleep = (1 / $this->rate) - (microtime(true) - $this->lastSent); if (0 < $sleep) { - $this->logger->debug(sprintf('Email transport "%s" sleeps for %.2f seconds', __CLASS__, $sleep)); + $this->logger->debug(\sprintf('Email transport "%s" sleeps for %.2f seconds', __CLASS__, $sleep)); usleep((int) ($sleep * 1000000)); } $this->lastSent = microtime(true); diff --git a/symfony/mailer/Transport/RoundRobinTransport.php b/symfony/mailer/Transport/RoundRobinTransport.php index ac9709bf7..25656396c 100644 --- a/symfony/mailer/Transport/RoundRobinTransport.php +++ b/symfony/mailer/Transport/RoundRobinTransport.php @@ -38,7 +38,7 @@ class RoundRobinTransport implements TransportInterface public function __construct(array $transports, int $retryPeriod = 60) { if (!$transports) { - throw new TransportException(sprintf('"%s" must have at least one transport configured.', static::class)); + throw new TransportException(\sprintf('"%s" must have at least one transport configured.', static::class)); } $this->transports = $transports; @@ -52,10 +52,10 @@ public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMess while ($transport = $this->getNextTransport()) { try { - return $transport->send($message, $envelope); + return $transport->send(clone $message, $envelope); } catch (TransportExceptionInterface $e) { $exception ??= new TransportException('All transports failed.'); - $exception->appendDebug(sprintf("Transport \"%s\": %s\n", $transport, $e->getDebug())); + $exception->appendDebug(\sprintf("Transport \"%s\": %s\n", $transport, $e->getDebug())); $this->deadTransports[$transport] = microtime(true); } } @@ -86,7 +86,7 @@ protected function getNextTransport(): ?TransportInterface } if ((microtime(true) - $this->deadTransports[$transport]) > $this->retryPeriod) { - $this->deadTransports->detach($transport); + unset($this->deadTransports[$transport]); break; } @@ -103,7 +103,7 @@ protected function getNextTransport(): ?TransportInterface protected function isTransportDead(TransportInterface $transport): bool { - return $this->deadTransports->contains($transport); + return $this->deadTransports->offsetExists($transport); } protected function getInitialCursor(): int diff --git a/symfony/mailer/Transport/SendmailTransport.php b/symfony/mailer/Transport/SendmailTransport.php index 774c0e563..45cf503e1 100644 --- a/symfony/mailer/Transport/SendmailTransport.php +++ b/symfony/mailer/Transport/SendmailTransport.php @@ -55,7 +55,7 @@ public function __construct(?string $command = null, ?EventDispatcherInterface $ if (null !== $command) { if (!str_contains($command, ' -bs') && !str_contains($command, ' -t')) { - throw new \InvalidArgumentException(sprintf('Unsupported sendmail command flags "%s"; must be one of "-bs" or "-t" but can include additional flags.', $command)); + throw new \InvalidArgumentException(\sprintf('Unsupported sendmail command flags "%s"; must be one of "-bs" or "-t" but can include additional flags.', $command)); } $this->command = $command; @@ -89,7 +89,7 @@ public function __toString(): string protected function doSend(SentMessage $message): void { - $this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__)); + $this->getLogger()->debug(\sprintf('Email transport "%s" starting', __CLASS__)); $command = $this->command; @@ -119,6 +119,6 @@ protected function doSend(SentMessage $message): void $this->stream->flush(); $this->stream->terminate(); - $this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__)); + $this->getLogger()->debug(\sprintf('Email transport "%s" stopped', __CLASS__)); } } diff --git a/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php b/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php index 79cddc469..119051938 100644 --- a/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php +++ b/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php @@ -34,7 +34,7 @@ public function authenticate(EsmtpTransport $client): void $challenge = $client->executeCommand("AUTH CRAM-MD5\r\n", [334]); $challenge = base64_decode(substr($challenge, 4)); $message = base64_encode($client->getUsername().' '.$this->getResponse($client->getPassword(), $challenge)); - $client->executeCommand(sprintf("%s\r\n", $message), [235]); + $client->executeCommand(\sprintf("%s\r\n", $message), [235]); } /** diff --git a/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php b/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php index e0b7d577e..82fe45366 100644 --- a/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php +++ b/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php @@ -31,7 +31,7 @@ public function getAuthKeyword(): string public function authenticate(EsmtpTransport $client): void { $client->executeCommand("AUTH LOGIN\r\n", [334]); - $client->executeCommand(sprintf("%s\r\n", base64_encode($client->getUsername())), [334]); - $client->executeCommand(sprintf("%s\r\n", base64_encode($client->getPassword())), [235]); + $client->executeCommand(\sprintf("%s\r\n", base64_encode($client->getUsername())), [334]); + $client->executeCommand(\sprintf("%s\r\n", base64_encode($client->getPassword())), [235]); } } diff --git a/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php b/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php index 6b680b511..7a6fefa15 100644 --- a/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php +++ b/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php @@ -30,6 +30,6 @@ public function getAuthKeyword(): string */ public function authenticate(EsmtpTransport $client): void { - $client->executeCommand(sprintf("AUTH PLAIN %s\r\n", base64_encode($client->getUsername().\chr(0).$client->getUsername().\chr(0).$client->getPassword())), [235]); + $client->executeCommand(\sprintf("AUTH PLAIN %s\r\n", base64_encode($client->getUsername().\chr(0).$client->getUsername().\chr(0).$client->getPassword())), [235]); } } diff --git a/symfony/mailer/Transport/Smtp/EsmtpTransport.php b/symfony/mailer/Transport/Smtp/EsmtpTransport.php index f5edfe112..05ca155cd 100644 --- a/symfony/mailer/Transport/Smtp/EsmtpTransport.php +++ b/symfony/mailer/Transport/Smtp/EsmtpTransport.php @@ -126,10 +126,10 @@ final protected function getCapabilities(): array private function doEhloCommand(): string { try { - $response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]); + $response = $this->executeCommand(\sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]); } catch (TransportExceptionInterface $e) { try { - return parent::executeCommand(sprintf("HELO %s\r\n", $this->getLocalDomain()), [250]); + return parent::executeCommand(\sprintf("HELO %s\r\n", $this->getLocalDomain()), [250]); } catch (TransportExceptionInterface $ex) { if (!$ex->getCode()) { throw $e; @@ -153,7 +153,7 @@ private function doEhloCommand(): string throw new TransportException('Unable to connect with STARTTLS.'); } - $response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]); + $response = $this->executeCommand(\sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]); $this->capabilities = $this->parseCapabilities($response); } @@ -215,12 +215,12 @@ private function handleAuth(array $modes): void } if (!$authNames) { - throw new TransportException(sprintf('Failed to find an authenticator supported by the SMTP server, which currently supports: "%s".', implode('", "', $modes)), $code ?: 504); + throw new TransportException(\sprintf('Failed to find an authenticator supported by the SMTP server, which currently supports: "%s".', implode('", "', $modes)), $code ?: 504); } - $message = sprintf('Failed to authenticate on SMTP server with username "%s" using the following authenticators: "%s".', $this->username, implode('", "', $authNames)); + $message = \sprintf('Failed to authenticate on SMTP server with username "%s" using the following authenticators: "%s".', $this->username, implode('", "', $authNames)); foreach ($errors as $name => $error) { - $message .= sprintf(' Authenticator "%s" returned "%s".', $name, $error); + $message .= \sprintf(' Authenticator "%s" returned "%s".', $name, $error); } throw new TransportException($message, $code ?: 535); diff --git a/symfony/mailer/Transport/Smtp/SmtpTransport.php b/symfony/mailer/Transport/Smtp/SmtpTransport.php index 7de2f91cb..2570e3fc2 100644 --- a/symfony/mailer/Transport/Smtp/SmtpTransport.php +++ b/symfony/mailer/Transport/Smtp/SmtpTransport.php @@ -154,24 +154,13 @@ public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMess protected function parseMessageId(string $mtaResult): string { - $regexps = [ - '/250 Ok (?P[0-9a-f-]+)\r?$/mis', - '/250 Ok:? queued as (?P[A-Z0-9]+)\r?$/mis', - ]; - $matches = []; - foreach ($regexps as $regexp) { - if (preg_match($regexp, $mtaResult, $matches)) { - return $matches['id']; - } - } - - return ''; + return preg_match('/^250 (?:\S+ )?Ok:?+ (?:queued as |id=)?+(?P[A-Z0-9._-]++)/im', $mtaResult, $matches) ? $matches['id'] : ''; } public function __toString(): string { if ($this->stream instanceof SocketStream) { - $name = sprintf('smtp%s://%s', ($tls = $this->stream->isTLS()) ? 's' : '', $this->stream->getHost()); + $name = \sprintf('smtp%s://%s', ($tls = $this->stream->isTLS()) ? 's' : '', $this->stream->getHost()); $port = $this->stream->getPort(); if (!(25 === $port || ($tls && 465 === $port))) { $name .= ':'.$port; @@ -227,7 +216,7 @@ protected function doSend(SentMessage $message): void } catch (\Exception $e) { $this->stream->terminate(); $this->started = false; - $this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__)); + $this->getLogger()->debug(\sprintf('Email transport "%s" stopped', __CLASS__)); throw $e; } $mtaResult = $this->executeCommand("\r\n.\r\n", [250]); @@ -251,17 +240,17 @@ protected function doSend(SentMessage $message): void */ protected function doHeloCommand(): void { - $this->executeCommand(sprintf("HELO %s\r\n", $this->domain), [250]); + $this->executeCommand(\sprintf("HELO %s\r\n", $this->domain), [250]); } private function doMailFromCommand(string $address): void { - $this->executeCommand(sprintf("MAIL FROM:<%s>\r\n", $address), [250]); + $this->executeCommand(\sprintf("MAIL FROM:<%s>\r\n", $address), [250]); } private function doRcptToCommand(string $address): void { - $this->executeCommand(sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252]); + $this->executeCommand(\sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252]); } public function start(): void @@ -270,7 +259,7 @@ public function start(): void return; } - $this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__)); + $this->getLogger()->debug(\sprintf('Email transport "%s" starting', __CLASS__)); $this->stream->initialize(); $this->assertResponseCode($this->getFullResponse(), [220]); @@ -278,7 +267,7 @@ public function start(): void $this->started = true; $this->lastMessageTime = 0; - $this->getLogger()->debug(sprintf('Email transport "%s" started', __CLASS__)); + $this->getLogger()->debug(\sprintf('Email transport "%s" started', __CLASS__)); } /** @@ -294,7 +283,7 @@ public function stop(): void return; } - $this->getLogger()->debug(sprintf('Email transport "%s" stopping', __CLASS__)); + $this->getLogger()->debug(\sprintf('Email transport "%s" stopping', __CLASS__)); try { $this->executeCommand("QUIT\r\n", [221]); @@ -302,7 +291,7 @@ public function stop(): void } finally { $this->stream->terminate(); $this->started = false; - $this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__)); + $this->getLogger()->debug(\sprintf('Email transport "%s" stopped', __CLASS__)); } } @@ -332,10 +321,10 @@ private function assertResponseCode(string $response, array $codes): void $valid = \in_array($code, $codes); if (!$valid || !$response) { - $codeStr = $code ? sprintf('code "%s"', $code) : 'empty code'; - $responseStr = $response ? sprintf(', with message "%s"', trim($response)) : ''; + $codeStr = $code ? \sprintf('code "%s"', $code) : 'empty code'; + $responseStr = $response ? \sprintf(', with message "%s"', trim($response)) : ''; - throw new UnexpectedResponseException(sprintf('Expected response code "%s" but got ', implode('/', $codes)).$codeStr.$responseStr.'.', $code ?: 0); + throw new UnexpectedResponseException(\sprintf('Expected response code "%s" but got ', implode('/', $codes)).$codeStr.$responseStr.'.', $code ?: 0); } } @@ -364,7 +353,7 @@ private function checkRestartThreshold(): void $this->stop(); if (0 < $sleep = $this->restartThresholdSleep) { - $this->getLogger()->debug(sprintf('Email transport "%s" sleeps for %d seconds after stopping', __CLASS__, $sleep)); + $this->getLogger()->debug(\sprintf('Email transport "%s" sleeps for %d seconds after stopping', __CLASS__, $sleep)); sleep($sleep); } @@ -372,15 +361,12 @@ private function checkRestartThreshold(): void $this->restartCounter = 0; } - public function __sleep(): array + public function __serialize(): array { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - /** - * @return void - */ - public function __wakeup() + public function __unserialize(array $data): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } diff --git a/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php b/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php index 55a2594ac..8363063a9 100644 --- a/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php +++ b/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php @@ -38,7 +38,7 @@ public function write(string $bytes, bool $debug = true): void { if ($debug) { foreach (explode("\n", trim($bytes)) as $line) { - $this->debug .= sprintf("> %s\n", $line); + $this->debug .= \sprintf("> %s\n", $line); } } @@ -81,17 +81,17 @@ public function readLine(): string $line = @fgets($this->out); if ('' === $line || false === $line) { if (stream_get_meta_data($this->out)['timed_out']) { - throw new TransportException(sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription())); + throw new TransportException(\sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription())); } if (feof($this->out)) { // don't use "eof" metadata, it's not accurate on Windows - throw new TransportException(sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription())); + throw new TransportException(\sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription())); } if (false === $line) { - throw new TransportException(sprintf('Unable to read from connection to "%s": ', $this->getReadConnectionDescription()).error_get_last()['message']); + throw new TransportException(\sprintf('Unable to read from connection to "%s": ', $this->getReadConnectionDescription().error_get_last()['message'] ?? '')); } } - $this->debug .= sprintf('< %s', $line); + $this->debug .= \sprintf('< %s', $line); return $line; } diff --git a/symfony/mailer/Transport/Smtp/Stream/SocketStream.php b/symfony/mailer/Transport/Smtp/Stream/SocketStream.php index 49e6ea499..560afb6d3 100644 --- a/symfony/mailer/Transport/Smtp/Stream/SocketStream.php +++ b/symfony/mailer/Transport/Smtp/Stream/SocketStream.php @@ -151,7 +151,7 @@ public function initialize(): void $timeout = $this->getTimeout(); set_error_handler(function ($type, $msg) { - throw new TransportException(sprintf('Connection could not be established with host "%s": ', $this->url).$msg); + throw new TransportException(\sprintf('Connection could not be established with host "%s": ', $this->url).$msg); }); try { $this->stream = stream_socket_client($this->url, $errno, $errstr, $timeout, \STREAM_CLIENT_CONNECT, $streamContext); diff --git a/symfony/mailer/Transport/Transports.php b/symfony/mailer/Transport/Transports.php index f02b9bc9b..1d97ea68e 100644 --- a/symfony/mailer/Transport/Transports.php +++ b/symfony/mailer/Transport/Transports.php @@ -40,7 +40,7 @@ public function __construct(iterable $transports) } if (!$this->transports) { - throw new LogicException(sprintf('"%s" must have at least one transport configured.', __CLASS__)); + throw new LogicException(\sprintf('"%s" must have at least one transport configured.', __CLASS__)); } } @@ -56,7 +56,7 @@ public function send(RawMessage $message, ?Envelope $envelope = null): ?SentMess $headers->remove('X-Transport'); if (!isset($this->transports[$transport])) { - throw new InvalidArgumentException(sprintf('The "%s" transport does not exist (available transports: "%s").', $transport, implode('", "', array_keys($this->transports)))); + throw new InvalidArgumentException(\sprintf('The "%s" transport does not exist (available transports: "%s").', $transport, implode('", "', array_keys($this->transports)))); } try { diff --git a/symfony/mime/Address.php b/symfony/mime/Address.php index ce57f77ee..a78b64321 100644 --- a/symfony/mime/Address.php +++ b/symfony/mime/Address.php @@ -42,7 +42,7 @@ final class Address public function __construct(string $address, string $name = '') { if (!class_exists(EmailValidator::class)) { - throw new LogicException(sprintf('The "%s" class cannot be used as it needs "%s". Try running "composer require egulias/email-validator".', __CLASS__, EmailValidator::class)); + throw new LogicException(\sprintf('The "%s" class cannot be used as it needs "%s". Try running "composer require egulias/email-validator".', __CLASS__, EmailValidator::class)); } self::$validator ??= new EmailValidator(); @@ -51,7 +51,7 @@ public function __construct(string $address, string $name = '') $this->name = trim(str_replace(["\n", "\r"], '', $name)); if (!self::$validator->isValid($this->address, class_exists(MessageIDValidation::class) ? new MessageIDValidation() : new RFCValidation())) { - throw new RfcComplianceException(sprintf('Email "%s" does not comply with addr-spec of RFC 2822.', $address)); + throw new RfcComplianceException(\sprintf('Email "%s" does not comply with addr-spec of RFC 2822.', $address)); } } @@ -83,7 +83,7 @@ public function getEncodedName(): string return ''; } - return sprintf('"%s"', preg_replace('/"/u', '\"', $this->getName())); + return \sprintf('"%s"', preg_replace('/"/u', '\"', $this->getName())); } public static function create(self|string $address): self @@ -97,7 +97,7 @@ public static function create(self|string $address): self } if (!preg_match(self::FROM_STRING_PATTERN, $address, $matches)) { - throw new InvalidArgumentException(sprintf('Could not parse "%s" to a "%s" instance.', $address, self::class)); + throw new InvalidArgumentException(\sprintf('Could not parse "%s" to a "%s" instance.', $address, self::class)); } return new self($matches['addrSpec'], trim($matches['displayName'], ' \'"')); diff --git a/symfony/mime/Crypto/DkimSigner.php b/symfony/mime/Crypto/DkimSigner.php index 1d2005e5c..2ef0ac519 100644 --- a/symfony/mime/Crypto/DkimSigner.php +++ b/symfony/mime/Crypto/DkimSigner.php @@ -62,7 +62,7 @@ public function sign(Message $message, array $options = []): Message { $options += $this->defaultOptions; if (!\in_array($options['algorithm'], [self::ALGO_SHA256, self::ALGO_ED25519], true)) { - throw new InvalidArgumentException(sprintf('Invalid DKIM signing algorithm "%s".', $options['algorithm'])); + throw new InvalidArgumentException(\sprintf('Invalid DKIM signing algorithm "%s".', $options['algorithm'])); } $headersToIgnore['return-path'] = true; $headersToIgnore['x-transport'] = true; @@ -119,7 +119,7 @@ public function sign(Message $message, array $options = []): Message throw new RuntimeException('Unable to sign DKIM hash: '.openssl_error_string()); } } else { - throw new \RuntimeException(sprintf('The "%s" DKIM signing algorithm is not supported yet.', self::ALGO_ED25519)); + throw new \RuntimeException(\sprintf('The "%s" DKIM signing algorithm is not supported yet.', self::ALGO_ED25519)); } $header->setValue($value.' b='.trim(chunk_split(base64_encode($signature), 73, ' '))); $headers->add($header); diff --git a/symfony/mime/Crypto/SMime.php b/symfony/mime/Crypto/SMime.php index cba95f210..f72ba010c 100644 --- a/symfony/mime/Crypto/SMime.php +++ b/symfony/mime/Crypto/SMime.php @@ -24,7 +24,7 @@ abstract class SMime protected function normalizeFilePath(string $path): string { if (!file_exists($path)) { - throw new RuntimeException(sprintf('File does not exist: "%s".', $path)); + throw new RuntimeException(\sprintf('File does not exist: "%s".', $path)); } return 'file://'.str_replace('\\', '/', realpath($path)); diff --git a/symfony/mime/Crypto/SMimeEncrypter.php b/symfony/mime/Crypto/SMimeEncrypter.php index c7c05452c..d7c0af68b 100644 --- a/symfony/mime/Crypto/SMimeEncrypter.php +++ b/symfony/mime/Crypto/SMimeEncrypter.php @@ -24,7 +24,7 @@ final class SMimeEncrypter extends SMime /** * @param string|string[] $certificate The path (or array of paths) of the file(s) containing the X.509 certificate(s) - * @param int|null $cipher A set of algorithms used to encrypt the message. Must be one of these PHP constants: https://www.php.net/manual/en/openssl.ciphers.php + * @param int|null $cipher A set of algorithms used to encrypt the message. Must be one of these PHP constants: https://php.net/openssl.ciphers */ public function __construct(string|array $certificate, ?int $cipher = null) { @@ -49,7 +49,7 @@ public function encrypt(Message $message): Message $this->iteratorToFile($message->toIterable(), $bufferFile); if (!@openssl_pkcs7_encrypt(stream_get_meta_data($bufferFile)['uri'], stream_get_meta_data($outputFile)['uri'], $this->certs, [], 0, $this->cipher)) { - throw new RuntimeException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string())); + throw new RuntimeException(\sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string())); } $mimePart = $this->convertMessageToSMimePart($outputFile, 'application', 'pkcs7-mime'); diff --git a/symfony/mime/Crypto/SMimeSigner.php b/symfony/mime/Crypto/SMimeSigner.php index eaa423d8c..d17e17754 100644 --- a/symfony/mime/Crypto/SMimeSigner.php +++ b/symfony/mime/Crypto/SMimeSigner.php @@ -57,7 +57,7 @@ public function sign(Message $message): Message $this->iteratorToFile($message->getBody()->toIterable(), $bufferFile); if (!@openssl_pkcs7_sign(stream_get_meta_data($bufferFile)['uri'], stream_get_meta_data($outputFile)['uri'], $this->signCertificate, $this->signPrivateKey, [], $this->signOptions, $this->extraCerts)) { - throw new RuntimeException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string())); + throw new RuntimeException(\sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string())); } return new Message($message->getHeaders(), $this->convertMessageToSMimePart($outputFile, 'multipart', 'signed')); diff --git a/symfony/mime/Email.php b/symfony/mime/Email.php index 797e0028f..c5a65641b 100644 --- a/symfony/mime/Email.php +++ b/symfony/mime/Email.php @@ -246,7 +246,7 @@ public function priority(int $priority): static $priority = 1; } - return $this->setHeaderBody('Text', 'X-Priority', sprintf('%d (%s)', $priority, self::PRIORITY_MAP[$priority])); + return $this->setHeaderBody('Text', 'X-Priority', \sprintf('%d (%s)', $priority, self::PRIORITY_MAP[$priority])); } /** @@ -270,7 +270,7 @@ public function getPriority(): int public function text($body, string $charset = 'utf-8'): static { if (null !== $body && !\is_string($body) && !\is_resource($body)) { - throw new \TypeError(sprintf('The body must be a string, a resource or null (got "%s").', get_debug_type($body))); + throw new \TypeError(\sprintf('The body must be a string, a resource or null (got "%s").', get_debug_type($body))); } $this->cachedBody = null; @@ -301,7 +301,7 @@ public function getTextCharset(): ?string public function html($body, string $charset = 'utf-8'): static { if (null !== $body && !\is_string($body) && !\is_resource($body)) { - throw new \TypeError(sprintf('The body must be a string, a resource or null (got "%s").', get_debug_type($body))); + throw new \TypeError(\sprintf('The body must be a string, a resource or null (got "%s").', get_debug_type($body))); } $this->cachedBody = null; @@ -507,7 +507,7 @@ private function prepareParts(): ?array } if ($name !== $part->getContentId()) { - $html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html, $count); + $html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html); } $relatedParts[$name] = $part; $part->setName($part->getContentId())->asInline(); diff --git a/symfony/mime/Encoder/Base64ContentEncoder.php b/symfony/mime/Encoder/Base64ContentEncoder.php index 440868af7..07cbca30f 100644 --- a/symfony/mime/Encoder/Base64ContentEncoder.php +++ b/symfony/mime/Encoder/Base64ContentEncoder.php @@ -21,7 +21,7 @@ final class Base64ContentEncoder extends Base64Encoder implements ContentEncoder public function encodeByteStream($stream, int $maxLineLength = 0): iterable { if (!\is_resource($stream)) { - throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); + throw new \TypeError(\sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); } $filter = stream_filter_append($stream, 'convert.base64-encode', \STREAM_FILTER_READ, [ diff --git a/symfony/mime/Encoder/IdnAddressEncoder.php b/symfony/mime/Encoder/IdnAddressEncoder.php index b56e7e396..07a32e9b3 100644 --- a/symfony/mime/Encoder/IdnAddressEncoder.php +++ b/symfony/mime/Encoder/IdnAddressEncoder.php @@ -35,7 +35,7 @@ public function encodeString(string $address): string $domain = substr($address, $i + 1); if (preg_match('/[^\x00-\x7F]/', $domain)) { - $address = sprintf('%s@%s', $local, idn_to_ascii($domain, \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI | \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII, \INTL_IDNA_VARIANT_UTS46)); + $address = \sprintf('%s@%s', $local, idn_to_ascii($domain, \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI | \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII, \INTL_IDNA_VARIANT_UTS46)); } } diff --git a/symfony/mime/Encoder/QpContentEncoder.php b/symfony/mime/Encoder/QpContentEncoder.php index 6f420fff3..c425b6759 100644 --- a/symfony/mime/Encoder/QpContentEncoder.php +++ b/symfony/mime/Encoder/QpContentEncoder.php @@ -19,7 +19,7 @@ final class QpContentEncoder implements ContentEncoderInterface public function encodeByteStream($stream, int $maxLineLength = 0): iterable { if (!\is_resource($stream)) { - throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); + throw new \TypeError(\sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); } // we don't use PHP stream filters here as the content should be small enough @@ -46,9 +46,9 @@ private function standardize(string $string): string // transform =0D=0A to CRLF $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'], ["=09\r\n", "=20\r\n", "\r\n"], $string); - return match (\ord(substr($string, -1))) { - 0x09 => substr_replace($string, '=09', -1), - 0x20 => substr_replace($string, '=20', -1), + return match ($string[-1] ?? '') { + "\x09" => substr_replace($string, '=09', -1), + "\x20" => substr_replace($string, '=20', -1), default => $string, }; } diff --git a/symfony/mime/Encoder/QpEncoder.php b/symfony/mime/Encoder/QpEncoder.php index 160dde329..76ec445a3 100644 --- a/symfony/mime/Encoder/QpEncoder.php +++ b/symfony/mime/Encoder/QpEncoder.php @@ -183,9 +183,9 @@ private function standardize(string $string): string { $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'], ["=09\r\n", "=20\r\n", "\r\n"], $string); - return match ($end = \ord(substr($string, -1))) { - 0x09, - 0x20 => substr_replace($string, self::QP_MAP[$end], -1), + return match ($end = ($string[-1] ?? '')) { + "\x09", + "\x20" => substr_replace($string, self::QP_MAP[\ord($end)], -1), default => $string, }; } diff --git a/symfony/mime/FileBinaryMimeTypeGuesser.php b/symfony/mime/FileBinaryMimeTypeGuesser.php index 83e2950ce..465f061a0 100644 --- a/symfony/mime/FileBinaryMimeTypeGuesser.php +++ b/symfony/mime/FileBinaryMimeTypeGuesser.php @@ -58,17 +58,17 @@ public function isGuesserSupported(): bool public function guessMimeType(string $path): ?string { if (!is_file($path) || !is_readable($path)) { - throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); + throw new InvalidArgumentException(\sprintf('The "%s" file does not exist or is not readable.', $path)); } if (!$this->isGuesserSupported()) { - throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); + throw new LogicException(\sprintf('The "%s" guesser is not supported.', __CLASS__)); } ob_start(); // need to use --mime instead of -i. see #6641 - passthru(sprintf($this->cmd, escapeshellarg((str_starts_with($path, '-') ? './' : '').$path)), $return); + passthru(\sprintf($this->cmd, escapeshellarg((str_starts_with($path, '-') ? './' : '').$path)), $return); if ($return > 0) { ob_end_clean(); diff --git a/symfony/mime/FileinfoMimeTypeGuesser.php b/symfony/mime/FileinfoMimeTypeGuesser.php index 776124f8c..7a8b502df 100644 --- a/symfony/mime/FileinfoMimeTypeGuesser.php +++ b/symfony/mime/FileinfoMimeTypeGuesser.php @@ -26,7 +26,7 @@ class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface /** * @param string|null $magicFile A magic file to use with the finfo instance * - * @see http://www.php.net/manual/en/function.finfo-open.php + * @see https://php.net/finfo-open */ public function __construct(?string $magicFile = null) { @@ -41,11 +41,11 @@ public function isGuesserSupported(): bool public function guessMimeType(string $path): ?string { if (!is_file($path) || !is_readable($path)) { - throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); + throw new InvalidArgumentException(\sprintf('The "%s" file does not exist or is not readable.', $path)); } if (!$this->isGuesserSupported()) { - throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); + throw new LogicException(\sprintf('The "%s" guesser is not supported.', __CLASS__)); } if (false === $finfo = new \finfo(\FILEINFO_MIME_TYPE, $this->magicFile)) { diff --git a/symfony/mime/Header/Headers.php b/symfony/mime/Header/Headers.php index 164f4ac33..789d15d92 100644 --- a/symfony/mime/Header/Headers.php +++ b/symfony/mime/Header/Headers.php @@ -170,7 +170,7 @@ public function add(HeaderInterface $header): static $name = strtolower($header->getName()); if (\in_array($name, self::UNIQUE_HEADERS, true) && isset($this->headers[$name]) && \count($this->headers[$name]) > 0) { - throw new LogicException(sprintf('Impossible to set header "%s" as it\'s already defined and must be unique.', $header->getName())); + throw new LogicException(\sprintf('Impossible to set header "%s" as it\'s already defined and must be unique.', $header->getName())); } $this->headers[$name][] = $header; @@ -241,7 +241,7 @@ public static function checkHeaderClass(HeaderInterface $header): void } } - throw new LogicException(sprintf('The "%s" header must be an instance of "%s" (got "%s").', $header->getName(), implode('" or "', $headerClasses), get_debug_type($header))); + throw new LogicException(\sprintf('The "%s" header must be an instance of "%s" (got "%s").', $header->getName(), implode('" or "', $headerClasses), get_debug_type($header))); } public function toString(): string @@ -291,7 +291,7 @@ public function getHeaderParameter(string $name, string $parameter): ?string $header = $this->get($name); if (!$header instanceof ParameterizedHeader) { - throw new LogicException(sprintf('Unable to get parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); + throw new LogicException(\sprintf('Unable to get parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); } return $header->getParameter($parameter); @@ -303,12 +303,12 @@ public function getHeaderParameter(string $name, string $parameter): ?string public function setHeaderParameter(string $name, string $parameter, ?string $value): void { if (!$this->has($name)) { - throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not defined.', $parameter, $name)); + throw new LogicException(\sprintf('Unable to set parameter "%s" on header "%s" as the header is not defined.', $parameter, $name)); } $header = $this->get($name); if (!$header instanceof ParameterizedHeader) { - throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); + throw new LogicException(\sprintf('Unable to set parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); } $header->setParameter($parameter, $value); diff --git a/symfony/mime/Header/PathHeader.php b/symfony/mime/Header/PathHeader.php index 63eb30af0..4b0b7d395 100644 --- a/symfony/mime/Header/PathHeader.php +++ b/symfony/mime/Header/PathHeader.php @@ -57,6 +57,6 @@ public function getAddress(): Address public function getBodyAsString(): string { - return '<'.$this->address->toString().'>'; + return '<'.$this->address->getEncodedAddress().'>'; } } diff --git a/symfony/mime/MessageConverter.php b/symfony/mime/MessageConverter.php index bdce921af..a07dd8720 100644 --- a/symfony/mime/MessageConverter.php +++ b/symfony/mime/MessageConverter.php @@ -55,13 +55,13 @@ public static function toEmail(Message $message): Email } elseif ($parts[0] instanceof TextPart) { $email = self::createEmailFromTextPart($message, $parts[0]); } else { - throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + throw new RuntimeException(\sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); } return self::addParts($email, \array_slice($parts, 1)); } - throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + throw new RuntimeException(\sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); } private static function createEmailFromTextPart(Message $message, TextPart $part): Email @@ -73,7 +73,7 @@ private static function createEmailFromTextPart(Message $message, TextPart $part return (new Email(clone $message->getHeaders()))->html($part->getBody(), $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8'); } - throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + throw new RuntimeException(\sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); } private static function createEmailFromAlternativePart(Message $message, AlternativePart $part): Email @@ -90,7 +90,7 @@ private static function createEmailFromAlternativePart(Message $message, Alterna ; } - throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + throw new RuntimeException(\sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); } private static function createEmailFromRelatedPart(Message $message, RelatedPart $part): Email @@ -101,7 +101,7 @@ private static function createEmailFromRelatedPart(Message $message, RelatedPart } elseif ($parts[0] instanceof TextPart) { $email = self::createEmailFromTextPart($message, $parts[0]); } else { - throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); + throw new RuntimeException(\sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); } return self::addParts($email, \array_slice($parts, 1)); @@ -111,7 +111,7 @@ private static function addParts(Email $email, array $parts): Email { foreach ($parts as $part) { if (!$part instanceof DataPart) { - throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($email))); + throw new RuntimeException(\sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($email))); } $email->addPart($part); diff --git a/symfony/mime/MimeTypes.php b/symfony/mime/MimeTypes.php index 19628b0b1..fd9881b72 100644 --- a/symfony/mime/MimeTypes.php +++ b/symfony/mime/MimeTypes.php @@ -135,7 +135,7 @@ public function guessMimeType(string $path): ?string /** * A map of MIME types and their default extensions. * - * Updated from upstream on 2023-10-14. + * Updated from upstream on 2025-11-15. * * @see Resources/bin/update_mime_types.php */ @@ -143,7 +143,10 @@ public function guessMimeType(string $path): ?string 'application/acrobat' => ['pdf'], 'application/andrew-inset' => ['ez'], 'application/annodex' => ['anx'], + 'application/appinstaller' => ['appinstaller'], 'application/applixware' => ['aw'], + 'application/appx' => ['appx'], + 'application/appxbundle' => ['appxbundle'], 'application/atom+xml' => ['atom'], 'application/atomcat+xml' => ['atomcat'], 'application/atomdeleted+xml' => ['atomdeleted'], @@ -151,8 +154,11 @@ public function guessMimeType(string $path): ?string 'application/atsc-dwd+xml' => ['dwd'], 'application/atsc-held+xml' => ['held'], 'application/atsc-rsat+xml' => ['rsat'], + 'application/automationml-aml+xml' => ['aml'], + 'application/automationml-amlx+zip' => ['amlx'], 'application/bat' => ['bat'], 'application/bdoc' => ['bdoc'], + 'application/buildstream+yaml' => ['bst'], 'application/bzip2' => ['bz2', 'bz'], 'application/calendar+xml' => ['xcs'], 'application/cbor' => ['cbor'], @@ -168,6 +174,7 @@ public function guessMimeType(string $path): ?string 'application/cpl+xml' => ['cpl'], 'application/csv' => ['csv'], 'application/cu-seeme' => ['cu'], + 'application/cwl' => ['cwl'], 'application/dash+xml' => ['mpd'], 'application/dash-patch+xml' => ['mpp'], 'application/davmount+xml' => ['davmount'], @@ -184,6 +191,7 @@ public function guessMimeType(string $path): ?string 'application/epub+zip' => ['epub'], 'application/exi' => ['exi'], 'application/express' => ['exp'], + 'application/fdf' => ['fdf'], 'application/fdt+xml' => ['fdt'], 'application/fits' => ['fits', 'fit', 'fts'], 'application/font-tdpfr' => ['pfr'], @@ -196,10 +204,12 @@ public function guessMimeType(string $path): ?string 'application/gpx+xml' => ['gpx'], 'application/gxf' => ['gxf'], 'application/gzip' => ['gz'], + 'application/har+json' => ['har'], 'application/hjson' => ['hjson'], + 'application/hta' => ['hta'], 'application/hyperstudio' => ['stk'], 'application/ico' => ['ico'], - 'application/ics' => ['vcs', 'ics'], + 'application/ics' => ['vcs', 'ics', 'ifb', 'icalendar'], 'application/illustrator' => ['ai'], 'application/inkml+xml' => ['ink', 'inkml'], 'application/ipfix' => ['ipfix'], @@ -209,7 +219,7 @@ public function guessMimeType(string $path): ?string 'application/java-byte-code' => ['class'], 'application/java-serialized-object' => ['ser'], 'application/java-vm' => ['class'], - 'application/javascript' => ['js', 'mjs', 'jsm'], + 'application/javascript' => ['js', 'cjs', 'jsm', 'mjs'], 'application/jrd+json' => ['jrd'], 'application/json' => ['json', 'map'], 'application/json-patch+json' => ['json-patch'], @@ -235,16 +245,20 @@ public function guessMimeType(string $path): ?string 'application/metalink+xml' => ['metalink'], 'application/metalink4+xml' => ['meta4'], 'application/mets+xml' => ['mets'], + 'application/microsoftpatch' => ['msp'], + 'application/microsoftupdate' => ['msu'], 'application/mmt-aei+xml' => ['maei'], 'application/mmt-usd+xml' => ['musd'], 'application/mods+xml' => ['mods'], 'application/mp21' => ['m21', 'mp21'], - 'application/mp4' => ['mp4s', 'm4p'], + 'application/mp4' => ['mp4', 'mpg4', 'mp4s', 'm4p'], 'application/mrb-consumer+xml' => ['xdf'], 'application/mrb-publish+xml' => ['xdf'], 'application/ms-tnef' => ['tnef', 'tnf'], 'application/msaccess' => ['mdb'], 'application/msexcel' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], + 'application/msix' => ['msix'], + 'application/msixbundle' => ['msixbundle'], 'application/mspowerpoint' => ['ppz', 'ppt', 'pps', 'pot'], 'application/msword' => ['doc', 'dot'], 'application/msword-template' => ['dot'], @@ -269,7 +283,7 @@ public function guessMimeType(string $path): ?string 'application/pgp' => ['pgp', 'gpg', 'asc'], 'application/pgp-encrypted' => ['pgp', 'gpg', 'asc'], 'application/pgp-keys' => ['asc', 'skr', 'pkr', 'pgp', 'gpg', 'key'], - 'application/pgp-signature' => ['asc', 'sig', 'pgp', 'gpg'], + 'application/pgp-signature' => ['sig', 'asc', 'pgp', 'gpg'], 'application/photoshop' => ['psd'], 'application/pics-rules' => ['prf'], 'application/pkcs10' => ['p10'], @@ -289,6 +303,8 @@ public function guessMimeType(string $path): ?string 'application/powerpoint' => ['ppz', 'ppt', 'pps', 'pot'], 'application/provenance+xml' => ['provx'], 'application/prs.cww' => ['cww'], + 'application/prs.wavefront-obj' => ['obj'], + 'application/prs.xsf+xml' => ['xsf'], 'application/pskc+xml' => ['pskcxml'], 'application/ram' => ['ram'], 'application/raml+yaml' => ['raml'], @@ -324,6 +340,7 @@ public function guessMimeType(string $path): ?string 'application/smil+xml' => ['smi', 'smil', 'sml', 'kino'], 'application/sparql-query' => ['rq', 'qs'], 'application/sparql-results+xml' => ['srx'], + 'application/spdx+json' => ['spdx.json'], 'application/sql' => ['sql'], 'application/srgs' => ['gram'], 'application/srgs+xml' => ['grxml'], @@ -339,6 +356,7 @@ public function guessMimeType(string $path): ?string 'application/toml' => ['toml'], 'application/trig' => ['trig'], 'application/ttml+xml' => ['ttml'], + 'application/typescript' => ['cts', 'mts', 'ts'], 'application/ubjson' => ['ubj'], 'application/urc-ressheet+xml' => ['rsheet'], 'application/urc-targetdesc+xml' => ['td'], @@ -371,6 +389,7 @@ public function guessMimeType(string $path): ?string 'application/vnd.anser-web-certificate-issue-initiation' => ['cii'], 'application/vnd.anser-web-funds-transfer-initiation' => ['fti'], 'application/vnd.antix.game-component' => ['atx'], + 'application/vnd.apache.parquet' => ['parquet'], 'application/vnd.appimage' => ['appimage'], 'application/vnd.apple.installer+xml' => ['mpkg'], 'application/vnd.apple.keynote' => ['key', 'keynote'], @@ -378,6 +397,7 @@ public function guessMimeType(string $path): ?string 'application/vnd.apple.numbers' => ['numbers'], 'application/vnd.apple.pages' => ['pages'], 'application/vnd.apple.pkpass' => ['pkpass'], + 'application/vnd.apple.pkpasses' => ['pkpasses'], 'application/vnd.aristanetworks.swi' => ['swi'], 'application/vnd.astraea-software.iota' => ['iota'], 'application/vnd.audiograph' => ['aep'], @@ -412,6 +432,8 @@ public function guessMimeType(string $path): ?string 'application/vnd.cups-ppd' => ['ppd'], 'application/vnd.curl.car' => ['car'], 'application/vnd.curl.pcurl' => ['pcurl'], + 'application/vnd.cyclonedx+json' => ['cdx.json'], + 'application/vnd.cyclonedx+xml' => ['cdx.xml'], 'application/vnd.dart' => ['dart'], 'application/vnd.data-vision.rdz' => ['rdz'], 'application/vnd.dbf' => ['dbf'], @@ -467,6 +489,7 @@ public function guessMimeType(string $path): ?string 'application/vnd.genomatix.tuxedo' => ['txd'], 'application/vnd.geo+json' => ['geojson', 'geo.json'], 'application/vnd.geogebra.file' => ['ggb'], + 'application/vnd.geogebra.slides' => ['ggs'], 'application/vnd.geogebra.tool' => ['ggt'], 'application/vnd.geometry-explorer' => ['gex', 'gre'], 'application/vnd.geonext' => ['gxt'], @@ -479,6 +502,7 @@ public function guessMimeType(string $path): ?string 'application/vnd.google-apps.spreadsheet' => ['gsheet'], 'application/vnd.google-earth.kml+xml' => ['kml'], 'application/vnd.google-earth.kmz' => ['kmz'], + 'application/vnd.gov.sk.xmldatacontainer+xml' => ['xdcf'], 'application/vnd.grafeq' => ['gqf', 'gqs'], 'application/vnd.groove-account' => ['gac'], 'application/vnd.groove-help' => ['ghf'], @@ -554,6 +578,7 @@ public function guessMimeType(string $path): ?string 'application/vnd.mfmp' => ['mfm'], 'application/vnd.micrografx.flo' => ['flo'], 'application/vnd.micrografx.igx' => ['igx'], + 'application/vnd.microsoft.portable-executable' => ['exe', 'dll', 'cpl', 'drv', 'scr', 'efi', 'ocx', 'sys', 'lib'], 'application/vnd.mif' => ['mif'], 'application/vnd.mobius.daf' => ['daf'], 'application/vnd.mobius.dis' => ['dis'], @@ -609,6 +634,7 @@ public function guessMimeType(string $path): ?string 'application/vnd.musician' => ['mus'], 'application/vnd.muvee.style' => ['msty'], 'application/vnd.mynfc' => ['taglet'], + 'application/vnd.nato.bindingdataobject+xml' => ['bdo'], 'application/vnd.neurolanguage.nlu' => ['nlu'], 'application/vnd.nintendo.snes.rom' => ['sfc', 'smc'], 'application/vnd.nitf' => ['ntf', 'nitf'], @@ -624,6 +650,7 @@ public function guessMimeType(string $path): ?string 'application/vnd.novadigm.edx' => ['edx'], 'application/vnd.novadigm.ext' => ['ext'], 'application/vnd.oasis.docbook+xml' => ['dbk', 'docbook'], + 'application/vnd.oasis.opendocument.base' => ['odb'], 'application/vnd.oasis.opendocument.chart' => ['odc'], 'application/vnd.oasis.opendocument.chart-template' => ['otc'], 'application/vnd.oasis.opendocument.database' => ['odb'], @@ -643,6 +670,7 @@ public function guessMimeType(string $path): ?string 'application/vnd.oasis.opendocument.text' => ['odt'], 'application/vnd.oasis.opendocument.text-flat-xml' => ['fodt'], 'application/vnd.oasis.opendocument.text-master' => ['odm'], + 'application/vnd.oasis.opendocument.text-master-template' => ['otm'], 'application/vnd.oasis.opendocument.text-template' => ['ott'], 'application/vnd.oasis.opendocument.text-web' => ['oth'], 'application/vnd.olpc-sugar' => ['xo'], @@ -673,7 +701,8 @@ public function guessMimeType(string $path): ?string 'application/vnd.proteus.magazine' => ['mgz'], 'application/vnd.publishare-delta-tree' => ['qps'], 'application/vnd.pvi.ptid1' => ['ptid'], - 'application/vnd.quark.quarkxpress' => ['qxd', 'qxt', 'qwd', 'qwt', 'qxl', 'qxb'], + 'application/vnd.pwg-xhtml-print+xml' => ['xhtm'], + 'application/vnd.quark.quarkxpress' => ['qxd', 'qxt', 'qwd', 'qwt', 'qxl', 'qxb', 'qxp'], 'application/vnd.rar' => ['rar'], 'application/vnd.realvnc.bed' => ['bed'], 'application/vnd.recordare.musicxml' => ['mxl'], @@ -702,15 +731,16 @@ public function guessMimeType(string $path): ?string 'application/vnd.spotfire.dxp' => ['dxp'], 'application/vnd.spotfire.sfs' => ['sfs'], 'application/vnd.sqlite3' => ['sqlite3'], - 'application/vnd.squashfs' => ['sqsh'], + 'application/vnd.squashfs' => ['sfs', 'sqfs', 'sqsh', 'squashfs'], 'application/vnd.stardivision.calc' => ['sdc'], 'application/vnd.stardivision.chart' => ['sds'], 'application/vnd.stardivision.draw' => ['sda'], - 'application/vnd.stardivision.impress' => ['sdd', 'sdp'], - 'application/vnd.stardivision.mail' => ['smd'], + 'application/vnd.stardivision.impress' => ['sdd'], + 'application/vnd.stardivision.impress-packed' => ['sdp'], + 'application/vnd.stardivision.mail' => ['sdm'], 'application/vnd.stardivision.math' => ['smf'], - 'application/vnd.stardivision.writer' => ['sdw', 'vor', 'sgl'], - 'application/vnd.stardivision.writer-global' => ['sgl', 'sdw', 'vor'], + 'application/vnd.stardivision.writer' => ['sdw', 'vor'], + 'application/vnd.stardivision.writer-global' => ['sgl'], 'application/vnd.stepmania.package' => ['smzip'], 'application/vnd.stepmania.stepchart' => ['sm'], 'application/vnd.sun.wadl+xml' => ['wadl'], @@ -743,7 +773,7 @@ public function guessMimeType(string $path): ?string 'application/vnd.uiq.theme' => ['utz'], 'application/vnd.umajin' => ['umj'], 'application/vnd.unity' => ['unityweb'], - 'application/vnd.uoml+xml' => ['uoml'], + 'application/vnd.uoml+xml' => ['uoml', 'uo'], 'application/vnd.vcx' => ['vcx'], 'application/vnd.visio' => ['vsd', 'vst', 'vss', 'vsw'], 'application/vnd.visionary' => ['vis'], @@ -786,7 +816,9 @@ public function guessMimeType(string $path): ?string 'application/x-abiword' => ['abw', 'abw.CRASHED', 'abw.gz', 'zabw'], 'application/x-ace' => ['ace'], 'application/x-ace-compressed' => ['ace'], + 'application/x-alpine-package-keeper-package' => ['apk'], 'application/x-alz' => ['alz'], + 'application/x-amf' => ['amf'], 'application/x-amiga-disk-format' => ['adf'], 'application/x-amipro' => ['sam'], 'application/x-annodex' => ['anx'], @@ -796,7 +828,7 @@ public function guessMimeType(string $path): ?string 'application/x-appleworks-document' => ['cwk'], 'application/x-applix-spreadsheet' => ['as'], 'application/x-applix-word' => ['aw'], - 'application/x-archive' => ['a', 'ar'], + 'application/x-archive' => ['a', 'ar', 'lib'], 'application/x-arj' => ['arj'], 'application/x-asar' => ['asar'], 'application/x-asp' => ['asp'], @@ -811,14 +843,16 @@ public function guessMimeType(string $path): ?string 'application/x-bcpio' => ['bcpio'], 'application/x-bdoc' => ['bdoc'], 'application/x-bittorrent' => ['torrent'], - 'application/x-blender' => ['blend', 'BLEND', 'blender'], + 'application/x-blender' => ['blend', 'blender'], 'application/x-blorb' => ['blb', 'blorb'], 'application/x-bps-patch' => ['bps'], 'application/x-bsdiff' => ['bsdiff'], 'application/x-bz2' => ['bz2'], 'application/x-bzdvi' => ['dvi.bz2'], - 'application/x-bzip' => ['bz'], - 'application/x-bzip-compressed-tar' => ['tar.bz', 'tbz', 'tbz2', 'tb2'], + 'application/x-bzip' => ['bz', 'bz2'], + 'application/x-bzip-compressed-tar' => ['tar.bz2', 'tbz2', 'tb2'], + 'application/x-bzip1' => ['bz'], + 'application/x-bzip1-compressed-tar' => ['tar.bz', 'tbz'], 'application/x-bzip2' => ['bz2', 'boz'], 'application/x-bzip2-compressed-tar' => ['tar.bz2', 'tbz2', 'tb2'], 'application/x-bzip3' => ['bz3'], @@ -866,6 +900,7 @@ public function guessMimeType(string $path): ?string 'application/x-docbook+xml' => ['dbk', 'docbook'], 'application/x-doom' => ['wad'], 'application/x-doom-wad' => ['wad'], + 'application/x-dosexec' => ['exe'], 'application/x-dreamcast-rom' => ['iso'], 'application/x-dtbncx+xml' => ['ncx'], 'application/x-dtbook+xml' => ['dtb'], @@ -900,6 +935,8 @@ public function guessMimeType(string $path): ?string 'application/x-font-woff' => ['woff'], 'application/x-frame' => ['fm'], 'application/x-freearc' => ['arc'], + 'application/x-freedesktop-appstream-component' => ['metainfo.xml', 'appdata.xml'], + 'application/x-freedesktop-appstream-releases' => ['releases.xml'], 'application/x-futuresplash' => ['spl'], 'application/x-gameboy-color-rom' => ['gbc', 'cgb'], 'application/x-gameboy-rom' => ['gb', 'sgb'], @@ -912,7 +949,7 @@ public function guessMimeType(string $path): ?string 'application/x-gdscript' => ['gd'], 'application/x-gedcom' => ['ged', 'gedcom'], 'application/x-genesis-32x-rom' => ['32x', 'mdx'], - 'application/x-genesis-rom' => ['gen', 'smd', 'sgd'], + 'application/x-genesis-rom' => ['gen', 'smd', 'md', 'sgd'], 'application/x-gerber' => ['gbr'], 'application/x-gerber-job' => ['gbrjob'], 'application/x-gettext' => ['po'], @@ -964,7 +1001,7 @@ public function guessMimeType(string $path): ?string 'application/x-java-keystore' => ['jks', 'ks'], 'application/x-java-pack200' => ['pack'], 'application/x-java-vm' => ['class'], - 'application/x-javascript' => ['js', 'jsm', 'mjs'], + 'application/x-javascript' => ['js', 'cjs', 'jsm', 'mjs'], 'application/x-jbuilder-project' => ['jpr', 'jpx'], 'application/x-karbon' => ['karbon'], 'application/x-kchart' => ['chrt'], @@ -1018,7 +1055,8 @@ public function guessMimeType(string $path): ?string 'application/x-modrinth-modpack+zip' => ['mrpack'], 'application/x-ms-application' => ['application'], 'application/x-ms-asx' => ['asx', 'wax', 'wvx', 'wmx'], - 'application/x-ms-dos-executable' => ['exe'], + 'application/x-ms-dos-executable' => ['exe', 'dll', 'cpl', 'drv', 'scr'], + 'application/x-ms-ne-executable' => ['exe', 'dll', 'cpl', 'drv', 'scr'], 'application/x-ms-pdb' => ['pdb'], 'application/x-ms-shortcut' => ['lnk'], 'application/x-ms-wim' => ['wim', 'swm'], @@ -1030,7 +1068,7 @@ public function guessMimeType(string $path): ?string 'application/x-mscardfile' => ['crd'], 'application/x-msclip' => ['clp'], 'application/x-msdos-program' => ['exe'], - 'application/x-msdownload' => ['exe', 'dll', 'com', 'bat', 'msi'], + 'application/x-msdownload' => ['exe', 'dll', 'com', 'bat', 'msi', 'cpl', 'drv', 'scr'], 'application/x-msexcel' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], 'application/x-msi' => ['msi'], 'application/x-msmediaview' => ['mvb', 'm13', 'm14'], @@ -1054,8 +1092,10 @@ public function guessMimeType(string $path): ?string 'application/x-nintendo-3ds-executable' => ['3dsx'], 'application/x-nintendo-3ds-rom' => ['3ds', 'cci'], 'application/x-nintendo-ds-rom' => ['nds'], + 'application/x-nintendo-switch-xci' => ['xci'], 'application/x-ns-proxy-autoconfig' => ['pac'], 'application/x-nuscript' => ['nu'], + 'application/x-nx-xci' => ['xci'], 'application/x-nzb' => ['nzb'], 'application/x-object' => ['o', 'mod'], 'application/x-ogg' => ['ogx'], @@ -1066,9 +1106,11 @@ public function guessMimeType(string $path): ?string 'application/x-pak' => ['pak'], 'application/x-palm-database' => ['prc', 'pdb', 'pqa', 'oprc'], 'application/x-par2' => ['PAR2', 'par2'], + 'application/x-parquet' => ['parquet'], 'application/x-partial-download' => ['wkdownload', 'crdownload', 'part'], 'application/x-pc-engine-rom' => ['pce'], 'application/x-pcap' => ['pcap', 'cap', 'dmp'], + 'application/x-pcapng' => ['pcapng', 'scap', 'ntar'], 'application/x-pdf' => ['pdf'], 'application/x-perl' => ['pl', 'pm', 'PL', 'al', 'perl', 'pod', 't'], 'application/x-photoshop' => ['psd'], @@ -1079,15 +1121,17 @@ public function guessMimeType(string $path): ?string 'application/x-pkcs7-certreqresp' => ['p7r'], 'application/x-planperfect' => ['pln'], 'application/x-pocket-word' => ['psw'], + 'application/x-powershell' => ['ps1'], 'application/x-pw' => ['pw'], 'application/x-pyspread-bz-spreadsheet' => ['pys'], 'application/x-pyspread-spreadsheet' => ['pysu'], 'application/x-python-bytecode' => ['pyc', 'pyo'], + 'application/x-qbrew' => ['qbrew'], 'application/x-qed-disk' => ['qed'], 'application/x-qemu-disk' => ['qcow2', 'qcow'], 'application/x-qpress' => ['qp'], 'application/x-qtiplot' => ['qti', 'qti.gz'], - 'application/x-quattropro' => ['wb1', 'wb2', 'wb3'], + 'application/x-quattropro' => ['wb1', 'wb2', 'wb3', 'qpw'], 'application/x-quicktime-media-link' => ['qtl'], 'application/x-quicktimeplayer' => ['qtl'], 'application/x-qw' => ['qif'], @@ -1102,6 +1146,8 @@ public function guessMimeType(string $path): ?string 'application/x-rnc' => ['rnc'], 'application/x-rpm' => ['rpm'], 'application/x-ruby' => ['rb'], + 'application/x-rzip' => ['rz'], + 'application/x-rzip-compressed-tar' => ['tar.rz', 'trz'], 'application/x-sami' => ['smi', 'sami'], 'application/x-sap-file' => ['sap'], 'application/x-saturn-rom' => ['iso'], @@ -1124,6 +1170,7 @@ public function guessMimeType(string $path): ?string 'application/x-smaf' => ['mmf', 'smaf'], 'application/x-sms-rom' => ['sms'], 'application/x-snes-rom' => ['sfc', 'smc'], + 'application/x-sony-bbeb' => ['lrf'], 'application/x-source-rpm' => ['src.rpm', 'spm'], 'application/x-spss-por' => ['por'], 'application/x-spss-sav' => ['sav', 'zsav'], @@ -1132,11 +1179,20 @@ public function guessMimeType(string $path): ?string 'application/x-sqlite2' => ['sqlite2'], 'application/x-sqlite3' => ['sqlite3'], 'application/x-srt' => ['srt'], + 'application/x-starcalc' => ['sdc'], + 'application/x-starchart' => ['sds'], + 'application/x-stardraw' => ['sda'], + 'application/x-starimpress' => ['sdd'], + 'application/x-starmail' => ['smd'], + 'application/x-starmath' => ['smf'], + 'application/x-starwriter' => ['sdw', 'vor'], + 'application/x-starwriter-global' => ['sgl'], 'application/x-stuffit' => ['sit'], 'application/x-stuffitx' => ['sitx'], 'application/x-subrip' => ['srt'], 'application/x-sv4cpio' => ['sv4cpio'], 'application/x-sv4crc' => ['sv4crc'], + 'application/x-sylk' => ['sylk', 'slk'], 'application/x-t3vm-image' => ['t3'], 'application/x-t602' => ['602'], 'application/x-tads' => ['gam'], @@ -1186,6 +1242,7 @@ public function guessMimeType(string $path): ?string 'application/x-wii-iso-image' => ['iso'], 'application/x-wii-rom' => ['iso'], 'application/x-wii-wad' => ['wad'], + 'application/x-win-lnk' => ['lnk'], 'application/x-windows-themepack' => ['themepack'], 'application/x-wmf' => ['wmf'], 'application/x-wonderswan-color-rom' => ['wsc'], @@ -1212,6 +1269,10 @@ public function guessMimeType(string $path): ?string 'application/x-zoo' => ['zoo'], 'application/x-zpaq' => ['zpaq'], 'application/x-zstd-compressed-tar' => ['tar.zst', 'tzst'], + 'application/x.sf3-archive' => ['ar.sf3', 'sf3'], + 'application/x.sf3-log' => ['log.sf3', 'sf3'], + 'application/x.sf3-table' => ['tab.sf3', 'sf3'], + 'application/x.sf3-text' => ['txt.sf3', 'sf3'], 'application/xaml+xml' => ['xaml'], 'application/xcap-att+xml' => ['xav'], 'application/xcap-caps+xml' => ['xca'], @@ -1220,6 +1281,7 @@ public function guessMimeType(string $path): ?string 'application/xcap-error+xml' => ['xer'], 'application/xcap-ns+xml' => ['xns'], 'application/xenc+xml' => ['xenc'], + 'application/xfdf' => ['xfdf'], 'application/xhtml+xml' => ['xhtml', 'xht', 'html', 'htm'], 'application/xliff+xml' => ['xlf', 'xliff'], 'application/xml' => ['xml', 'xsl', 'xsd', 'rng', 'xbl'], @@ -1304,6 +1366,7 @@ public function guessMimeType(string $path): ?string 'audio/x-dff' => ['dff'], 'audio/x-dsd' => ['dsf'], 'audio/x-dsf' => ['dsf'], + 'audio/x-dsp' => ['dsm', 'dsp'], 'audio/x-dts' => ['dts'], 'audio/x-dtshd' => ['dtshd'], 'audio/x-flac' => ['flac'], @@ -1363,6 +1426,7 @@ public function guessMimeType(string $path): ?string 'audio/x-xi' => ['xi'], 'audio/x-xm' => ['xm'], 'audio/x-xmf' => ['xmf'], + 'audio/x.sf3' => ['au.sf3', 'sf3'], 'audio/xm' => ['xm'], 'audio/xmf' => ['xmf'], 'chemical/x-cdx' => ['cdx'], @@ -1370,6 +1434,7 @@ public function guessMimeType(string $path): ?string 'chemical/x-cmdf' => ['cmdf'], 'chemical/x-cml' => ['cml'], 'chemical/x-csml' => ['csml'], + 'chemical/x-pdb' => ['pdb', 'brk'], 'chemical/x-xyz' => ['xyz'], 'flv-application/octet-stream' => ['flv'], 'font/collection' => ['ttc'], @@ -1388,6 +1453,7 @@ public function guessMimeType(string $path): ?string 'image/cdr' => ['cdr'], 'image/cgm' => ['cgm'], 'image/dicom-rle' => ['drle'], + 'image/dpx' => ['dpx'], 'image/emf' => ['emf'], 'image/fax-g3' => ['g3'], 'image/fits' => ['fits', 'fit', 'fts'], @@ -1404,7 +1470,7 @@ public function guessMimeType(string $path): ?string 'image/ief' => ['ief'], 'image/jls' => ['jls'], 'image/jp2' => ['jp2', 'jpg2'], - 'image/jpeg' => ['jpg', 'jpeg', 'jpe'], + 'image/jpeg' => ['jpg', 'jpeg', 'jpe', 'jfif'], 'image/jpeg2000' => ['jp2', 'jpg2'], 'image/jpeg2000-image' => ['jp2', 'jpg2'], 'image/jph' => ['jph'], @@ -1424,9 +1490,9 @@ public function guessMimeType(string $path): ?string 'image/openraster' => ['ora'], 'image/pdf' => ['pdf'], 'image/photoshop' => ['psd'], - 'image/pjpeg' => ['jpg', 'jpeg', 'jpe'], + 'image/pjpeg' => ['jpg', 'jpeg', 'jpe', 'jfif'], 'image/png' => ['png'], - 'image/prs.btif' => ['btif'], + 'image/prs.btif' => ['btif', 'btf'], 'image/prs.pti' => ['pti'], 'image/psd' => ['psd'], 'image/qoi' => ['qoi'], @@ -1460,6 +1526,7 @@ public function guessMimeType(string $path): ?string 'image/vnd.ms-photo' => ['wdp', 'jxr', 'hdp'], 'image/vnd.net-fpx' => ['npx'], 'image/vnd.pco.b16' => ['b16'], + 'image/vnd.radiance' => ['hdr', 'pic', 'rgbe', 'xyze'], 'image/vnd.rn-realpix' => ['rp'], 'image/vnd.tencent.tap' => ['tap'], 'image/vnd.valve.source.texture' => ['vtf'], @@ -1486,12 +1553,14 @@ public function guessMimeType(string $path): ?string 'image/x-eps' => ['eps', 'epsi', 'epsf'], 'image/x-exr' => ['exr'], 'image/x-fits' => ['fits', 'fit', 'fts'], + 'image/x-fpx' => ['fpx'], 'image/x-freehand' => ['fh', 'fhc', 'fh4', 'fh5', 'fh7'], 'image/x-fuji-raf' => ['raf'], 'image/x-gimp-gbr' => ['gbr'], 'image/x-gimp-gih' => ['gih'], 'image/x-gimp-pat' => ['pat'], 'image/x-gzeps' => ['eps.gz', 'epsi.gz', 'epsf.gz'], + 'image/x-hdr' => ['hdr', 'pic', 'rgbe', 'xyze'], 'image/x-icb' => ['tga', 'icb', 'tpic', 'vda', 'vst'], 'image/x-icns' => ['icns'], 'image/x-ico' => ['ico'], @@ -1501,6 +1570,7 @@ public function guessMimeType(string $path): ?string 'image/x-jng' => ['jng'], 'image/x-jp2-codestream' => ['j2c', 'j2k', 'jpc'], 'image/x-jpeg2000-image' => ['jp2', 'jpg2'], + 'image/x-kiss-cel' => ['cel', 'kcf'], 'image/x-kodak-dcr' => ['dcr'], 'image/x-kodak-k25' => ['k25'], 'image/x-kodak-kdc' => ['kdc'], @@ -1520,6 +1590,8 @@ public function guessMimeType(string $path): ?string 'image/x-panasonic-rw2' => ['rw2'], 'image/x-pcx' => ['pcx'], 'image/x-pentax-pef' => ['pef'], + 'image/x-pfm' => ['pfm'], + 'image/x-phm' => ['phm'], 'image/x-photo-cd' => ['pcd'], 'image/x-photoshop' => ['psd'], 'image/x-pict' => ['pic', 'pct', 'pict', 'pict1', 'pict2'], @@ -1528,8 +1600,10 @@ public function guessMimeType(string $path): ?string 'image/x-portable-graymap' => ['pgm'], 'image/x-portable-pixmap' => ['ppm'], 'image/x-psd' => ['psd'], + 'image/x-pxr' => ['pxr'], 'image/x-quicktime' => ['qtif', 'qif'], 'image/x-rgb' => ['rgb'], + 'image/x-sct' => ['sct'], 'image/x-sgi' => ['sgi'], 'image/x-sigma-x3f' => ['x3f'], 'image/x-skencil' => ['sk', 'sk1'], @@ -1549,6 +1623,8 @@ public function guessMimeType(string $path): ?string 'image/x-xpm' => ['xpm'], 'image/x-xwindowdump' => ['xwd'], 'image/x.djvu' => ['djvu', 'djv'], + 'image/x.sf3' => ['img.sf3', 'sf3'], + 'image/x.sf3-vector' => ['vec.sf3', 'sf3'], 'message/disposition-notification' => ['disposition-notification'], 'message/global' => ['u8msg'], 'message/global-delivery-status' => ['u8dsn'], @@ -1560,13 +1636,19 @@ public function guessMimeType(string $path): ?string 'model/gltf+json' => ['gltf'], 'model/gltf-binary' => ['glb'], 'model/iges' => ['igs', 'iges'], + 'model/jt' => ['jt'], 'model/mesh' => ['msh', 'mesh', 'silo'], 'model/mtl' => ['mtl'], 'model/obj' => ['obj'], + 'model/prc' => ['prc'], + 'model/step' => ['step', 'stp'], 'model/step+xml' => ['stpx'], 'model/step+zip' => ['stpz'], 'model/step-xml+zip' => ['stpxz'], 'model/stl' => ['stl'], + 'model/u3d' => ['u3d'], + 'model/vnd.bary' => ['bary'], + 'model/vnd.cld' => ['cld'], 'model/vnd.collada+xml' => ['dae'], 'model/vnd.dwf' => ['dwf'], 'model/vnd.gdl' => ['gdl'], @@ -1575,11 +1657,15 @@ public function guessMimeType(string $path): ?string 'model/vnd.opengex' => ['ogex'], 'model/vnd.parasolid.transmit.binary' => ['x_b'], 'model/vnd.parasolid.transmit.text' => ['x_t'], + 'model/vnd.pytha.pyox' => ['pyo', 'pyox'], 'model/vnd.sap.vds' => ['vds'], + 'model/vnd.usda' => ['usda'], 'model/vnd.usdz+zip' => ['usdz'], 'model/vnd.valve.source.compiled-map' => ['bsp'], 'model/vnd.vtu' => ['vtu'], 'model/vrml' => ['wrl', 'vrml', 'vrm'], + 'model/x.sf3' => ['mod.sf3', 'sf3'], + 'model/x.sf3-physics' => ['phys.sf3', 'sf3'], 'model/x.stl-ascii' => ['stl'], 'model/x.stl-binary' => ['stl'], 'model/x3d+binary' => ['x3db', 'x3dbz'], @@ -1588,7 +1674,7 @@ public function guessMimeType(string $path): ?string 'model/x3d+xml' => ['x3d', 'x3dz'], 'model/x3d-vrml' => ['x3dv'], 'text/cache-manifest' => ['appcache', 'manifest'], - 'text/calendar' => ['ics', 'ifb', 'vcs'], + 'text/calendar' => ['ics', 'ifb', 'vcs', 'icalendar'], 'text/coffeescript' => ['coffee', 'litcoffee'], 'text/crystal' => ['cr'], 'text/css' => ['css'], @@ -1601,7 +1687,9 @@ public function guessMimeType(string $path): ?string 'text/html' => ['html', 'htm', 'shtml'], 'text/ico' => ['ico'], 'text/jade' => ['jade'], - 'text/javascript' => ['js', 'jsm', 'mjs'], + 'text/javascript' => ['js', 'mjs', 'cjs', 'jsm'], + 'text/jscript' => ['cjs', 'js', 'jsm', 'mjs'], + 'text/jscript.encode' => ['jse'], 'text/jsx' => ['jsx'], 'text/julia' => ['jl'], 'text/less' => ['less'], @@ -1630,6 +1718,7 @@ public function guessMimeType(string $path): ?string 'text/uri-list' => ['uri', 'uris', 'urls'], 'text/vbs' => ['vbs'], 'text/vbscript' => ['vbs'], + 'text/vbscript.encode' => ['vbe'], 'text/vcard' => ['vcard', 'vcf', 'vct', 'gcrd'], 'text/vnd.curl' => ['curl'], 'text/vnd.curl.dcurl' => ['dcurl'], @@ -1647,11 +1736,14 @@ public function guessMimeType(string $path): ?string 'text/vnd.senx.warpscript' => ['mc2'], 'text/vnd.sun.j2me.app-descriptor' => ['jad'], 'text/vnd.trolltech.linguist' => ['ts'], + 'text/vnd.typst' => ['typ'], 'text/vnd.wap.wml' => ['wml'], 'text/vnd.wap.wmlscript' => ['wmls'], 'text/vtt' => ['vtt'], + 'text/wgsl' => ['wgsl'], 'text/x-adasrc' => ['adb', 'ads'], 'text/x-asm' => ['s', 'asm'], + 'text/x-basic' => ['bas'], 'text/x-bibtex' => ['bib'], 'text/x-blueprint' => ['blp'], 'text/x-c' => ['c', 'cc', 'cxx', 'cpp', 'h', 'hh', 'dic'], @@ -1667,12 +1759,14 @@ public function guessMimeType(string $path): ?string 'text/x-csharp' => ['cs'], 'text/x-csrc' => ['c'], 'text/x-csv' => ['csv'], + 'text/x-cython' => ['pxd', 'pxi', 'pyx'], 'text/x-dart' => ['dart'], 'text/x-dbus-service' => ['service'], 'text/x-dcl' => ['dcl'], 'text/x-devicetree-binary' => ['dtb'], 'text/x-devicetree-source' => ['dts', 'dtsi'], 'text/x-diff' => ['diff', 'patch'], + 'text/x-dockerfile' => ['Dockerfile'], 'text/x-dsl' => ['dsl'], 'text/x-dsrc' => ['d', 'di'], 'text/x-dtd' => ['dtd'], @@ -1717,17 +1811,24 @@ public function guessMimeType(string $path): ?string 'text/x-mpsub' => ['sub'], 'text/x-mrml' => ['mrml', 'mrl'], 'text/x-ms-regedit' => ['reg'], + 'text/x-ms-visualstudio.project' => ['dsp'], + 'text/x-ms-visualstudio.workspace' => ['dsw'], 'text/x-mup' => ['mup', 'not'], 'text/x-nfo' => ['nfo'], 'text/x-nim' => ['nim'], 'text/x-nimscript' => ['nims', 'nimble'], + 'text/x-nix' => ['nix'], + 'text/x-nsis' => ['nsi', 'nsh'], 'text/x-nu' => ['nu'], + 'text/x-nushell' => ['nu'], 'text/x-objc++src' => ['mm'], 'text/x-objcsrc' => ['m'], 'text/x-ocaml' => ['ml', 'mli'], 'text/x-ocl' => ['ocl'], 'text/x-octave' => ['m'], 'text/x-ooc' => ['ooc'], + 'text/x-opencl-c++src' => ['clcpp'], + 'text/x-opencl-csrc' => ['cl'], 'text/x-opencl-src' => ['cl'], 'text/x-opml' => ['opml'], 'text/x-opml+xml' => ['opml'], @@ -1738,12 +1839,14 @@ public function guessMimeType(string $path): ?string 'text/x-po' => ['po'], 'text/x-pot' => ['pot'], 'text/x-processing' => ['pde'], - 'text/x-python' => ['py', 'pyx', 'wsgi'], - 'text/x-python3' => ['py', 'py3', 'py3x', 'pyi'], + 'text/x-python' => ['py', 'wsgi'], + 'text/x-python2' => ['py', 'py2'], + 'text/x-python3' => ['py', 'py3', 'pyi'], 'text/x-qml' => ['qml', 'qmltypes', 'qmlproject'], 'text/x-reject' => ['rej'], 'text/x-rpm-spec' => ['spec'], 'text/x-rst' => ['rst'], + 'text/x-ruby' => ['rb'], 'text/x-sagemath' => ['sage'], 'text/x-sass' => ['sass'], 'text/x-scala' => ['scala', 'sc'], @@ -1754,6 +1857,7 @@ public function guessMimeType(string $path): ?string 'text/x-sh' => ['sh'], 'text/x-sql' => ['sql'], 'text/x-ssa' => ['ssa', 'ass'], + 'text/x-ssh-public-key' => ['pub'], 'text/x-subviewer' => ['sub'], 'text/x-suse-ymp' => ['ymp'], 'text/x-svhdr' => ['svh'], @@ -1772,7 +1876,8 @@ public function guessMimeType(string $path): ?string 'text/x-uil' => ['uil'], 'text/x-uuencode' => ['uu', 'uue'], 'text/x-vala' => ['vala', 'vapi'], - 'text/x-vcalendar' => ['vcs', 'ics'], + 'text/x-vb' => ['vb'], + 'text/x-vcalendar' => ['vcs', 'ics', 'ifb', 'icalendar'], 'text/x-vcard' => ['vcf', 'vcard', 'vct', 'gcrd'], 'text/x-verilog' => ['v'], 'text/x-vhdl' => ['vhd', 'vhdl'], @@ -1801,10 +1906,11 @@ public function guessMimeType(string $path): ?string 'video/jpm' => ['jpm', 'jpgm'], 'video/mj2' => ['mj2', 'mjp2'], 'video/mp2t' => ['ts', 'm2t', 'm2ts', 'mts', 'cpi', 'clpi', 'mpl', 'mpls', 'bdm', 'bdmv'], - 'video/mp4' => ['mp4', 'mp4v', 'mpg4', 'm4v', 'f4v', 'lrv'], - 'video/mp4v-es' => ['mp4', 'm4v', 'f4v', 'lrv'], + 'video/mp4' => ['mp4', 'mp4v', 'mpg4', 'm4v', 'f4v', 'lrv', 'lrf'], + 'video/mp4v-es' => ['mp4', 'm4v', 'f4v', 'lrv', 'lrf'], 'video/mpeg' => ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v', 'mp2', 'vob'], 'video/mpeg-system' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/mpg4' => ['mpg4'], 'video/msvideo' => ['avi', 'avf', 'divx'], 'video/ogg' => ['ogv', 'ogg'], 'video/quicktime' => ['mov', 'qt', 'moov', 'qtvr'], @@ -1835,7 +1941,7 @@ public function guessMimeType(string $path): ?string 'video/x-flic' => ['fli', 'flc'], 'video/x-flv' => ['flv'], 'video/x-javafx' => ['fxm'], - 'video/x-m4v' => ['m4v', 'mp4', 'f4v', 'lrv'], + 'video/x-m4v' => ['m4v', 'mp4', 'f4v', 'lrv', 'lrf'], 'video/x-matroska' => ['mkv', 'mk3d', 'mks'], 'video/x-matroska-3d' => ['mk3d'], 'video/x-mjpeg' => ['mjpeg', 'mjpg'], @@ -1892,8 +1998,8 @@ public function guessMimeType(string $path): ?string '669' => ['audio/x-mod'], '7z' => ['application/x-7z-compressed'], '7z.001' => ['application/x-7z-compressed'], - 'BLEND' => ['application/x-blender'], 'C' => ['text/x-c++src'], + 'Dockerfile' => ['text/x-dockerfile'], 'PAR2' => ['application/x-par2'], 'PL' => ['application/x-perl', 'text/x-perl'], 'Z' => ['application/x-compress'], @@ -1937,7 +2043,10 @@ public function guessMimeType(string $path): ?string 'ait' => ['application/vnd.dvb.ait'], 'al' => ['application/x-perl', 'text/x-perl'], 'alz' => ['application/x-alz'], + 'amf' => ['application/x-amf'], 'ami' => ['application/vnd.amiga.ami'], + 'aml' => ['application/automationml-aml+xml'], + 'amlx' => ['application/automationml-amlx+zip'], 'amr' => ['audio/amr', 'audio/amr-encrypted'], 'amz' => ['audio/x-amzxml'], 'ani' => ['application/x-navi-animation'], @@ -1953,13 +2062,18 @@ public function guessMimeType(string $path): ?string 'animj' => ['video/x-anim'], 'anx' => ['application/annodex', 'application/x-annodex'], 'ape' => ['audio/x-ape'], - 'apk' => ['application/vnd.android.package-archive'], + 'apk' => ['application/vnd.android.package-archive', 'application/x-alpine-package-keeper-package'], 'apng' => ['image/apng', 'image/vnd.mozilla.apng'], 'appcache' => ['text/cache-manifest'], + 'appdata.xml' => ['application/x-freedesktop-appstream-component'], 'appimage' => ['application/vnd.appimage', 'application/x-iso9660-appimage'], + 'appinstaller' => ['application/appinstaller'], 'application' => ['application/x-ms-application'], + 'appx' => ['application/appx'], + 'appxbundle' => ['application/appxbundle'], 'apr' => ['application/vnd.lotus-approach'], 'ar' => ['application/x-archive'], + 'ar.sf3' => ['application/x.sf3-archive'], 'arc' => ['application/x-freearc'], 'arj' => ['application/x-arj'], 'arw' => ['image/x-sony-arw'], @@ -1982,6 +2096,7 @@ public function guessMimeType(string $path): ?string 'atomsvc' => ['application/atomsvc+xml'], 'atx' => ['application/vnd.antix.game-component'], 'au' => ['audio/basic'], + 'au.sf3' => ['audio/x.sf3'], 'automount' => ['text/x-systemd-unit'], 'avci' => ['image/avci'], 'avcs' => ['image/avcs'], @@ -2001,11 +2116,14 @@ public function guessMimeType(string $path): ?string 'azw3' => ['application/vnd.amazon.mobi8-ebook', 'application/x-mobi8-ebook'], 'b16' => ['image/vnd.pco.b16'], 'bak' => ['application/x-trash'], + 'bary' => ['model/vnd.bary'], + 'bas' => ['text/x-basic'], 'bat' => ['application/bat', 'application/x-bat', 'application/x-msdownload'], 'bcpio' => ['application/x-bcpio'], 'bdf' => ['application/x-font-bdf'], 'bdm' => ['application/vnd.syncml.dm+wbxml', 'video/mp2t'], 'bdmv' => ['video/mp2t'], + 'bdo' => ['application/vnd.nato.bindingdataobject+xml'], 'bdoc' => ['application/bdoc', 'application/x-bdoc'], 'bed' => ['application/vnd.realvnc.bed'], 'bh2' => ['application/vnd.fujitsu.oasysprs'], @@ -2025,11 +2143,14 @@ public function guessMimeType(string $path): ?string 'box' => ['application/vnd.previewsystems.box'], 'boz' => ['application/x-bzip2'], 'bps' => ['application/x-bps-patch'], + 'brk' => ['chemical/x-pdb'], 'bsdiff' => ['application/x-bsdiff'], 'bsp' => ['model/vnd.valve.source.compiled-map'], + 'bst' => ['application/buildstream+yaml'], + 'btf' => ['image/prs.btif'], 'btif' => ['image/prs.btif'], - 'bz' => ['application/bzip2', 'application/x-bzip'], - 'bz2' => ['application/x-bz2', 'application/bzip2', 'application/x-bzip2'], + 'bz' => ['application/bzip2', 'application/x-bzip', 'application/x-bzip1'], + 'bz2' => ['application/x-bz2', 'application/bzip2', 'application/x-bzip', 'application/x-bzip2'], 'bz3' => ['application/x-bzip3'], 'c' => ['text/x-c', 'text/x-csrc'], 'c++' => ['text/x-c++src'], @@ -2070,8 +2191,11 @@ public function guessMimeType(string $path): ?string 'cdmiq' => ['application/cdmi-queue'], 'cdr' => ['application/cdr', 'application/coreldraw', 'application/vnd.corel-draw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'], 'cdx' => ['chemical/x-cdx'], + 'cdx.json' => ['application/vnd.cyclonedx+json'], + 'cdx.xml' => ['application/vnd.cyclonedx+xml'], 'cdxml' => ['application/vnd.chemdraw+xml'], 'cdy' => ['application/vnd.cinderella'], + 'cel' => ['image/x-kiss-cel'], 'cer' => ['application/pkix-cert'], 'cert' => ['application/x-x509-ca-cert'], 'cfs' => ['application/x-cfs-compressed'], @@ -2084,10 +2208,12 @@ public function guessMimeType(string $path): ?string 'cif' => ['chemical/x-cif'], 'cii' => ['application/vnd.anser-web-certificate-issue-initiation'], 'cil' => ['application/vnd.ms-artgalry'], - 'cjs' => ['application/node'], - 'cl' => ['text/x-opencl-src'], + 'cjs' => ['application/javascript', 'application/node', 'application/x-javascript', 'text/javascript', 'text/jscript'], + 'cl' => ['text/x-opencl-csrc', 'text/x-opencl-src'], 'cla' => ['application/vnd.claymore'], 'class' => ['application/java', 'application/java-byte-code', 'application/java-vm', 'application/x-java', 'application/x-java-class', 'application/x-java-vm'], + 'clcpp' => ['text/x-opencl-c++src'], + 'cld' => ['model/vnd.cld'], 'clkk' => ['application/vnd.crick.clicker.keyboard'], 'clkp' => ['application/vnd.crick.clicker.palette'], 'clkt' => ['application/vnd.crick.clicker.template'], @@ -2110,7 +2236,7 @@ public function guessMimeType(string $path): ?string 'cpi' => ['video/mp2t'], 'cpio' => ['application/x-cpio'], 'cpio.gz' => ['application/x-cpio-compressed'], - 'cpl' => ['application/cpl+xml'], + 'cpl' => ['application/cpl+xml', 'application/vnd.microsoft.portable-executable', 'application/x-ms-dos-executable', 'application/x-ms-ne-executable', 'application/x-msdownload'], 'cpp' => ['text/x-c', 'text/x-c++src'], 'cpt' => ['application/mac-compactpro'], 'cr' => ['text/crystal', 'text/x-crystal'], @@ -2133,11 +2259,13 @@ public function guessMimeType(string $path): ?string 'cst' => ['application/x-director'], 'csv' => ['text/csv', 'application/csv', 'text/x-comma-separated-values', 'text/x-csv'], 'csvs' => ['text/csv-schema'], + 'cts' => ['application/typescript'], 'cu' => ['application/cu-seeme'], 'cue' => ['application/x-cue'], 'cur' => ['image/x-win-bitmap'], 'curl' => ['text/vnd.curl'], 'cwk' => ['application/x-appleworks-document'], + 'cwl' => ['application/cwl'], 'cww' => ['application/prs.cww'], 'cxt' => ['application/x-director'], 'cxx' => ['text/x-c', 'text/x-c++src'], @@ -2178,7 +2306,7 @@ public function guessMimeType(string $path): ?string 'divx' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.avi', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], 'djv' => ['image/vnd.djvu', 'image/vnd.djvu+multipage', 'image/x-djvu', 'image/x.djvu'], 'djvu' => ['image/vnd.djvu', 'image/vnd.djvu+multipage', 'image/x-djvu', 'image/x.djvu'], - 'dll' => ['application/x-msdownload'], + 'dll' => ['application/vnd.microsoft.portable-executable', 'application/x-ms-dos-executable', 'application/x-ms-ne-executable', 'application/x-msdownload'], 'dmg' => ['application/x-apple-diskimage'], 'dmp' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], 'dna' => ['application/vnd.dna'], @@ -2192,13 +2320,18 @@ public function guessMimeType(string $path): ?string 'dotx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.template'], 'dp' => ['application/vnd.osgi.dp'], 'dpg' => ['application/vnd.dpgraph'], + 'dpx' => ['image/dpx'], 'dra' => ['audio/vnd.dra'], 'drl' => ['application/x-excellon'], 'drle' => ['image/dicom-rle'], + 'drv' => ['application/vnd.microsoft.portable-executable', 'application/x-ms-dos-executable', 'application/x-ms-ne-executable', 'application/x-msdownload'], 'dsc' => ['text/prs.lines.tag'], 'dsf' => ['audio/dsd', 'audio/dsf', 'audio/x-dsd', 'audio/x-dsf'], 'dsl' => ['text/x-dsl'], + 'dsm' => ['audio/x-dsp'], + 'dsp' => ['audio/x-dsp', 'text/x-ms-visualstudio.project'], 'dssc' => ['application/dssc+der'], + 'dsw' => ['text/x-ms-visualstudio.workspace'], 'dtb' => ['application/x-dtbook+xml', 'text/x-devicetree-binary'], 'dtd' => ['application/xml-dtd', 'text/x-dtd'], 'dts' => ['audio/vnd.dts', 'audio/x-dts', 'text/x-devicetree-source'], @@ -2224,6 +2357,7 @@ public function guessMimeType(string $path): ?string 'ecma' => ['application/ecmascript'], 'edm' => ['application/vnd.novadigm.edm'], 'edx' => ['application/vnd.novadigm.edx'], + 'efi' => ['application/vnd.microsoft.portable-executable'], 'efif' => ['application/vnd.picsel'], 'egon' => ['application/x-egon'], 'ei6' => ['application/vnd.pg.osasli'], @@ -2261,7 +2395,7 @@ public function guessMimeType(string $path): ?string 'eva' => ['application/x-eva'], 'evy' => ['application/x-envoy'], 'ex' => ['text/x-elixir'], - 'exe' => ['application/x-ms-dos-executable', 'application/x-msdos-program', 'application/x-msdownload'], + 'exe' => ['application/vnd.microsoft.portable-executable', 'application/x-dosexec', 'application/x-ms-dos-executable', 'application/x-ms-ne-executable', 'application/x-msdos-program', 'application/x-msdownload'], 'exi' => ['application/exi'], 'exp' => ['application/express'], 'exr' => ['image/aces', 'image/x-exr'], @@ -2284,7 +2418,7 @@ public function guessMimeType(string $path): ?string 'fcdt' => ['application/vnd.adobe.formscentral.fcdt'], 'fcs' => ['application/vnd.isac.fcs'], 'fd' => ['application/x-fd-file', 'application/x-raw-floppy-disk-image'], - 'fdf' => ['application/vnd.fdf'], + 'fdf' => ['application/fdf', 'application/vnd.fdf'], 'fds' => ['application/x-fds-disk'], 'fdt' => ['application/fdt+xml'], 'fe_launch' => ['application/vnd.denovo.fcselayout-link'], @@ -2320,7 +2454,7 @@ public function guessMimeType(string $path): ?string 'fods' => ['application/vnd.oasis.opendocument.spreadsheet-flat-xml'], 'fodt' => ['application/vnd.oasis.opendocument.text-flat-xml'], 'for' => ['text/x-fortran'], - 'fpx' => ['image/vnd.fpx'], + 'fpx' => ['image/vnd.fpx', 'image/x-fpx'], 'frame' => ['application/vnd.framemaker'], 'fsc' => ['application/vnd.fsc.weblaunch'], 'fst' => ['image/vnd.fst'], @@ -2361,6 +2495,7 @@ public function guessMimeType(string $path): ?string 'gf' => ['application/x-tex-gf'], 'gg' => ['application/x-gamegear-rom'], 'ggb' => ['application/vnd.geogebra.file'], + 'ggs' => ['application/vnd.geogebra.slides'], 'ggt' => ['application/vnd.geogebra.tool'], 'ghf' => ['application/vnd.groove-help'], 'gif' => ['image/gif'], @@ -2418,6 +2553,7 @@ public function guessMimeType(string $path): ?string 'h4' => ['application/x-hdf'], 'h5' => ['application/x-hdf'], 'hal' => ['application/vnd.hal+xml'], + 'har' => ['application/har+json'], 'hbci' => ['application/vnd.hbci'], 'hbs' => ['text/x-handlebars-template'], 'hdd' => ['application/x-virtualbox-hdd'], @@ -2425,6 +2561,7 @@ public function guessMimeType(string $path): ?string 'hdf4' => ['application/x-hdf'], 'hdf5' => ['application/x-hdf'], 'hdp' => ['image/jxr', 'image/vnd.ms-photo'], + 'hdr' => ['image/vnd.radiance', 'image/x-hdr'], 'heic' => ['image/heic', 'image/heic-sequence', 'image/heif', 'image/heif-sequence'], 'heics' => ['image/heic-sequence'], 'heif' => ['image/heic', 'image/heic-sequence', 'image/heif', 'image/heif-sequence'], @@ -2444,6 +2581,7 @@ public function guessMimeType(string $path): ?string 'hqx' => ['application/stuffit', 'application/mac-binhex40'], 'hs' => ['text/x-haskell'], 'hsj2' => ['image/hsj2'], + 'hta' => ['application/hta'], 'htc' => ['text/x-component'], 'htke' => ['application/vnd.kenameaapp'], 'htm' => ['text/html', 'application/xhtml+xml'], @@ -2456,6 +2594,7 @@ public function guessMimeType(string $path): ?string 'hxx' => ['text/x-c++hdr'], 'i2g' => ['application/vnd.intergeo'], 'ica' => ['application/x-ica'], + 'icalendar' => ['application/ics', 'text/calendar', 'text/x-vcalendar'], 'icb' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], 'icc' => ['application/vnd.iccprofile'], 'ice' => ['x-conference/x-cooltalk'], @@ -2465,7 +2604,7 @@ public function guessMimeType(string $path): ?string 'ics' => ['application/ics', 'text/calendar', 'text/x-vcalendar'], 'idl' => ['text/x-idl'], 'ief' => ['image/ief'], - 'ifb' => ['text/calendar'], + 'ifb' => ['application/ics', 'text/calendar', 'text/x-vcalendar'], 'iff' => ['image/x-iff', 'image/x-ilbm'], 'ifm' => ['application/vnd.shana.informed.formdata'], 'iges' => ['model/iges'], @@ -2477,6 +2616,7 @@ public function guessMimeType(string $path): ?string 'ilbm' => ['image/x-iff', 'image/x-ilbm'], 'ime' => ['audio/imelody', 'audio/x-imelody', 'text/x-imelody'], 'img' => ['application/vnd.efi.img', 'application/x-raw-disk-image'], + 'img.sf3' => ['image/x.sf3'], 'img.xz' => ['application/x-raw-disk-image-xz-compressed'], 'imp' => ['application/vnd.accpac.simply.imp'], 'ims' => ['application/vnd.ms-ims'], @@ -2512,6 +2652,7 @@ public function guessMimeType(string $path): ?string 'jardiff' => ['application/x-java-archive-diff'], 'java' => ['text/x-java', 'text/x-java-source'], 'jceks' => ['application/x-java-jce-keystore'], + 'jfif' => ['image/jpeg', 'image/pjpeg'], 'jhc' => ['image/jphc'], 'jisp' => ['application/vnd.jisp'], 'jks' => ['application/x-java-keystore'], @@ -2535,14 +2676,16 @@ public function guessMimeType(string $path): ?string 'jpr' => ['application/x-jbuilder-project'], 'jpx' => ['application/x-jbuilder-project', 'image/jpx'], 'jrd' => ['application/jrd+json'], - 'js' => ['text/javascript', 'application/javascript', 'application/x-javascript'], - 'jsm' => ['application/javascript', 'application/x-javascript', 'text/javascript'], + 'js' => ['text/javascript', 'application/javascript', 'application/x-javascript', 'text/jscript'], + 'jse' => ['text/jscript.encode'], + 'jsm' => ['application/javascript', 'application/x-javascript', 'text/javascript', 'text/jscript'], 'json' => ['application/json', 'application/schema+json'], 'json-patch' => ['application/json-patch+json'], 'json5' => ['application/json5'], 'jsonld' => ['application/ld+json'], 'jsonml' => ['application/jsonml+json'], 'jsx' => ['text/jsx'], + 'jt' => ['model/jt'], 'jxl' => ['image/jxl'], 'jxr' => ['image/jxr', 'image/vnd.ms-photo'], 'jxra' => ['image/jxra'], @@ -2555,6 +2698,7 @@ public function guessMimeType(string $path): ?string 'k7' => ['application/x-thomson-cassette'], 'kar' => ['audio/midi', 'audio/x-midi'], 'karbon' => ['application/vnd.kde.karbon', 'application/x-karbon'], + 'kcf' => ['image/x-kiss-cel'], 'kdbx' => ['application/x-keepass2'], 'kdc' => ['image/x-kodak-kdc'], 'kdelnk' => ['application/x-desktop', 'application/x-gnome-app-info'], @@ -2603,6 +2747,7 @@ public function guessMimeType(string $path): ?string 'lha' => ['application/x-lha', 'application/x-lzh-compressed'], 'lhs' => ['text/x-literate-haskell'], 'lhz' => ['application/x-lhz'], + 'lib' => ['application/vnd.microsoft.portable-executable', 'application/x-archive'], 'link66' => ['application/vnd.route66.link66+xml'], 'lisp' => ['text/x-common-lisp'], 'list' => ['text/plain'], @@ -2610,11 +2755,13 @@ public function guessMimeType(string $path): ?string 'listafp' => ['application/vnd.ibm.modcap'], 'litcoffee' => ['text/coffeescript'], 'lmdb' => ['application/x-lmdb'], - 'lnk' => ['application/x-ms-shortcut'], + 'lnk' => ['application/x-ms-shortcut', 'application/x-win-lnk'], 'lnx' => ['application/x-atari-lynx-rom'], 'loas' => ['audio/usac'], 'log' => ['text/plain', 'text/x-log'], + 'log.sf3' => ['application/x.sf3-log'], 'lostxml' => ['application/lost+xml'], + 'lrf' => ['application/x-sony-bbeb', 'video/mp4', 'video/mp4v-es', 'video/x-m4v'], 'lrm' => ['application/vnd.ms-lrm'], 'lrv' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], 'lrz' => ['application/x-lrzip'], @@ -2676,7 +2823,7 @@ public function guessMimeType(string $path): ?string 'mc2' => ['text/vnd.senx.warpscript'], 'mcd' => ['application/vnd.mcd'], 'mcurl' => ['text/vnd.curl.mcurl'], - 'md' => ['text/markdown', 'text/x-markdown'], + 'md' => ['text/markdown', 'text/x-markdown', 'application/x-genesis-rom'], 'mdb' => ['application/x-msaccess', 'application/mdb', 'application/msaccess', 'application/vnd.ms-access', 'application/vnd.msaccess', 'application/x-lmdb', 'application/x-mdb', 'zz-application/zz-winassoc-mdb'], 'mdi' => ['image/vnd.ms-modi'], 'mdx' => ['application/x-genesis-32x-rom', 'text/mdx'], @@ -2684,6 +2831,7 @@ public function guessMimeType(string $path): ?string 'med' => ['audio/x-mod'], 'mesh' => ['model/mesh'], 'meta4' => ['application/metalink4+xml'], + 'metainfo.xml' => ['application/x-freedesktop-appstream-component'], 'metalink' => ['application/metalink+xml'], 'mets' => ['application/mets+xml'], 'mfm' => ['application/vnd.mfmp'], @@ -2702,7 +2850,7 @@ public function guessMimeType(string $path): ?string 'mjp2' => ['video/mj2'], 'mjpeg' => ['video/x-mjpeg'], 'mjpg' => ['video/x-mjpeg'], - 'mjs' => ['application/javascript', 'application/x-javascript', 'text/javascript'], + 'mjs' => ['application/javascript', 'application/x-javascript', 'text/javascript', 'text/jscript'], 'mk' => ['text/x-makefile'], 'mk3d' => ['video/x-matroska', 'video/x-matroska-3d'], 'mka' => ['audio/x-matroska'], @@ -2724,6 +2872,7 @@ public function guessMimeType(string $path): ?string 'mobi' => ['application/x-mobipocket-ebook'], 'moc' => ['text/x-moc'], 'mod' => ['application/x-object', 'audio/x-mod'], + 'mod.sf3' => ['model/x.sf3'], 'mods' => ['application/mods+xml'], 'mof' => ['text/x-mof'], 'moov' => ['video/quicktime'], @@ -2735,7 +2884,7 @@ public function guessMimeType(string $path): ?string 'mp21' => ['application/mp21'], 'mp2a' => ['audio/mpeg'], 'mp3' => ['audio/mpeg', 'audio/mp3', 'audio/x-mp3', 'audio/x-mpeg', 'audio/x-mpg'], - 'mp4' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], + 'mp4' => ['video/mp4', 'application/mp4', 'video/mp4v-es', 'video/x-m4v'], 'mp4a' => ['audio/mp4'], 'mp4s' => ['application/mp4'], 'mp4v' => ['video/mp4'], @@ -2745,7 +2894,7 @@ public function guessMimeType(string $path): ?string 'mpeg' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], 'mpf' => ['application/media-policy-dataset+xml'], 'mpg' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], - 'mpg4' => ['video/mp4'], + 'mpg4' => ['video/mpg4', 'application/mp4', 'video/mp4'], 'mpga' => ['audio/mp3', 'audio/mpeg', 'audio/x-mp3', 'audio/x-mpeg', 'audio/x-mpg'], 'mpkg' => ['application/vnd.apple.installer+xml'], 'mpl' => ['text/x-mpl2', 'video/mp2t'], @@ -2770,13 +2919,17 @@ public function guessMimeType(string $path): ?string 'msg' => ['application/vnd.ms-outlook'], 'msh' => ['model/mesh'], 'msi' => ['application/x-msdownload', 'application/x-msi'], + 'msix' => ['application/msix'], + 'msixbundle' => ['application/msixbundle'], 'msl' => ['application/vnd.mobius.msl'], 'msod' => ['image/x-msod'], + 'msp' => ['application/microsoftpatch'], 'msty' => ['application/vnd.muvee.style'], + 'msu' => ['application/microsoftupdate'], 'msx' => ['application/x-msx-rom'], 'mtl' => ['model/mtl'], 'mtm' => ['audio/x-mod'], - 'mts' => ['model/vnd.mts', 'video/mp2t'], + 'mts' => ['application/typescript', 'model/vnd.mts', 'video/mp2t'], 'mup' => ['text/x-mup'], 'mus' => ['application/vnd.musician'], 'musd' => ['application/mmt-usd+xml'], @@ -2809,6 +2962,7 @@ public function guessMimeType(string $path): ?string 'nimble' => ['text/x-nimscript'], 'nims' => ['text/x-nimscript'], 'nitf' => ['application/vnd.nitf'], + 'nix' => ['text/x-nix'], 'nlu' => ['application/vnd.neurolanguage.nlu'], 'nml' => ['application/vnd.enliven'], 'nnd' => ['application/vnd.noblenet-directory'], @@ -2820,10 +2974,13 @@ public function guessMimeType(string $path): ?string 'nrw' => ['image/x-nikon-nrw'], 'nsc' => ['application/x-conference', 'application/x-netshow-channel'], 'nsf' => ['application/vnd.lotus-notes'], + 'nsh' => ['text/x-nsis'], + 'nsi' => ['text/x-nsis'], 'nsv' => ['video/x-nsv'], 'nt' => ['application/n-triples'], + 'ntar' => ['application/x-pcapng'], 'ntf' => ['application/vnd.nitf'], - 'nu' => ['application/x-nuscript', 'text/x-nu'], + 'nu' => ['application/x-nuscript', 'text/x-nu', 'text/x-nushell'], 'numbers' => ['application/vnd.apple.numbers', 'application/x-iwork-numbers-sffnumbers'], 'nzb' => ['application/x-nzb'], 'o' => ['application/x-object'], @@ -2832,10 +2989,11 @@ public function guessMimeType(string $path): ?string 'oas' => ['application/vnd.fujitsu.oasys'], 'obd' => ['application/x-msbinder'], 'obgx' => ['application/vnd.openblox.game+xml'], - 'obj' => ['application/x-tgif', 'model/obj'], + 'obj' => ['application/prs.wavefront-obj', 'application/x-tgif', 'model/obj'], 'ocl' => ['text/x-ocl'], + 'ocx' => ['application/vnd.microsoft.portable-executable'], 'oda' => ['application/oda'], - 'odb' => ['application/vnd.oasis.opendocument.database', 'application/vnd.sun.xml.base'], + 'odb' => ['application/vnd.oasis.opendocument.base', 'application/vnd.oasis.opendocument.database', 'application/vnd.sun.xml.base'], 'odc' => ['application/vnd.oasis.opendocument.chart'], 'odf' => ['application/vnd.oasis.opendocument.formula'], 'odft' => ['application/vnd.oasis.opendocument.formula-template'], @@ -2875,6 +3033,7 @@ public function guessMimeType(string $path): ?string 'otg' => ['application/vnd.oasis.opendocument.graphics-template'], 'oth' => ['application/vnd.oasis.opendocument.text-web'], 'oti' => ['application/vnd.oasis.opendocument.image-template'], + 'otm' => ['application/vnd.oasis.opendocument.text-master-template'], 'otp' => ['application/vnd.oasis.opendocument.presentation-template'], 'ots' => ['application/vnd.oasis.opendocument.spreadsheet-template'], 'ott' => ['application/vnd.oasis.opendocument.text-template'], @@ -2901,6 +3060,7 @@ public function guessMimeType(string $path): ?string 'pages' => ['application/vnd.apple.pages', 'application/x-iwork-pages-sffpages'], 'pak' => ['application/x-pak'], 'par2' => ['application/x-par2'], + 'parquet' => ['application/vnd.apache.parquet', 'application/x-parquet'], 'part' => ['application/x-partial-download'], 'pas' => ['text/x-pascal'], 'pat' => ['image/x-gimp-pat'], @@ -2910,6 +3070,7 @@ public function guessMimeType(string $path): ?string 'pbd' => ['application/vnd.powerbuilder6'], 'pbm' => ['image/x-portable-bitmap'], 'pcap' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], + 'pcapng' => ['application/x-pcapng'], 'pcd' => ['image/x-photo-cd'], 'pce' => ['application/x-pc-engine-rom'], 'pcf' => ['application/x-cisco-vpn-settings', 'application/x-font-pcf'], @@ -2920,7 +3081,7 @@ public function guessMimeType(string $path): ?string 'pct' => ['image/x-pict'], 'pcurl' => ['application/vnd.curl.pcurl'], 'pcx' => ['image/vnd.zbrush.pcx', 'image/x-pcx'], - 'pdb' => ['application/vnd.palm', 'application/x-aportisdoc', 'application/x-ms-pdb', 'application/x-palm-database', 'application/x-pilot'], + 'pdb' => ['application/vnd.palm', 'application/x-aportisdoc', 'application/x-ms-pdb', 'application/x-palm-database', 'application/x-pilot', 'chemical/x-pdb'], 'pdc' => ['application/x-aportisdoc'], 'pde' => ['text/x-processing'], 'pdf' => ['application/pdf', 'application/acrobat', 'application/nappdf', 'application/x-pdf', 'image/pdf'], @@ -2933,18 +3094,20 @@ public function guessMimeType(string $path): ?string 'perl' => ['application/x-perl', 'text/x-perl'], 'pfa' => ['application/x-font-type1'], 'pfb' => ['application/x-font-type1'], - 'pfm' => ['application/x-font-type1'], + 'pfm' => ['application/x-font-type1', 'image/x-pfm'], 'pfr' => ['application/font-tdpfr', 'application/vnd.truedoc'], 'pfx' => ['application/pkcs12', 'application/x-pkcs12'], 'pgm' => ['image/x-portable-graymap'], 'pgn' => ['application/vnd.chess-pgn', 'application/x-chess-pgn'], 'pgp' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature'], + 'phm' => ['image/x-phm'], 'php' => ['application/x-php', 'application/x-httpd-php'], 'php3' => ['application/x-php'], 'php4' => ['application/x-php'], 'php5' => ['application/x-php'], 'phps' => ['application/x-php'], - 'pic' => ['image/x-pict'], + 'phys.sf3' => ['model/x.sf3-physics'], + 'pic' => ['image/vnd.radiance', 'image/x-hdr', 'image/x-pict'], 'pict' => ['image/x-pict'], 'pict1' => ['image/x-pict'], 'pict2' => ['image/x-pict'], @@ -2953,6 +3116,7 @@ public function guessMimeType(string $path): ?string 'pki' => ['application/pkixcmp'], 'pkipath' => ['application/pkix-pkipath'], 'pkpass' => ['application/vnd.apple.pkpass'], + 'pkpasses' => ['application/vnd.apple.pkpasses'], 'pkr' => ['application/pgp-keys'], 'pl' => ['application/x-perl', 'text/x-perl'], 'pla' => ['audio/x-iriver-pla'], @@ -2986,13 +3150,14 @@ public function guessMimeType(string $path): ?string 'pptx' => ['application/vnd.openxmlformats-officedocument.presentationml.presentation'], 'ppz' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint'], 'pqa' => ['application/vnd.palm', 'application/x-palm-database'], - 'prc' => ['application/vnd.palm', 'application/x-mobipocket-ebook', 'application/x-palm-database', 'application/x-pilot'], + 'prc' => ['application/vnd.palm', 'application/x-mobipocket-ebook', 'application/x-palm-database', 'application/x-pilot', 'model/prc'], 'pre' => ['application/vnd.lotus-freelance'], 'prf' => ['application/pics-rules'], 'provx' => ['application/provenance+xml'], 'ps' => ['application/postscript'], 'ps.bz2' => ['application/x-bzpostscript'], 'ps.gz' => ['application/x-gzpostscript'], + 'ps1' => ['application/x-powershell'], 'psb' => ['application/vnd.3gpp.pic-bw-small'], 'psd' => ['application/photoshop', 'application/x-photoshop', 'image/photoshop', 'image/psd', 'image/vnd.adobe.photoshop', 'image/x-photoshop', 'image/x-psd'], 'psf' => ['application/x-font-linux-psf', 'audio/x-psf'], @@ -3003,23 +3168,28 @@ public function guessMimeType(string $path): ?string 'psw' => ['application/x-pocket-word'], 'pti' => ['image/prs.pti'], 'ptid' => ['application/vnd.pvi.ptid1'], - 'pub' => ['application/vnd.ms-publisher', 'application/x-mspublisher'], + 'pub' => ['application/vnd.ms-publisher', 'application/x-mspublisher', 'text/x-ssh-public-key'], 'pvb' => ['application/vnd.3gpp.pic-bw-var'], 'pw' => ['application/x-pw'], 'pwn' => ['application/vnd.3m.post-it-notes'], - 'py' => ['text/x-python', 'text/x-python3'], + 'pxd' => ['text/x-cython'], + 'pxi' => ['text/x-cython'], + 'pxr' => ['image/x-pxr'], + 'py' => ['text/x-python', 'text/x-python2', 'text/x-python3'], + 'py2' => ['text/x-python2'], 'py3' => ['text/x-python3'], - 'py3x' => ['text/x-python3'], 'pya' => ['audio/vnd.ms-playready.media.pya'], 'pyc' => ['application/x-python-bytecode'], 'pyi' => ['text/x-python3'], - 'pyo' => ['application/x-python-bytecode'], + 'pyo' => ['application/x-python-bytecode', 'model/vnd.pytha.pyox'], + 'pyox' => ['model/vnd.pytha.pyox'], 'pys' => ['application/x-pyspread-bz-spreadsheet'], 'pysu' => ['application/x-pyspread-spreadsheet'], 'pyv' => ['video/vnd.ms-playready.media.pyv'], - 'pyx' => ['text/x-python'], + 'pyx' => ['text/x-cython'], 'qam' => ['application/vnd.epson.quickanime'], 'qbo' => ['application/vnd.intu.qbo'], + 'qbrew' => ['application/x-qbrew'], 'qcow' => ['application/x-qemu-disk'], 'qcow2' => ['application/x-qemu-disk'], 'qd' => ['application/x-fd-file', 'application/x-raw-floppy-disk-image'], @@ -3032,6 +3202,7 @@ public function guessMimeType(string $path): ?string 'qoi' => ['image/qoi'], 'qp' => ['application/x-qpress'], 'qps' => ['application/vnd.publishare-delta-tree'], + 'qpw' => ['application/x-quattropro'], 'qs' => ['application/sparql-query'], 'qt' => ['video/quicktime'], 'qti' => ['application/x-qtiplot'], @@ -3044,6 +3215,7 @@ public function guessMimeType(string $path): ?string 'qxb' => ['application/vnd.quark.quarkxpress'], 'qxd' => ['application/vnd.quark.quarkxpress'], 'qxl' => ['application/vnd.quark.quarkxpress'], + 'qxp' => ['application/vnd.quark.quarkxpress'], 'qxt' => ['application/vnd.quark.quarkxpress'], 'ra' => ['audio/vnd.m-realaudio', 'audio/vnd.rn-realaudio', 'audio/x-pn-realaudio', 'audio/x-realaudio'], 'raf' => ['image/x-fuji-raf'], @@ -3056,17 +3228,19 @@ public function guessMimeType(string $path): ?string 'raw-disk-image' => ['application/vnd.efi.img', 'application/x-raw-disk-image'], 'raw-disk-image.xz' => ['application/x-raw-disk-image-xz-compressed'], 'rax' => ['audio/vnd.m-realaudio', 'audio/vnd.rn-realaudio', 'audio/x-pn-realaudio'], - 'rb' => ['application/x-ruby'], + 'rb' => ['application/x-ruby', 'text/x-ruby'], 'rcprofile' => ['application/vnd.ipunplugged.rcprofile'], 'rdf' => ['application/rdf+xml', 'text/rdf'], 'rdfs' => ['application/rdf+xml', 'text/rdf'], 'rdz' => ['application/vnd.data-vision.rdz'], 'reg' => ['text/x-ms-regedit'], 'rej' => ['application/x-reject', 'text/x-reject'], + 'releases.xml' => ['application/x-freedesktop-appstream-releases'], 'relo' => ['application/p2p-overlay+xml'], 'rep' => ['application/vnd.businessobjects'], 'res' => ['application/x-dtbresource+xml', 'application/x-godot-resource'], 'rgb' => ['image/x-rgb'], + 'rgbe' => ['image/vnd.radiance', 'image/x-hdr'], 'rif' => ['application/reginfo+xml'], 'rip' => ['audio/vnd.rip'], 'ris' => ['application/x-research-info-systems'], @@ -3107,6 +3281,7 @@ public function guessMimeType(string $path): ?string 'rv' => ['video/vnd.rn-realvideo', 'video/x-real-video'], 'rvx' => ['video/vnd.rn-realvideo', 'video/x-real-video'], 'rw2' => ['image/x-panasonic-raw2', 'image/x-panasonic-rw2'], + 'rz' => ['application/x-rzip'], 's' => ['text/x-asm'], 's3m' => ['audio/s3m', 'audio/x-s3m'], 'saf' => ['application/vnd.yamaha.smaf-audio'], @@ -3119,22 +3294,26 @@ public function guessMimeType(string $path): ?string 'sbml' => ['application/sbml+xml'], 'sc' => ['application/vnd.ibm.secure-container', 'text/x-scala'], 'scala' => ['text/x-scala'], + 'scap' => ['application/x-pcapng'], 'scd' => ['application/x-msschedule'], 'scm' => ['application/vnd.lotus-screencam', 'text/x-scheme'], 'scn' => ['application/x-godot-scene'], 'scope' => ['text/x-systemd-unit'], 'scq' => ['application/scvp-cv-request'], + 'scr' => ['application/vnd.microsoft.portable-executable', 'application/x-ms-dos-executable', 'application/x-ms-ne-executable', 'application/x-msdownload'], 'scs' => ['application/scvp-cv-response'], 'scss' => ['text/x-scss'], + 'sct' => ['image/x-sct'], 'scurl' => ['text/vnd.curl.scurl'], - 'sda' => ['application/vnd.stardivision.draw'], - 'sdc' => ['application/vnd.stardivision.calc'], - 'sdd' => ['application/vnd.stardivision.impress'], + 'sda' => ['application/vnd.stardivision.draw', 'application/x-stardraw'], + 'sdc' => ['application/vnd.stardivision.calc', 'application/x-starcalc'], + 'sdd' => ['application/vnd.stardivision.impress', 'application/x-starimpress'], 'sdkd' => ['application/vnd.solent.sdkm+xml'], 'sdkm' => ['application/vnd.solent.sdkm+xml'], - 'sdp' => ['application/sdp', 'application/vnd.sdp', 'application/vnd.stardivision.impress', 'application/x-sdp'], - 'sds' => ['application/vnd.stardivision.chart'], - 'sdw' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'sdm' => ['application/vnd.stardivision.mail'], + 'sdp' => ['application/sdp', 'application/vnd.sdp', 'application/vnd.stardivision.impress-packed', 'application/x-sdp'], + 'sds' => ['application/vnd.stardivision.chart', 'application/x-starchart'], + 'sdw' => ['application/vnd.stardivision.writer', 'application/x-starwriter'], 'sea' => ['application/x-sea'], 'see' => ['application/vnd.seemail'], 'seed' => ['application/vnd.fdsn.seed'], @@ -3147,16 +3326,17 @@ public function guessMimeType(string $path): ?string 'service' => ['text/x-dbus-service', 'text/x-systemd-unit'], 'setpay' => ['application/set-payment-initiation'], 'setreg' => ['application/set-registration-initiation'], + 'sf3' => ['application/x.sf3-archive', 'application/x.sf3-log', 'application/x.sf3-table', 'application/x.sf3-text', 'audio/x.sf3', 'image/x.sf3', 'image/x.sf3-vector', 'model/x.sf3', 'model/x.sf3-physics'], 'sfc' => ['application/vnd.nintendo.snes.rom', 'application/x-snes-rom'], 'sfd-hdstx' => ['application/vnd.hydrostatix.sof-data'], - 'sfs' => ['application/vnd.spotfire.sfs'], + 'sfs' => ['application/vnd.spotfire.sfs', 'application/vnd.squashfs'], 'sfv' => ['text/x-sfv'], 'sg' => ['application/x-sg1000-rom'], 'sgb' => ['application/x-gameboy-rom'], 'sgd' => ['application/x-genesis-rom'], 'sgf' => ['application/x-go-sgf'], 'sgi' => ['image/sgi', 'image/x-sgi'], - 'sgl' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'sgl' => ['application/vnd.stardivision.writer-global', 'application/x-starwriter-global'], 'sgm' => ['text/sgml'], 'sgml' => ['text/sgml'], 'sh' => ['application/x-sh', 'application/x-shellscript', 'text/x-sh'], @@ -3189,15 +3369,15 @@ public function guessMimeType(string $path): ?string 'sldx' => ['application/vnd.openxmlformats-officedocument.presentationml.slide'], 'slice' => ['text/x-systemd-unit'], 'slim' => ['text/slim'], - 'slk' => ['text/spreadsheet'], + 'slk' => ['application/x-sylk', 'text/spreadsheet'], 'slm' => ['text/slim'], 'sls' => ['application/route-s-tsid+xml'], 'slt' => ['application/vnd.epson.salt'], 'sm' => ['application/vnd.stepmania.stepchart'], 'smaf' => ['application/vnd.smaf', 'application/x-smaf'], 'smc' => ['application/vnd.nintendo.snes.rom', 'application/x-snes-rom'], - 'smd' => ['application/vnd.stardivision.mail', 'application/x-genesis-rom'], - 'smf' => ['application/vnd.stardivision.math'], + 'smd' => ['application/x-genesis-rom', 'application/x-starmail'], + 'smf' => ['application/vnd.stardivision.math', 'application/x-starmath'], 'smi' => ['application/smil', 'application/smil+xml', 'application/x-sami'], 'smil' => ['application/smil', 'application/smil+xml'], 'smk' => ['video/vnd.radgamettools.smacker'], @@ -3213,6 +3393,7 @@ public function guessMimeType(string $path): ?string 'spc' => ['application/x-pkcs7-certificates'], 'spd' => ['application/x-font-speedo'], 'spdx' => ['text/spdx'], + 'spdx.json' => ['application/spdx+json'], 'spec' => ['text/x-rpm-spec'], 'spf' => ['application/vnd.yamaha.smaf-phrase'], 'spl' => ['application/futuresplash', 'application/vnd.adobe.flash.movie', 'application/x-futuresplash', 'application/x-shockwave-flash'], @@ -3221,10 +3402,12 @@ public function guessMimeType(string $path): ?string 'spp' => ['application/scvp-vp-response'], 'spq' => ['application/scvp-vp-request'], 'spx' => ['application/x-apple-systemprofiler+xml', 'audio/ogg', 'audio/x-speex', 'audio/x-speex+ogg'], + 'sqfs' => ['application/vnd.squashfs'], 'sql' => ['application/sql', 'application/x-sql', 'text/x-sql'], 'sqlite2' => ['application/x-sqlite2'], 'sqlite3' => ['application/vnd.sqlite3', 'application/x-sqlite3'], 'sqsh' => ['application/vnd.squashfs'], + 'squashfs' => ['application/vnd.squashfs'], 'sr2' => ['image/x-sony-sr2'], 'src' => ['application/x-wais-source'], 'src.rpm' => ['application/x-source-rpm'], @@ -3241,11 +3424,13 @@ public function guessMimeType(string $path): ?string 'st' => ['application/vnd.sailingtracker.track'], 'stc' => ['application/vnd.sun.xml.calc.template'], 'std' => ['application/vnd.sun.xml.draw.template'], + 'step' => ['model/step'], 'stf' => ['application/vnd.wt.stf'], 'sti' => ['application/vnd.sun.xml.impress.template'], 'stk' => ['application/hyperstudio'], 'stl' => ['application/vnd.ms-pki.stl', 'model/stl', 'model/x.stl-ascii', 'model/x.stl-binary'], 'stm' => ['audio/x-stm'], + 'stp' => ['model/step'], 'stpx' => ['model/step+xml'], 'stpxz' => ['model/step-xml+zip'], 'stpz' => ['model/step+zip'], @@ -3279,19 +3464,21 @@ public function guessMimeType(string $path): ?string 'sxi' => ['application/vnd.sun.xml.impress'], 'sxm' => ['application/vnd.sun.xml.math'], 'sxw' => ['application/vnd.sun.xml.writer'], - 'sylk' => ['text/spreadsheet'], + 'sylk' => ['application/x-sylk', 'text/spreadsheet'], + 'sys' => ['application/vnd.microsoft.portable-executable'], 't' => ['application/x-perl', 'application/x-troff', 'text/troff', 'text/x-perl', 'text/x-troff'], 't2t' => ['text/x-txt2tags'], 't3' => ['application/x-t3vm-image'], 't38' => ['image/t38'], + 'tab.sf3' => ['application/x.sf3-table'], 'taglet' => ['application/vnd.mynfc'], 'tak' => ['audio/x-tak'], 'tao' => ['application/vnd.tao.intent-module-archive'], 'tap' => ['image/vnd.tencent.tap'], 'tar' => ['application/x-tar', 'application/x-gtar'], 'tar.Z' => ['application/x-tarz'], - 'tar.bz' => ['application/x-bzip-compressed-tar'], - 'tar.bz2' => ['application/x-bzip2-compressed-tar'], + 'tar.bz' => ['application/x-bzip1-compressed-tar'], + 'tar.bz2' => ['application/x-bzip-compressed-tar', 'application/x-bzip2-compressed-tar'], 'tar.bz3' => ['application/x-bzip3-compressed-tar'], 'tar.gz' => ['application/x-compressed-tar'], 'tar.lrz' => ['application/x-lrzip-compressed-tar'], @@ -3299,13 +3486,14 @@ public function guessMimeType(string $path): ?string 'tar.lz4' => ['application/x-lz4-compressed-tar'], 'tar.lzma' => ['application/x-lzma-compressed-tar'], 'tar.lzo' => ['application/x-tzo'], + 'tar.rz' => ['application/x-rzip-compressed-tar'], 'tar.xz' => ['application/x-xz-compressed-tar'], 'tar.zst' => ['application/x-zstd-compressed-tar'], 'target' => ['text/x-systemd-unit'], 'taz' => ['application/x-tarz'], - 'tb2' => ['application/x-bzip2-compressed-tar', 'application/x-bzip-compressed-tar'], - 'tbz' => ['application/x-bzip-compressed-tar'], - 'tbz2' => ['application/x-bzip2-compressed-tar', 'application/x-bzip-compressed-tar'], + 'tb2' => ['application/x-bzip-compressed-tar', 'application/x-bzip2-compressed-tar'], + 'tbz' => ['application/x-bzip1-compressed-tar'], + 'tbz2' => ['application/x-bzip-compressed-tar', 'application/x-bzip2-compressed-tar'], 'tbz3' => ['application/x-bzip3-compressed-tar'], 'tcap' => ['application/vnd.3gpp2.tcap'], 'tcl' => ['application/x-tcl', 'text/tcl', 'text/x-tcl'], @@ -3346,7 +3534,8 @@ public function guessMimeType(string $path): ?string 'tres' => ['application/x-godot-resource'], 'trig' => ['application/trig', 'application/x-trig'], 'trm' => ['application/x-msterminal'], - 'ts' => ['application/x-linguist', 'text/vnd.qt.linguist', 'text/vnd.trolltech.linguist', 'video/mp2t'], + 'trz' => ['application/x-rzip-compressed-tar'], + 'ts' => ['application/typescript', 'application/x-linguist', 'text/vnd.qt.linguist', 'text/vnd.trolltech.linguist', 'video/mp2t'], 'tscn' => ['application/x-godot-scene'], 'tsd' => ['application/timestamped-data'], 'tsv' => ['text/tab-separated-values'], @@ -3363,11 +3552,13 @@ public function guessMimeType(string $path): ?string 'txd' => ['application/vnd.genomatix.tuxedo'], 'txf' => ['application/vnd.mobius.txf'], 'txt' => ['text/plain'], + 'txt.sf3' => ['application/x.sf3-text'], 'txz' => ['application/x-xz-compressed-tar'], - 'typ' => ['text/x-typst'], + 'typ' => ['text/vnd.typst', 'text/x-typst'], 'tzo' => ['application/x-tzo'], 'tzst' => ['application/x-zstd-compressed-tar'], 'u32' => ['application/x-authorware-bin'], + 'u3d' => ['model/u3d'], 'u8dsn' => ['message/global-delivery-status'], 'u8hdr' => ['message/global-headers'], 'u8mdn' => ['message/global-disposition-notification'], @@ -3386,11 +3577,13 @@ public function guessMimeType(string $path): ?string 'uni' => ['audio/x-mod'], 'unif' => ['application/x-nes-rom'], 'unityweb' => ['application/vnd.unity'], + 'uo' => ['application/vnd.uoml+xml'], 'uoml' => ['application/vnd.uoml+xml'], 'uri' => ['text/uri-list'], 'uris' => ['text/uri-list'], 'url' => ['application/x-mswinurl'], 'urls' => ['text/uri-list'], + 'usda' => ['model/vnd.usda'], 'usdz' => ['model/vnd.usdz+zip'], 'ustar' => ['application/x-ustar'], 'utz' => ['application/vnd.uiq.theme'], @@ -3428,7 +3621,8 @@ public function guessMimeType(string $path): ?string 'v64' => ['application/x-n64-rom'], 'vala' => ['text/x-vala'], 'vapi' => ['text/x-vala'], - 'vb' => ['application/x-virtual-boy-rom'], + 'vb' => ['application/x-virtual-boy-rom', 'text/x-vb'], + 'vbe' => ['text/vbscript.encode'], 'vbox' => ['application/x-virtualbox-vbox'], 'vbox-extpack' => ['application/x-virtualbox-vbox-extpack'], 'vbs' => ['text/vbs', 'text/vbscript'], @@ -3442,6 +3636,7 @@ public function guessMimeType(string $path): ?string 'vda' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], 'vdi' => ['application/x-vdi-disk', 'application/x-virtualbox-vdi'], 'vds' => ['model/vnd.sap.vds'], + 'vec.sf3' => ['image/x.sf3-vector'], 'vhd' => ['application/x-vhd-disk', 'application/x-virtualbox-vhd', 'text/x-vhdl'], 'vhdl' => ['text/x-vhdl'], 'vhdx' => ['application/x-vhdx-disk', 'application/x-virtualbox-vhdx'], @@ -3452,7 +3647,7 @@ public function guessMimeType(string $path): ?string 'vmdk' => ['application/x-virtualbox-vmdk', 'application/x-vmdk-disk'], 'vob' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2', 'video/x-ms-vob'], 'voc' => ['audio/x-voc'], - 'vor' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'vor' => ['application/vnd.stardivision.writer', 'application/x-starwriter'], 'vox' => ['application/x-authorware-bin'], 'vpc' => ['application/x-vhd-disk', 'application/x-virtualbox-vhd'], 'vrm' => ['model/vrml'], @@ -3494,6 +3689,7 @@ public function guessMimeType(string $path): ?string 'webmanifest' => ['application/manifest+json'], 'webp' => ['image/webp'], 'wg' => ['application/vnd.pmi.widget'], + 'wgsl' => ['text/wgsl'], 'wgt' => ['application/widget'], 'wif' => ['application/watcherinfo+xml'], 'wim' => ['application/x-ms-wim'], @@ -3562,7 +3758,9 @@ public function guessMimeType(string $path): ?string 'xcf' => ['image/x-xcf'], 'xcf.bz2' => ['image/x-compressed-xcf'], 'xcf.gz' => ['image/x-compressed-xcf'], + 'xci' => ['application/x-nintendo-switch-xci', 'application/x-nx-xci'], 'xcs' => ['application/calendar+xml'], + 'xdcf' => ['application/vnd.gov.sk.xmldatacontainer+xml'], 'xdf' => ['application/mrb-consumer+xml', 'application/mrb-publish+xml', 'application/xcap-diff+xml'], 'xdgapp' => ['application/vnd.flatpak', 'application/vnd.xdgapp'], 'xdm' => ['application/vnd.syncml.dm+xml'], @@ -3572,10 +3770,11 @@ public function guessMimeType(string $path): ?string 'xel' => ['application/xcap-el+xml'], 'xenc' => ['application/xenc+xml'], 'xer' => ['application/patch-ops-error+xml', 'application/xcap-error+xml'], - 'xfdf' => ['application/vnd.adobe.xfdf'], + 'xfdf' => ['application/vnd.adobe.xfdf', 'application/xfdf'], 'xfdl' => ['application/vnd.xfdl'], 'xhe' => ['audio/usac'], 'xht' => ['application/xhtml+xml'], + 'xhtm' => ['application/vnd.pwg-xhtml-print+xml'], 'xhtml' => ['application/xhtml+xml'], 'xhvml' => ['application/xv+xml'], 'xi' => ['audio/x-xi'], @@ -3612,6 +3811,7 @@ public function guessMimeType(string $path): ?string 'xpw' => ['application/vnd.intercon.formnet'], 'xpx' => ['application/vnd.intercon.formnet'], 'xsd' => ['application/xml', 'text/xml'], + 'xsf' => ['application/prs.xsf+xml'], 'xsl' => ['application/xml', 'application/xslt+xml'], 'xslfo' => ['text/x-xslfo'], 'xslt' => ['application/xslt+xml'], @@ -3622,6 +3822,7 @@ public function guessMimeType(string $path): ?string 'xvml' => ['application/xv+xml'], 'xwd' => ['image/x-xwindowdump'], 'xyz' => ['chemical/x-xyz'], + 'xyze' => ['image/vnd.radiance', 'image/x-hdr'], 'xz' => ['application/x-xz'], 'yaml' => ['application/yaml', 'application/x-yaml', 'text/x-yaml', 'text/yaml'], 'yang' => ['application/yang'], diff --git a/symfony/mime/Part/DataPart.php b/symfony/mime/Part/DataPart.php index 9d2f3be4b..f550f31fc 100644 --- a/symfony/mime/Part/DataPart.php +++ b/symfony/mime/Part/DataPart.php @@ -66,7 +66,7 @@ public function asInline(): static public function setContentId(string $cid): static { if (!str_contains($cid, '@')) { - throw new InvalidArgumentException(sprintf('Invalid cid "%s".', $cid)); + throw new InvalidArgumentException(\sprintf('Invalid cid "%s".', $cid)); } $this->cid = $cid; diff --git a/symfony/mime/Part/MessagePart.php b/symfony/mime/Part/MessagePart.php index 9d30544ae..704211e46 100644 --- a/symfony/mime/Part/MessagePart.php +++ b/symfony/mime/Part/MessagePart.php @@ -60,13 +60,15 @@ public function bodyToIterable(): iterable return $this->message->toIterable(); } - public function __sleep(): array + public function __serialize(): array { - return ['message']; + return ['message' => $this->message]; } - public function __wakeup(): void + public function __unserialize(array $data): void { + $this->message = $data['message'] ?? $data["\0".self::class."\0message"]; + $this->__construct($this->message); } } diff --git a/symfony/mime/Part/Multipart/FormDataPart.php b/symfony/mime/Part/Multipart/FormDataPart.php index 0db5dfa0a..4ccfd3071 100644 --- a/symfony/mime/Part/Multipart/FormDataPart.php +++ b/symfony/mime/Part/Multipart/FormDataPart.php @@ -13,7 +13,6 @@ use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Part\AbstractMultipartPart; -use Symfony\Component\Mime\Part\DataPart; use Symfony\Component\Mime\Part\TextPart; /** @@ -55,14 +54,14 @@ private function prepareFields(array $fields): array $prepare = function ($item, $key, $root = null) use (&$values, &$prepare) { if (null === $root && \is_int($key) && \is_array($item)) { if (1 !== \count($item)) { - throw new InvalidArgumentException(sprintf('Form field values with integer keys can only have one array element, the key being the field name and the value being the field value, %d provided.', \count($item))); + throw new InvalidArgumentException(\sprintf('Form field values with integer keys can only have one array element, the key being the field name and the value being the field value, %d provided.', \count($item))); } $key = key($item); $item = $item[$key]; } - $fieldName = null !== $root ? sprintf('%s[%s]', $root, $key) : $key; + $fieldName = null !== $root ? \sprintf('%s[%s]', $root, $key) : $key; if (\is_array($item)) { array_walk($item, $prepare, $fieldName); @@ -71,7 +70,7 @@ private function prepareFields(array $fields): array } if (!\is_string($item) && !$item instanceof TextPart) { - throw new InvalidArgumentException(sprintf('The value of the form field "%s" can only be a string, an array, or an instance of TextPart, "%s" given.', $fieldName, get_debug_type($item))); + throw new InvalidArgumentException(\sprintf('The value of the form field "%s" can only be a string, an array, or an instance of TextPart, "%s" given.', $fieldName, get_debug_type($item))); } $values[] = $this->preparePart($fieldName, $item); diff --git a/symfony/mime/Part/TextPart.php b/symfony/mime/Part/TextPart.php index 2a8dd5852..30e3005ff 100644 --- a/symfony/mime/Part/TextPart.php +++ b/symfony/mime/Part/TextPart.php @@ -45,13 +45,13 @@ public function __construct($body, ?string $charset = 'utf-8', string $subtype = parent::__construct(); if (!\is_string($body) && !\is_resource($body) && !$body instanceof File) { - throw new \TypeError(sprintf('The body of "%s" must be a string, a resource, or an instance of "%s" (got "%s").', self::class, File::class, get_debug_type($body))); + throw new \TypeError(\sprintf('The body of "%s" must be a string, a resource, or an instance of "%s" (got "%s").', self::class, File::class, get_debug_type($body))); } if ($body instanceof File) { $path = $body->getPath(); if ((is_file($path) && !is_readable($path)) || is_dir($path)) { - throw new InvalidArgumentException(sprintf('Path "%s" is not readable.', $path)); + throw new InvalidArgumentException(\sprintf('Path "%s" is not readable.', $path)); } } @@ -64,7 +64,7 @@ public function __construct($body, ?string $charset = 'utf-8', string $subtype = $this->encoding = $this->chooseEncoding(); } else { if ('quoted-printable' !== $encoding && 'base64' !== $encoding && '8bit' !== $encoding) { - throw new InvalidArgumentException(sprintf('The encoding must be one of "quoted-printable", "base64", or "8bit" ("%s" given).', $encoding)); + throw new InvalidArgumentException(\sprintf('The encoding must be one of "quoted-printable", "base64", or "8bit" ("%s" given).', $encoding)); } $this->encoding = $encoding; } @@ -151,7 +151,7 @@ public function bodyToIterable(): iterable if ($this->body instanceof File) { $path = $this->body->getPath(); if (false === $handle = @fopen($path, 'r', false)) { - throw new InvalidArgumentException(sprintf('Unable to open path "%s".', $path)); + throw new InvalidArgumentException(\sprintf('Unable to open path "%s".', $path)); } yield from $this->getEncoder()->encodeByteStream($handle); diff --git a/symfony/polyfill-intl-grapheme/Grapheme.php b/symfony/polyfill-intl-grapheme/Grapheme.php index 5373f1685..f9e9e5741 100644 --- a/symfony/polyfill-intl-grapheme/Grapheme.php +++ b/symfony/polyfill-intl-grapheme/Grapheme.php @@ -26,6 +26,7 @@ * - grapheme_strrpos - Find position (in grapheme units) of last occurrence of a string * - grapheme_strstr - Returns part of haystack string from the first occurrence of needle to the end of haystack * - grapheme_substr - Return part of a string + * - grapheme_str_split - Splits a string into an array of individual or chunks of graphemes * * @author Nicolas Grekas * @@ -191,6 +192,37 @@ public static function grapheme_strstr($s, $needle, $beforeNeedle = false) return mb_strstr($s, $needle, $beforeNeedle, 'UTF-8'); } + public static function grapheme_str_split($s, $len = 1) + { + if (0 > $len || 1073741823 < $len) { + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError('grapheme_str_split(): Argument #2 ($length) must be greater than 0 and less than or equal to 1073741823.'); + } + + if ('' === $s) { + return []; + } + + if (!preg_match_all('/('.SYMFONY_GRAPHEME_CLUSTER_RX.')/u', $s, $matches)) { + return false; + } + + if (1 === $len) { + return $matches[0]; + } + + $chunks = array_chunk($matches[0], $len); + + foreach ($chunks as &$chunk) { + $chunk = implode('', $chunk); + } + + return $chunks; + } + private static function grapheme_position($s, $needle, $offset, $mode) { $needle = (string) $needle; diff --git a/symfony/polyfill-intl-grapheme/bootstrap.php b/symfony/polyfill-intl-grapheme/bootstrap.php index a9ea03c7e..374dbd3a7 100644 --- a/symfony/polyfill-intl-grapheme/bootstrap.php +++ b/symfony/polyfill-intl-grapheme/bootstrap.php @@ -11,10 +11,6 @@ use Symfony\Polyfill\Intl\Grapheme as p; -if (extension_loaded('intl')) { - return; -} - if (\PHP_VERSION_ID >= 80000) { return require __DIR__.'/bootstrap80.php'; } @@ -56,3 +52,6 @@ function grapheme_strstr($haystack, $needle, $beforeNeedle = false) { return p\G if (!function_exists('grapheme_substr')) { function grapheme_substr($string, $offset, $length = null) { return p\Grapheme::grapheme_substr($string, $offset, $length); } } +if (!function_exists('grapheme_str_split')) { + function grapheme_str_split($string, $length = 1) { return p\Grapheme::grapheme_str_split($string, $length); } +} diff --git a/symfony/polyfill-intl-grapheme/bootstrap80.php b/symfony/polyfill-intl-grapheme/bootstrap80.php index b8c078677..d71175530 100644 --- a/symfony/polyfill-intl-grapheme/bootstrap80.php +++ b/symfony/polyfill-intl-grapheme/bootstrap80.php @@ -11,6 +11,14 @@ use Symfony\Polyfill\Intl\Grapheme as p; +if (!function_exists('grapheme_str_split')) { + function grapheme_str_split(string $string, int $length = 1): array|false { return p\Grapheme::grapheme_str_split($string, $length); } +} + +if (extension_loaded('intl')) { + return; +} + if (!defined('GRAPHEME_EXTR_COUNT')) { define('GRAPHEME_EXTR_COUNT', 0); } diff --git a/symfony/polyfill-intl-idn/Idn.php b/symfony/polyfill-intl-idn/Idn.php index 334f8ee70..448f74cef 100644 --- a/symfony/polyfill-intl-idn/Idn.php +++ b/symfony/polyfill-intl-idn/Idn.php @@ -145,6 +145,10 @@ final class Idn */ public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = []) { + if (\PHP_VERSION_ID > 80400 && '' === $domainName) { + throw new \ValueError('idn_to_ascii(): Argument #1 ($domain) cannot be empty'); + } + if (self::INTL_IDNA_VARIANT_2003 === $variant) { @trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED); } @@ -198,6 +202,10 @@ public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, */ public static function idn_to_utf8($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = []) { + if (\PHP_VERSION_ID > 80400 && '' === $domainName) { + throw new \ValueError('idn_to_utf8(): Argument #1 ($domain) cannot be empty'); + } + if (self::INTL_IDNA_VARIANT_2003 === $variant) { @trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED); } diff --git a/symfony/polyfill-mbstring/Mbstring.php b/symfony/polyfill-mbstring/Mbstring.php index 3d45c9d9a..31e36a368 100644 --- a/symfony/polyfill-mbstring/Mbstring.php +++ b/symfony/polyfill-mbstring/Mbstring.php @@ -983,7 +983,7 @@ public static function mb_ltrim(string $string, ?string $characters = null, ?str public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { - return self::mb_internal_trim('{[%s]+$}D', $string, $characters, $encoding, __FUNCTION__); + return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__); } private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string diff --git a/symfony/polyfill-mbstring/bootstrap80.php b/symfony/polyfill-mbstring/bootstrap80.php index 5be7d2018..5236e6dcc 100644 --- a/symfony/polyfill-mbstring/bootstrap80.php +++ b/symfony/polyfill-mbstring/bootstrap80.php @@ -133,11 +133,11 @@ function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $ } if (!function_exists('mb_ucfirst')) { - function mb_ucfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } + function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } } if (!function_exists('mb_lcfirst')) { - function mb_lcfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } + function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } } if (!function_exists('mb_trim')) { diff --git a/symfony/polyfill-php80/PhpToken.php b/symfony/polyfill-php80/PhpToken.php index fe6e69105..cd78c4ccc 100644 --- a/symfony/polyfill-php80/PhpToken.php +++ b/symfony/polyfill-php80/PhpToken.php @@ -29,7 +29,7 @@ class PhpToken implements \Stringable public $text; /** - * @var int + * @var -1|positive-int */ public $line; @@ -38,6 +38,9 @@ class PhpToken implements \Stringable */ public $pos; + /** + * @param -1|positive-int $line + */ public function __construct(int $id, string $text, int $line = -1, int $position = -1) { $this->id = $id; @@ -80,7 +83,7 @@ public function __toString(): string } /** - * @return static[] + * @return list */ public static function tokenize(string $code, int $flags = 0): array { diff --git a/symfony/polyfill-php83/Php83.php b/symfony/polyfill-php83/Php83.php index 3d94b6c32..8b7ee4c70 100644 --- a/symfony/polyfill-php83/Php83.php +++ b/symfony/polyfill-php83/Php83.php @@ -35,7 +35,7 @@ public static function json_validate(string $json, int $depth = 512, int $flags throw new \ValueError(sprintf('json_validate(): Argument #2 ($depth) must be less than %d', self::JSON_MAX_DEPTH)); } - json_decode($json, null, $depth, $flags); + json_decode($json, true, $depth, $flags); return \JSON_ERROR_NONE === json_last_error(); } diff --git a/symfony/process/Exception/ProcessFailedException.php b/symfony/process/Exception/ProcessFailedException.php index 19b40570c..29cd386bb 100644 --- a/symfony/process/Exception/ProcessFailedException.php +++ b/symfony/process/Exception/ProcessFailedException.php @@ -28,7 +28,7 @@ public function __construct(Process $process) throw new InvalidArgumentException('Expected a failed process, but the given process was successful.'); } - $error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s", + $error = \sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s", $process->getCommandLine(), $process->getExitCode(), $process->getExitCodeText(), @@ -36,7 +36,7 @@ public function __construct(Process $process) ); if (!$process->isOutputDisabled()) { - $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", + $error .= \sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", $process->getOutput(), $process->getErrorOutput() ); diff --git a/symfony/process/Exception/ProcessSignaledException.php b/symfony/process/Exception/ProcessSignaledException.php index 0fed8ac30..12eb4b3b8 100644 --- a/symfony/process/Exception/ProcessSignaledException.php +++ b/symfony/process/Exception/ProcessSignaledException.php @@ -26,7 +26,7 @@ public function __construct(Process $process) { $this->process = $process; - parent::__construct(sprintf('The process has been signaled with signal "%s".', $process->getTermSignal())); + parent::__construct(\sprintf('The process has been signaled with signal "%s".', $process->getTermSignal())); } public function getProcess(): Process diff --git a/symfony/process/Exception/ProcessTimedOutException.php b/symfony/process/Exception/ProcessTimedOutException.php index 1cecdae75..94c1a33af 100644 --- a/symfony/process/Exception/ProcessTimedOutException.php +++ b/symfony/process/Exception/ProcessTimedOutException.php @@ -31,7 +31,7 @@ public function __construct(Process $process, int $timeoutType) $this->process = $process; $this->timeoutType = $timeoutType; - parent::__construct(sprintf( + parent::__construct(\sprintf( 'The process "%s" exceeded the timeout of %s seconds.', $process->getCommandLine(), $this->getExceededTimeout() @@ -67,7 +67,7 @@ public function getExceededTimeout(): ?float return match ($this->timeoutType) { self::TYPE_GENERAL => $this->process->getTimeout(), self::TYPE_IDLE => $this->process->getIdleTimeout(), - default => throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType)), + default => throw new \LogicException(\sprintf('Unknown timeout type "%d".', $this->timeoutType)), }; } } diff --git a/symfony/process/ExecutableFinder.php b/symfony/process/ExecutableFinder.php index 1838d54ba..4d8202621 100644 --- a/symfony/process/ExecutableFinder.php +++ b/symfony/process/ExecutableFinder.php @@ -74,7 +74,7 @@ public function find(string $name, ?string $default = null, array $extraDirs = [ $suffixes = $this->suffixes; $suffixes = array_merge($suffixes, $pathExt ? explode(\PATH_SEPARATOR, $pathExt) : ['.exe', '.bat', '.cmd', '.com']); } - $suffixes = '' !== pathinfo($name, PATHINFO_EXTENSION) ? array_merge([''], $suffixes) : array_merge($suffixes, ['']); + $suffixes = '' !== pathinfo($name, \PATHINFO_EXTENSION) ? array_merge([''], $suffixes) : array_merge($suffixes, ['']); foreach ($suffixes as $suffix) { foreach ($dirs as $dir) { if ('' === $dir) { diff --git a/symfony/process/InputStream.php b/symfony/process/InputStream.php index 931217c85..3bcbfe84d 100644 --- a/symfony/process/InputStream.php +++ b/symfony/process/InputStream.php @@ -50,7 +50,7 @@ public function write(mixed $input) return; } if ($this->isClosed()) { - throw new RuntimeException(sprintf('"%s" is closed.', static::class)); + throw new RuntimeException(\sprintf('"%s" is closed.', static::class)); } $this->input[] = ProcessUtils::validateInput(__METHOD__, $input); } diff --git a/symfony/process/PhpProcess.php b/symfony/process/PhpProcess.php index 6e2ab59fb..db6ebf2a2 100644 --- a/symfony/process/PhpProcess.php +++ b/symfony/process/PhpProcess.php @@ -52,7 +52,7 @@ public function __construct(string $script, ?string $cwd = null, ?array $env = n public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static { - throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); + throw new LogicException(\sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); } /** diff --git a/symfony/process/PhpSubprocess.php b/symfony/process/PhpSubprocess.php index 04fd8ea87..bdd4173c2 100644 --- a/symfony/process/PhpSubprocess.php +++ b/symfony/process/PhpSubprocess.php @@ -75,7 +75,7 @@ public function __construct(array $command, ?string $cwd = null, ?array $env = n public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static { - throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); + throw new LogicException(\sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); } public function start(?callable $callback = null, array $env = []): void diff --git a/symfony/process/Pipes/AbstractPipes.php b/symfony/process/Pipes/AbstractPipes.php index cbbb72770..158f0487f 100644 --- a/symfony/process/Pipes/AbstractPipes.php +++ b/symfony/process/Pipes/AbstractPipes.php @@ -52,14 +52,26 @@ public function close(): void /** * Returns true if a system call has been interrupted. + * + * stream_select() returns false when the `select` system call is interrupted by an incoming signal. */ protected function hasSystemCallBeenInterrupted(): bool { $lastError = $this->lastError; $this->lastError = null; - // stream_select returns false when the `select` system call is interrupted by an incoming signal - return null !== $lastError && false !== stripos($lastError, 'interrupted system call'); + if (null === $lastError) { + return false; + } + + if (false !== stripos($lastError, 'interrupted system call')) { + return true; + } + + // on applications with a different locale than english, the message above is not found because + // it's translated. So we also check for the SOCKET_EINTR constant which is defined under + // Windows and UNIX-like platforms (if available on the platform). + return \defined('SOCKET_EINTR') && str_starts_with($lastError, 'stream_select(): Unable to select ['.\SOCKET_EINTR.']'); } /** @@ -72,10 +84,10 @@ protected function unblock(): void } foreach ($this->pipes as $pipe) { - stream_set_blocking($pipe, 0); + stream_set_blocking($pipe, false); } if (\is_resource($this->input)) { - stream_set_blocking($this->input, 0); + stream_set_blocking($this->input, false); } $this->blocked = false; @@ -97,11 +109,11 @@ protected function write(): ?array if (!$input->valid()) { $input = null; } elseif (\is_resource($input = $input->current())) { - stream_set_blocking($input, 0); + stream_set_blocking($input, false); } elseif (!isset($this->inputBuffer[0])) { if (!\is_string($input)) { if (!\is_scalar($input)) { - throw new InvalidArgumentException(sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input))); + throw new InvalidArgumentException(\sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', get_debug_type($this->input), get_debug_type($input))); } $input = (string) $input; } diff --git a/symfony/process/Pipes/UnixPipes.php b/symfony/process/Pipes/UnixPipes.php index 7bd0db0e9..8838c68af 100644 --- a/symfony/process/Pipes/UnixPipes.php +++ b/symfony/process/Pipes/UnixPipes.php @@ -35,12 +35,12 @@ public function __construct(?bool $ttyMode, bool $ptyMode, mixed $input, bool $h parent::__construct($input); } - public function __sleep(): array + public function __serialize(): array { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - public function __wakeup(): void + public function __unserialize(array $data): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } @@ -74,7 +74,7 @@ public function getDescriptors(): array return [ ['pty'], ['pty'], - ['pty'], + ['pipe', 'w'], // stderr needs to be in a pipe to correctly split error and output, since PHP will use the same stream for both ]; } diff --git a/symfony/process/Pipes/WindowsPipes.php b/symfony/process/Pipes/WindowsPipes.php index 8033442a4..bec37358c 100644 --- a/symfony/process/Pipes/WindowsPipes.php +++ b/symfony/process/Pipes/WindowsPipes.php @@ -53,7 +53,7 @@ public function __construct(mixed $input, bool $haveReadSupport) set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; }); for ($i = 0;; ++$i) { foreach ($pipes as $pipe => $name) { - $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); + $file = \sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); if (!$h = fopen($file.'.lock', 'w')) { if (file_exists($file.'.lock')) { @@ -88,12 +88,12 @@ public function __construct(mixed $input, bool $haveReadSupport) parent::__construct($input); } - public function __sleep(): array + public function __serialize(): array { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - public function __wakeup(): void + public function __unserialize(array $data): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } diff --git a/symfony/process/Process.php b/symfony/process/Process.php index 280a732d5..ce730f98e 100644 --- a/symfony/process/Process.php +++ b/symfony/process/Process.php @@ -80,7 +80,6 @@ class Process implements \IteratorAggregate private WindowsPipes|UnixPipes $processPipes; private ?int $latestSignal = null; - private ?int $cachedExitCode = null; private static ?bool $sigchild = null; @@ -195,15 +194,12 @@ public static function fromShellCommandline(string $command, ?string $cwd = null return $process; } - public function __sleep(): array + public function __serialize(): array { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - /** - * @return void - */ - public function __wakeup() + public function __unserialize(array $data): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } @@ -341,7 +337,7 @@ public function start(?callable $callback = null, array $env = []) } if (!is_dir($this->cwd)) { - throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd)); + throw new RuntimeException(\sprintf('The provided cwd "%s" does not exist.', $this->cwd)); } $process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options); @@ -1198,7 +1194,7 @@ public function setOptions(array $options) foreach ($options as $key => $value) { if (!\in_array($key, $existingOptions)) { $this->options = $defaultOptions; - throw new LogicException(sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, implode('", "', $existingOptions))); + throw new LogicException(\sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, implode('", "', $existingOptions))); } $this->options[$key] = $value; } @@ -1289,21 +1285,10 @@ protected function updateStatus(bool $blocking) return; } - $this->processInformation = proc_get_status($this->process); - $running = $this->processInformation['running']; - - // In PHP < 8.3, "proc_get_status" only returns the correct exit status on the first call. - // Subsequent calls return -1 as the process is discarded. This workaround caches the first - // retrieved exit status for consistent results in later calls, mimicking PHP 8.3 behavior. - if (\PHP_VERSION_ID < 80300) { - if (!isset($this->cachedExitCode) && !$running && -1 !== $this->processInformation['exitcode']) { - $this->cachedExitCode = $this->processInformation['exitcode']; - } - - if (isset($this->cachedExitCode) && !$running && -1 === $this->processInformation['exitcode']) { - $this->processInformation['exitcode'] = $this->cachedExitCode; - } + if ($this->processInformation['running'] ?? true) { + $this->processInformation = proc_get_status($this->process); } + $running = $this->processInformation['running']; $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running); @@ -1465,10 +1450,10 @@ private function doSignal(int $signal, bool $throwException): bool } if ('\\' === \DIRECTORY_SEPARATOR) { - exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode); + exec(\sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode); if ($exitCode && $this->isRunning()) { if ($throwException) { - throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output))); + throw new RuntimeException(\sprintf('Unable to kill the process (%s).', implode(' ', $output))); } return false; @@ -1478,12 +1463,12 @@ private function doSignal(int $signal, bool $throwException): bool $ok = @proc_terminate($this->process, $signal); } elseif (\function_exists('posix_kill')) { $ok = @posix_kill($pid, $signal); - } elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) { + } elseif ($ok = proc_open(\sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) { $ok = false === fgets($pipes[2]); } if (!$ok) { if ($throwException) { - throw new RuntimeException(sprintf('Error while sending signal "%s".', $signal)); + throw new RuntimeException(\sprintf('Error while sending signal "%s".', $signal)); } return false; @@ -1540,7 +1525,7 @@ function ($m) use (&$env, $uid) { if (!$comSpec && $comSpec = (new ExecutableFinder())->find('cmd.exe')) { // Escape according to CommandLineToArgvW rules - $comSpec = '"'.preg_replace('{(\\\\*+)"}', '$1$1\"', $comSpec) .'"'; + $comSpec = '"'.preg_replace('{(\\\\*+)"}', '$1$1\"', $comSpec).'"'; } $cmd = ($comSpec ?? 'cmd').' /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')'; @@ -1559,7 +1544,7 @@ function ($m) use (&$env, $uid) { private function requireProcessIsStarted(string $functionName): void { if (!$this->isStarted()) { - throw new LogicException(sprintf('Process must be started before calling "%s()".', $functionName)); + throw new LogicException(\sprintf('Process must be started before calling "%s()".', $functionName)); } } @@ -1571,7 +1556,7 @@ private function requireProcessIsStarted(string $functionName): void private function requireProcessIsTerminated(string $functionName): void { if (!$this->isTerminated()) { - throw new LogicException(sprintf('Process must be terminated before calling "%s()".', $functionName)); + throw new LogicException(\sprintf('Process must be terminated before calling "%s()".', $functionName)); } } @@ -1601,7 +1586,7 @@ private function replacePlaceholders(string $commandline, array $env): string { return preg_replace_callback('/"\$\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\}"/', function ($matches) use ($commandline, $env) { if (!isset($env[$matches[1]]) || false === $env[$matches[1]]) { - throw new InvalidArgumentException(sprintf('Command line is missing a value for parameter "%s": ', $matches[1]).$commandline); + throw new InvalidArgumentException(\sprintf('Command line is missing a value for parameter "%s": ', $matches[1]).$commandline); } return $this->escapeArgument($env[$matches[1]]); diff --git a/symfony/process/ProcessUtils.php b/symfony/process/ProcessUtils.php index 092c5ccf7..a2dbde9f7 100644 --- a/symfony/process/ProcessUtils.php +++ b/symfony/process/ProcessUtils.php @@ -56,7 +56,7 @@ public static function validateInput(string $caller, mixed $input): mixed return new \IteratorIterator($input); } - throw new InvalidArgumentException(sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller)); + throw new InvalidArgumentException(\sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller)); } return $input; diff --git a/symfony/routing/Attribute/Route.php b/symfony/routing/Attribute/Route.php index a1d86fe61..32ee18e81 100644 --- a/symfony/routing/Attribute/Route.php +++ b/symfony/routing/Attribute/Route.php @@ -49,7 +49,7 @@ public function __construct( ?string $format = null, ?bool $utf8 = null, ?bool $stateless = null, - private ?string $env = null + private ?string $env = null, ) { if (\is_array($path)) { $this->localizedPaths = $path; diff --git a/symfony/routing/Exception/MissingMandatoryParametersException.php b/symfony/routing/Exception/MissingMandatoryParametersException.php index 72d063abb..b64d6d84a 100644 --- a/symfony/routing/Exception/MissingMandatoryParametersException.php +++ b/symfony/routing/Exception/MissingMandatoryParametersException.php @@ -31,7 +31,7 @@ public function __construct(string $routeName = '', $missingParameters = null, $ if (\is_array($missingParameters)) { $this->routeName = $routeName; $this->missingParameters = $missingParameters; - $message = sprintf('Some mandatory parameters are missing ("%s") to generate a URL for route "%s".', implode('", "', $missingParameters), $routeName); + $message = \sprintf('Some mandatory parameters are missing ("%s") to generate a URL for route "%s".', implode('", "', $missingParameters), $routeName); } else { trigger_deprecation('symfony/routing', '6.1', 'Construction of "%s" with an exception message is deprecated, provide the route name and an array of missing parameters instead.', __CLASS__); $message = $routeName; diff --git a/symfony/routing/Exception/RouteCircularReferenceException.php b/symfony/routing/Exception/RouteCircularReferenceException.php index 841e35989..3e20cbcbf 100644 --- a/symfony/routing/Exception/RouteCircularReferenceException.php +++ b/symfony/routing/Exception/RouteCircularReferenceException.php @@ -15,6 +15,6 @@ class RouteCircularReferenceException extends RuntimeException { public function __construct(string $routeId, array $path) { - parent::__construct(sprintf('Circular reference detected for route "%s", path: "%s".', $routeId, implode(' -> ', $path))); + parent::__construct(\sprintf('Circular reference detected for route "%s", path: "%s".', $routeId, implode(' -> ', $path))); } } diff --git a/symfony/routing/Generator/CompiledUrlGenerator.php b/symfony/routing/Generator/CompiledUrlGenerator.php index de209cdcf..b7429d1fd 100644 --- a/symfony/routing/Generator/CompiledUrlGenerator.php +++ b/symfony/routing/Generator/CompiledUrlGenerator.php @@ -47,7 +47,7 @@ public function generate(string $name, array $parameters = [], int $referenceTyp } if (!isset($this->compiledRoutes[$name])) { - throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name)); + throw new RouteNotFoundException(\sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name)); } [$variables, $defaults, $requirements, $tokens, $hostTokens, $requiredSchemes, $deprecations] = $this->compiledRoutes[$name] + [6 => []]; diff --git a/symfony/routing/Generator/Dumper/CompiledUrlGeneratorDumper.php b/symfony/routing/Generator/Dumper/CompiledUrlGeneratorDumper.php index 1144fed5c..555c5bfbd 100644 --- a/symfony/routing/Generator/Dumper/CompiledUrlGeneratorDumper.php +++ b/symfony/routing/Generator/Dumper/CompiledUrlGeneratorDumper.php @@ -69,7 +69,7 @@ public function getCompiledAliases(): array } if (null === $target = $routes->get($currentId)) { - throw new RouteNotFoundException(sprintf('Target route "%s" for alias "%s" does not exist.', $currentId, $name)); + throw new RouteNotFoundException(\sprintf('Target route "%s" for alias "%s" does not exist.', $currentId, $name)); } $compiledTarget = $target->compile(); @@ -109,11 +109,11 @@ private function generateDeclaredRoutes(): string { $routes = ''; foreach ($this->getCompiledRoutes() as $name => $properties) { - $routes .= sprintf("\n '%s' => %s,", $name, CompiledUrlMatcherDumper::export($properties)); + $routes .= \sprintf("\n '%s' => %s,", $name, CompiledUrlMatcherDumper::export($properties)); } foreach ($this->getCompiledAliases() as $alias => $properties) { - $routes .= sprintf("\n '%s' => %s,", $alias, CompiledUrlMatcherDumper::export($properties)); + $routes .= \sprintf("\n '%s' => %s,", $alias, CompiledUrlMatcherDumper::export($properties)); } return $routes; diff --git a/symfony/routing/Generator/UrlGenerator.php b/symfony/routing/Generator/UrlGenerator.php index 28f30d617..4c8f8f74c 100644 --- a/symfony/routing/Generator/UrlGenerator.php +++ b/symfony/routing/Generator/UrlGenerator.php @@ -131,7 +131,7 @@ public function generate(string $name, array $parameters = [], int $referenceTyp } if (null === $route ??= $this->routes->get($name)) { - throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name)); + throw new RouteNotFoundException(\sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name)); } // the Route has a cache of its own and is not recompiled as long as it does not get modified diff --git a/symfony/routing/Loader/AttributeClassLoader.php b/symfony/routing/Loader/AttributeClassLoader.php index 132da8028..6506feae1 100644 --- a/symfony/routing/Loader/AttributeClassLoader.php +++ b/symfony/routing/Loader/AttributeClassLoader.php @@ -94,7 +94,7 @@ public function __construct($env = null) } elseif ($env instanceof \Stringable || \is_scalar($env)) { $this->env = (string) $env; } else { - throw new \TypeError(__METHOD__.sprintf(': Parameter $env was expected to be a string or null, "%s" given.', get_debug_type($env))); + throw new \TypeError(__METHOD__.\sprintf(': Parameter $env was expected to be a string or null, "%s" given.', get_debug_type($env))); } } @@ -114,12 +114,12 @@ public function setRouteAnnotationClass(string $class) public function load(mixed $class, ?string $type = null): RouteCollection { if (!class_exists($class)) { - throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); + throw new \InvalidArgumentException(\sprintf('Class "%s" does not exist.', $class)); } $class = new \ReflectionClass($class); if ($class->isAbstract()) { - throw new \InvalidArgumentException(sprintf('Attributes from class "%s" cannot be read as it is abstract.', $class->getName())); + throw new \InvalidArgumentException(\sprintf('Attributes from class "%s" cannot be read as it is abstract.', $class->getName())); } $this->hasDeprecatedAnnotations = false; @@ -144,7 +144,7 @@ public function load(mixed $class, ?string $type = null): RouteCollection if (1 === $collection->count() - \count($routeNamesBefore)) { $newRouteName = current(array_diff(array_keys($collection->all()), $routeNamesBefore)); - if ($newRouteName !== $aliasName = sprintf('%s::%s', $class->name, $method->name)) { + if ($newRouteName !== $aliasName = \sprintf('%s::%s', $class->name, $method->name)) { $collection->addAlias($aliasName, $newRouteName); } } @@ -162,7 +162,7 @@ public function load(mixed $class, ?string $type = null): RouteCollection $collection->addAlias($class->name, $invokeRouteName); } - if ($invokeRouteName !== $aliasName = sprintf('%s::__invoke', $class->name)) { + if ($invokeRouteName !== $aliasName = \sprintf('%s::__invoke', $class->name)) { $collection->addAlias($aliasName, $invokeRouteName); } } @@ -195,7 +195,7 @@ protected function addRoute(RouteCollection $collection, object $annot, array $g foreach ($requirements as $placeholder => $requirement) { if (\is_int($placeholder)) { - throw new \InvalidArgumentException(sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s::%s()"?', $placeholder, $requirement, $name, $class->getName(), $method->getName())); + throw new \InvalidArgumentException(\sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s::%s()"?', $placeholder, $requirement, $name, $class->getName(), $method->getName())); } } @@ -219,11 +219,11 @@ protected function addRoute(RouteCollection $collection, object $annot, array $g $paths[$locale] = $prefix.$localePath; } } elseif ($missing = array_diff_key($prefix, $path)) { - throw new \LogicException(sprintf('Route to "%s" is missing paths for locale(s) "%s".', $class->name.'::'.$method->name, implode('", "', array_keys($missing)))); + throw new \LogicException(\sprintf('Route to "%s" is missing paths for locale(s) "%s".', $class->name.'::'.$method->name, implode('", "', array_keys($missing)))); } else { foreach ($path as $locale => $localePath) { if (!isset($prefix[$locale])) { - throw new \LogicException(sprintf('Route to "%s" with locale "%s" is missing a corresponding prefix in class "%s".', $method->name, $locale, $class->name)); + throw new \LogicException(\sprintf('Route to "%s" with locale "%s" is missing a corresponding prefix in class "%s".', $method->name, $locale, $class->name)); } $paths[$locale] = $prefix[$locale].$localePath; @@ -242,7 +242,7 @@ protected function addRoute(RouteCollection $collection, object $annot, array $g continue; } foreach ($paths as $locale => $path) { - if (preg_match(sprintf('/\{%s(?:<.*?>)?\}/', preg_quote($param->name)), $path)) { + if (preg_match(\sprintf('/\{%s(?:<.*?>)?\}/', preg_quote($param->name)), $path)) { if (\is_scalar($defaultValue = $param->getDefaultValue()) || null === $defaultValue) { $defaults[$param->name] = $defaultValue; } elseif ($defaultValue instanceof \BackedEnum) { @@ -360,7 +360,7 @@ protected function getGlobals(\ReflectionClass $class) foreach ($globals['requirements'] as $placeholder => $requirement) { if (\is_int($placeholder)) { - throw new \InvalidArgumentException(sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" in "%s"?', $placeholder, $requirement, $class->getName())); + throw new \InvalidArgumentException(\sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" in "%s"?', $placeholder, $requirement, $class->getName())); } } } diff --git a/symfony/routing/Loader/AttributeFileLoader.php b/symfony/routing/Loader/AttributeFileLoader.php index e9a13e597..8d522f473 100644 --- a/symfony/routing/Loader/AttributeFileLoader.php +++ b/symfony/routing/Loader/AttributeFileLoader.php @@ -82,7 +82,7 @@ protected function findClass(string $file): string|false $tokens = token_get_all(file_get_contents($file)); if (1 === \count($tokens) && \T_INLINE_HTML === $tokens[0][0]) { - throw new \InvalidArgumentException(sprintf('The file "%s" does not contain PHP code. Did you forget to add the " true, \T_STRING => true]; diff --git a/symfony/routing/Loader/Configurator/CollectionConfigurator.php b/symfony/routing/Loader/Configurator/CollectionConfigurator.php index 1abf3bc0c..fe4cab4a2 100644 --- a/symfony/routing/Loader/Configurator/CollectionConfigurator.php +++ b/symfony/routing/Loader/Configurator/CollectionConfigurator.php @@ -38,15 +38,12 @@ public function __construct(RouteCollection $parent, string $name, ?self $parent $this->parentPrefixes = $parentPrefixes; } - public function __sleep(): array + public function __serialize(): array { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - /** - * @return void - */ - public function __wakeup() + public function __unserialize(array $data): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } @@ -84,11 +81,11 @@ final public function prefix(string|array $prefix): static if (null === $this->parentPrefixes) { // no-op } elseif ($missing = array_diff_key($this->parentPrefixes, $prefix)) { - throw new \LogicException(sprintf('Collection "%s" is missing prefixes for locale(s) "%s".', $this->name, implode('", "', array_keys($missing)))); + throw new \LogicException(\sprintf('Collection "%s" is missing prefixes for locale(s) "%s".', $this->name, implode('", "', array_keys($missing)))); } else { foreach ($prefix as $locale => $localePrefix) { if (!isset($this->parentPrefixes[$locale])) { - throw new \LogicException(sprintf('Collection "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $this->name, $locale)); + throw new \LogicException(\sprintf('Collection "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $this->name, $locale)); } $prefix[$locale] = $this->parentPrefixes[$locale].$localePrefix; diff --git a/symfony/routing/Loader/Configurator/ImportConfigurator.php b/symfony/routing/Loader/Configurator/ImportConfigurator.php index 9c92a7d72..ad0c6d131 100644 --- a/symfony/routing/Loader/Configurator/ImportConfigurator.php +++ b/symfony/routing/Loader/Configurator/ImportConfigurator.php @@ -30,15 +30,12 @@ public function __construct(RouteCollection $parent, RouteCollection $route) $this->route = $route; } - public function __sleep(): array + public function __serialize(): array { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } - /** - * @return void - */ - public function __wakeup() + public function __unserialize(array $data): void { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } diff --git a/symfony/routing/Loader/Configurator/Traits/HostTrait.php b/symfony/routing/Loader/Configurator/Traits/HostTrait.php index 1050bb0fb..e584f356f 100644 --- a/symfony/routing/Loader/Configurator/Traits/HostTrait.php +++ b/symfony/routing/Loader/Configurator/Traits/HostTrait.php @@ -39,7 +39,7 @@ final protected function addHost(RouteCollection $routes, string|array $hosts): $routes->add($name.'.'.$locale, $localizedRoute, $priority); } } elseif (!isset($hosts[$locale])) { - throw new \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding host in its parent collection.', $name, $locale)); + throw new \InvalidArgumentException(\sprintf('Route "%s" with locale "%s" is missing a corresponding host in its parent collection.', $name, $locale)); } else { $route->setHost($hosts[$locale]); $route->setRequirement('_locale', preg_quote($locale)); diff --git a/symfony/routing/Loader/Configurator/Traits/LocalizedRouteTrait.php b/symfony/routing/Loader/Configurator/Traits/LocalizedRouteTrait.php index a26a73420..d90ef9d36 100644 --- a/symfony/routing/Loader/Configurator/Traits/LocalizedRouteTrait.php +++ b/symfony/routing/Loader/Configurator/Traits/LocalizedRouteTrait.php @@ -37,11 +37,11 @@ final protected function createLocalizedRoute(RouteCollection $collection, strin if (null === $prefixes) { $paths = $path; } elseif ($missing = array_diff_key($prefixes, $path)) { - throw new \LogicException(sprintf('Route "%s" is missing routes for locale(s) "%s".', $name, implode('", "', array_keys($missing)))); + throw new \LogicException(\sprintf('Route "%s" is missing routes for locale(s) "%s".', $name, implode('", "', array_keys($missing)))); } else { foreach ($path as $locale => $localePath) { if (!isset($prefixes[$locale])) { - throw new \LogicException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale)); + throw new \LogicException(\sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale)); } $paths[$locale] = $prefixes[$locale].$localePath; diff --git a/symfony/routing/Loader/Configurator/Traits/PrefixTrait.php b/symfony/routing/Loader/Configurator/Traits/PrefixTrait.php index 89a65d8f7..9f2284c5c 100644 --- a/symfony/routing/Loader/Configurator/Traits/PrefixTrait.php +++ b/symfony/routing/Loader/Configurator/Traits/PrefixTrait.php @@ -27,10 +27,17 @@ final protected function addPrefix(RouteCollection $routes, string|array $prefix foreach ($prefix as $locale => $localePrefix) { $prefix[$locale] = trim(trim($localePrefix), '/'); } + $aliases = []; + foreach ($routes->getAliases() as $name => $alias) { + $aliases[$alias->getId()][] = $name; + } foreach ($routes->all() as $name => $route) { if (null === $locale = $route->getDefault('_locale')) { $priority = $routes->getPriority($name) ?? 0; $routes->remove($name); + foreach ($aliases[$name] ?? [] as $aliasName) { + $routes->remove($aliasName); + } foreach ($prefix as $locale => $localePrefix) { $localizedRoute = clone $route; $localizedRoute->setDefault('_locale', $locale); @@ -38,9 +45,12 @@ final protected function addPrefix(RouteCollection $routes, string|array $prefix $localizedRoute->setDefault('_canonical_route', $name); $localizedRoute->setPath($localePrefix.(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath())); $routes->add($name.'.'.$locale, $localizedRoute, $priority); + foreach ($aliases[$name] ?? [] as $aliasName) { + $routes->addAlias($aliasName.'.'.$locale, $name.'.'.$locale); + } } } elseif (!isset($prefix[$locale])) { - throw new \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale)); + throw new \InvalidArgumentException(\sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale)); } else { $route->setPath($prefix[$locale].(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath())); $routes->add($name, $route, $routes->getPriority($name) ?? 0); diff --git a/symfony/routing/Loader/ObjectLoader.php b/symfony/routing/Loader/ObjectLoader.php index c2ad6a03f..d4234c135 100644 --- a/symfony/routing/Loader/ObjectLoader.php +++ b/symfony/routing/Loader/ObjectLoader.php @@ -36,7 +36,7 @@ abstract protected function getObject(string $id): object; public function load(mixed $resource, ?string $type = null): RouteCollection { if (!preg_match('/^[^\:]+(?:::(?:[^\:]+))?$/', $resource)) { - throw new \InvalidArgumentException(sprintf('Invalid resource "%s" passed to the %s route loader: use the format "object_id::method" or "object_id" if your object class has an "__invoke" method.', $resource, \is_string($type) ? '"'.$type.'"' : 'object')); + throw new \InvalidArgumentException(\sprintf('Invalid resource "%s" passed to the %s route loader: use the format "object_id::method" or "object_id" if your object class has an "__invoke" method.', $resource, \is_string($type) ? '"'.$type.'"' : 'object')); } $parts = explode('::', $resource); @@ -45,11 +45,11 @@ public function load(mixed $resource, ?string $type = null): RouteCollection $loaderObject = $this->getObject($parts[0]); if (!\is_object($loaderObject)) { - throw new \TypeError(sprintf('"%s:getObject()" must return an object: "%s" returned.', static::class, get_debug_type($loaderObject))); + throw new \TypeError(\sprintf('"%s:getObject()" must return an object: "%s" returned.', static::class, get_debug_type($loaderObject))); } if (!\is_callable([$loaderObject, $method])) { - throw new \BadMethodCallException(sprintf('Method "%s" not found on "%s" when importing routing resource "%s".', $method, get_debug_type($loaderObject), $resource)); + throw new \BadMethodCallException(\sprintf('Method "%s" not found on "%s" when importing routing resource "%s".', $method, get_debug_type($loaderObject), $resource)); } $routeCollection = $loaderObject->$method($this, $this->env); @@ -57,7 +57,7 @@ public function load(mixed $resource, ?string $type = null): RouteCollection if (!$routeCollection instanceof RouteCollection) { $type = get_debug_type($routeCollection); - throw new \LogicException(sprintf('The "%s::%s()" method must return a RouteCollection: "%s" returned.', get_debug_type($loaderObject), $method, $type)); + throw new \LogicException(\sprintf('The "%s::%s()" method must return a RouteCollection: "%s" returned.', get_debug_type($loaderObject), $method, $type)); } // make the object file tracked so that if it changes, the cache rebuilds diff --git a/symfony/routing/Loader/XmlFileLoader.php b/symfony/routing/Loader/XmlFileLoader.php index 1e3e3283d..5b41bd698 100644 --- a/symfony/routing/Loader/XmlFileLoader.php +++ b/symfony/routing/Loader/XmlFileLoader.php @@ -90,7 +90,7 @@ protected function parseNode(RouteCollection $collection, \DOMElement $node, str } break; default: - throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "route" or "import".', $node->localName, $path)); + throw new \InvalidArgumentException(\sprintf('Unknown tag "%s" used in file "%s". Expected "route" or "import".', $node->localName, $path)); } } @@ -109,7 +109,7 @@ public function supports(mixed $resource, ?string $type = null): bool protected function parseRoute(RouteCollection $collection, \DOMElement $node, string $path) { if ('' === $id = $node->getAttribute('id')) { - throw new \InvalidArgumentException(sprintf('The element in file "%s" must have an "id" attribute.', $path)); + throw new \InvalidArgumentException(\sprintf('The element in file "%s" must have an "id" attribute.', $path)); } if ('' !== $alias = $node->getAttribute('alias')) { @@ -128,11 +128,11 @@ protected function parseRoute(RouteCollection $collection, \DOMElement $node, st [$defaults, $requirements, $options, $condition, $paths, /* $prefixes */, $hosts] = $this->parseConfigs($node, $path); if (!$paths && '' === $node->getAttribute('path')) { - throw new \InvalidArgumentException(sprintf('The element in file "%s" must have a "path" attribute or child nodes.', $path)); + throw new \InvalidArgumentException(\sprintf('The element in file "%s" must have a "path" attribute or child nodes.', $path)); } if ($paths && '' !== $node->getAttribute('path')) { - throw new \InvalidArgumentException(sprintf('The element in file "%s" must not have both a "path" attribute and child nodes.', $path)); + throw new \InvalidArgumentException(\sprintf('The element in file "%s" must not have both a "path" attribute and child nodes.', $path)); } $routes = $this->createLocalizedRoute(new RouteCollection(), $id, $paths ?: $node->getAttribute('path')); @@ -169,7 +169,7 @@ protected function parseImport(RouteCollection $collection, \DOMElement $node, s } if (!$resource) { - throw new \InvalidArgumentException(sprintf('The element in file "%s" must have a "resource" attribute or element.', $path)); + throw new \InvalidArgumentException(\sprintf('The element in file "%s" must have a "resource" attribute or element.', $path)); } $type = $node->getAttribute('type'); @@ -182,7 +182,7 @@ protected function parseImport(RouteCollection $collection, \DOMElement $node, s [$defaults, $requirements, $options, $condition, /* $paths */, $prefixes, $hosts] = $this->parseConfigs($node, $path); if ('' !== $prefix && $prefixes) { - throw new \InvalidArgumentException(sprintf('The element in file "%s" must not have both a "prefix" attribute and child nodes.', $path)); + throw new \InvalidArgumentException(\sprintf('The element in file "%s" must not have both a "prefix" attribute and child nodes.', $path)); } $exclude = []; @@ -296,15 +296,15 @@ private function parseConfigs(\DOMElement $node, string $path): array case 'resource': break; default: - throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "default", "requirement", "option" or "condition".', $n->localName, $path)); + throw new \InvalidArgumentException(\sprintf('Unknown tag "%s" used in file "%s". Expected "default", "requirement", "option" or "condition".', $n->localName, $path)); } } if ($controller = $node->getAttribute('controller')) { if (isset($defaults['_controller'])) { - $name = $node->hasAttribute('id') ? sprintf('"%s".', $node->getAttribute('id')) : sprintf('the "%s" tag.', $node->tagName); + $name = $node->hasAttribute('id') ? \sprintf('"%s".', $node->getAttribute('id')) : \sprintf('the "%s" tag.', $node->tagName); - throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "controller" attribute and the defaults key "_controller" for ', $path).$name); + throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "controller" attribute and the defaults key "_controller" for ', $path).$name); } $defaults['_controller'] = $controller; @@ -320,9 +320,9 @@ private function parseConfigs(\DOMElement $node, string $path): array } if ($stateless = $node->getAttribute('stateless')) { if (isset($defaults['_stateless'])) { - $name = $node->hasAttribute('id') ? sprintf('"%s".', $node->getAttribute('id')) : sprintf('the "%s" tag.', $node->tagName); + $name = $node->hasAttribute('id') ? \sprintf('"%s".', $node->getAttribute('id')) : \sprintf('the "%s" tag.', $node->tagName); - throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "stateless" attribute and the defaults key "_stateless" for ', $path).$name); + throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "stateless" attribute and the defaults key "_stateless" for ', $path).$name); } $defaults['_stateless'] = XmlUtils::phpize($stateless); @@ -418,7 +418,7 @@ private function parseDefaultNode(\DOMElement $node, string $path): array|bool|f return $map; default: - throw new \InvalidArgumentException(sprintf('Unknown tag "%s" used in file "%s". Expected "bool", "int", "float", "string", "list", or "map".', $node->localName, $path)); + throw new \InvalidArgumentException(\sprintf('Unknown tag "%s" used in file "%s". Expected "bool", "int", "float", "string", "list", or "map".', $node->localName, $path)); } } @@ -446,7 +446,7 @@ private function parseDeprecation(\DOMElement $node, string $path): array continue; } if ('deprecated' !== $child->localName) { - throw new \InvalidArgumentException(sprintf('Invalid child element "%s" defined for alias "%s" in "%s".', $child->localName, $node->getAttribute('id'), $path)); + throw new \InvalidArgumentException(\sprintf('Invalid child element "%s" defined for alias "%s" in "%s".', $child->localName, $node->getAttribute('id'), $path)); } $deprecatedNode = $child; @@ -457,10 +457,10 @@ private function parseDeprecation(\DOMElement $node, string $path): array } if (!$deprecatedNode->hasAttribute('package')) { - throw new \InvalidArgumentException(sprintf('The element in file "%s" must have a "package" attribute.', $path)); + throw new \InvalidArgumentException(\sprintf('The element in file "%s" must have a "package" attribute.', $path)); } if (!$deprecatedNode->hasAttribute('version')) { - throw new \InvalidArgumentException(sprintf('The element in file "%s" must have a "version" attribute.', $path)); + throw new \InvalidArgumentException(\sprintf('The element in file "%s" must have a "version" attribute.', $path)); } return [ diff --git a/symfony/routing/Loader/YamlFileLoader.php b/symfony/routing/Loader/YamlFileLoader.php index 09beb7cd5..c1924ba65 100644 --- a/symfony/routing/Loader/YamlFileLoader.php +++ b/symfony/routing/Loader/YamlFileLoader.php @@ -46,11 +46,11 @@ public function load(mixed $file, ?string $type = null): RouteCollection $path = $this->locator->locate($file); if (!stream_is_local($path)) { - throw new \InvalidArgumentException(sprintf('This is not a local file "%s".', $path)); + throw new \InvalidArgumentException(\sprintf('This is not a local file "%s".', $path)); } if (!file_exists($path)) { - throw new \InvalidArgumentException(sprintf('File "%s" not found.', $path)); + throw new \InvalidArgumentException(\sprintf('File "%s" not found.', $path)); } $this->yamlParser ??= new YamlParser(); @@ -58,7 +58,7 @@ public function load(mixed $file, ?string $type = null): RouteCollection try { $parsedConfig = $this->yamlParser->parseFile($path, Yaml::PARSE_CONSTANT); } catch (ParseException $e) { - throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML: ', $path).$e->getMessage(), 0, $e); + throw new \InvalidArgumentException(\sprintf('The file "%s" does not contain valid YAML: ', $path).$e->getMessage(), 0, $e); } $collection = new RouteCollection(); @@ -71,7 +71,7 @@ public function load(mixed $file, ?string $type = null): RouteCollection // not an array if (!\is_array($parsedConfig)) { - throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $path)); + throw new \InvalidArgumentException(\sprintf('The file "%s" must contain a YAML array.', $path)); } foreach ($parsedConfig as $name => $config) { @@ -137,7 +137,7 @@ protected function parseRoute(RouteCollection $collection, string $name, array $ foreach ($requirements as $placeholder => $requirement) { if (\is_int($placeholder)) { - throw new \InvalidArgumentException(sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s"?', $placeholder, $requirement, $name, $path)); + throw new \InvalidArgumentException(\sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s"?', $placeholder, $requirement, $name, $path)); } } @@ -252,7 +252,7 @@ protected function parseImport(RouteCollection $collection, array $config, strin protected function validate(mixed $config, string $name, string $path) { if (!\is_array($config)) { - throw new \InvalidArgumentException(sprintf('The definition of "%s" in "%s" must be a YAML array.', $name, $path)); + throw new \InvalidArgumentException(\sprintf('The definition of "%s" in "%s" must be a YAML array.', $name, $path)); } if (isset($config['alias'])) { $this->validateAlias($config, $name, $path); @@ -260,22 +260,22 @@ protected function validate(mixed $config, string $name, string $path) return; } if ($extraKeys = array_diff(array_keys($config), self::AVAILABLE_KEYS)) { - throw new \InvalidArgumentException(sprintf('The routing file "%s" contains unsupported keys for "%s": "%s". Expected one of: "%s".', $path, $name, implode('", "', $extraKeys), implode('", "', self::AVAILABLE_KEYS))); + throw new \InvalidArgumentException(\sprintf('The routing file "%s" contains unsupported keys for "%s": "%s". Expected one of: "%s".', $path, $name, implode('", "', $extraKeys), implode('", "', self::AVAILABLE_KEYS))); } if (isset($config['resource']) && isset($config['path'])) { - throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "resource" key and the "path" key for "%s". Choose between an import and a route definition.', $path, $name)); + throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "resource" key and the "path" key for "%s". Choose between an import and a route definition.', $path, $name)); } if (!isset($config['resource']) && isset($config['type'])) { - throw new \InvalidArgumentException(sprintf('The "type" key for the route definition "%s" in "%s" is unsupported. It is only available for imports in combination with the "resource" key.', $name, $path)); + throw new \InvalidArgumentException(\sprintf('The "type" key for the route definition "%s" in "%s" is unsupported. It is only available for imports in combination with the "resource" key.', $name, $path)); } if (!isset($config['resource']) && !isset($config['path'])) { - throw new \InvalidArgumentException(sprintf('You must define a "path" for the route "%s" in file "%s".', $name, $path)); + throw new \InvalidArgumentException(\sprintf('You must define a "path" for the route "%s" in file "%s".', $name, $path)); } if (isset($config['controller']) && isset($config['defaults']['_controller'])) { - throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "controller" key and the defaults key "_controller" for "%s".', $path, $name)); + throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "controller" key and the defaults key "_controller" for "%s".', $path, $name)); } if (isset($config['stateless']) && isset($config['defaults']['_stateless'])) { - throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "stateless" key and the defaults key "_stateless" for "%s".', $path, $name)); + throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify both the "stateless" key and the defaults key "_stateless" for "%s".', $path, $name)); } } @@ -287,16 +287,16 @@ private function validateAlias(array $config, string $name, string $path): void { foreach ($config as $key => $value) { if (!\in_array($key, ['alias', 'deprecated'], true)) { - throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify other keys than "alias" and "deprecated" for "%s".', $path, $name)); + throw new \InvalidArgumentException(\sprintf('The routing file "%s" must not specify other keys than "alias" and "deprecated" for "%s".', $path, $name)); } if ('deprecated' === $key) { if (!isset($value['package'])) { - throw new \InvalidArgumentException(sprintf('The routing file "%s" must specify the attribute "package" of the "deprecated" option for "%s".', $path, $name)); + throw new \InvalidArgumentException(\sprintf('The routing file "%s" must specify the attribute "package" of the "deprecated" option for "%s".', $path, $name)); } if (!isset($value['version'])) { - throw new \InvalidArgumentException(sprintf('The routing file "%s" must specify the attribute "version" of the "deprecated" option for "%s".', $path, $name)); + throw new \InvalidArgumentException(\sprintf('The routing file "%s" must specify the attribute "version" of the "deprecated" option for "%s".', $path, $name)); } } } diff --git a/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php b/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php index a7639cd4c..f71264ce9 100644 --- a/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php +++ b/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php @@ -137,7 +137,7 @@ private function generateCompiledRoutes(): string $code .= '[ // $staticRoutes'."\n"; foreach ($staticRoutes as $path => $routes) { - $code .= sprintf(" %s => [\n", self::export($path)); + $code .= \sprintf(" %s => [\n", self::export($path)); foreach ($routes as $route) { $code .= vsprintf(" [%s, %s, %s, %s, %s, %s, %s],\n", array_map([__CLASS__, 'export'], $route)); } @@ -145,11 +145,11 @@ private function generateCompiledRoutes(): string } $code .= "],\n"; - $code .= sprintf("[ // \$regexpList%s\n],\n", $regexpCode); + $code .= \sprintf("[ // \$regexpList%s\n],\n", $regexpCode); $code .= '[ // $dynamicRoutes'."\n"; foreach ($dynamicRoutes as $path => $routes) { - $code .= sprintf(" %s => [\n", self::export($path)); + $code .= \sprintf(" %s => [\n", self::export($path)); foreach ($routes as $route) { $code .= vsprintf(" [%s, %s, %s, %s, %s, %s, %s],\n", array_map([__CLASS__, 'export'], $route)); } @@ -222,7 +222,12 @@ private function compileStaticRoutes(array $staticRoutes, array &$conditions): a foreach ($staticRoutes as $url => $routes) { $compiledRoutes[$url] = []; foreach ($routes as $name => [$route, $hasTrailingSlash]) { - $compiledRoutes[$url][] = $this->compileRoute($route, $name, (!$route->compile()->getHostVariables() ? $route->getHost() : $route->compile()->getHostRegex()) ?: null, $hasTrailingSlash, false, $conditions); + if ($route->compile()->getHostVariables()) { + $host = $route->compile()->getHostRegex(); + } elseif ($host = $route->getHost()) { + $host = strtolower($host); + } + $compiledRoutes[$url][] = $this->compileRoute($route, $name, $host ?: null, $hasTrailingSlash, false, $conditions); } } @@ -402,7 +407,7 @@ private function compileStaticPrefixCollection(StaticPrefixCollection $tree, \st $state->mark += 3 + $state->markTail + \strlen($regex) - $prefixLen; $state->markTail = 2 + \strlen($state->mark); - $rx = sprintf('|%s(*:%s)', substr($regex, $prefixLen), $state->mark); + $rx = \sprintf('|%s(*:%s)', substr($regex, $prefixLen), $state->mark); $code .= "\n .".self::export($rx); $state->regex .= $rx; diff --git a/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php b/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php index 50abf4587..5177c269a 100644 --- a/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php +++ b/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php @@ -42,7 +42,7 @@ public function match(string $pathinfo): array throw new MethodNotAllowedException(array_keys($allow)); } if (!$this instanceof RedirectableUrlMatcherInterface) { - throw new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo)); + throw new ResourceNotFoundException(\sprintf('No routes found for "%s".', $pathinfo)); } if (!\in_array($this->context->getMethod(), ['HEAD', 'GET'], true)) { // no-op @@ -57,7 +57,7 @@ public function match(string $pathinfo): array } finally { $this->context->setScheme($scheme); } - } elseif ('/' !== $trimmedPathinfo = rtrim($pathinfo, '/') ?: '/') { + } elseif ('' !== $trimmedPathinfo = rtrim($pathinfo, '/')) { $pathinfo = $trimmedPathinfo === $pathinfo ? $pathinfo.'/' : $trimmedPathinfo; if ($ret = $this->doMatch($pathinfo, $allow, $allowSchemes)) { return $this->redirect($pathinfo, $ret['_route']) + $ret; @@ -67,14 +67,14 @@ public function match(string $pathinfo): array } } - throw new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo)); + throw new ResourceNotFoundException(\sprintf('No routes found for "%s".', $pathinfo)); } private function doMatch(string $pathinfo, array &$allow = [], array &$allowSchemes = []): array { $allow = $allowSchemes = []; - $pathinfo = rawurldecode($pathinfo) ?: '/'; - $trimmedPathinfo = rtrim($pathinfo, '/') ?: '/'; + $pathinfo = '' === ($pathinfo = rawurldecode($pathinfo)) ? '/' : $pathinfo; + $trimmedPathinfo = '' === ($trimmedPathinfo = rtrim($pathinfo, '/')) ? '/' : $trimmedPathinfo; $context = $this->context; $requestMethod = $canonicalMethod = $context->getMethod(); diff --git a/symfony/routing/Matcher/ExpressionLanguageProvider.php b/symfony/routing/Matcher/ExpressionLanguageProvider.php index 3aeebe699..a910a07a2 100644 --- a/symfony/routing/Matcher/ExpressionLanguageProvider.php +++ b/symfony/routing/Matcher/ExpressionLanguageProvider.php @@ -36,7 +36,7 @@ public function getFunctions(): array foreach ($this->functions->getProvidedServices() as $function => $type) { $functions[] = new ExpressionFunction( $function, - static fn (...$args) => sprintf('($context->getParameter(\'_functions\')->get(%s)(%s))', var_export($function, true), implode(', ', $args)), + static fn (...$args) => \sprintf('($context->getParameter(\'_functions\')->get(%s)(%s))', var_export($function, true), implode(', ', $args)), fn ($values, ...$args) => $values['context']->getParameter('_functions')->get($function)(...$args) ); } diff --git a/symfony/routing/Matcher/RedirectableUrlMatcher.php b/symfony/routing/Matcher/RedirectableUrlMatcher.php index 8d1ad4f90..3e7b78b5e 100644 --- a/symfony/routing/Matcher/RedirectableUrlMatcher.php +++ b/symfony/routing/Matcher/RedirectableUrlMatcher.php @@ -41,7 +41,7 @@ public function match(string $pathinfo): array } finally { $this->context->setScheme($scheme); } - } elseif ('/' === $trimmedPathinfo = rtrim($pathinfo, '/') ?: '/') { + } elseif ('' === $trimmedPathinfo = rtrim($pathinfo, '/')) { throw $e; } else { try { diff --git a/symfony/routing/Matcher/TraceableUrlMatcher.php b/symfony/routing/Matcher/TraceableUrlMatcher.php index 3c7e24d06..8ff018309 100644 --- a/symfony/routing/Matcher/TraceableUrlMatcher.php +++ b/symfony/routing/Matcher/TraceableUrlMatcher.php @@ -63,7 +63,7 @@ protected function matchCollection(string $pathinfo, RouteCollection $routes): a $method = 'GET'; } $supportsTrailingSlash = 'GET' === $method && $this instanceof RedirectableUrlMatcherInterface; - $trimmedPathinfo = rtrim($pathinfo, '/') ?: '/'; + $trimmedPathinfo = '' === ($trimmedPathinfo = rtrim($pathinfo, '/')) ? '/' : $trimmedPathinfo; foreach ($routes as $name => $route) { $compiledRoute = $route->compile(); @@ -72,7 +72,7 @@ protected function matchCollection(string $pathinfo, RouteCollection $routes): a // check the static prefix of the URL first. Only use the more expensive preg_match when it matches if ('' !== $staticPrefix && !str_starts_with($trimmedPathinfo, $staticPrefix)) { - $this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route); + $this->addTrace(\sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route); continue; } $regex = $compiledRoute->getRegex(); @@ -86,7 +86,7 @@ protected function matchCollection(string $pathinfo, RouteCollection $routes): a $r = new Route($route->getPath(), $route->getDefaults(), [], $route->getOptions()); $cr = $r->compile(); if (!preg_match($cr->getRegex(), $pathinfo)) { - $this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route); + $this->addTrace(\sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route); continue; } @@ -96,7 +96,7 @@ protected function matchCollection(string $pathinfo, RouteCollection $routes): a $cr = $r->compile(); if (\in_array($n, $cr->getVariables()) && !preg_match($cr->getRegex(), $pathinfo)) { - $this->addTrace(sprintf('Requirement for "%s" does not match (%s)', $n, $regex), self::ROUTE_ALMOST_MATCHES, $name, $route); + $this->addTrace(\sprintf('Requirement for "%s" does not match (%s)', $n, $regex), self::ROUTE_ALMOST_MATCHES, $name, $route); continue 2; } @@ -117,7 +117,7 @@ protected function matchCollection(string $pathinfo, RouteCollection $routes): a $hostMatches = []; if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) { - $this->addTrace(sprintf('Host "%s" does not match the requirement ("%s")', $this->context->getHost(), $route->getHost()), self::ROUTE_ALMOST_MATCHES, $name, $route); + $this->addTrace(\sprintf('Host "%s" does not match the requirement ("%s")', $this->context->getHost(), $route->getHost()), self::ROUTE_ALMOST_MATCHES, $name, $route); continue; } @@ -126,7 +126,7 @@ protected function matchCollection(string $pathinfo, RouteCollection $routes): a $status = $this->handleRouteRequirements($pathinfo, $name, $route, $attributes); if (self::REQUIREMENT_MISMATCH === $status[0]) { - $this->addTrace(sprintf('Condition "%s" does not evaluate to "true"', $route->getCondition()), self::ROUTE_ALMOST_MATCHES, $name, $route); + $this->addTrace(\sprintf('Condition "%s" does not evaluate to "true"', $route->getCondition()), self::ROUTE_ALMOST_MATCHES, $name, $route); continue; } @@ -136,19 +136,19 @@ protected function matchCollection(string $pathinfo, RouteCollection $routes): a return $this->allow = $this->allowSchemes = []; } - $this->addTrace(sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route); + $this->addTrace(\sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route); continue; } if ($route->getSchemes() && !$route->hasScheme($this->context->getScheme())) { $this->allowSchemes = array_merge($this->allowSchemes, $route->getSchemes()); - $this->addTrace(sprintf('Scheme "%s" does not match any of the required schemes (%s)', $this->context->getScheme(), implode(', ', $route->getSchemes())), self::ROUTE_ALMOST_MATCHES, $name, $route); + $this->addTrace(\sprintf('Scheme "%s" does not match any of the required schemes (%s)', $this->context->getScheme(), implode(', ', $route->getSchemes())), self::ROUTE_ALMOST_MATCHES, $name, $route); continue; } if ($requiredMethods && !\in_array($method, $requiredMethods)) { $this->allow = array_merge($this->allow, $requiredMethods); - $this->addTrace(sprintf('Method "%s" does not match any of the required methods (%s)', $this->context->getMethod(), implode(', ', $requiredMethods)), self::ROUTE_ALMOST_MATCHES, $name, $route); + $this->addTrace(\sprintf('Method "%s" does not match any of the required methods (%s)', $this->context->getMethod(), implode(', ', $requiredMethods)), self::ROUTE_ALMOST_MATCHES, $name, $route); continue; } diff --git a/symfony/routing/Matcher/UrlMatcher.php b/symfony/routing/Matcher/UrlMatcher.php index 778d154ed..f3ab414f0 100644 --- a/symfony/routing/Matcher/UrlMatcher.php +++ b/symfony/routing/Matcher/UrlMatcher.php @@ -78,8 +78,9 @@ public function getContext(): RequestContext public function match(string $pathinfo): array { $this->allow = $this->allowSchemes = []; + $pathinfo = '' === ($pathinfo = rawurldecode($pathinfo)) ? '/' : $pathinfo; - if ($ret = $this->matchCollection(rawurldecode($pathinfo) ?: '/', $this->routes)) { + if ($ret = $this->matchCollection($pathinfo, $this->routes)) { return $ret; } @@ -87,7 +88,7 @@ public function match(string $pathinfo): array throw new NoConfigurationException(); } - throw 0 < \count($this->allow) ? new MethodNotAllowedException(array_unique($this->allow)) : new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo)); + throw 0 < \count($this->allow) ? new MethodNotAllowedException(array_unique($this->allow)) : new ResourceNotFoundException(\sprintf('No routes found for "%s".', $pathinfo)); } public function matchRequest(Request $request): array @@ -125,7 +126,7 @@ protected function matchCollection(string $pathinfo, RouteCollection $routes): a $method = 'GET'; } $supportsTrailingSlash = 'GET' === $method && $this instanceof RedirectableUrlMatcherInterface; - $trimmedPathinfo = rtrim($pathinfo, '/') ?: '/'; + $trimmedPathinfo = '' === ($trimmedPathinfo = rtrim($pathinfo, '/')) ? '/' : $trimmedPathinfo; foreach ($routes as $name => $route) { $compiledRoute = $route->compile(); @@ -225,7 +226,7 @@ protected function handleRouteRequirements(string $pathinfo, string $name, Route $routeParameters = func_get_arg(3); if (!\is_array($routeParameters)) { - throw new \TypeError(sprintf('"%s": Argument $routeParameters is expected to be an array, got "%s".', __METHOD__, get_debug_type($routeParameters))); + throw new \TypeError(\sprintf('"%s": Argument $routeParameters is expected to be an array, got "%s".', __METHOD__, get_debug_type($routeParameters))); } } diff --git a/symfony/routing/Requirement/EnumRequirement.php b/symfony/routing/Requirement/EnumRequirement.php index 3ab2ed332..acbd3bab0 100644 --- a/symfony/routing/Requirement/EnumRequirement.php +++ b/symfony/routing/Requirement/EnumRequirement.php @@ -26,7 +26,7 @@ public function __construct(string|array $cases = []) { if (\is_string($cases)) { if (!is_subclass_of($cases, \BackedEnum::class, true)) { - throw new InvalidArgumentException(sprintf('"%s" is not a "BackedEnum" class.', $cases)); + throw new InvalidArgumentException(\sprintf('"%s" is not a "BackedEnum" class.', $cases)); } $cases = $cases::cases(); @@ -35,13 +35,13 @@ public function __construct(string|array $cases = []) foreach ($cases as $case) { if (!$case instanceof \BackedEnum) { - throw new InvalidArgumentException(sprintf('Case must be a "BackedEnum" instance, "%s" given.', get_debug_type($case))); + throw new InvalidArgumentException(\sprintf('Case must be a "BackedEnum" instance, "%s" given.', get_debug_type($case))); } $class ??= $case::class; if (!$case instanceof $class) { - throw new InvalidArgumentException(sprintf('"%s::%s" is not a case of "%s".', get_debug_type($case), $case->name, $class)); + throw new InvalidArgumentException(\sprintf('"%s::%s" is not a case of "%s".', get_debug_type($case), $case->name, $class)); } } } diff --git a/symfony/routing/Route.php b/symfony/routing/Route.php index ac8d8bc6e..e34dcb75e 100644 --- a/symfony/routing/Route.php +++ b/symfony/routing/Route.php @@ -35,7 +35,7 @@ class Route implements \Serializable * Available options: * * * compiler_class: A class name able to compile this route instance (RouteCompiler by default) - * * utf8: Whether UTF-8 matching is enforced ot not + * * utf8: Whether UTF-8 matching is enforced or not * * @param string $path The path pattern to match * @param array $defaults An array of default parameter values @@ -445,7 +445,7 @@ private function sanitizeRequirement(string $key, string $regex): string } if ('' === $regex) { - throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty.', $key)); + throw new \InvalidArgumentException(\sprintf('Routing requirement for "%s" cannot be empty.', $key)); } return $regex; diff --git a/symfony/routing/RouteCollection.php b/symfony/routing/RouteCollection.php index 2f49ad217..a253bc56d 100644 --- a/symfony/routing/RouteCollection.php +++ b/symfony/routing/RouteCollection.php @@ -239,7 +239,13 @@ public function addNamePrefix(string $prefix) } foreach ($this->aliases as $name => $alias) { - $prefixedAliases[$prefix.$name] = $alias->withId($prefix.$alias->getId()); + $targetId = $alias->getId(); + + if (isset($this->routes[$targetId]) || isset($this->aliases[$targetId])) { + $targetId = $prefix.$targetId; + } + + $prefixedAliases[$prefix.$name] = $alias->withId($targetId); } $this->routes = $prefixedRoutes; @@ -387,7 +393,7 @@ public function addResource(ResourceInterface $resource) public function addAlias(string $name, string $alias): Alias { if ($name === $alias) { - throw new InvalidArgumentException(sprintf('Route alias "%s" can not reference itself.', $name)); + throw new InvalidArgumentException(\sprintf('Route alias "%s" can not reference itself.', $name)); } unset($this->routes[$name], $this->priorities[$name]); diff --git a/symfony/routing/RouteCompiler.php b/symfony/routing/RouteCompiler.php index 330639f48..a96fb9ad9 100644 --- a/symfony/routing/RouteCompiler.php +++ b/symfony/routing/RouteCompiler.php @@ -75,7 +75,7 @@ public static function compile(Route $route): CompiledRoute foreach ($pathVariables as $pathParam) { if ('_fragment' === $pathParam) { - throw new \InvalidArgumentException(sprintf('Route pattern "%s" cannot contain "_fragment" as a path parameter.', $route->getPath())); + throw new \InvalidArgumentException(\sprintf('Route pattern "%s" cannot contain "_fragment" as a path parameter.', $route->getPath())); } } @@ -107,10 +107,10 @@ private static function compilePattern(Route $route, string $pattern, bool $isHo $needsUtf8 = $route->getOption('utf8'); if (!$needsUtf8 && $useUtf8 && preg_match('/[\x80-\xFF]/', $pattern)) { - throw new \LogicException(sprintf('Cannot use UTF-8 route patterns without setting the "utf8" option for route "%s".', $route->getPath())); + throw new \LogicException(\sprintf('Cannot use UTF-8 route patterns without setting the "utf8" option for route "%s".', $route->getPath())); } if (!$useUtf8 && $needsUtf8) { - throw new \LogicException(sprintf('Cannot mix UTF-8 requirements with non-UTF-8 pattern "%s".', $pattern)); + throw new \LogicException(\sprintf('Cannot mix UTF-8 requirements with non-UTF-8 pattern "%s".', $pattern)); } // Match all variables enclosed in "{}" and iterate over them. But we only want to match the innermost variable @@ -136,14 +136,14 @@ private static function compilePattern(Route $route, string $pattern, bool $isHo // A PCRE subpattern name must start with a non-digit. Also a PHP variable cannot start with a digit so the // variable would not be usable as a Controller action argument. if (preg_match('/^\d/', $varName)) { - throw new \DomainException(sprintf('Variable name "%s" cannot start with a digit in route pattern "%s". Please use a different name.', $varName, $pattern)); + throw new \DomainException(\sprintf('Variable name "%s" cannot start with a digit in route pattern "%s". Please use a different name.', $varName, $pattern)); } if (\in_array($varName, $variables)) { - throw new \LogicException(sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $pattern, $varName)); + throw new \LogicException(\sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $pattern, $varName)); } if (\strlen($varName) > self::VARIABLE_MAXIMUM_LENGTH) { - throw new \DomainException(sprintf('Variable name "%s" cannot be longer than %d characters in route pattern "%s". Please use a shorter name.', $varName, self::VARIABLE_MAXIMUM_LENGTH, $pattern)); + throw new \DomainException(\sprintf('Variable name "%s" cannot be longer than %d characters in route pattern "%s". Please use a shorter name.', $varName, self::VARIABLE_MAXIMUM_LENGTH, $pattern)); } if ($isSeparator && $precedingText !== $precedingChar) { @@ -163,7 +163,7 @@ private static function compilePattern(Route $route, string $pattern, bool $isHo // Also even if {_format} was not optional the requirement prevents that {page} matches something that was originally // part of {_format} when generating the URL, e.g. _format = 'mobile.html'. $nextSeparator = self::findNextSeparator($followingPattern, $useUtf8); - $regexp = sprintf( + $regexp = \sprintf( '[^%s%s]+', preg_quote($defaultSeparator), $defaultSeparator !== $nextSeparator && '' !== $nextSeparator ? preg_quote($nextSeparator) : '' @@ -180,10 +180,10 @@ private static function compilePattern(Route $route, string $pattern, bool $isHo if (!preg_match('//u', $regexp)) { $useUtf8 = false; } elseif (!$needsUtf8 && preg_match('/[\x80-\xFF]|(?%s)?', preg_quote($token[1]), $token[3], $token[2]); + return \sprintf('%s(?P<%s>%s)?', preg_quote($token[1]), $token[3], $token[2]); } else { - $regexp = sprintf('%s(?P<%s>%s)', preg_quote($token[1]), $token[3], $token[2]); + $regexp = \sprintf('%s(?P<%s>%s)', preg_quote($token[1]), $token[3], $token[2]); if ($index >= $firstOptional) { // Enclose each optional token in a subpattern to make it optional. // "?:" means it is non-capturing, i.e. the portion of the subject string that diff --git a/symfony/routing/Router.php b/symfony/routing/Router.php index b769caee6..95f6091d7 100644 --- a/symfony/routing/Router.php +++ b/symfony/routing/Router.php @@ -144,7 +144,7 @@ public function setOptions(array $options) } if ($invalid) { - throw new \InvalidArgumentException(sprintf('The Router does not support the following options: "%s".', implode('", "', $invalid))); + throw new \InvalidArgumentException(\sprintf('The Router does not support the following options: "%s".', implode('", "', $invalid))); } } @@ -158,7 +158,7 @@ public function setOptions(array $options) public function setOption(string $key, mixed $value) { if (!\array_key_exists($key, $this->options)) { - throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key)); + throw new \InvalidArgumentException(\sprintf('The Router does not support the "%s" option.', $key)); } $this->options[$key] = $value; @@ -172,7 +172,7 @@ public function setOption(string $key, mixed $value) public function getOption(string $key): mixed { if (!\array_key_exists($key, $this->options)) { - throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key)); + throw new \InvalidArgumentException(\sprintf('The Router does not support the "%s" option.', $key)); } return $this->options[$key]; diff --git a/symfony/service-contracts/ServiceLocatorTrait.php b/symfony/service-contracts/ServiceLocatorTrait.php index b62ec3e53..bbe454843 100644 --- a/symfony/service-contracts/ServiceLocatorTrait.php +++ b/symfony/service-contracts/ServiceLocatorTrait.php @@ -26,16 +26,15 @@ class_exists(NotFoundExceptionInterface::class); */ trait ServiceLocatorTrait { - private array $factories; private array $loading = []; private array $providedTypes; /** * @param array $factories */ - public function __construct(array $factories) - { - $this->factories = $factories; + public function __construct( + private array $factories, + ) { } public function has(string $id): bool @@ -91,16 +90,16 @@ private function createNotFoundException(string $id): NotFoundExceptionInterface } else { $last = array_pop($alternatives); if ($alternatives) { - $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); + $message = \sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); } else { - $message = sprintf('only knows about the "%s" service.', $last); + $message = \sprintf('only knows about the "%s" service.', $last); } } if ($this->loading) { - $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); + $message = \sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); } else { - $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); + $message = \sprintf('Service "%s" not found: the current service locator %s', $id, $message); } return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { @@ -109,7 +108,7 @@ private function createNotFoundException(string $id): NotFoundExceptionInterface private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface { - return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { + return new class(\sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { }; } } diff --git a/symfony/service-contracts/ServiceMethodsSubscriberTrait.php b/symfony/service-contracts/ServiceMethodsSubscriberTrait.php index 0d89d9f25..844be8907 100644 --- a/symfony/service-contracts/ServiceMethodsSubscriberTrait.php +++ b/symfony/service-contracts/ServiceMethodsSubscriberTrait.php @@ -42,18 +42,18 @@ public static function getSubscribedServices(): array } if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { - throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); } if (!$returnType = $method->getReturnType()) { - throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); } /* @var SubscribedService $attribute */ $attribute = $attribute->newInstance(); $attribute->key ??= self::class.'::'.$method->name; $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - $attribute->nullable = $returnType->allowsNull(); + $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull(); if ($attribute->attributes) { $services[] = $attribute; diff --git a/symfony/service-contracts/ServiceSubscriberTrait.php b/symfony/service-contracts/ServiceSubscriberTrait.php index cc3bc321a..58ea7c549 100644 --- a/symfony/service-contracts/ServiceSubscriberTrait.php +++ b/symfony/service-contracts/ServiceSubscriberTrait.php @@ -46,18 +46,18 @@ public static function getSubscribedServices(): array } if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { - throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); } if (!$returnType = $method->getReturnType()) { - throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); } - /* @var SubscribedService $attribute */ + /** @var SubscribedService $attribute */ $attribute = $attribute->newInstance(); $attribute->key ??= self::class.'::'.$method->name; $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - $attribute->nullable = $returnType->allowsNull(); + $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull(); if ($attribute->attributes) { $services[] = $attribute; diff --git a/symfony/string/AbstractString.php b/symfony/string/AbstractString.php index f55c72161..45bcf0c03 100644 --- a/symfony/string/AbstractString.php +++ b/symfony/string/AbstractString.php @@ -263,7 +263,7 @@ public function containsAny(string|iterable $needle): bool public function endsWith(string|iterable $suffix): bool { if (\is_string($suffix)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($suffix as $s) { @@ -312,7 +312,7 @@ public function ensureStart(string $prefix): static public function equalsTo(string|iterable $string): bool { if (\is_string($string)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($string as $s) { @@ -340,7 +340,7 @@ public function ignoreCase(): static public function indexOf(string|iterable $needle, int $offset = 0): ?int { if (\is_string($needle)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } $i = \PHP_INT_MAX; @@ -362,7 +362,7 @@ public function indexOf(string|iterable $needle, int $offset = 0): ?int public function indexOfLast(string|iterable $needle, int $offset = 0): ?int { if (\is_string($needle)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } $i = null; @@ -414,7 +414,7 @@ abstract public function prepend(string ...$prefix): static; public function repeat(int $multiplier): static { if (0 > $multiplier) { - throw new InvalidArgumentException(sprintf('Multiplier must be positive, %d given.', $multiplier)); + throw new InvalidArgumentException(\sprintf('Multiplier must be positive, %d given.', $multiplier)); } $str = clone $this; @@ -481,7 +481,7 @@ public function split(string $delimiter, ?int $limit = null, ?int $flags = null) public function startsWith(string|iterable $prefix): bool { if (\is_string($prefix)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($prefix as $prefix) { diff --git a/symfony/string/AbstractUnicodeString.php b/symfony/string/AbstractUnicodeString.php index 70598e409..6ea79938f 100644 --- a/symfony/string/AbstractUnicodeString.php +++ b/symfony/string/AbstractUnicodeString.php @@ -124,7 +124,7 @@ public function ascii(array $rules = []): self } if (null === $transliterator) { - throw new InvalidArgumentException(sprintf('Unknown transliteration rule "%s".', $rule)); + throw new InvalidArgumentException(\sprintf('Unknown transliteration rule "%s".', $rule)); } self::$transliterators['any-latin/bgn'] = $transliterator; @@ -135,15 +135,21 @@ public function ascii(array $rules = []): self } elseif (!\function_exists('iconv')) { $s = preg_replace('/[^\x00-\x7F]/u', '?', $s); } else { - $s = @preg_replace_callback('/[^\x00-\x7F]/u', static function ($c) { - $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); - - if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { - throw new \LogicException(sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); - } + $previousLocale = setlocale(\LC_CTYPE, 0); + try { + setlocale(\LC_CTYPE, 'C'); + $s = @preg_replace_callback('/[^\x00-\x7F]/u', static function ($c) { + $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); + + if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { + throw new \LogicException(\sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); + } - return 1 < \strlen($c) ? ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); - }, $s); + return 1 < \strlen($c) ? ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); + }, $s); + } finally { + setlocale(\LC_CTYPE, $previousLocale); + } } } diff --git a/symfony/string/ByteString.php b/symfony/string/ByteString.php index 3ebe43c10..e96a184ca 100644 --- a/symfony/string/ByteString.php +++ b/symfony/string/ByteString.php @@ -45,7 +45,7 @@ public function __construct(string $string = '') public static function fromRandom(int $length = 16, ?string $alphabet = null): self { if ($length <= 0) { - throw new InvalidArgumentException(sprintf('A strictly positive length is expected, "%d" given.', $length)); + throw new InvalidArgumentException(\sprintf('A strictly positive length is expected, "%d" given.', $length)); } $alphabet ??= self::ALPHABET_ALPHANUMERIC; @@ -436,7 +436,7 @@ public function toCodePointString(?string $fromEncoding = null): CodePointString } if (!$validEncoding) { - throw new InvalidArgumentException(sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252')); + throw new InvalidArgumentException(\sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252')); } $u->string = mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252'); diff --git a/symfony/string/Inflector/EnglishInflector.php b/symfony/string/Inflector/EnglishInflector.php index a5be28d66..558366996 100644 --- a/symfony/string/Inflector/EnglishInflector.php +++ b/symfony/string/Inflector/EnglishInflector.php @@ -25,9 +25,22 @@ final class EnglishInflector implements InflectorInterface // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: singular suffix, normal + // insignias (insigne), insignia (insigne) + ['saingisni', 9, true, true, 'insigne'], + ['aingisni', 8, true, true, 'insigne'], + + // passersby (passerby) + ['ybsressap', 9, true, true, 'passerby'], + + // nodes (node) + ['sedon', 5, true, true, 'node'], + // bacteria (bacterium) ['airetcab', 8, true, true, 'bacterium'], + // issues (issue) + ['seussi', 6, true, true, 'issue'], + // corpora (corpus) ['aroproc', 7, true, true, 'corpus'], @@ -166,6 +179,9 @@ final class EnglishInflector implements InflectorInterface // edges (edge) ['segd', 4, true, true, 'dge'], + // outages (outage) - specific fix to avoid 'outag' + ['segatuo', 7, true, true, 'outage'], + // roses (rose), garages (garage), cassettes (cassette), // waltzes (waltz), heroes (hero), bushes (bush), arches (arch), // shoes (shoe) @@ -196,6 +212,15 @@ final class EnglishInflector implements InflectorInterface // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: plural suffix, normal + // passerby (passersby) + ['ybressap', 8, true, true, 'passersby'], + + // insigne (insignia, insignias) + ['engisni', 7, true, true, ['insignia', 'insignias']], + + // nodes (node) + ['edon', 4, true, true, 'nodes'], + // axes (axis) ['sixa', 4, false, false, 'axes'], @@ -333,6 +358,9 @@ final class EnglishInflector implements InflectorInterface // conspectuses (conspectus), prospectuses (prospectus) ['sutcep', 6, true, true, 'pectuses'], + // nexuses (nexus) + ['suxen', 5, false, false, 'nexuses'], + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) ['su', 2, true, true, 'i'], diff --git a/symfony/string/LazyString.php b/symfony/string/LazyString.php index 3d893ef9e..b89ec4df1 100644 --- a/symfony/string/LazyString.php +++ b/symfony/string/LazyString.php @@ -26,7 +26,7 @@ class LazyString implements \Stringable, \JsonSerializable public static function fromCallable(callable|array $callback, mixed ...$arguments): static { if (\is_array($callback) && !\is_callable($callback) && !(($callback[0] ?? null) instanceof \Closure || 2 < \count($callback))) { - throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, '['.implode(', ', array_map('get_debug_type', $callback)).']')); + throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, '['.implode(', ', array_map('get_debug_type', $callback)).']')); } $lazyString = new static(); @@ -94,7 +94,7 @@ public function __toString(): string $r = new \ReflectionFunction($this->value); $callback = $r->getStaticVariables()['callback']; - $e = new \TypeError(sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); + $e = new \TypeError(\sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); } throw $e; diff --git a/symfony/string/Slugger/AsciiSlugger.php b/symfony/string/Slugger/AsciiSlugger.php index a9693d494..d4d4e942a 100644 --- a/symfony/string/Slugger/AsciiSlugger.php +++ b/symfony/string/Slugger/AsciiSlugger.php @@ -95,7 +95,7 @@ public function getLocale(): string public function withEmoji(bool|string $emoji = true): static { if (false !== $emoji && !class_exists(EmojiTransliterator::class)) { - throw new \LogicException(sprintf('You cannot use the "%s()" method as the "symfony/intl" package is not installed. Try running "composer require symfony/intl".', __METHOD__)); + throw new \LogicException(\sprintf('You cannot use the "%s()" method as the "symfony/intl" package is not installed. Try running "composer require symfony/intl".', __METHOD__)); } $new = clone $this; @@ -131,8 +131,8 @@ public function slug(string $string, string $separator = '-', ?string $locale = if (\is_array($this->symbolsMap)) { $map = null; - if (isset($this->symbolsMap[$locale])) { - $map = $this->symbolsMap[$locale]; + if (isset($this->symbolsMap[$locale ?? ''])) { + $map = $this->symbolsMap[$locale ?? '']; } else { $parent = self::getParentLocale($locale); if ($parent && isset($this->symbolsMap[$parent])) { diff --git a/symfony/string/UnicodeString.php b/symfony/string/UnicodeString.php index 75af2da42..f416ee1b2 100644 --- a/symfony/string/UnicodeString.php +++ b/symfony/string/UnicodeString.php @@ -362,6 +362,44 @@ public function startsWith(string|iterable|AbstractString $prefix): bool return $prefix === grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES); } + public function trimPrefix($prefix): static + { + if (\is_array($prefix) || $prefix instanceof \Traversable) { + return parent::trimPrefix($prefix); + } + + if ($prefix instanceof AbstractString) { + $prefix = $prefix->string; + } else { + $prefix = (string) $prefix; + } + + if (!normalizer_is_normalized($prefix, \Normalizer::NFC)) { + $prefix = normalizer_normalize($prefix, \Normalizer::NFC); + } + + return parent::trimPrefix($prefix); + } + + public function trimSuffix($suffix): static + { + if (\is_array($suffix) || $suffix instanceof \Traversable) { + return parent::trimSuffix($suffix); + } + + if ($suffix instanceof AbstractString) { + $suffix = $suffix->string; + } else { + $suffix = (string) $suffix; + } + + if (!normalizer_is_normalized($suffix, \Normalizer::NFC)) { + $suffix = normalizer_normalize($suffix, \Normalizer::NFC); + } + + return parent::trimSuffix($suffix); + } + /** * @return void */ diff --git a/symfony/translation-contracts/TranslatorTrait.php b/symfony/translation-contracts/TranslatorTrait.php index 63f6fb333..afedd9928 100644 --- a/symfony/translation-contracts/TranslatorTrait.php +++ b/symfony/translation-contracts/TranslatorTrait.php @@ -41,6 +41,12 @@ public function trans(?string $id, array $parameters = [], ?string $domain = nul return ''; } + foreach ($parameters as $k => $v) { + if ($v instanceof TranslatableInterface) { + $parameters[$k] = $v->trans($this, $locale); + } + } + if (!isset($parameters['%count%']) || !is_numeric($parameters['%count%'])) { return strtr($id, $parameters); } @@ -111,7 +117,7 @@ public function trans(?string $id, array $parameters = [], ?string $domain = nul return strtr($standardRules[0], $parameters); } - $message = sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $id, $locale, $number); + $message = \sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $id, $locale, $number); if (class_exists(InvalidArgumentException::class)) { throw new InvalidArgumentException($message); diff --git a/symfony/translation/Catalogue/AbstractOperation.php b/symfony/translation/Catalogue/AbstractOperation.php index 7dff58ff4..32fc5813c 100644 --- a/symfony/translation/Catalogue/AbstractOperation.php +++ b/symfony/translation/Catalogue/AbstractOperation.php @@ -97,7 +97,7 @@ public function getDomains(): array public function getMessages(string $domain): array { if (!\in_array($domain, $this->getDomains())) { - throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain)); + throw new InvalidArgumentException(\sprintf('Invalid domain: "%s".', $domain)); } if (!isset($this->messages[$domain][self::ALL_BATCH])) { @@ -110,7 +110,7 @@ public function getMessages(string $domain): array public function getNewMessages(string $domain): array { if (!\in_array($domain, $this->getDomains())) { - throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain)); + throw new InvalidArgumentException(\sprintf('Invalid domain: "%s".', $domain)); } if (!isset($this->messages[$domain][self::NEW_BATCH])) { @@ -123,7 +123,7 @@ public function getNewMessages(string $domain): array public function getObsoleteMessages(string $domain): array { if (!\in_array($domain, $this->getDomains())) { - throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain)); + throw new InvalidArgumentException(\sprintf('Invalid domain: "%s".', $domain)); } if (!isset($this->messages[$domain][self::OBSOLETE_BATCH])) { @@ -160,7 +160,7 @@ public function moveMessagesToIntlDomainsIfPossible(string $batch = self::ALL_BA self::OBSOLETE_BATCH => $this->getObsoleteMessages($domain), self::NEW_BATCH => $this->getNewMessages($domain), self::ALL_BATCH => $this->getMessages($domain), - default => throw new \InvalidArgumentException(sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH)), + default => throw new \InvalidArgumentException(\sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH)), }; if (!$messages || (!$this->source->all($intlDomain) && $this->source->all($domain))) { diff --git a/symfony/translation/Command/TranslationPullCommand.php b/symfony/translation/Command/TranslationPullCommand.php index 5d9c092c3..2394b3efe 100644 --- a/symfony/translation/Command/TranslationPullCommand.php +++ b/symfony/translation/Command/TranslationPullCommand.php @@ -92,10 +92,10 @@ protected function configure(): void new InputArgument('provider', null !== $defaultProvider ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The provider to pull translations from.', $defaultProvider), new InputOption('force', null, InputOption::VALUE_NONE, 'Override existing translations with provider ones (it will delete not synchronized messages).'), new InputOption('intl-icu', null, InputOption::VALUE_NONE, 'Associated to --force option, it will write messages in "%domain%+intl-icu.%locale%.xlf" files.'), - new InputOption('domains', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the domains to pull.'), - new InputOption('locales', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the locales to pull.'), - new InputOption('format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format.', 'xlf12'), - new InputOption('as-tree', null, InputOption::VALUE_OPTIONAL, 'Write messages as a tree-like structure. Needs --format=yaml. The given value defines the level where to switch to inline YAML'), + new InputOption('domains', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the domains to pull.'), + new InputOption('locales', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to pull.'), + new InputOption('format', null, InputOption::VALUE_REQUIRED, 'Override the default output format.', 'xlf12'), + new InputOption('as-tree', null, InputOption::VALUE_REQUIRED, 'Write messages as a tree-like structure. Needs --format=yaml. The given value defines the level where to switch to inline YAML'), ]) ->setHelp(<<<'EOF' The %command.name% command pulls translations from the given provider. Only @@ -163,7 +163,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->writer->write($operation->getResult(), $format, $writeOptions); } - $io->success(sprintf('Local translations has been updated from "%s" (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); + $io->success(\sprintf('Local translations has been updated from "%s" (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } @@ -177,7 +177,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->writer->write($catalogue, $format, $writeOptions); } - $io->success(sprintf('New translations from "%s" has been written locally (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); + $io->success(\sprintf('New translations from "%s" has been written locally (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } diff --git a/symfony/translation/Command/TranslationPushCommand.php b/symfony/translation/Command/TranslationPushCommand.php index 1d04adbc9..e0be0f447 100644 --- a/symfony/translation/Command/TranslationPushCommand.php +++ b/symfony/translation/Command/TranslationPushCommand.php @@ -83,8 +83,8 @@ protected function configure(): void new InputArgument('provider', null !== $defaultProvider ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The provider to push translations to.', $defaultProvider), new InputOption('force', null, InputOption::VALUE_NONE, 'Override existing translations with local ones (it will delete not synchronized messages).'), new InputOption('delete-missing', null, InputOption::VALUE_NONE, 'Delete translations available on provider but not locally.'), - new InputOption('domains', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the domains to push.'), - new InputOption('locales', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the locales to push.', $this->enabledLocales), + new InputOption('domains', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the domains to push.'), + new InputOption('locales', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Specify the locales to push.', $this->enabledLocales), ]) ->setHelp(<<<'EOF' The %command.name% command pushes translations to the given provider. Only new @@ -115,7 +115,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $provider = $this->providers->get($input->getArgument('provider')); if (!$this->enabledLocales) { - throw new InvalidArgumentException(sprintf('You must define "framework.enabled_locales" or "framework.translator.providers.%s.locales" config key in order to work with translation providers.', parse_url($provider, \PHP_URL_SCHEME))); + throw new InvalidArgumentException(\sprintf('You must define "framework.enabled_locales" or "framework.translator.providers.%s.locales" config key in order to work with translation providers.', parse_url($provider, \PHP_URL_SCHEME))); } $io = new SymfonyStyle($input, $output); @@ -139,7 +139,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if (!$deleteMissing && $force) { $provider->write($localTranslations); - $io->success(sprintf('All local translations has been sent to "%s" (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); + $io->success(\sprintf('All local translations has been sent to "%s" (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } @@ -149,7 +149,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($deleteMissing) { $provider->delete($providerTranslations->diff($localTranslations)); - $io->success(sprintf('Missing translations on "%s" has been deleted (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); + $io->success(\sprintf('Missing translations on "%s" has been deleted (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); // Read provider translations again, after missing translations deletion, // to avoid push freshly deleted translations. @@ -164,7 +164,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $provider->write($translationsToWrite); - $io->success(sprintf('%s local translations has been sent to "%s" (for "%s" locale(s), and "%s" domain(s)).', $force ? 'All' : 'New', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); + $io->success(\sprintf('%s local translations has been sent to "%s" (for "%s" locale(s), and "%s" domain(s)).', $force ? 'All' : 'New', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } diff --git a/symfony/translation/Command/XliffLintCommand.php b/symfony/translation/Command/XliffLintCommand.php index ba946389e..7220e24a9 100644 --- a/symfony/translation/Command/XliffLintCommand.php +++ b/symfony/translation/Command/XliffLintCommand.php @@ -57,7 +57,7 @@ protected function configure() { $this ->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN') - ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions()))) + ->addOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions()))) ->setHelp(<<%command.name% command lints an XLIFF file and outputs to STDOUT the first encountered syntax error. @@ -98,7 +98,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $filesInfo = []; foreach ($filenames as $filename) { if (!$this->isReadable($filename)) { - throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename)); + throw new RuntimeException(\sprintf('File or directory "%s" is not readable.', $filename)); } foreach ($this->getFiles($filename) as $file) { @@ -124,18 +124,18 @@ private function validate(string $content, ?string $file = null): array $document->loadXML($content); if (null !== $targetLanguage = $this->getTargetLanguageFromFile($document)) { - $normalizedLocalePattern = sprintf('(%s|%s)', preg_quote($targetLanguage, '/'), preg_quote(str_replace('-', '_', $targetLanguage), '/')); + $normalizedLocalePattern = \sprintf('(%s|%s)', preg_quote($targetLanguage, '/'), preg_quote(str_replace('-', '_', $targetLanguage), '/')); // strict file names require translation files to be named '____.locale.xlf' // otherwise, both '____.locale.xlf' and 'locale.____.xlf' are allowed // also, the regexp matching must be case-insensitive, as defined for 'target-language' values // http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#target-language - $expectedFilenamePattern = $this->requireStrictFileNames ? sprintf('/^.*\.(?i:%s)\.(?:xlf|xliff)/', $normalizedLocalePattern) : sprintf('/^(?:.*\.(?i:%s)|(?i:%s)\..*)\.(?:xlf|xliff)/', $normalizedLocalePattern, $normalizedLocalePattern); + $expectedFilenamePattern = $this->requireStrictFileNames ? \sprintf('/^.*\.(?i:%s)\.(?:xlf|xliff)/', $normalizedLocalePattern) : \sprintf('/^(?:.*\.(?i:%s)|(?i:%s)\..*)\.(?:xlf|xliff)/', $normalizedLocalePattern, $normalizedLocalePattern); if (0 === preg_match($expectedFilenamePattern, basename($file))) { $errors[] = [ 'line' => -1, 'column' => -1, - 'message' => sprintf('There is a mismatch between the language included in the file name ("%s") and the "%s" value used in the "target-language" attribute of the file.', basename($file), $targetLanguage), + 'message' => \sprintf('There is a mismatch between the language included in the file name ("%s") and the "%s" value used in the "target-language" attribute of the file.', basename($file), $targetLanguage), ]; } } @@ -160,7 +160,7 @@ private function display(SymfonyStyle $io, array $files): int 'txt' => $this->displayTxt($io, $files), 'json' => $this->displayJson($io, $files), 'github' => $this->displayTxt($io, $files, true), - default => throw new InvalidArgumentException(sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))), + default => throw new InvalidArgumentException(\sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))), }; } @@ -172,25 +172,25 @@ private function displayTxt(SymfonyStyle $io, array $filesInfo, bool $errorAsGit foreach ($filesInfo as $info) { if ($info['valid'] && $this->displayCorrectFiles) { - $io->comment('OK'.($info['file'] ? sprintf(' in %s', $info['file']) : '')); + $io->comment('OK'.($info['file'] ? \sprintf(' in %s', $info['file']) : '')); } elseif (!$info['valid']) { ++$erroredFiles; - $io->text(' ERROR '.($info['file'] ? sprintf(' in %s', $info['file']) : '')); + $io->text(' ERROR '.($info['file'] ? \sprintf(' in %s', $info['file']) : '')); $io->listing(array_map(function ($error) use ($info, $githubReporter) { // general document errors have a '-1' line number $line = -1 === $error['line'] ? null : $error['line']; $githubReporter?->error($error['message'], $info['file'], $line, null !== $line ? $error['column'] : null); - return null === $line ? $error['message'] : sprintf('Line %d, Column %d: %s', $line, $error['column'], $error['message']); + return null === $line ? $error['message'] : \sprintf('Line %d, Column %d: %s', $line, $error['column'], $error['message']); }, $info['messages'])); } } if (0 === $erroredFiles) { - $io->success(sprintf('All %d XLIFF files contain valid syntax.', $countFiles)); + $io->success(\sprintf('All %d XLIFF files contain valid syntax.', $countFiles)); } else { - $io->warning(sprintf('%d XLIFF files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles)); + $io->warning(\sprintf('%d XLIFF files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles)); } return min($erroredFiles, 1); diff --git a/symfony/translation/DataCollectorTranslator.php b/symfony/translation/DataCollectorTranslator.php index a2832ee8e..7ab3b047b 100644 --- a/symfony/translation/DataCollectorTranslator.php +++ b/symfony/translation/DataCollectorTranslator.php @@ -34,7 +34,7 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter public function __construct(TranslatorInterface $translator) { if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) { - throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', get_debug_type($translator))); + throw new InvalidArgumentException(\sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', get_debug_type($translator))); } $this->translator = $translator; diff --git a/symfony/translation/DependencyInjection/LoggingTranslatorPass.php b/symfony/translation/DependencyInjection/LoggingTranslatorPass.php index c21552f97..fba86981c 100644 --- a/symfony/translation/DependencyInjection/LoggingTranslatorPass.php +++ b/symfony/translation/DependencyInjection/LoggingTranslatorPass.php @@ -37,7 +37,7 @@ public function process(ContainerBuilder $container): void $class = $container->getParameterBag()->resolveValue($definition->getClass()); if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $translatorAlias)); + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $translatorAlias)); } if (!$r->isSubclassOf(TranslatorInterface::class) || !$r->isSubclassOf(TranslatorBagInterface::class)) { diff --git a/symfony/translation/DependencyInjection/TranslationExtractorPass.php b/symfony/translation/DependencyInjection/TranslationExtractorPass.php index 1baf9341e..5e9b5af34 100644 --- a/symfony/translation/DependencyInjection/TranslationExtractorPass.php +++ b/symfony/translation/DependencyInjection/TranslationExtractorPass.php @@ -34,7 +34,7 @@ public function process(ContainerBuilder $container) foreach ($container->findTaggedServiceIds('translation.extractor', true) as $id => $attributes) { if (!isset($attributes[0]['alias'])) { - throw new RuntimeException(sprintf('The alias for the tag "translation.extractor" of service "%s" must be set.', $id)); + throw new RuntimeException(\sprintf('The alias for the tag "translation.extractor" of service "%s" must be set.', $id)); } $definition->addMethodCall('addExtractor', [$attributes[0]['alias'], new Reference($id)]); diff --git a/symfony/translation/DependencyInjection/TranslatorPathsPass.php b/symfony/translation/DependencyInjection/TranslatorPathsPass.php index 1756e3c8c..b6112e5b3 100644 --- a/symfony/translation/DependencyInjection/TranslatorPathsPass.php +++ b/symfony/translation/DependencyInjection/TranslatorPathsPass.php @@ -96,10 +96,10 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed $class = $this->definitions[$i]->getClass(); if (ServiceLocator::class === $class) { - if (!isset($this->controllers[$this->currentId])) { + if (!isset($this->controllers[$this->currentId ?? ''])) { continue; } - foreach ($this->controllers[$this->currentId] as $class => $_) { + foreach ($this->controllers[$this->currentId ?? ''] as $class => $_) { $this->paths[$class] = true; } } else { diff --git a/symfony/translation/Dumper/FileDumper.php b/symfony/translation/Dumper/FileDumper.php index e30d4770e..8f3a953e3 100644 --- a/symfony/translation/Dumper/FileDumper.php +++ b/symfony/translation/Dumper/FileDumper.php @@ -57,7 +57,7 @@ public function dump(MessageCatalogue $messages, array $options = []) if (!file_exists($fullpath)) { $directory = \dirname($fullpath); if (!file_exists($directory) && !@mkdir($directory, 0777, true)) { - throw new RuntimeException(sprintf('Unable to create directory "%s".', $directory)); + throw new RuntimeException(\sprintf('Unable to create directory "%s".', $directory)); } } diff --git a/symfony/translation/Dumper/PoFileDumper.php b/symfony/translation/Dumper/PoFileDumper.php index a2d0deb78..acf046c14 100644 --- a/symfony/translation/Dumper/PoFileDumper.php +++ b/symfony/translation/Dumper/PoFileDumper.php @@ -51,14 +51,14 @@ public function formatCatalogue(MessageCatalogue $messages, string $domain, arra $sourceRules = $this->getStandardRules($source); $targetRules = $this->getStandardRules($target); if (2 == \count($sourceRules) && [] !== $targetRules) { - $output .= sprintf('msgid "%s"'."\n", $this->escape($sourceRules[0])); - $output .= sprintf('msgid_plural "%s"'."\n", $this->escape($sourceRules[1])); + $output .= \sprintf('msgid "%s"'."\n", $this->escape($sourceRules[0])); + $output .= \sprintf('msgid_plural "%s"'."\n", $this->escape($sourceRules[1])); foreach ($targetRules as $i => $targetRule) { - $output .= sprintf('msgstr[%d] "%s"'."\n", $i, $this->escape($targetRule)); + $output .= \sprintf('msgstr[%d] "%s"'."\n", $i, $this->escape($targetRule)); } } else { - $output .= sprintf('msgid "%s"'."\n", $this->escape($source)); - $output .= sprintf('msgstr "%s"'."\n", $this->escape($target)); + $output .= \sprintf('msgid "%s"'."\n", $this->escape($source)); + $output .= \sprintf('msgstr "%s"'."\n", $this->escape($target)); } } @@ -123,7 +123,7 @@ private function formatComments(string|array $comments, string $prefix = ''): ?s $output = null; foreach ((array) $comments as $comment) { - $output .= sprintf('#%s %s'."\n", $prefix, $comment); + $output .= \sprintf('#%s %s'."\n", $prefix, $comment); } return $output; diff --git a/symfony/translation/Dumper/XliffFileDumper.php b/symfony/translation/Dumper/XliffFileDumper.php index d0f016b23..a2dfcd16d 100644 --- a/symfony/translation/Dumper/XliffFileDumper.php +++ b/symfony/translation/Dumper/XliffFileDumper.php @@ -46,7 +46,7 @@ public function formatCatalogue(MessageCatalogue $messages, string $domain, arra return $this->dumpXliff2($defaultLocale, $messages, $domain); } - throw new InvalidArgumentException(sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion)); + throw new InvalidArgumentException(\sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion)); } protected function getExtension(): string @@ -176,7 +176,7 @@ private function dumpXliff2(string $defaultLocale, MessageCatalogue $messages, ? $metadata = $messages->getMetadata($source, $domain); // Add notes section - if ($this->hasMetadataArrayInfo('notes', $metadata)) { + if ($this->hasMetadataArrayInfo('notes', $metadata) && $metadata['notes']) { $notesElement = $dom->createElement('notes'); foreach ($metadata['notes'] as $note) { $n = $dom->createElement('note'); diff --git a/symfony/translation/Exception/IncompleteDsnException.php b/symfony/translation/Exception/IncompleteDsnException.php index b304bde01..6c9247f89 100644 --- a/symfony/translation/Exception/IncompleteDsnException.php +++ b/symfony/translation/Exception/IncompleteDsnException.php @@ -16,7 +16,7 @@ class IncompleteDsnException extends InvalidArgumentException public function __construct(string $message, ?string $dsn = null, ?\Throwable $previous = null) { if ($dsn) { - $message = sprintf('Invalid "%s" provider DSN: ', $dsn).$message; + $message = \sprintf('Invalid "%s" provider DSN: ', $dsn).$message; } parent::__construct($message, 0, $previous); diff --git a/symfony/translation/Exception/MissingRequiredOptionException.php b/symfony/translation/Exception/MissingRequiredOptionException.php index 46152e254..8cef03a81 100644 --- a/symfony/translation/Exception/MissingRequiredOptionException.php +++ b/symfony/translation/Exception/MissingRequiredOptionException.php @@ -18,7 +18,7 @@ class MissingRequiredOptionException extends IncompleteDsnException { public function __construct(string $option, ?string $dsn = null, ?\Throwable $previous = null) { - $message = sprintf('The option "%s" is required but missing.', $option); + $message = \sprintf('The option "%s" is required but missing.', $option); parent::__construct($message, $dsn, $previous); } diff --git a/symfony/translation/Exception/UnsupportedSchemeException.php b/symfony/translation/Exception/UnsupportedSchemeException.php index 8d3295184..ca18444e4 100644 --- a/symfony/translation/Exception/UnsupportedSchemeException.php +++ b/symfony/translation/Exception/UnsupportedSchemeException.php @@ -43,14 +43,14 @@ public function __construct(Dsn $dsn, ?string $name = null, array $supported = [ } $package = self::SCHEME_TO_PACKAGE_MAP[$provider] ?? null; if ($package && !class_exists($package['class'])) { - parent::__construct(sprintf('Unable to synchronize translations via "%s" as the provider is not installed. Try running "composer require %s".', $provider, $package['package'])); + parent::__construct(\sprintf('Unable to synchronize translations via "%s" as the provider is not installed. Try running "composer require %s".', $provider, $package['package'])); return; } - $message = sprintf('The "%s" scheme is not supported', $dsn->getScheme()); + $message = \sprintf('The "%s" scheme is not supported', $dsn->getScheme()); if ($name && $supported) { - $message .= sprintf('; supported schemes for translation provider "%s" are: "%s"', $name, implode('", "', $supported)); + $message .= \sprintf('; supported schemes for translation provider "%s" are: "%s"', $name, implode('", "', $supported)); } parent::__construct($message.'.'); diff --git a/symfony/translation/Extractor/AbstractFileExtractor.php b/symfony/translation/Extractor/AbstractFileExtractor.php index 4c088b94f..8af022402 100644 --- a/symfony/translation/Extractor/AbstractFileExtractor.php +++ b/symfony/translation/Extractor/AbstractFileExtractor.php @@ -49,7 +49,7 @@ private function toSplFileInfo(string $file): \SplFileInfo protected function isFile(string $file): bool { if (!is_file($file)) { - throw new InvalidArgumentException(sprintf('The "%s" file does not exist.', $file)); + throw new InvalidArgumentException(\sprintf('The "%s" file does not exist.', $file)); } return true; diff --git a/symfony/translation/Extractor/PhpAstExtractor.php b/symfony/translation/Extractor/PhpAstExtractor.php index 06fc77de3..a5375f480 100644 --- a/symfony/translation/Extractor/PhpAstExtractor.php +++ b/symfony/translation/Extractor/PhpAstExtractor.php @@ -36,7 +36,7 @@ public function __construct( private string $prefix = '', ) { if (!class_exists(ParserFactory::class)) { - throw new \LogicException(sprintf('You cannot use "%s" as the "nikic/php-parser" package is not installed. Try running "composer require nikic/php-parser".', static::class)); + throw new \LogicException(\sprintf('You cannot use "%s" as the "nikic/php-parser" package is not installed. Try running "composer require nikic/php-parser".', static::class)); } $this->parser = (new ParserFactory())->createForHostVersion(); @@ -77,7 +77,7 @@ protected function canBeExtracted(string $file): bool protected function extractFromDirectory(array|string $resource): iterable|Finder { if (!class_exists(Finder::class)) { - throw new \LogicException(sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class)); + throw new \LogicException(\sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class)); } return (new Finder())->files()->name('*.php')->in($resource); diff --git a/symfony/translation/Extractor/PhpExtractor.php b/symfony/translation/Extractor/PhpExtractor.php index 7ff27f7c8..72afe4777 100644 --- a/symfony/translation/Extractor/PhpExtractor.php +++ b/symfony/translation/Extractor/PhpExtractor.php @@ -323,7 +323,7 @@ protected function canBeExtracted(string $file): bool protected function extractFromDirectory(string|array $directory): iterable { if (!class_exists(Finder::class)) { - throw new \LogicException(sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class)); + throw new \LogicException(\sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class)); } $finder = new Finder(); diff --git a/symfony/translation/Extractor/Visitor/ConstraintVisitor.php b/symfony/translation/Extractor/Visitor/ConstraintVisitor.php index 00fb9eedc..45cae3536 100644 --- a/symfony/translation/Extractor/Visitor/ConstraintVisitor.php +++ b/symfony/translation/Extractor/Visitor/ConstraintVisitor.php @@ -22,7 +22,7 @@ final class ConstraintVisitor extends AbstractVisitor implements NodeVisitor { public function __construct( - private readonly array $constraintClassNames = [] + private readonly array $constraintClassNames = [], ) { } diff --git a/symfony/translation/Formatter/IntlFormatter.php b/symfony/translation/Formatter/IntlFormatter.php index e62de253f..87cb00733 100644 --- a/symfony/translation/Formatter/IntlFormatter.php +++ b/symfony/translation/Formatter/IntlFormatter.php @@ -37,7 +37,7 @@ public function formatIntl(string $message, string $locale, array $parameters = try { $this->cache[$locale][$message] = $formatter = new \MessageFormatter($locale, $message); } catch (\IntlException $e) { - throw new InvalidArgumentException(sprintf('Invalid message format (error #%d): ', intl_get_error_code()).intl_get_error_message(), 0, $e); + throw new InvalidArgumentException(\sprintf('Invalid message format (error #%d): ', intl_get_error_code()).intl_get_error_message(), 0, $e); } } @@ -49,7 +49,7 @@ public function formatIntl(string $message, string $locale, array $parameters = } if (false === $message = $formatter->format($parameters)) { - throw new InvalidArgumentException(sprintf('Unable to format message (error #%s): ', $formatter->getErrorCode()).$formatter->getErrorMessage()); + throw new InvalidArgumentException(\sprintf('Unable to format message (error #%s): ', $formatter->getErrorCode()).$formatter->getErrorMessage()); } return $message; diff --git a/symfony/translation/Loader/CsvFileLoader.php b/symfony/translation/Loader/CsvFileLoader.php index 93bee730b..9d26611e5 100644 --- a/symfony/translation/Loader/CsvFileLoader.php +++ b/symfony/translation/Loader/CsvFileLoader.php @@ -31,7 +31,7 @@ protected function loadResource(string $resource): array try { $file = new \SplFileObject($resource, 'rb'); } catch (\RuntimeException $e) { - throw new NotFoundResourceException(sprintf('Error opening file "%s".', $resource), 0, $e); + throw new NotFoundResourceException(\sprintf('Error opening file "%s".', $resource), 0, $e); } $file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY); diff --git a/symfony/translation/Loader/FileLoader.php b/symfony/translation/Loader/FileLoader.php index 877c3bbc7..94f6e2022 100644 --- a/symfony/translation/Loader/FileLoader.php +++ b/symfony/translation/Loader/FileLoader.php @@ -24,11 +24,11 @@ abstract class FileLoader extends ArrayLoader public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { if (!stream_is_local($resource)) { - throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource)) { - throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); + throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource)); } $messages = $this->loadResource($resource); @@ -38,7 +38,7 @@ public function load(mixed $resource, string $locale, string $domain = 'messages // not an array if (!\is_array($messages)) { - throw new InvalidResourceException(sprintf('Unable to load file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('Unable to load file "%s".', $resource)); } $catalogue = parent::load($messages, $locale, $domain); diff --git a/symfony/translation/Loader/IcuDatFileLoader.php b/symfony/translation/Loader/IcuDatFileLoader.php index 76e4e7f02..1af864303 100644 --- a/symfony/translation/Loader/IcuDatFileLoader.php +++ b/symfony/translation/Loader/IcuDatFileLoader.php @@ -26,11 +26,11 @@ class IcuDatFileLoader extends IcuResFileLoader public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { if (!stream_is_local($resource.'.dat')) { - throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource.'.dat')) { - throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); + throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource)); } try { @@ -40,7 +40,7 @@ public function load(mixed $resource, string $locale, string $domain = 'messages } if (!$rb) { - throw new InvalidResourceException(sprintf('Cannot load resource "%s".', $resource)); + throw new InvalidResourceException(\sprintf('Cannot load resource "%s".', $resource)); } elseif (intl_is_failure($rb->getErrorCode())) { throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode()); } diff --git a/symfony/translation/Loader/IcuResFileLoader.php b/symfony/translation/Loader/IcuResFileLoader.php index 949dd9792..8ada43dca 100644 --- a/symfony/translation/Loader/IcuResFileLoader.php +++ b/symfony/translation/Loader/IcuResFileLoader.php @@ -26,11 +26,11 @@ class IcuResFileLoader implements LoaderInterface public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { if (!stream_is_local($resource)) { - throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource)); } if (!is_dir($resource)) { - throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); + throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource)); } try { @@ -40,7 +40,7 @@ public function load(mixed $resource, string $locale, string $domain = 'messages } if (!$rb) { - throw new InvalidResourceException(sprintf('Cannot load resource "%s".', $resource)); + throw new InvalidResourceException(\sprintf('Cannot load resource "%s".', $resource)); } elseif (intl_is_failure($rb->getErrorCode())) { throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode()); } diff --git a/symfony/translation/Loader/QtFileLoader.php b/symfony/translation/Loader/QtFileLoader.php index 235f85ee9..1b167bd6d 100644 --- a/symfony/translation/Loader/QtFileLoader.php +++ b/symfony/translation/Loader/QtFileLoader.php @@ -32,17 +32,17 @@ public function load(mixed $resource, string $locale, string $domain = 'messages } if (!stream_is_local($resource)) { - throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource)) { - throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); + throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource)); } try { $dom = XmlUtils::loadFile($resource); } catch (\InvalidArgumentException $e) { - throw new InvalidResourceException(sprintf('Unable to load "%s".', $resource), $e->getCode(), $e); + throw new InvalidResourceException(\sprintf('Unable to load "%s".', $resource), $e->getCode(), $e); } $internalErrors = libxml_use_internal_errors(true); diff --git a/symfony/translation/Loader/XliffFileLoader.php b/symfony/translation/Loader/XliffFileLoader.php index ffe4bbbd8..98c759fae 100644 --- a/symfony/translation/Loader/XliffFileLoader.php +++ b/symfony/translation/Loader/XliffFileLoader.php @@ -36,15 +36,15 @@ public function load(mixed $resource, string $locale, string $domain = 'messages if (!$this->isXmlString($resource)) { if (!stream_is_local($resource)) { - throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource)) { - throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); + throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource)); } if (!is_file($resource)) { - throw new InvalidResourceException(sprintf('This is neither a file nor an XLIFF string "%s".', $resource)); + throw new InvalidResourceException(\sprintf('This is neither a file nor an XLIFF string "%s".', $resource)); } } @@ -55,11 +55,11 @@ public function load(mixed $resource, string $locale, string $domain = 'messages $dom = XmlUtils::loadFile($resource); } } catch (\InvalidArgumentException|XmlParsingException|InvalidXmlException $e) { - throw new InvalidResourceException(sprintf('Unable to load "%s": ', $resource).$e->getMessage(), $e->getCode(), $e); + throw new InvalidResourceException(\sprintf('Unable to load "%s": ', $resource).$e->getMessage(), $e->getCode(), $e); } if ($errors = XliffUtils::validateSchema($dom)) { - throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: ', $resource).XliffUtils::getErrorsAsString($errors)); + throw new InvalidResourceException(\sprintf('Invalid resource provided: "%s"; Errors: ', $resource).XliffUtils::getErrorsAsString($errors)); } $catalogue = new MessageCatalogue($locale); diff --git a/symfony/translation/Loader/YamlFileLoader.php b/symfony/translation/Loader/YamlFileLoader.php index 48e735d16..39d5a0e99 100644 --- a/symfony/translation/Loader/YamlFileLoader.php +++ b/symfony/translation/Loader/YamlFileLoader.php @@ -29,7 +29,7 @@ class YamlFileLoader extends FileLoader protected function loadResource(string $resource): array { if (!isset($this->yamlParser)) { - if (!class_exists(\Symfony\Component\Yaml\Parser::class)) { + if (!class_exists(YamlParser::class)) { throw new LogicException('Loading translations from the YAML format requires the Symfony Yaml component.'); } @@ -39,11 +39,11 @@ protected function loadResource(string $resource): array try { $messages = $this->yamlParser->parseFile($resource, Yaml::PARSE_CONSTANT); } catch (ParseException $e) { - throw new InvalidResourceException(sprintf('The file "%s" does not contain valid YAML: ', $resource).$e->getMessage(), 0, $e); + throw new InvalidResourceException(\sprintf('The file "%s" does not contain valid YAML: ', $resource).$e->getMessage(), 0, $e); } if (null !== $messages && !\is_array($messages)) { - throw new InvalidResourceException(sprintf('Unable to load file "%s".', $resource)); + throw new InvalidResourceException(\sprintf('Unable to load file "%s".', $resource)); } return $messages ?: []; diff --git a/symfony/translation/LoggingTranslator.php b/symfony/translation/LoggingTranslator.php index 4a560bd6a..629f3f7ad 100644 --- a/symfony/translation/LoggingTranslator.php +++ b/symfony/translation/LoggingTranslator.php @@ -30,7 +30,7 @@ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface, public function __construct(TranslatorInterface $translator, LoggerInterface $logger) { if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) { - throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', get_debug_type($translator))); + throw new InvalidArgumentException(\sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', get_debug_type($translator))); } $this->translator = $translator; @@ -56,7 +56,7 @@ public function setLocale(string $locale) return; } - $this->logger->debug(sprintf('The locale of the translator has changed from "%s" to "%s".', $prev, $locale)); + $this->logger->debug(\sprintf('The locale of the translator has changed from "%s" to "%s".', $prev, $locale)); } public function getLocale(): string diff --git a/symfony/translation/MessageCatalogue.php b/symfony/translation/MessageCatalogue.php index d56f04393..9098619e8 100644 --- a/symfony/translation/MessageCatalogue.php +++ b/symfony/translation/MessageCatalogue.php @@ -155,7 +155,7 @@ public function add(array $messages, string $domain = 'messages') public function addCatalogue(MessageCatalogueInterface $catalogue) { if ($catalogue->getLocale() !== $this->locale) { - throw new LogicException(sprintf('Cannot add a catalogue for locale "%s" as the current locale for this catalogue is "%s".', $catalogue->getLocale(), $this->locale)); + throw new LogicException(\sprintf('Cannot add a catalogue for locale "%s" as the current locale for this catalogue is "%s".', $catalogue->getLocale(), $this->locale)); } foreach ($catalogue->all() as $domain => $messages) { @@ -190,14 +190,14 @@ public function addFallbackCatalogue(MessageCatalogueInterface $catalogue) $c = $catalogue; while ($c = $c->getFallbackCatalogue()) { if ($c->getLocale() === $this->getLocale()) { - throw new LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale())); + throw new LogicException(\sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale())); } } $c = $this; do { if ($c->getLocale() === $catalogue->getLocale()) { - throw new LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale())); + throw new LogicException(\sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale())); } foreach ($catalogue->getResources() as $resource) { @@ -237,6 +237,16 @@ public function getMetadata(string $key = '', string $domain = 'messages'): mixe return $this->metadata; } + if (isset($this->metadata[$domain.self::INTL_DOMAIN_SUFFIX])) { + if ('' === $key) { + return $this->metadata[$domain.self::INTL_DOMAIN_SUFFIX]; + } + + if (isset($this->metadata[$domain.self::INTL_DOMAIN_SUFFIX][$key])) { + return $this->metadata[$domain.self::INTL_DOMAIN_SUFFIX][$key]; + } + } + if (isset($this->metadata[$domain])) { if ('' == $key) { return $this->metadata[$domain]; diff --git a/symfony/translation/Provider/TranslationProviderCollection.php b/symfony/translation/Provider/TranslationProviderCollection.php index b917415ba..878998fec 100644 --- a/symfony/translation/Provider/TranslationProviderCollection.php +++ b/symfony/translation/Provider/TranslationProviderCollection.php @@ -44,7 +44,7 @@ public function has(string $name): bool public function get(string $name): ProviderInterface { if (!$this->has($name)) { - throw new InvalidArgumentException(sprintf('Provider "%s" not found. Available: "%s".', $name, (string) $this)); + throw new InvalidArgumentException(\sprintf('Provider "%s" not found. Available: "%s".', $name, (string) $this)); } return $this->providers[$name]; diff --git a/symfony/translation/PseudoLocalizationTranslator.php b/symfony/translation/PseudoLocalizationTranslator.php index f26909f5e..4bfbba901 100644 --- a/symfony/translation/PseudoLocalizationTranslator.php +++ b/symfony/translation/PseudoLocalizationTranslator.php @@ -55,7 +55,7 @@ final class PseudoLocalizationTranslator implements TranslatorInterface * * parse_html: * type: boolean * default: false - * description: parse the translated string as HTML - looking for HTML tags has a performance impact but allows to preserve them from alterations - it also allows to compute the visible translated string length which is useful to correctly expand ot when it contains HTML + * description: parse the translated string as HTML - looking for HTML tags has a performance impact but allows to preserve them from alterations - it also allows to compute the visible translated string length which is useful to correctly expand or when it contains HTML * warning: unclosed tags are unsupported, they will be fixed (closed) by the parser - eg, "foo
bar" => "foo
bar
" * * * localizable_html_attributes: diff --git a/symfony/translation/Resources/data/parents.json b/symfony/translation/Resources/data/parents.json index 24d4d119e..0197e451b 100644 --- a/symfony/translation/Resources/data/parents.json +++ b/symfony/translation/Resources/data/parents.json @@ -18,29 +18,37 @@ "en_CM": "en_001", "en_CX": "en_001", "en_CY": "en_001", + "en_CZ": "en_150", "en_DE": "en_150", "en_DG": "en_001", "en_DK": "en_150", "en_DM": "en_001", + "en_EE": "en_150", "en_ER": "en_001", + "en_ES": "en_150", "en_FI": "en_150", "en_FJ": "en_001", "en_FK": "en_001", "en_FM": "en_001", + "en_FR": "en_150", "en_GB": "en_001", "en_GD": "en_001", + "en_GE": "en_150", "en_GG": "en_001", "en_GH": "en_001", "en_GI": "en_001", "en_GM": "en_001", + "en_GS": "en_001", "en_GY": "en_001", "en_HK": "en_001", + "en_HU": "en_150", "en_ID": "en_001", "en_IE": "en_001", "en_IL": "en_001", "en_IM": "en_001", "en_IN": "en_001", "en_IO": "en_001", + "en_IT": "en_150", "en_JE": "en_001", "en_JM": "en_001", "en_KE": "en_001", @@ -50,6 +58,8 @@ "en_LC": "en_001", "en_LR": "en_001", "en_LS": "en_001", + "en_LT": "en_150", + "en_LV": "en_150", "en_MG": "en_001", "en_MO": "en_001", "en_MS": "en_001", @@ -62,13 +72,17 @@ "en_NF": "en_001", "en_NG": "en_001", "en_NL": "en_150", + "en_NO": "en_150", "en_NR": "en_001", "en_NU": "en_001", "en_NZ": "en_001", "en_PG": "en_001", "en_PK": "en_001", + "en_PL": "en_150", "en_PN": "en_001", + "en_PT": "en_150", "en_PW": "en_001", + "en_RO": "en_150", "en_RW": "en_001", "en_SB": "en_001", "en_SC": "en_001", @@ -77,6 +91,7 @@ "en_SG": "en_001", "en_SH": "en_001", "en_SI": "en_150", + "en_SK": "en_150", "en_SL": "en_001", "en_SS": "en_001", "en_SX": "en_001", @@ -87,6 +102,7 @@ "en_TT": "en_001", "en_TV": "en_001", "en_TZ": "en_001", + "en_UA": "en_150", "en_UG": "en_001", "en_VC": "en_001", "en_VG": "en_001", @@ -119,6 +135,7 @@ "es_VE": "es_419", "ff_Adlm": "root", "hi_Latn": "en_IN", + "kk_Arab": "root", "ks_Deva": "root", "nb": "no", "nn": "no", diff --git a/symfony/translation/TranslatableMessage.php b/symfony/translation/TranslatableMessage.php index c591e68c2..8f6063c50 100644 --- a/symfony/translation/TranslatableMessage.php +++ b/symfony/translation/TranslatableMessage.php @@ -52,9 +52,13 @@ public function getDomain(): ?string public function trans(TranslatorInterface $translator, ?string $locale = null): string { - return $translator->trans($this->getMessage(), array_map( - static fn ($parameter) => $parameter instanceof TranslatableInterface ? $parameter->trans($translator, $locale) : $parameter, - $this->getParameters() - ), $this->getDomain(), $locale); + $parameters = $this->getParameters(); + foreach ($parameters as $k => $v) { + if ($v instanceof TranslatableInterface) { + $parameters[$k] = $v->trans($translator, $locale); + } + } + + return $translator->trans($this->getMessage(), $parameters, $this->getDomain(), $locale); } } diff --git a/symfony/translation/Translator.php b/symfony/translation/Translator.php index 1973d079f..d3396c515 100644 --- a/symfony/translation/Translator.php +++ b/symfony/translation/Translator.php @@ -290,7 +290,7 @@ private function dumpCatalogue(string $locale, ConfigCacheInterface $cache): voi $this->initializeCatalogue($locale); $fallbackContent = $this->getFallbackContent($this->catalogues[$locale]); - $content = sprintf(<<addFallbackCatalogue($catalogue%s); @@ -356,10 +356,10 @@ protected function doLoadCatalogue(string $locale): void foreach ($this->resources[$locale] as $resource) { if (!isset($this->loaders[$resource[0]])) { if (\is_string($resource[1])) { - throw new RuntimeException(sprintf('No loader is registered for the "%s" format when loading the "%s" resource.', $resource[0], $resource[1])); + throw new RuntimeException(\sprintf('No loader is registered for the "%s" format when loading the "%s" resource.', $resource[0], $resource[1])); } - throw new RuntimeException(sprintf('No loader is registered for the "%s" format.', $resource[0])); + throw new RuntimeException(\sprintf('No loader is registered for the "%s" format.', $resource[0])); } $this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2])); } @@ -438,7 +438,7 @@ protected function computeFallbackLocales(string $locale) protected function assertValidLocale(string $locale) { if (!preg_match('/^[a-z0-9@_\\.\\-]*$/i', $locale)) { - throw new InvalidArgumentException(sprintf('Invalid "%s" locale.', $locale)); + throw new InvalidArgumentException(\sprintf('Invalid "%s" locale.', $locale)); } } diff --git a/symfony/translation/Util/XliffUtils.php b/symfony/translation/Util/XliffUtils.php index 335c34beb..e76e12284 100644 --- a/symfony/translation/Util/XliffUtils.php +++ b/symfony/translation/Util/XliffUtils.php @@ -41,7 +41,7 @@ public static function getVersionNumber(\DOMDocument $dom): string $namespace = $xliff->attributes->getNamedItem('xmlns'); if ($namespace) { if (0 !== substr_compare('urn:oasis:names:tc:xliff:document:', $namespace->nodeValue, 0, 34)) { - throw new InvalidArgumentException(sprintf('Not a valid XLIFF namespace "%s".', $namespace)); + throw new InvalidArgumentException(\sprintf('Not a valid XLIFF namespace "%s".', $namespace)); } return substr($namespace, 34); @@ -113,7 +113,7 @@ public static function getErrorsAsString(array $xmlErrors): string $errorsAsString = ''; foreach ($xmlErrors as $error) { - $errorsAsString .= sprintf("[%s %s] %s (in %s - line %d, column %d)\n", + $errorsAsString .= \sprintf("[%s %s] %s (in %s - line %d, column %d)\n", \LIBXML_ERR_WARNING === $error['level'] ? 'WARNING' : 'ERROR', $error['code'], $error['message'], @@ -135,7 +135,7 @@ private static function getSchema(string $xliffVersion): string $schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/xliff-core-2.0.xsd'); $xmlUri = 'informativeCopiesOf3rdPartySchemas/w3c/xml.xsd'; } else { - throw new InvalidArgumentException(sprintf('No support implemented for loading XLIFF version "%s".', $xliffVersion)); + throw new InvalidArgumentException(\sprintf('No support implemented for loading XLIFF version "%s".', $xliffVersion)); } return self::fixXmlLocation($schemaSource, $xmlUri); diff --git a/symfony/translation/Writer/TranslationWriter.php b/symfony/translation/Writer/TranslationWriter.php index 61e03cb0e..464a83c5b 100644 --- a/symfony/translation/Writer/TranslationWriter.php +++ b/symfony/translation/Writer/TranslationWriter.php @@ -59,14 +59,14 @@ public function getFormats(): array public function write(MessageCatalogue $catalogue, string $format, array $options = []) { if (!isset($this->dumpers[$format])) { - throw new InvalidArgumentException(sprintf('There is no dumper associated with format "%s".', $format)); + throw new InvalidArgumentException(\sprintf('There is no dumper associated with format "%s".', $format)); } // get the right dumper $dumper = $this->dumpers[$format]; if (isset($options['path']) && !is_dir($options['path']) && !@mkdir($options['path'], 0777, true) && !is_dir($options['path'])) { - throw new RuntimeException(sprintf('Translation Writer was not able to create directory "%s".', $options['path'])); + throw new RuntimeException(\sprintf('Translation Writer was not able to create directory "%s".', $options['path'])); } // save