diff --git a/composer.lock b/composer.lock index 5a6f85f400..be99d6b178 100644 --- a/composer.lock +++ b/composer.lock @@ -1721,16 +1721,16 @@ }, { "name": "symfony/cache", - "version": "v6.4.12", + "version": "v6.4.33", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "a463451b7f6ac4a47b98dbfc78ec2d3560c759d8" + "reference": "5b088fa41eb9568748dc255c45e4054c387ba73b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/a463451b7f6ac4a47b98dbfc78ec2d3560c759d8", - "reference": "a463451b7f6ac4a47b98dbfc78ec2d3560c759d8", + "url": "https://api.github.com/repos/symfony/cache/zipball/5b088fa41eb9568748dc255c45e4054c387ba73b", + "reference": "5b088fa41eb9568748dc255c45e4054c387ba73b", "shasum": "" }, "require": { @@ -1797,7 +1797,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.12" + "source": "https://github.com/symfony/cache/tree/v6.4.33" }, "funding": [ { @@ -1808,12 +1808,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-16T16:01:33+00:00" + "time": "2026-01-27T15:05:20+00:00" }, { "name": "symfony/cache-contracts", @@ -1893,16 +1897,16 @@ }, { "name": "symfony/config", - "version": "v6.4.24", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "80e2cf005cf17138c97193be0434cdcfd1b2212e" + "reference": "d445badf0ad2c2a492e38c0378c39997a56ef97b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/80e2cf005cf17138c97193be0434cdcfd1b2212e", - "reference": "80e2cf005cf17138c97193be0434cdcfd1b2212e", + "url": "https://api.github.com/repos/symfony/config/zipball/d445badf0ad2c2a492e38c0378c39997a56ef97b", + "reference": "d445badf0ad2c2a492e38c0378c39997a56ef97b", "shasum": "" }, "require": { @@ -1948,7 +1952,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.4.24" + "source": "https://github.com/symfony/config/tree/v6.4.32" }, "funding": [ { @@ -1968,20 +1972,20 @@ "type": "tidelift" } ], - "time": "2025-07-26T13:50:30+00:00" + "time": "2026-01-13T08:40:30+00:00" }, { "name": "symfony/console", - "version": "v6.4.25", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae" + "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", - "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", + "url": "https://api.github.com/repos/symfony/console/zipball/0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", + "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", "shasum": "" }, "require": { @@ -2046,7 +2050,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.25" + "source": "https://github.com/symfony/console/tree/v6.4.32" }, "funding": [ { @@ -2066,7 +2070,7 @@ "type": "tidelift" } ], - "time": "2025-08-22T10:21:53+00:00" + "time": "2026-01-13T08:45:59+00:00" }, { "name": "symfony/css-selector", @@ -2139,16 +2143,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v6.4.25", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "900da8a42eceeb4a13a0ec34caa7db49328daff3" + "reference": "b17882e933c4c606620247b6708ab53aa3b88753" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/900da8a42eceeb4a13a0ec34caa7db49328daff3", - "reference": "900da8a42eceeb4a13a0ec34caa7db49328daff3", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/b17882e933c4c606620247b6708ab53aa3b88753", + "reference": "b17882e933c4c606620247b6708ab53aa3b88753", "shasum": "" }, "require": { @@ -2200,7 +2204,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.4.25" + "source": "https://github.com/symfony/dependency-injection/tree/v6.4.32" }, "funding": [ { @@ -2220,7 +2224,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2026-01-23T10:54:33+00:00" }, { "name": "symfony/deprecation-contracts", @@ -2291,16 +2295,16 @@ }, { "name": "symfony/dotenv", - "version": "v6.4.24", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "234b6c602f12b00693f4b0d1054386fb30dfc8ff" + "reference": "924edbc9631b75302def0258ed1697948b17baf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/234b6c602f12b00693f4b0d1054386fb30dfc8ff", - "reference": "234b6c602f12b00693f4b0d1054386fb30dfc8ff", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/924edbc9631b75302def0258ed1697948b17baf6", + "reference": "924edbc9631b75302def0258ed1697948b17baf6", "shasum": "" }, "require": { @@ -2345,7 +2349,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.4.24" + "source": "https://github.com/symfony/dotenv/tree/v6.4.30" }, "funding": [ { @@ -2365,20 +2369,20 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-11-14T17:33:48+00:00" }, { "name": "symfony/error-handler", - "version": "v6.4.24", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "30fd0b3cf0e972e82636038ce4db0e4fe777112c" + "reference": "8c18400784fcb014dc73c8d5601a9576af7f8ad4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/30fd0b3cf0e972e82636038ce4db0e4fe777112c", - "reference": "30fd0b3cf0e972e82636038ce4db0e4fe777112c", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/8c18400784fcb014dc73c8d5601a9576af7f8ad4", + "reference": "8c18400784fcb014dc73c8d5601a9576af7f8ad4", "shasum": "" }, "require": { @@ -2424,7 +2428,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.4.24" + "source": "https://github.com/symfony/error-handler/tree/v6.4.32" }, "funding": [ { @@ -2444,20 +2448,20 @@ "type": "tidelift" } ], - "time": "2025-07-24T08:25:04+00:00" + "time": "2026-01-19T19:28:19+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.4.25", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b0cf3162020603587363f0551cd3be43958611ff" + "reference": "99d7e101826e6610606b9433248f80c1997cd20b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff", - "reference": "b0cf3162020603587363f0551cd3be43958611ff", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99d7e101826e6610606b9433248f80c1997cd20b", + "reference": "99d7e101826e6610606b9433248f80c1997cd20b", "shasum": "" }, "require": { @@ -2508,7 +2512,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.25" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.32" }, "funding": [ { @@ -2528,7 +2532,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2026-01-05T11:13:48+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -2608,16 +2612,16 @@ }, { "name": "symfony/filesystem", - "version": "v6.4.24", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8" + "reference": "441c6b69f7222aadae7cbf5df588496d5ee37789" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", - "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/441c6b69f7222aadae7cbf5df588496d5ee37789", + "reference": "441c6b69f7222aadae7cbf5df588496d5ee37789", "shasum": "" }, "require": { @@ -2654,7 +2658,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.24" + "source": "https://github.com/symfony/filesystem/tree/v6.4.30" }, "funding": [ { @@ -2674,20 +2678,20 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-11-26T14:43:45+00:00" }, { "name": "symfony/finder", - "version": "v6.4.24", + "version": "v6.4.33", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "73089124388c8510efb8d2d1689285d285937b08" + "reference": "24965ca011dac87431729640feef8bcf7b5523e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/73089124388c8510efb8d2d1689285d285937b08", - "reference": "73089124388c8510efb8d2d1689285d285937b08", + "url": "https://api.github.com/repos/symfony/finder/zipball/24965ca011dac87431729640feef8bcf7b5523e0", + "reference": "24965ca011dac87431729640feef8bcf7b5523e0", "shasum": "" }, "require": { @@ -2722,7 +2726,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.24" + "source": "https://github.com/symfony/finder/tree/v6.4.33" }, "funding": [ { @@ -2742,20 +2746,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T12:02:45+00:00" + "time": "2026-01-26T13:03:48+00:00" }, { "name": "symfony/form", - "version": "v6.4.26", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "b40cdbe70be9274ea807ef61da7d0f8d1c70dc51" + "reference": "b758162fb45024f898640ec27f4ac90be0dbfb8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/b40cdbe70be9274ea807ef61da7d0f8d1c70dc51", - "reference": "b40cdbe70be9274ea807ef61da7d0f8d1c70dc51", + "url": "https://api.github.com/repos/symfony/form/zipball/b758162fb45024f898640ec27f4ac90be0dbfb8f", + "reference": "b758162fb45024f898640ec27f4ac90be0dbfb8f", "shasum": "" }, "require": { @@ -2823,7 +2827,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v6.4.26" + "source": "https://github.com/symfony/form/tree/v6.4.32" }, "funding": [ { @@ -2843,20 +2847,20 @@ "type": "tidelift" } ], - "time": "2025-09-20T07:40:41+00:00" + "time": "2026-01-22T20:17:27+00:00" }, { "name": "symfony/framework-bundle", - "version": "v6.4.25", + "version": "v6.4.33", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "1d6a764b58e4f780df00f71c20ba3a61095ea447" + "reference": "9ef2d0b63b9e855ba351e770a603d89699115801" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/1d6a764b58e4f780df00f71c20ba3a61095ea447", - "reference": "1d6a764b58e4f780df00f71c20ba3a61095ea447", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/9ef2d0b63b9e855ba351e770a603d89699115801", + "reference": "9ef2d0b63b9e855ba351e770a603d89699115801", "shasum": "" }, "require": { @@ -2976,7 +2980,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.4.25" + "source": "https://github.com/symfony/framework-bundle/tree/v6.4.33" }, "funding": [ { @@ -2996,20 +3000,20 @@ "type": "tidelift" } ], - "time": "2025-08-26T10:44:20+00:00" + "time": "2026-01-26T14:46:41+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.4.29", + "version": "v6.4.33", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "b03d11e015552a315714c127d8d1e0f9e970ec88" + "reference": "f1a490cc9d595ba7ebe684220e625d1e472ad278" }, "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/f1a490cc9d595ba7ebe684220e625d1e472ad278", + "reference": "f1a490cc9d595ba7ebe684220e625d1e472ad278", "shasum": "" }, "require": { @@ -3057,7 +3061,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.33" }, "funding": [ { @@ -3077,20 +3081,20 @@ "type": "tidelift" } ], - "time": "2025-11-08T16:40:12+00:00" + "time": "2026-01-27T15:04:55+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.25", + "version": "v6.4.33", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "a0ee3cea5cabf4ed960fd2ef57668ceeacdb6e15" + "reference": "73fa5c999d7f741ca544a97d3c791cc97890ae4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a0ee3cea5cabf4ed960fd2ef57668ceeacdb6e15", - "reference": "a0ee3cea5cabf4ed960fd2ef57668ceeacdb6e15", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/73fa5c999d7f741ca544a97d3c791cc97890ae4d", + "reference": "73fa5c999d7f741ca544a97d3c791cc97890ae4d", "shasum": "" }, "require": { @@ -3175,7 +3179,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.25" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.33" }, "funding": [ { @@ -3195,20 +3199,20 @@ "type": "tidelift" } ], - "time": "2025-08-29T07:55:45+00:00" + "time": "2026-01-28T10:02:13+00:00" }, { "name": "symfony/mailer", - "version": "v6.4.25", + "version": "v6.4.31", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "628b43b45a3e6b15c8a633fb22df547ed9b492a2" + "reference": "8835f93333474780fda1b987cae37e33c3e026ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/628b43b45a3e6b15c8a633fb22df547ed9b492a2", - "reference": "628b43b45a3e6b15c8a633fb22df547ed9b492a2", + "url": "https://api.github.com/repos/symfony/mailer/zipball/8835f93333474780fda1b987cae37e33c3e026ca", + "reference": "8835f93333474780fda1b987cae37e33c3e026ca", "shasum": "" }, "require": { @@ -3259,7 +3263,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.4.25" + "source": "https://github.com/symfony/mailer/tree/v6.4.31" }, "funding": [ { @@ -3279,20 +3283,20 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2025-12-12T07:33:25+00:00" }, { "name": "symfony/mime", - "version": "v6.4.24", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "664d5e844a2de5e11c8255d0aef6bc15a9660ac7" + "reference": "7409686879ca36c09fc970a5fa8ff6e93504dba4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/664d5e844a2de5e11c8255d0aef6bc15a9660ac7", - "reference": "664d5e844a2de5e11c8255d0aef6bc15a9660ac7", + "url": "https://api.github.com/repos/symfony/mime/zipball/7409686879ca36c09fc970a5fa8ff6e93504dba4", + "reference": "7409686879ca36c09fc970a5fa8ff6e93504dba4", "shasum": "" }, "require": { @@ -3348,7 +3352,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.24" + "source": "https://github.com/symfony/mime/tree/v6.4.32" }, "funding": [ { @@ -3368,20 +3372,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T12:02:45+00:00" + "time": "2026-01-04T11:53:14+00:00" }, { "name": "symfony/options-resolver", - "version": "v6.4.25", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe" + "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d28e7e2db8a73e9511df892d36445f61314bbebe", - "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", + "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", "shasum": "" }, "require": { @@ -3419,7 +3423,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.4.25" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.30" }, "funding": [ { @@ -3439,20 +3443,20 @@ "type": "tidelift" } ], - "time": "2025-08-04T17:06:28+00:00" + "time": "2025-11-12T13:06:53+00:00" }, { "name": "symfony/password-hasher", - "version": "v6.4.24", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "dcab5ac87450aaed26483ba49c2ce86808da7557" + "reference": "fbdfa5a2ca218ec8bb9029517426df2d780bdba9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/dcab5ac87450aaed26483ba49c2ce86808da7557", - "reference": "dcab5ac87450aaed26483ba49c2ce86808da7557", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/fbdfa5a2ca218ec8bb9029517426df2d780bdba9", + "reference": "fbdfa5a2ca218ec8bb9029517426df2d780bdba9", "shasum": "" }, "require": { @@ -3495,7 +3499,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v6.4.24" + "source": "https://github.com/symfony/password-hasher/tree/v6.4.32" }, "funding": [ { @@ -3515,7 +3519,7 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2026-01-01T21:24:53+00:00" }, { "name": "symfony/polyfill-ctype", @@ -4109,22 +4113,22 @@ }, { "name": "symfony/property-access", - "version": "v6.4.25", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "fedc771326d4978a7d3167fa009a509b06a2e168" + "reference": "6dfa655ac9e9860c05cabb287f34da86b18c237e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/fedc771326d4978a7d3167fa009a509b06a2e168", - "reference": "fedc771326d4978a7d3167fa009a509b06a2e168", + "url": "https://api.github.com/repos/symfony/property-access/zipball/6dfa655ac9e9860c05cabb287f34da86b18c237e", + "reference": "6dfa655ac9e9860c05cabb287f34da86b18c237e", "shasum": "" }, "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/property-info": "^5.4|^6.0|^7.0" + "symfony/property-info": "^6.4.32|~7.3.10|^7.4.4" }, "require-dev": { "symfony/cache": "^5.4|^6.0|^7.0" @@ -4166,7 +4170,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v6.4.25" + "source": "https://github.com/symfony/property-access/tree/v6.4.32" }, "funding": [ { @@ -4186,20 +4190,20 @@ "type": "tidelift" } ], - "time": "2025-08-12T15:42:57+00:00" + "time": "2026-01-05T08:25:17+00:00" }, { "name": "symfony/property-info", - "version": "v6.4.24", + "version": "v6.4.33", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "1056ae3621eeddd78d7c5ec074f1c1784324eec6" + "reference": "7d961dbb543fcfaa57fa55e555edd466e90160be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/1056ae3621eeddd78d7c5ec074f1c1784324eec6", - "reference": "1056ae3621eeddd78d7c5ec074f1c1784324eec6", + "url": "https://api.github.com/repos/symfony/property-info/zipball/7d961dbb543fcfaa57fa55e555edd466e90160be", + "reference": "7d961dbb543fcfaa57fa55e555edd466e90160be", "shasum": "" }, "require": { @@ -4208,7 +4212,7 @@ }, "conflict": { "doctrine/annotations": "<1.12", - "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/reflection-docblock": "<5.2|>=6", "phpdocumentor/type-resolver": "<1.5.1", "symfony/cache": "<5.4", "symfony/dependency-injection": "<5.4|>=6.0,<6.4", @@ -4256,7 +4260,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v6.4.24" + "source": "https://github.com/symfony/property-info/tree/v6.4.33" }, "funding": [ { @@ -4276,20 +4280,20 @@ "type": "tidelift" } ], - "time": "2025-07-14T16:38:25+00:00" + "time": "2026-01-27T15:12:57+00:00" }, { "name": "symfony/routing", - "version": "v6.4.24", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "e4f94e625c8e6f910aa004a0042f7b2d398278f5" + "reference": "0dc6253e864e71b486e8ba4970a56ab849106ebe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/e4f94e625c8e6f910aa004a0042f7b2d398278f5", - "reference": "e4f94e625c8e6f910aa004a0042f7b2d398278f5", + "url": "https://api.github.com/repos/symfony/routing/zipball/0dc6253e864e71b486e8ba4970a56ab849106ebe", + "reference": "0dc6253e864e71b486e8ba4970a56ab849106ebe", "shasum": "" }, "require": { @@ -4343,7 +4347,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.24" + "source": "https://github.com/symfony/routing/tree/v6.4.32" }, "funding": [ { @@ -4363,20 +4367,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T08:46:37+00:00" + "time": "2026-01-12T08:31:19+00:00" }, { "name": "symfony/security-core", - "version": "v6.4.26", + "version": "v6.4.31", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "8b7c95bf04d82fcd0c06a918b2d849bfb2ab9cc0" + "reference": "fa269ad61a021cc54329dc96e57bed78ba720bfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/8b7c95bf04d82fcd0c06a918b2d849bfb2ab9cc0", - "reference": "8b7c95bf04d82fcd0c06a918b2d849bfb2ab9cc0", + "url": "https://api.github.com/repos/symfony/security-core/zipball/fa269ad61a021cc54329dc96e57bed78ba720bfe", + "reference": "fa269ad61a021cc54329dc96e57bed78ba720bfe", "shasum": "" }, "require": { @@ -4433,7 +4437,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.4.26" + "source": "https://github.com/symfony/security-core/tree/v6.4.31" }, "funding": [ { @@ -4453,20 +4457,20 @@ "type": "tidelift" } ], - "time": "2025-09-02T19:15:26+00:00" + "time": "2025-12-17T22:32:13+00:00" }, { "name": "symfony/security-csrf", - "version": "v6.4.24", + "version": "v6.4.31", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "9a1efc8c10b86bcedc9233affd10c716b54ca1b7" + "reference": "52f62836fcb19cd351ef3a2aa9cf61a489e8990f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/9a1efc8c10b86bcedc9233affd10c716b54ca1b7", - "reference": "9a1efc8c10b86bcedc9233affd10c716b54ca1b7", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/52f62836fcb19cd351ef3a2aa9cf61a489e8990f", + "reference": "52f62836fcb19cd351ef3a2aa9cf61a489e8990f", "shasum": "" }, "require": { @@ -4505,7 +4509,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v6.4.24" + "source": "https://github.com/symfony/security-csrf/tree/v6.4.31" }, "funding": [ { @@ -4525,7 +4529,7 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-12-17T22:32:13+00:00" }, { "name": "symfony/service-contracts", @@ -4616,16 +4620,16 @@ }, { "name": "symfony/string", - "version": "v6.4.25", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1" + "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", - "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", + "url": "https://api.github.com/repos/symfony/string/zipball/50590a057841fa6bf69d12eceffce3465b9e32cb", + "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb", "shasum": "" }, "require": { @@ -4639,7 +4643,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", @@ -4682,7 +4685,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.25" + "source": "https://github.com/symfony/string/tree/v6.4.30" }, "funding": [ { @@ -4702,20 +4705,20 @@ "type": "tidelift" } ], - "time": "2025-08-22T12:33:20+00:00" + "time": "2025-11-21T18:03:05+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" + "reference": "65a8bc82080447fae78373aa10f8d13b38338977" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", + "reference": "65a8bc82080447fae78373aa10f8d13b38338977", "shasum": "" }, "require": { @@ -4764,7 +4767,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1" }, "funding": [ { @@ -4775,25 +4778,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-27T08:32:26+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/twig-bridge", - "version": "v6.4.25", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "9d13e87591c9de3221c8d6f23cd9a2b5958607bf" + "reference": "1dcf980dd4f79885b986befdeb1c1bc0d6aedfc8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/9d13e87591c9de3221c8d6f23cd9a2b5958607bf", - "reference": "9d13e87591c9de3221c8d6f23cd9a2b5958607bf", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/1dcf980dd4f79885b986befdeb1c1bc0d6aedfc8", + "reference": "1dcf980dd4f79885b986befdeb1c1bc0d6aedfc8", "shasum": "" }, "require": { @@ -4806,7 +4813,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/console": "<5.4", - "symfony/form": "<6.3", + "symfony/form": "<6.4.32|>7,<7.3.10|>7.4,<7.4.4", "symfony/http-foundation": "<5.4", "symfony/http-kernel": "<6.4", "symfony/mime": "<6.2", @@ -4824,7 +4831,7 @@ "symfony/dependency-injection": "^5.4|^6.0|^7.0", "symfony/expression-language": "^5.4|^6.0|^7.0", "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/form": "^6.4.20|^7.2.5", + "symfony/form": "^6.4.32|~7.3.10|^7.4.4", "symfony/html-sanitizer": "^6.1|^7.0", "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/http-kernel": "^6.4|^7.0", @@ -4873,7 +4880,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.4.25" + "source": "https://github.com/symfony/twig-bridge/tree/v6.4.32" }, "funding": [ { @@ -4893,20 +4900,20 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2026-01-03T23:03:08+00:00" }, { "name": "symfony/twig-bundle", - "version": "v6.4.24", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "3b48b6e8225495c6d2438828982b4d219ca565ba" + "reference": "a5c8dcc11a5bf9c96320da20070d2e158a4e0b30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/3b48b6e8225495c6d2438828982b4d219ca565ba", - "reference": "3b48b6e8225495c6d2438828982b4d219ca565ba", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/a5c8dcc11a5bf9c96320da20070d2e158a4e0b30", + "reference": "a5c8dcc11a5bf9c96320da20070d2e158a4e0b30", "shasum": "" }, "require": { @@ -4961,7 +4968,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v6.4.24" + "source": "https://github.com/symfony/twig-bundle/tree/v6.4.32" }, "funding": [ { @@ -4981,20 +4988,20 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2026-01-05T12:44:39+00:00" }, { "name": "symfony/validator", - "version": "v6.4.29", + "version": "v6.4.33", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "99df8a769e64e399f510166141ea74f450e8dd1d" + "reference": "da1a40418439c0483ca7e0d4ae4c4f744f6b8536" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/99df8a769e64e399f510166141ea74f450e8dd1d", - "reference": "99df8a769e64e399f510166141ea74f450e8dd1d", + "url": "https://api.github.com/repos/symfony/validator/zipball/da1a40418439c0483ca7e0d4ae4c4f744f6b8536", + "reference": "da1a40418439c0483ca7e0d4ae4c4f744f6b8536", "shasum": "" }, "require": { @@ -5062,7 +5069,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v6.4.29" + "source": "https://github.com/symfony/validator/tree/v6.4.33" }, "funding": [ { @@ -5082,20 +5089,20 @@ "type": "tidelift" } ], - "time": "2025-11-06T20:26:06+00:00" + "time": "2026-01-26T16:20:53+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.26", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a" + "reference": "131fc9915e0343052af5ed5040401b481ca192aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/cfae1497a2f1eaad78dbc0590311c599c7178d4a", - "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/131fc9915e0343052af5ed5040401b481ca192aa", + "reference": "131fc9915e0343052af5ed5040401b481ca192aa", "shasum": "" }, "require": { @@ -5150,7 +5157,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.26" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.32" }, "funding": [ { @@ -5170,7 +5177,7 @@ "type": "tidelift" } ], - "time": "2025-09-25T15:37:27+00:00" + "time": "2026-01-01T13:34:06+00:00" }, { "name": "symfony/var-exporter", @@ -5255,16 +5262,16 @@ }, { "name": "symfony/yaml", - "version": "v6.4.25", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e54b060bc9c3dc3d4258bf0d165d0064e755f565" + "reference": "8207ae83da19ee3748d6d4f567b4d9a7c656e331" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e54b060bc9c3dc3d4258bf0d165d0064e755f565", - "reference": "e54b060bc9c3dc3d4258bf0d165d0064e755f565", + "url": "https://api.github.com/repos/symfony/yaml/zipball/8207ae83da19ee3748d6d4f567b4d9a7c656e331", + "reference": "8207ae83da19ee3748d6d4f567b4d9a7c656e331", "shasum": "" }, "require": { @@ -5307,7 +5314,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.25" + "source": "https://github.com/symfony/yaml/tree/v6.4.30" }, "funding": [ { @@ -5327,7 +5334,7 @@ "type": "tidelift" } ], - "time": "2025-08-26T16:59:00+00:00" + "time": "2025-12-02T11:50:18+00:00" }, { "name": "tecnickcom/tcpdf", @@ -5462,16 +5469,16 @@ }, { "name": "twig/twig", - "version": "v3.21.1", + "version": "v3.23.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d" + "reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d", - "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", + "reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", "shasum": "" }, "require": { @@ -5525,7 +5532,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.21.1" + "source": "https://github.com/twigphp/Twig/tree/v3.23.0" }, "funding": [ { @@ -5537,7 +5544,7 @@ "type": "tidelift" } ], - "time": "2025-05-03T07:21:55+00:00" + "time": "2026-01-23T21:00:41+00:00" } ], "packages-dev": [ @@ -5609,16 +5616,16 @@ }, { "name": "symfony/web-profiler-bundle", - "version": "v6.4.25", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "4c1754d6b3ffe52e9eaed0d9a392eb43a60fc910" + "reference": "011f59e3f3d20f60d11b4e78b8dc63504f56e145" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/4c1754d6b3ffe52e9eaed0d9a392eb43a60fc910", - "reference": "4c1754d6b3ffe52e9eaed0d9a392eb43a60fc910", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/011f59e3f3d20f60d11b4e78b8dc63504f56e145", + "reference": "011f59e3f3d20f60d11b4e78b8dc63504f56e145", "shasum": "" }, "require": { @@ -5671,7 +5678,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.25" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.32" }, "funding": [ { @@ -5691,7 +5698,7 @@ "type": "tidelift" } ], - "time": "2025-08-07T12:02:05+00:00" + "time": "2026-01-06T09:13:42+00:00" } ], "aliases": [], diff --git a/lib/bin/patch-type-declarations.bat b/lib/bin/patch-type-declarations.bat new file mode 100755 index 0000000000..2b0707968a --- /dev/null +++ b/lib/bin/patch-type-declarations.bat @@ -0,0 +1,5 @@ +@ECHO OFF +setlocal DISABLEDELAYEDEXPANSION +SET BIN_TARGET=%~dp0/patch-type-declarations +SET COMPOSER_RUNTIME_BIN_DIR=%~dp0 +php "%BIN_TARGET%" %* diff --git a/lib/bin/yaml-lint.bat b/lib/bin/yaml-lint.bat new file mode 100755 index 0000000000..fa76637484 --- /dev/null +++ b/lib/bin/yaml-lint.bat @@ -0,0 +1,5 @@ +@ECHO OFF +setlocal DISABLEDELAYEDEXPANSION +SET BIN_TARGET=%~dp0/yaml-lint +SET COMPOSER_RUNTIME_BIN_DIR=%~dp0 +php "%BIN_TARGET%" %* diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index 1a4ffaece5..c8a593ee06 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -1593,6 +1593,8 @@ 'Symfony\\Bridge\\Twig\\Node\\StopwatchNode' => $vendorDir . '/symfony/twig-bridge/Node/StopwatchNode.php', 'Symfony\\Bridge\\Twig\\Node\\TransDefaultDomainNode' => $vendorDir . '/symfony/twig-bridge/Node/TransDefaultDomainNode.php', 'Symfony\\Bridge\\Twig\\Node\\TransNode' => $vendorDir . '/symfony/twig-bridge/Node/TransNode.php', + 'Symfony\\Bridge\\Twig\\Test\\FormLayoutTestCase' => $vendorDir . '/symfony/twig-bridge/Test/FormLayoutTestCase.php', + 'Symfony\\Bridge\\Twig\\Test\\Traits\\RuntimeLoaderProvider' => $vendorDir . '/symfony/twig-bridge/Test/Traits/RuntimeLoaderProvider.php', 'Symfony\\Bridge\\Twig\\TokenParser\\DumpTokenParser' => $vendorDir . '/symfony/twig-bridge/TokenParser/DumpTokenParser.php', 'Symfony\\Bridge\\Twig\\TokenParser\\FormThemeTokenParser' => $vendorDir . '/symfony/twig-bridge/TokenParser/FormThemeTokenParser.php', 'Symfony\\Bridge\\Twig\\TokenParser\\StopwatchTokenParser' => $vendorDir . '/symfony/twig-bridge/TokenParser/StopwatchTokenParser.php', @@ -1767,22 +1769,43 @@ 'Symfony\\Component\\Cache\\Psr16Cache' => $vendorDir . '/symfony/cache/Psr16Cache.php', 'Symfony\\Component\\Cache\\ResettableInterface' => $vendorDir . '/symfony/cache/ResettableInterface.php', 'Symfony\\Component\\Cache\\Traits\\AbstractAdapterTrait' => $vendorDir . '/symfony/cache/Traits/AbstractAdapterTrait.php', + 'Symfony\\Component\\Cache\\Traits\\CachedValueInterface' => $vendorDir . '/symfony/cache/Traits/CachedValueInterface.php', 'Symfony\\Component\\Cache\\Traits\\ContractsTrait' => $vendorDir . '/symfony/cache/Traits/ContractsTrait.php', 'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemCommonTrait.php', 'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => $vendorDir . '/symfony/cache/Traits/FilesystemTrait.php', 'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => $vendorDir . '/symfony/cache/Traits/ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\Redis5Proxy' => $vendorDir . '/symfony/cache/Traits/Redis5Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\Redis61ProxyTrait' => $vendorDir . '/symfony/cache/Traits/Redis61ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Redis62ProxyTrait' => $vendorDir . '/symfony/cache/Traits/Redis62ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Redis63ProxyTrait' => $vendorDir . '/symfony/cache/Traits/Redis63ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\Redis6Proxy' => $vendorDir . '/symfony/cache/Traits/Redis6Proxy.php', - 'Symfony\\Component\\Cache\\Traits\\Redis6ProxyTrait' => $vendorDir . '/symfony/cache/Traits/Redis6ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\RedisCluster5Proxy' => $vendorDir . '/symfony/cache/Traits/RedisCluster5Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster61ProxyTrait' => $vendorDir . '/symfony/cache/Traits/RedisCluster61ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster62ProxyTrait' => $vendorDir . '/symfony/cache/Traits/RedisCluster62ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster63ProxyTrait' => $vendorDir . '/symfony/cache/Traits/RedisCluster63ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\RedisCluster6Proxy' => $vendorDir . '/symfony/cache/Traits/RedisCluster6Proxy.php', - 'Symfony\\Component\\Cache\\Traits\\RedisCluster6ProxyTrait' => $vendorDir . '/symfony/cache/Traits/RedisCluster6ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\RedisClusterNodeProxy' => $vendorDir . '/symfony/cache/Traits/RedisClusterNodeProxy.php', 'Symfony\\Component\\Cache\\Traits\\RedisClusterProxy' => $vendorDir . '/symfony/cache/Traits/RedisClusterProxy.php', 'Symfony\\Component\\Cache\\Traits\\RedisProxy' => $vendorDir . '/symfony/cache/Traits/RedisProxy.php', 'Symfony\\Component\\Cache\\Traits\\RedisTrait' => $vendorDir . '/symfony/cache/Traits/RedisTrait.php', 'Symfony\\Component\\Cache\\Traits\\RelayProxy' => $vendorDir . '/symfony/cache/Traits/RelayProxy.php', 'Symfony\\Component\\Cache\\Traits\\RelayProxyTrait' => $vendorDir . '/symfony/cache/Traits/RelayProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\BgsaveTrait' => $vendorDir . '/symfony/cache/Traits/Relay/BgsaveTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\CopyTrait' => $vendorDir . '/symfony/cache/Traits/Relay/CopyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\FtTrait' => $vendorDir . '/symfony/cache/Traits/Relay/FtTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\GeosearchTrait' => $vendorDir . '/symfony/cache/Traits/Relay/GeosearchTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\GetWithMetaTrait' => $vendorDir . '/symfony/cache/Traits/Relay/GetWithMetaTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\GetrangeTrait' => $vendorDir . '/symfony/cache/Traits/Relay/GetrangeTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\HsetTrait' => $vendorDir . '/symfony/cache/Traits/Relay/HsetTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\IsTrackedTrait' => $vendorDir . '/symfony/cache/Traits/Relay/IsTrackedTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\MoveTrait' => $vendorDir . '/symfony/cache/Traits/Relay/MoveTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\NullableReturnTrait' => $vendorDir . '/symfony/cache/Traits/Relay/NullableReturnTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\PfcountTrait' => $vendorDir . '/symfony/cache/Traits/Relay/PfcountTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\Relay11Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay11Trait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\Relay121Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay121Trait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\Relay12Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay12Trait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\Relay20Trait' => $vendorDir . '/symfony/cache/Traits/Relay/Relay20Trait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\SwapdbTrait' => $vendorDir . '/symfony/cache/Traits/Relay/SwapdbTrait.php', 'Symfony\\Component\\Config\\Builder\\ClassBuilder' => $vendorDir . '/symfony/config/Builder/ClassBuilder.php', 'Symfony\\Component\\Config\\Builder\\ConfigBuilderGenerator' => $vendorDir . '/symfony/config/Builder/ConfigBuilderGenerator.php', 'Symfony\\Component\\Config\\Builder\\ConfigBuilderGeneratorInterface' => $vendorDir . '/symfony/config/Builder/ConfigBuilderGeneratorInterface.php', @@ -1947,6 +1970,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', @@ -2513,6 +2537,13 @@ 'Symfony\\Component\\Form\\SubmitButton' => $vendorDir . '/symfony/form/SubmitButton.php', 'Symfony\\Component\\Form\\SubmitButtonBuilder' => $vendorDir . '/symfony/form/SubmitButtonBuilder.php', 'Symfony\\Component\\Form\\SubmitButtonTypeInterface' => $vendorDir . '/symfony/form/SubmitButtonTypeInterface.php', + 'Symfony\\Component\\Form\\Test\\FormBuilderInterface' => $vendorDir . '/symfony/form/Test/FormBuilderInterface.php', + 'Symfony\\Component\\Form\\Test\\FormIntegrationTestCase' => $vendorDir . '/symfony/form/Test/FormIntegrationTestCase.php', + 'Symfony\\Component\\Form\\Test\\FormInterface' => $vendorDir . '/symfony/form/Test/FormInterface.php', + 'Symfony\\Component\\Form\\Test\\FormPerformanceTestCase' => $vendorDir . '/symfony/form/Test/FormPerformanceTestCase.php', + 'Symfony\\Component\\Form\\Test\\Traits\\RunTestTrait' => $vendorDir . '/symfony/form/Test/Traits/RunTestTrait.php', + 'Symfony\\Component\\Form\\Test\\Traits\\ValidatorExtensionTrait' => $vendorDir . '/symfony/form/Test/Traits/ValidatorExtensionTrait.php', + 'Symfony\\Component\\Form\\Test\\TypeTestCase' => $vendorDir . '/symfony/form/Test/TypeTestCase.php', 'Symfony\\Component\\Form\\Util\\FormUtil' => $vendorDir . '/symfony/form/Util/FormUtil.php', 'Symfony\\Component\\Form\\Util\\InheritDataAwareIterator' => $vendorDir . '/symfony/form/Util/InheritDataAwareIterator.php', 'Symfony\\Component\\Form\\Util\\OptionsResolverWrapper' => $vendorDir . '/symfony/form/Util/OptionsResolverWrapper.php', @@ -2821,6 +2852,9 @@ 'Symfony\\Component\\Mailer\\Messenger\\MessageHandler' => $vendorDir . '/symfony/mailer/Messenger/MessageHandler.php', 'Symfony\\Component\\Mailer\\Messenger\\SendEmailMessage' => $vendorDir . '/symfony/mailer/Messenger/SendEmailMessage.php', 'Symfony\\Component\\Mailer\\SentMessage' => $vendorDir . '/symfony/mailer/SentMessage.php', + 'Symfony\\Component\\Mailer\\Test\\Constraint\\EmailCount' => $vendorDir . '/symfony/mailer/Test/Constraint/EmailCount.php', + 'Symfony\\Component\\Mailer\\Test\\Constraint\\EmailIsQueued' => $vendorDir . '/symfony/mailer/Test/Constraint/EmailIsQueued.php', + 'Symfony\\Component\\Mailer\\Test\\TransportFactoryTestCase' => $vendorDir . '/symfony/mailer/Test/TransportFactoryTestCase.php', 'Symfony\\Component\\Mailer\\Transport' => $vendorDir . '/symfony/mailer/Transport.php', 'Symfony\\Component\\Mailer\\Transport\\AbstractApiTransport' => $vendorDir . '/symfony/mailer/Transport/AbstractApiTransport.php', 'Symfony\\Component\\Mailer\\Transport\\AbstractHttpTransport' => $vendorDir . '/symfony/mailer/Transport/AbstractHttpTransport.php', @@ -2911,6 +2945,13 @@ 'Symfony\\Component\\Mime\\Part\\SMimePart' => $vendorDir . '/symfony/mime/Part/SMimePart.php', 'Symfony\\Component\\Mime\\Part\\TextPart' => $vendorDir . '/symfony/mime/Part/TextPart.php', 'Symfony\\Component\\Mime\\RawMessage' => $vendorDir . '/symfony/mime/RawMessage.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailAddressContains' => $vendorDir . '/symfony/mime/Test/Constraint/EmailAddressContains.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailAttachmentCount' => $vendorDir . '/symfony/mime/Test/Constraint/EmailAttachmentCount.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailHasHeader' => $vendorDir . '/symfony/mime/Test/Constraint/EmailHasHeader.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailHeaderSame' => $vendorDir . '/symfony/mime/Test/Constraint/EmailHeaderSame.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailHtmlBodyContains' => $vendorDir . '/symfony/mime/Test/Constraint/EmailHtmlBodyContains.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailSubjectContains' => $vendorDir . '/symfony/mime/Test/Constraint/EmailSubjectContains.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailTextBodyContains' => $vendorDir . '/symfony/mime/Test/Constraint/EmailTextBodyContains.php', 'Symfony\\Component\\OptionsResolver\\Debug\\OptionsResolverIntrospector' => $vendorDir . '/symfony/options-resolver/Debug/OptionsResolverIntrospector.php', 'Symfony\\Component\\OptionsResolver\\Exception\\AccessException' => $vendorDir . '/symfony/options-resolver/Exception/AccessException.php', 'Symfony\\Component\\OptionsResolver\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/options-resolver/Exception/ExceptionInterface.php', @@ -3136,6 +3177,7 @@ 'Symfony\\Component\\Security\\Core\\Signature\\Exception\\InvalidSignatureException' => $vendorDir . '/symfony/security-core/Signature/Exception/InvalidSignatureException.php', 'Symfony\\Component\\Security\\Core\\Signature\\ExpiredSignatureStorage' => $vendorDir . '/symfony/security-core/Signature/ExpiredSignatureStorage.php', 'Symfony\\Component\\Security\\Core\\Signature\\SignatureHasher' => $vendorDir . '/symfony/security-core/Signature/SignatureHasher.php', + 'Symfony\\Component\\Security\\Core\\Test\\AccessDecisionStrategyTestCase' => $vendorDir . '/symfony/security-core/Test/AccessDecisionStrategyTestCase.php', 'Symfony\\Component\\Security\\Core\\User\\AttributesBasedUserProviderInterface' => $vendorDir . '/symfony/security-core/User/AttributesBasedUserProviderInterface.php', 'Symfony\\Component\\Security\\Core\\User\\ChainUserChecker' => $vendorDir . '/symfony/security-core/User/ChainUserChecker.php', 'Symfony\\Component\\Security\\Core\\User\\ChainUserProvider' => $vendorDir . '/symfony/security-core/User/ChainUserProvider.php', @@ -3391,6 +3433,7 @@ 'Symfony\\Component\\Validator\\Mapping\\PropertyMetadataInterface' => $vendorDir . '/symfony/validator/Mapping/PropertyMetadataInterface.php', 'Symfony\\Component\\Validator\\Mapping\\TraversalStrategy' => $vendorDir . '/symfony/validator/Mapping/TraversalStrategy.php', 'Symfony\\Component\\Validator\\ObjectInitializerInterface' => $vendorDir . '/symfony/validator/ObjectInitializerInterface.php', + 'Symfony\\Component\\Validator\\Test\\ConstraintValidatorTestCase' => $vendorDir . '/symfony/validator/Test/ConstraintValidatorTestCase.php', 'Symfony\\Component\\Validator\\Util\\PropertyPath' => $vendorDir . '/symfony/validator/Util/PropertyPath.php', 'Symfony\\Component\\Validator\\Validation' => $vendorDir . '/symfony/validator/Validation.php', 'Symfony\\Component\\Validator\\ValidatorBuilder' => $vendorDir . '/symfony/validator/ValidatorBuilder.php', @@ -3466,6 +3509,7 @@ 'Symfony\\Component\\VarDumper\\Exception\\ThrowingCasterException' => $vendorDir . '/symfony/var-dumper/Exception/ThrowingCasterException.php', 'Symfony\\Component\\VarDumper\\Server\\Connection' => $vendorDir . '/symfony/var-dumper/Server/Connection.php', 'Symfony\\Component\\VarDumper\\Server\\DumpServer' => $vendorDir . '/symfony/var-dumper/Server/DumpServer.php', + 'Symfony\\Component\\VarDumper\\Test\\VarDumperTestTrait' => $vendorDir . '/symfony/var-dumper/Test/VarDumperTestTrait.php', 'Symfony\\Component\\VarDumper\\VarDumper' => $vendorDir . '/symfony/var-dumper/VarDumper.php', 'Symfony\\Component\\VarExporter\\Exception\\ClassNotFoundException' => $vendorDir . '/symfony/var-exporter/Exception/ClassNotFoundException.php', 'Symfony\\Component\\VarExporter\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/var-exporter/Exception/ExceptionInterface.php', @@ -3623,6 +3667,7 @@ 'Twig\\ExpressionParser\\InfixExpressionParserInterface' => $vendorDir . '/twig/twig/src/ExpressionParser/InfixExpressionParserInterface.php', 'Twig\\ExpressionParser\\Infix\\ArgumentsTrait' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php', 'Twig\\ExpressionParser\\Infix\\ArrowExpressionParser' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/ArrowExpressionParser.php', + 'Twig\\ExpressionParser\\Infix\\AssignmentExpressionParser' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/AssignmentExpressionParser.php', 'Twig\\ExpressionParser\\Infix\\BinaryOperatorExpressionParser' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/BinaryOperatorExpressionParser.php', 'Twig\\ExpressionParser\\Infix\\ConditionalTernaryExpressionParser' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/ConditionalTernaryExpressionParser.php', 'Twig\\ExpressionParser\\Infix\\DotExpressionParser' => $vendorDir . '/twig/twig/src/ExpressionParser/Infix/DotExpressionParser.php', @@ -3708,10 +3753,15 @@ 'Twig\\Node\\Expression\\Binary\\MulBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/MulBinary.php', 'Twig\\Node\\Expression\\Binary\\NotEqualBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php', 'Twig\\Node\\Expression\\Binary\\NotInBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/NotInBinary.php', + 'Twig\\Node\\Expression\\Binary\\NotSameAsBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/NotSameAsBinary.php', 'Twig\\Node\\Expression\\Binary\\NullCoalesceBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/NullCoalesceBinary.php', + 'Twig\\Node\\Expression\\Binary\\ObjectDestructuringSetBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/ObjectDestructuringSetBinary.php', 'Twig\\Node\\Expression\\Binary\\OrBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/OrBinary.php', 'Twig\\Node\\Expression\\Binary\\PowerBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/PowerBinary.php', 'Twig\\Node\\Expression\\Binary\\RangeBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/RangeBinary.php', + 'Twig\\Node\\Expression\\Binary\\SameAsBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/SameAsBinary.php', + 'Twig\\Node\\Expression\\Binary\\SequenceDestructuringSetBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/SequenceDestructuringSetBinary.php', + 'Twig\\Node\\Expression\\Binary\\SetBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/SetBinary.php', 'Twig\\Node\\Expression\\Binary\\SpaceshipBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/SpaceshipBinary.php', 'Twig\\Node\\Expression\\Binary\\StartsWithBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php', 'Twig\\Node\\Expression\\Binary\\SubBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/SubBinary.php', @@ -3720,6 +3770,7 @@ 'Twig\\Node\\Expression\\CallExpression' => $vendorDir . '/twig/twig/src/Node/Expression/CallExpression.php', 'Twig\\Node\\Expression\\ConditionalExpression' => $vendorDir . '/twig/twig/src/Node/Expression/ConditionalExpression.php', 'Twig\\Node\\Expression\\ConstantExpression' => $vendorDir . '/twig/twig/src/Node/Expression/ConstantExpression.php', + 'Twig\\Node\\Expression\\EmptyExpression' => $vendorDir . '/twig/twig/src/Node/Expression/EmptyExpression.php', 'Twig\\Node\\Expression\\FilterExpression' => $vendorDir . '/twig/twig/src/Node/Expression/FilterExpression.php', 'Twig\\Node\\Expression\\Filter\\DefaultFilter' => $vendorDir . '/twig/twig/src/Node/Expression/Filter/DefaultFilter.php', 'Twig\\Node\\Expression\\Filter\\RawFilter' => $vendorDir . '/twig/twig/src/Node/Expression/Filter/RawFilter.php', @@ -3813,6 +3864,8 @@ 'Twig\\Source' => $vendorDir . '/twig/twig/src/Source.php', 'Twig\\Template' => $vendorDir . '/twig/twig/src/Template.php', 'Twig\\TemplateWrapper' => $vendorDir . '/twig/twig/src/TemplateWrapper.php', + 'Twig\\Test\\IntegrationTestCase' => $vendorDir . '/twig/twig/src/Test/IntegrationTestCase.php', + 'Twig\\Test\\NodeTestCase' => $vendorDir . '/twig/twig/src/Test/NodeTestCase.php', 'Twig\\Token' => $vendorDir . '/twig/twig/src/Token.php', 'Twig\\TokenParser\\AbstractTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/AbstractTokenParser.php', 'Twig\\TokenParser\\ApplyTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/ApplyTokenParser.php', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index a54a206024..2eaa492ecb 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -1979,6 +1979,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Symfony\\Bridge\\Twig\\Node\\StopwatchNode' => __DIR__ . '/..' . '/symfony/twig-bridge/Node/StopwatchNode.php', 'Symfony\\Bridge\\Twig\\Node\\TransDefaultDomainNode' => __DIR__ . '/..' . '/symfony/twig-bridge/Node/TransDefaultDomainNode.php', 'Symfony\\Bridge\\Twig\\Node\\TransNode' => __DIR__ . '/..' . '/symfony/twig-bridge/Node/TransNode.php', + 'Symfony\\Bridge\\Twig\\Test\\FormLayoutTestCase' => __DIR__ . '/..' . '/symfony/twig-bridge/Test/FormLayoutTestCase.php', + 'Symfony\\Bridge\\Twig\\Test\\Traits\\RuntimeLoaderProvider' => __DIR__ . '/..' . '/symfony/twig-bridge/Test/Traits/RuntimeLoaderProvider.php', 'Symfony\\Bridge\\Twig\\TokenParser\\DumpTokenParser' => __DIR__ . '/..' . '/symfony/twig-bridge/TokenParser/DumpTokenParser.php', 'Symfony\\Bridge\\Twig\\TokenParser\\FormThemeTokenParser' => __DIR__ . '/..' . '/symfony/twig-bridge/TokenParser/FormThemeTokenParser.php', 'Symfony\\Bridge\\Twig\\TokenParser\\StopwatchTokenParser' => __DIR__ . '/..' . '/symfony/twig-bridge/TokenParser/StopwatchTokenParser.php', @@ -2153,22 +2155,43 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Symfony\\Component\\Cache\\Psr16Cache' => __DIR__ . '/..' . '/symfony/cache/Psr16Cache.php', 'Symfony\\Component\\Cache\\ResettableInterface' => __DIR__ . '/..' . '/symfony/cache/ResettableInterface.php', 'Symfony\\Component\\Cache\\Traits\\AbstractAdapterTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/AbstractAdapterTrait.php', + 'Symfony\\Component\\Cache\\Traits\\CachedValueInterface' => __DIR__ . '/..' . '/symfony/cache/Traits/CachedValueInterface.php', 'Symfony\\Component\\Cache\\Traits\\ContractsTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ContractsTrait.php', 'Symfony\\Component\\Cache\\Traits\\FilesystemCommonTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemCommonTrait.php', 'Symfony\\Component\\Cache\\Traits\\FilesystemTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/FilesystemTrait.php', 'Symfony\\Component\\Cache\\Traits\\ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\Redis5Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis5Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\Redis61ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis61ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Redis62ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis62ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Redis63ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis63ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\Redis6Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis6Proxy.php', - 'Symfony\\Component\\Cache\\Traits\\Redis6ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Redis6ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\RedisCluster5Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster5Proxy.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster61ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster61ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster62ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster62ProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\RedisCluster63ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster63ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\RedisCluster6Proxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster6Proxy.php', - 'Symfony\\Component\\Cache\\Traits\\RedisCluster6ProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisCluster6ProxyTrait.php', 'Symfony\\Component\\Cache\\Traits\\RedisClusterNodeProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisClusterNodeProxy.php', 'Symfony\\Component\\Cache\\Traits\\RedisClusterProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisClusterProxy.php', 'Symfony\\Component\\Cache\\Traits\\RedisProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisProxy.php', 'Symfony\\Component\\Cache\\Traits\\RedisTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RedisTrait.php', 'Symfony\\Component\\Cache\\Traits\\RelayProxy' => __DIR__ . '/..' . '/symfony/cache/Traits/RelayProxy.php', 'Symfony\\Component\\Cache\\Traits\\RelayProxyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/RelayProxyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\BgsaveTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/BgsaveTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\CopyTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/CopyTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\FtTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/FtTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\GeosearchTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/GeosearchTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\GetWithMetaTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/GetWithMetaTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\GetrangeTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/GetrangeTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\HsetTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/HsetTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\IsTrackedTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/IsTrackedTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\MoveTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/MoveTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\NullableReturnTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/NullableReturnTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\PfcountTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/PfcountTrait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\Relay11Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay11Trait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\Relay121Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay121Trait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\Relay12Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay12Trait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\Relay20Trait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/Relay20Trait.php', + 'Symfony\\Component\\Cache\\Traits\\Relay\\SwapdbTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/Relay/SwapdbTrait.php', 'Symfony\\Component\\Config\\Builder\\ClassBuilder' => __DIR__ . '/..' . '/symfony/config/Builder/ClassBuilder.php', 'Symfony\\Component\\Config\\Builder\\ConfigBuilderGenerator' => __DIR__ . '/..' . '/symfony/config/Builder/ConfigBuilderGenerator.php', 'Symfony\\Component\\Config\\Builder\\ConfigBuilderGeneratorInterface' => __DIR__ . '/..' . '/symfony/config/Builder/ConfigBuilderGeneratorInterface.php', @@ -2333,6 +2356,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f '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', @@ -2899,6 +2923,13 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Symfony\\Component\\Form\\SubmitButton' => __DIR__ . '/..' . '/symfony/form/SubmitButton.php', 'Symfony\\Component\\Form\\SubmitButtonBuilder' => __DIR__ . '/..' . '/symfony/form/SubmitButtonBuilder.php', 'Symfony\\Component\\Form\\SubmitButtonTypeInterface' => __DIR__ . '/..' . '/symfony/form/SubmitButtonTypeInterface.php', + 'Symfony\\Component\\Form\\Test\\FormBuilderInterface' => __DIR__ . '/..' . '/symfony/form/Test/FormBuilderInterface.php', + 'Symfony\\Component\\Form\\Test\\FormIntegrationTestCase' => __DIR__ . '/..' . '/symfony/form/Test/FormIntegrationTestCase.php', + 'Symfony\\Component\\Form\\Test\\FormInterface' => __DIR__ . '/..' . '/symfony/form/Test/FormInterface.php', + 'Symfony\\Component\\Form\\Test\\FormPerformanceTestCase' => __DIR__ . '/..' . '/symfony/form/Test/FormPerformanceTestCase.php', + 'Symfony\\Component\\Form\\Test\\Traits\\RunTestTrait' => __DIR__ . '/..' . '/symfony/form/Test/Traits/RunTestTrait.php', + 'Symfony\\Component\\Form\\Test\\Traits\\ValidatorExtensionTrait' => __DIR__ . '/..' . '/symfony/form/Test/Traits/ValidatorExtensionTrait.php', + 'Symfony\\Component\\Form\\Test\\TypeTestCase' => __DIR__ . '/..' . '/symfony/form/Test/TypeTestCase.php', 'Symfony\\Component\\Form\\Util\\FormUtil' => __DIR__ . '/..' . '/symfony/form/Util/FormUtil.php', 'Symfony\\Component\\Form\\Util\\InheritDataAwareIterator' => __DIR__ . '/..' . '/symfony/form/Util/InheritDataAwareIterator.php', 'Symfony\\Component\\Form\\Util\\OptionsResolverWrapper' => __DIR__ . '/..' . '/symfony/form/Util/OptionsResolverWrapper.php', @@ -3207,6 +3238,9 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Symfony\\Component\\Mailer\\Messenger\\MessageHandler' => __DIR__ . '/..' . '/symfony/mailer/Messenger/MessageHandler.php', 'Symfony\\Component\\Mailer\\Messenger\\SendEmailMessage' => __DIR__ . '/..' . '/symfony/mailer/Messenger/SendEmailMessage.php', 'Symfony\\Component\\Mailer\\SentMessage' => __DIR__ . '/..' . '/symfony/mailer/SentMessage.php', + 'Symfony\\Component\\Mailer\\Test\\Constraint\\EmailCount' => __DIR__ . '/..' . '/symfony/mailer/Test/Constraint/EmailCount.php', + 'Symfony\\Component\\Mailer\\Test\\Constraint\\EmailIsQueued' => __DIR__ . '/..' . '/symfony/mailer/Test/Constraint/EmailIsQueued.php', + 'Symfony\\Component\\Mailer\\Test\\TransportFactoryTestCase' => __DIR__ . '/..' . '/symfony/mailer/Test/TransportFactoryTestCase.php', 'Symfony\\Component\\Mailer\\Transport' => __DIR__ . '/..' . '/symfony/mailer/Transport.php', 'Symfony\\Component\\Mailer\\Transport\\AbstractApiTransport' => __DIR__ . '/..' . '/symfony/mailer/Transport/AbstractApiTransport.php', 'Symfony\\Component\\Mailer\\Transport\\AbstractHttpTransport' => __DIR__ . '/..' . '/symfony/mailer/Transport/AbstractHttpTransport.php', @@ -3297,6 +3331,13 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Symfony\\Component\\Mime\\Part\\SMimePart' => __DIR__ . '/..' . '/symfony/mime/Part/SMimePart.php', 'Symfony\\Component\\Mime\\Part\\TextPart' => __DIR__ . '/..' . '/symfony/mime/Part/TextPart.php', 'Symfony\\Component\\Mime\\RawMessage' => __DIR__ . '/..' . '/symfony/mime/RawMessage.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailAddressContains' => __DIR__ . '/..' . '/symfony/mime/Test/Constraint/EmailAddressContains.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailAttachmentCount' => __DIR__ . '/..' . '/symfony/mime/Test/Constraint/EmailAttachmentCount.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailHasHeader' => __DIR__ . '/..' . '/symfony/mime/Test/Constraint/EmailHasHeader.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailHeaderSame' => __DIR__ . '/..' . '/symfony/mime/Test/Constraint/EmailHeaderSame.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailHtmlBodyContains' => __DIR__ . '/..' . '/symfony/mime/Test/Constraint/EmailHtmlBodyContains.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailSubjectContains' => __DIR__ . '/..' . '/symfony/mime/Test/Constraint/EmailSubjectContains.php', + 'Symfony\\Component\\Mime\\Test\\Constraint\\EmailTextBodyContains' => __DIR__ . '/..' . '/symfony/mime/Test/Constraint/EmailTextBodyContains.php', 'Symfony\\Component\\OptionsResolver\\Debug\\OptionsResolverIntrospector' => __DIR__ . '/..' . '/symfony/options-resolver/Debug/OptionsResolverIntrospector.php', 'Symfony\\Component\\OptionsResolver\\Exception\\AccessException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/AccessException.php', 'Symfony\\Component\\OptionsResolver\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/ExceptionInterface.php', @@ -3522,6 +3563,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Symfony\\Component\\Security\\Core\\Signature\\Exception\\InvalidSignatureException' => __DIR__ . '/..' . '/symfony/security-core/Signature/Exception/InvalidSignatureException.php', 'Symfony\\Component\\Security\\Core\\Signature\\ExpiredSignatureStorage' => __DIR__ . '/..' . '/symfony/security-core/Signature/ExpiredSignatureStorage.php', 'Symfony\\Component\\Security\\Core\\Signature\\SignatureHasher' => __DIR__ . '/..' . '/symfony/security-core/Signature/SignatureHasher.php', + 'Symfony\\Component\\Security\\Core\\Test\\AccessDecisionStrategyTestCase' => __DIR__ . '/..' . '/symfony/security-core/Test/AccessDecisionStrategyTestCase.php', 'Symfony\\Component\\Security\\Core\\User\\AttributesBasedUserProviderInterface' => __DIR__ . '/..' . '/symfony/security-core/User/AttributesBasedUserProviderInterface.php', 'Symfony\\Component\\Security\\Core\\User\\ChainUserChecker' => __DIR__ . '/..' . '/symfony/security-core/User/ChainUserChecker.php', 'Symfony\\Component\\Security\\Core\\User\\ChainUserProvider' => __DIR__ . '/..' . '/symfony/security-core/User/ChainUserProvider.php', @@ -3777,6 +3819,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Symfony\\Component\\Validator\\Mapping\\PropertyMetadataInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/PropertyMetadataInterface.php', 'Symfony\\Component\\Validator\\Mapping\\TraversalStrategy' => __DIR__ . '/..' . '/symfony/validator/Mapping/TraversalStrategy.php', 'Symfony\\Component\\Validator\\ObjectInitializerInterface' => __DIR__ . '/..' . '/symfony/validator/ObjectInitializerInterface.php', + 'Symfony\\Component\\Validator\\Test\\ConstraintValidatorTestCase' => __DIR__ . '/..' . '/symfony/validator/Test/ConstraintValidatorTestCase.php', 'Symfony\\Component\\Validator\\Util\\PropertyPath' => __DIR__ . '/..' . '/symfony/validator/Util/PropertyPath.php', 'Symfony\\Component\\Validator\\Validation' => __DIR__ . '/..' . '/symfony/validator/Validation.php', 'Symfony\\Component\\Validator\\ValidatorBuilder' => __DIR__ . '/..' . '/symfony/validator/ValidatorBuilder.php', @@ -3852,6 +3895,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Symfony\\Component\\VarDumper\\Exception\\ThrowingCasterException' => __DIR__ . '/..' . '/symfony/var-dumper/Exception/ThrowingCasterException.php', 'Symfony\\Component\\VarDumper\\Server\\Connection' => __DIR__ . '/..' . '/symfony/var-dumper/Server/Connection.php', 'Symfony\\Component\\VarDumper\\Server\\DumpServer' => __DIR__ . '/..' . '/symfony/var-dumper/Server/DumpServer.php', + 'Symfony\\Component\\VarDumper\\Test\\VarDumperTestTrait' => __DIR__ . '/..' . '/symfony/var-dumper/Test/VarDumperTestTrait.php', 'Symfony\\Component\\VarDumper\\VarDumper' => __DIR__ . '/..' . '/symfony/var-dumper/VarDumper.php', 'Symfony\\Component\\VarExporter\\Exception\\ClassNotFoundException' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/ClassNotFoundException.php', 'Symfony\\Component\\VarExporter\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/ExceptionInterface.php', @@ -4009,6 +4053,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Twig\\ExpressionParser\\InfixExpressionParserInterface' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/InfixExpressionParserInterface.php', 'Twig\\ExpressionParser\\Infix\\ArgumentsTrait' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php', 'Twig\\ExpressionParser\\Infix\\ArrowExpressionParser' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/ArrowExpressionParser.php', + 'Twig\\ExpressionParser\\Infix\\AssignmentExpressionParser' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/AssignmentExpressionParser.php', 'Twig\\ExpressionParser\\Infix\\BinaryOperatorExpressionParser' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/BinaryOperatorExpressionParser.php', 'Twig\\ExpressionParser\\Infix\\ConditionalTernaryExpressionParser' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/ConditionalTernaryExpressionParser.php', 'Twig\\ExpressionParser\\Infix\\DotExpressionParser' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser/Infix/DotExpressionParser.php', @@ -4094,10 +4139,15 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Twig\\Node\\Expression\\Binary\\MulBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/MulBinary.php', 'Twig\\Node\\Expression\\Binary\\NotEqualBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php', 'Twig\\Node\\Expression\\Binary\\NotInBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/NotInBinary.php', + 'Twig\\Node\\Expression\\Binary\\NotSameAsBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/NotSameAsBinary.php', 'Twig\\Node\\Expression\\Binary\\NullCoalesceBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/NullCoalesceBinary.php', + 'Twig\\Node\\Expression\\Binary\\ObjectDestructuringSetBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/ObjectDestructuringSetBinary.php', 'Twig\\Node\\Expression\\Binary\\OrBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/OrBinary.php', 'Twig\\Node\\Expression\\Binary\\PowerBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/PowerBinary.php', 'Twig\\Node\\Expression\\Binary\\RangeBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/RangeBinary.php', + 'Twig\\Node\\Expression\\Binary\\SameAsBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/SameAsBinary.php', + 'Twig\\Node\\Expression\\Binary\\SequenceDestructuringSetBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/SequenceDestructuringSetBinary.php', + 'Twig\\Node\\Expression\\Binary\\SetBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/SetBinary.php', 'Twig\\Node\\Expression\\Binary\\SpaceshipBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/SpaceshipBinary.php', 'Twig\\Node\\Expression\\Binary\\StartsWithBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php', 'Twig\\Node\\Expression\\Binary\\SubBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/SubBinary.php', @@ -4106,6 +4156,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Twig\\Node\\Expression\\CallExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/CallExpression.php', 'Twig\\Node\\Expression\\ConditionalExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/ConditionalExpression.php', 'Twig\\Node\\Expression\\ConstantExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/ConstantExpression.php', + 'Twig\\Node\\Expression\\EmptyExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/EmptyExpression.php', 'Twig\\Node\\Expression\\FilterExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/FilterExpression.php', 'Twig\\Node\\Expression\\Filter\\DefaultFilter' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Filter/DefaultFilter.php', 'Twig\\Node\\Expression\\Filter\\RawFilter' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Filter/RawFilter.php', @@ -4199,6 +4250,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Twig\\Source' => __DIR__ . '/..' . '/twig/twig/src/Source.php', 'Twig\\Template' => __DIR__ . '/..' . '/twig/twig/src/Template.php', 'Twig\\TemplateWrapper' => __DIR__ . '/..' . '/twig/twig/src/TemplateWrapper.php', + 'Twig\\Test\\IntegrationTestCase' => __DIR__ . '/..' . '/twig/twig/src/Test/IntegrationTestCase.php', + 'Twig\\Test\\NodeTestCase' => __DIR__ . '/..' . '/twig/twig/src/Test/NodeTestCase.php', 'Twig\\Token' => __DIR__ . '/..' . '/twig/twig/src/Token.php', 'Twig\\TokenParser\\AbstractTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/AbstractTokenParser.php', 'Twig\\TokenParser\\ApplyTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/ApplyTokenParser.php', diff --git a/lib/composer/installed.json b/lib/composer/installed.json index a6a6734157..f26be27362 100644 --- a/lib/composer/installed.json +++ b/lib/composer/installed.json @@ -1793,17 +1793,17 @@ }, { "name": "symfony/cache", - "version": "v6.4.12", - "version_normalized": "6.4.12.0", + "version": "v6.4.33", + "version_normalized": "6.4.33.0", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "a463451b7f6ac4a47b98dbfc78ec2d3560c759d8" + "reference": "5b088fa41eb9568748dc255c45e4054c387ba73b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/a463451b7f6ac4a47b98dbfc78ec2d3560c759d8", - "reference": "a463451b7f6ac4a47b98dbfc78ec2d3560c759d8", + "url": "https://api.github.com/repos/symfony/cache/zipball/5b088fa41eb9568748dc255c45e4054c387ba73b", + "reference": "5b088fa41eb9568748dc255c45e4054c387ba73b", "shasum": "" }, "require": { @@ -1837,7 +1837,7 @@ "symfony/messenger": "^5.4|^6.0|^7.0", "symfony/var-dumper": "^5.4|^6.0|^7.0" }, - "time": "2024-09-16T16:01:33+00:00", + "time": "2026-01-27T15:05:20+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1872,7 +1872,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.12" + "source": "https://github.com/symfony/cache/tree/v6.4.33" }, "funding": [ { @@ -1883,6 +1883,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" @@ -1971,17 +1975,17 @@ }, { "name": "symfony/config", - "version": "v6.4.24", - "version_normalized": "6.4.24.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "80e2cf005cf17138c97193be0434cdcfd1b2212e" + "reference": "d445badf0ad2c2a492e38c0378c39997a56ef97b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/80e2cf005cf17138c97193be0434cdcfd1b2212e", - "reference": "80e2cf005cf17138c97193be0434cdcfd1b2212e", + "url": "https://api.github.com/repos/symfony/config/zipball/d445badf0ad2c2a492e38c0378c39997a56ef97b", + "reference": "d445badf0ad2c2a492e38c0378c39997a56ef97b", "shasum": "" }, "require": { @@ -2001,7 +2005,7 @@ "symfony/service-contracts": "^2.5|^3", "symfony/yaml": "^5.4|^6.0|^7.0" }, - "time": "2025-07-26T13:50:30+00:00", + "time": "2026-01-13T08:40:30+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2029,7 +2033,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.4.24" + "source": "https://github.com/symfony/config/tree/v6.4.32" }, "funding": [ { @@ -2053,17 +2057,17 @@ }, { "name": "symfony/console", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae" + "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", - "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", + "url": "https://api.github.com/repos/symfony/console/zipball/0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", + "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", "shasum": "" }, "require": { @@ -2096,7 +2100,7 @@ "symfony/stopwatch": "^5.4|^6.0|^7.0", "symfony/var-dumper": "^5.4|^6.0|^7.0" }, - "time": "2025-08-22T10:21:53+00:00", + "time": "2026-01-13T08:45:59+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2130,7 +2134,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.25" + "source": "https://github.com/symfony/console/tree/v6.4.32" }, "funding": [ { @@ -2226,17 +2230,17 @@ }, { "name": "symfony/dependency-injection", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "900da8a42eceeb4a13a0ec34caa7db49328daff3" + "reference": "b17882e933c4c606620247b6708ab53aa3b88753" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/900da8a42eceeb4a13a0ec34caa7db49328daff3", - "reference": "900da8a42eceeb4a13a0ec34caa7db49328daff3", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/b17882e933c4c606620247b6708ab53aa3b88753", + "reference": "b17882e933c4c606620247b6708ab53aa3b88753", "shasum": "" }, "require": { @@ -2262,7 +2266,7 @@ "symfony/expression-language": "^5.4|^6.0|^7.0", "symfony/yaml": "^5.4|^6.0|^7.0" }, - "time": "2025-08-13T09:41:44+00:00", + "time": "2026-01-23T10:54:33+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2290,7 +2294,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.4.25" + "source": "https://github.com/symfony/dependency-injection/tree/v6.4.32" }, "funding": [ { @@ -2384,17 +2388,17 @@ }, { "name": "symfony/dotenv", - "version": "v6.4.24", - "version_normalized": "6.4.24.0", + "version": "v6.4.30", + "version_normalized": "6.4.30.0", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "234b6c602f12b00693f4b0d1054386fb30dfc8ff" + "reference": "924edbc9631b75302def0258ed1697948b17baf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/234b6c602f12b00693f4b0d1054386fb30dfc8ff", - "reference": "234b6c602f12b00693f4b0d1054386fb30dfc8ff", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/924edbc9631b75302def0258ed1697948b17baf6", + "reference": "924edbc9631b75302def0258ed1697948b17baf6", "shasum": "" }, "require": { @@ -2408,7 +2412,7 @@ "symfony/console": "^5.4|^6.0|^7.0", "symfony/process": "^5.4|^6.0|^7.0" }, - "time": "2025-07-10T08:14:14+00:00", + "time": "2025-11-14T17:33:48+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2441,7 +2445,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.4.24" + "source": "https://github.com/symfony/dotenv/tree/v6.4.30" }, "funding": [ { @@ -2465,17 +2469,17 @@ }, { "name": "symfony/error-handler", - "version": "v6.4.24", - "version_normalized": "6.4.24.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "30fd0b3cf0e972e82636038ce4db0e4fe777112c" + "reference": "8c18400784fcb014dc73c8d5601a9576af7f8ad4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/30fd0b3cf0e972e82636038ce4db0e4fe777112c", - "reference": "30fd0b3cf0e972e82636038ce4db0e4fe777112c", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/8c18400784fcb014dc73c8d5601a9576af7f8ad4", + "reference": "8c18400784fcb014dc73c8d5601a9576af7f8ad4", "shasum": "" }, "require": { @@ -2492,7 +2496,7 @@ "symfony/http-kernel": "^6.4|^7.0", "symfony/serializer": "^5.4|^6.0|^7.0" }, - "time": "2025-07-24T08:25:04+00:00", + "time": "2026-01-19T19:28:19+00:00", "bin": [ "Resources/bin/patch-type-declarations" ], @@ -2523,7 +2527,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.4.24" + "source": "https://github.com/symfony/error-handler/tree/v6.4.32" }, "funding": [ { @@ -2547,17 +2551,17 @@ }, { "name": "symfony/event-dispatcher", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b0cf3162020603587363f0551cd3be43958611ff" + "reference": "99d7e101826e6610606b9433248f80c1997cd20b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff", - "reference": "b0cf3162020603587363f0551cd3be43958611ff", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99d7e101826e6610606b9433248f80c1997cd20b", + "reference": "99d7e101826e6610606b9433248f80c1997cd20b", "shasum": "" }, "require": { @@ -2582,7 +2586,7 @@ "symfony/service-contracts": "^2.5|^3", "symfony/stopwatch": "^5.4|^6.0|^7.0" }, - "time": "2025-08-13T09:41:44+00:00", + "time": "2026-01-05T11:13:48+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2610,7 +2614,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.25" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.32" }, "funding": [ { @@ -2713,17 +2717,17 @@ }, { "name": "symfony/filesystem", - "version": "v6.4.24", - "version_normalized": "6.4.24.0", + "version": "v6.4.30", + "version_normalized": "6.4.30.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8" + "reference": "441c6b69f7222aadae7cbf5df588496d5ee37789" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", - "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/441c6b69f7222aadae7cbf5df588496d5ee37789", + "reference": "441c6b69f7222aadae7cbf5df588496d5ee37789", "shasum": "" }, "require": { @@ -2734,7 +2738,7 @@ "require-dev": { "symfony/process": "^5.4|^6.4|^7.0" }, - "time": "2025-07-10T08:14:14+00:00", + "time": "2025-11-26T14:43:45+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2762,7 +2766,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.24" + "source": "https://github.com/symfony/filesystem/tree/v6.4.30" }, "funding": [ { @@ -2786,17 +2790,17 @@ }, { "name": "symfony/finder", - "version": "v6.4.24", - "version_normalized": "6.4.24.0", + "version": "v6.4.33", + "version_normalized": "6.4.33.0", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "73089124388c8510efb8d2d1689285d285937b08" + "reference": "24965ca011dac87431729640feef8bcf7b5523e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/73089124388c8510efb8d2d1689285d285937b08", - "reference": "73089124388c8510efb8d2d1689285d285937b08", + "url": "https://api.github.com/repos/symfony/finder/zipball/24965ca011dac87431729640feef8bcf7b5523e0", + "reference": "24965ca011dac87431729640feef8bcf7b5523e0", "shasum": "" }, "require": { @@ -2805,7 +2809,7 @@ "require-dev": { "symfony/filesystem": "^6.0|^7.0" }, - "time": "2025-07-15T12:02:45+00:00", + "time": "2026-01-26T13:03:48+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2833,7 +2837,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.24" + "source": "https://github.com/symfony/finder/tree/v6.4.33" }, "funding": [ { @@ -2857,17 +2861,17 @@ }, { "name": "symfony/form", - "version": "v6.4.26", - "version_normalized": "6.4.26.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "b40cdbe70be9274ea807ef61da7d0f8d1c70dc51" + "reference": "b758162fb45024f898640ec27f4ac90be0dbfb8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/b40cdbe70be9274ea807ef61da7d0f8d1c70dc51", - "reference": "b40cdbe70be9274ea807ef61da7d0f8d1c70dc51", + "url": "https://api.github.com/repos/symfony/form/zipball/b758162fb45024f898640ec27f4ac90be0dbfb8f", + "reference": "b758162fb45024f898640ec27f4ac90be0dbfb8f", "shasum": "" }, "require": { @@ -2909,7 +2913,7 @@ "symfony/validator": "^5.4|^6.0|^7.0", "symfony/var-dumper": "^5.4|^6.0|^7.0" }, - "time": "2025-09-20T07:40:41+00:00", + "time": "2026-01-22T20:17:27+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2937,7 +2941,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v6.4.26" + "source": "https://github.com/symfony/form/tree/v6.4.32" }, "funding": [ { @@ -2961,17 +2965,17 @@ }, { "name": "symfony/framework-bundle", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.33", + "version_normalized": "6.4.33.0", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "1d6a764b58e4f780df00f71c20ba3a61095ea447" + "reference": "9ef2d0b63b9e855ba351e770a603d89699115801" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/1d6a764b58e4f780df00f71c20ba3a61095ea447", - "reference": "1d6a764b58e4f780df00f71c20ba3a61095ea447", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/9ef2d0b63b9e855ba351e770a603d89699115801", + "reference": "9ef2d0b63b9e855ba351e770a603d89699115801", "shasum": "" }, "require": { @@ -3065,7 +3069,7 @@ "symfony/yaml": "^5.4|^6.0|^7.0", "twig/twig": "^2.10|^3.0.4" }, - "time": "2025-08-26T10:44:20+00:00", + "time": "2026-01-26T14:46:41+00:00", "type": "symfony-bundle", "installation-source": "dist", "autoload": { @@ -3093,7 +3097,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.4.25" + "source": "https://github.com/symfony/framework-bundle/tree/v6.4.33" }, "funding": [ { @@ -3117,17 +3121,17 @@ }, { "name": "symfony/http-foundation", - "version": "v6.4.29", - "version_normalized": "6.4.29.0", + "version": "v6.4.33", + "version_normalized": "6.4.33.0", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "b03d11e015552a315714c127d8d1e0f9e970ec88" + "reference": "f1a490cc9d595ba7ebe684220e625d1e472ad278" }, "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/f1a490cc9d595ba7ebe684220e625d1e472ad278", + "reference": "f1a490cc9d595ba7ebe684220e625d1e472ad278", "shasum": "" }, "require": { @@ -3149,7 +3153,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": "2026-01-27T15:04:55+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3177,7 +3181,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.33" }, "funding": [ { @@ -3201,17 +3205,17 @@ }, { "name": "symfony/http-kernel", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.33", + "version_normalized": "6.4.33.0", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "a0ee3cea5cabf4ed960fd2ef57668ceeacdb6e15" + "reference": "73fa5c999d7f741ca544a97d3c791cc97890ae4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a0ee3cea5cabf4ed960fd2ef57668ceeacdb6e15", - "reference": "a0ee3cea5cabf4ed960fd2ef57668ceeacdb6e15", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/73fa5c999d7f741ca544a97d3c791cc97890ae4d", + "reference": "73fa5c999d7f741ca544a97d3c791cc97890ae4d", "shasum": "" }, "require": { @@ -3270,7 +3274,7 @@ "symfony/var-exporter": "^6.2|^7.0", "twig/twig": "^2.13|^3.0.4" }, - "time": "2025-08-29T07:55:45+00:00", + "time": "2026-01-28T10:02:13+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3298,7 +3302,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.25" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.33" }, "funding": [ { @@ -3322,17 +3326,17 @@ }, { "name": "symfony/mailer", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.31", + "version_normalized": "6.4.31.0", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "628b43b45a3e6b15c8a633fb22df547ed9b492a2" + "reference": "8835f93333474780fda1b987cae37e33c3e026ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/628b43b45a3e6b15c8a633fb22df547ed9b492a2", - "reference": "628b43b45a3e6b15c8a633fb22df547ed9b492a2", + "url": "https://api.github.com/repos/symfony/mailer/zipball/8835f93333474780fda1b987cae37e33c3e026ca", + "reference": "8835f93333474780fda1b987cae37e33c3e026ca", "shasum": "" }, "require": { @@ -3357,7 +3361,7 @@ "symfony/messenger": "^6.2|^7.0", "symfony/twig-bridge": "^6.2|^7.0" }, - "time": "2025-08-13T09:41:44+00:00", + "time": "2025-12-12T07:33:25+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3385,7 +3389,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.4.25" + "source": "https://github.com/symfony/mailer/tree/v6.4.31" }, "funding": [ { @@ -3409,17 +3413,17 @@ }, { "name": "symfony/mime", - "version": "v6.4.24", - "version_normalized": "6.4.24.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "664d5e844a2de5e11c8255d0aef6bc15a9660ac7" + "reference": "7409686879ca36c09fc970a5fa8ff6e93504dba4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/664d5e844a2de5e11c8255d0aef6bc15a9660ac7", - "reference": "664d5e844a2de5e11c8255d0aef6bc15a9660ac7", + "url": "https://api.github.com/repos/symfony/mime/zipball/7409686879ca36c09fc970a5fa8ff6e93504dba4", + "reference": "7409686879ca36c09fc970a5fa8ff6e93504dba4", "shasum": "" }, "require": { @@ -3445,7 +3449,7 @@ "symfony/property-info": "^5.4|^6.0|^7.0", "symfony/serializer": "^6.4.3|^7.0.3" }, - "time": "2025-07-15T12:02:45+00:00", + "time": "2026-01-04T11:53:14+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3477,7 +3481,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.24" + "source": "https://github.com/symfony/mime/tree/v6.4.32" }, "funding": [ { @@ -3501,24 +3505,24 @@ }, { "name": "symfony/options-resolver", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.30", + "version_normalized": "6.4.30.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe" + "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d28e7e2db8a73e9511df892d36445f61314bbebe", - "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", + "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", "shasum": "" }, "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3" }, - "time": "2025-08-04T17:06:28+00:00", + "time": "2025-11-12T13:06:53+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3551,7 +3555,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.4.25" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.30" }, "funding": [ { @@ -3575,17 +3579,17 @@ }, { "name": "symfony/password-hasher", - "version": "v6.4.24", - "version_normalized": "6.4.24.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "dcab5ac87450aaed26483ba49c2ce86808da7557" + "reference": "fbdfa5a2ca218ec8bb9029517426df2d780bdba9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/dcab5ac87450aaed26483ba49c2ce86808da7557", - "reference": "dcab5ac87450aaed26483ba49c2ce86808da7557", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/fbdfa5a2ca218ec8bb9029517426df2d780bdba9", + "reference": "fbdfa5a2ca218ec8bb9029517426df2d780bdba9", "shasum": "" }, "require": { @@ -3598,7 +3602,7 @@ "symfony/console": "^5.4|^6.0|^7.0", "symfony/security-core": "^5.4|^6.0|^7.0" }, - "time": "2025-07-10T08:14:14+00:00", + "time": "2026-01-01T21:24:53+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3630,7 +3634,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v6.4.24" + "source": "https://github.com/symfony/password-hasher/tree/v6.4.32" }, "funding": [ { @@ -4265,28 +4269,28 @@ }, { "name": "symfony/property-access", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "fedc771326d4978a7d3167fa009a509b06a2e168" + "reference": "6dfa655ac9e9860c05cabb287f34da86b18c237e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/fedc771326d4978a7d3167fa009a509b06a2e168", - "reference": "fedc771326d4978a7d3167fa009a509b06a2e168", + "url": "https://api.github.com/repos/symfony/property-access/zipball/6dfa655ac9e9860c05cabb287f34da86b18c237e", + "reference": "6dfa655ac9e9860c05cabb287f34da86b18c237e", "shasum": "" }, "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/property-info": "^5.4|^6.0|^7.0" + "symfony/property-info": "^6.4.32|~7.3.10|^7.4.4" }, "require-dev": { "symfony/cache": "^5.4|^6.0|^7.0" }, - "time": "2025-08-12T15:42:57+00:00", + "time": "2026-01-05T08:25:17+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -4325,7 +4329,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v6.4.25" + "source": "https://github.com/symfony/property-access/tree/v6.4.32" }, "funding": [ { @@ -4349,17 +4353,17 @@ }, { "name": "symfony/property-info", - "version": "v6.4.24", - "version_normalized": "6.4.24.0", + "version": "v6.4.33", + "version_normalized": "6.4.33.0", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "1056ae3621eeddd78d7c5ec074f1c1784324eec6" + "reference": "7d961dbb543fcfaa57fa55e555edd466e90160be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/1056ae3621eeddd78d7c5ec074f1c1784324eec6", - "reference": "1056ae3621eeddd78d7c5ec074f1c1784324eec6", + "url": "https://api.github.com/repos/symfony/property-info/zipball/7d961dbb543fcfaa57fa55e555edd466e90160be", + "reference": "7d961dbb543fcfaa57fa55e555edd466e90160be", "shasum": "" }, "require": { @@ -4368,7 +4372,7 @@ }, "conflict": { "doctrine/annotations": "<1.12", - "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/reflection-docblock": "<5.2|>=6", "phpdocumentor/type-resolver": "<1.5.1", "symfony/cache": "<5.4", "symfony/dependency-injection": "<5.4|>=6.0,<6.4", @@ -4382,7 +4386,7 @@ "symfony/dependency-injection": "^5.4|^6.0|^7.0", "symfony/serializer": "^5.4|^6.4|^7.0" }, - "time": "2025-07-14T16:38:25+00:00", + "time": "2026-01-27T15:12:57+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -4418,7 +4422,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v6.4.24" + "source": "https://github.com/symfony/property-info/tree/v6.4.33" }, "funding": [ { @@ -4442,17 +4446,17 @@ }, { "name": "symfony/routing", - "version": "v6.4.24", - "version_normalized": "6.4.24.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "e4f94e625c8e6f910aa004a0042f7b2d398278f5" + "reference": "0dc6253e864e71b486e8ba4970a56ab849106ebe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/e4f94e625c8e6f910aa004a0042f7b2d398278f5", - "reference": "e4f94e625c8e6f910aa004a0042f7b2d398278f5", + "url": "https://api.github.com/repos/symfony/routing/zipball/0dc6253e864e71b486e8ba4970a56ab849106ebe", + "reference": "0dc6253e864e71b486e8ba4970a56ab849106ebe", "shasum": "" }, "require": { @@ -4474,7 +4478,7 @@ "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/yaml": "^5.4|^6.0|^7.0" }, - "time": "2025-07-15T08:46:37+00:00", + "time": "2026-01-12T08:31:19+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -4508,7 +4512,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.24" + "source": "https://github.com/symfony/routing/tree/v6.4.32" }, "funding": [ { @@ -4532,17 +4536,17 @@ }, { "name": "symfony/security-core", - "version": "v6.4.26", - "version_normalized": "6.4.26.0", + "version": "v6.4.31", + "version_normalized": "6.4.31.0", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "8b7c95bf04d82fcd0c06a918b2d849bfb2ab9cc0" + "reference": "fa269ad61a021cc54329dc96e57bed78ba720bfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/8b7c95bf04d82fcd0c06a918b2d849bfb2ab9cc0", - "reference": "8b7c95bf04d82fcd0c06a918b2d849bfb2ab9cc0", + "url": "https://api.github.com/repos/symfony/security-core/zipball/fa269ad61a021cc54329dc96e57bed78ba720bfe", + "reference": "fa269ad61a021cc54329dc96e57bed78ba720bfe", "shasum": "" }, "require": { @@ -4573,7 +4577,7 @@ "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", "symfony/validator": "^6.4|^7.0" }, - "time": "2025-09-02T19:15:26+00:00", + "time": "2025-12-17T22:32:13+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -4601,7 +4605,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.4.26" + "source": "https://github.com/symfony/security-core/tree/v6.4.31" }, "funding": [ { @@ -4625,17 +4629,17 @@ }, { "name": "symfony/security-csrf", - "version": "v6.4.24", - "version_normalized": "6.4.24.0", + "version": "v6.4.31", + "version_normalized": "6.4.31.0", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "9a1efc8c10b86bcedc9233affd10c716b54ca1b7" + "reference": "52f62836fcb19cd351ef3a2aa9cf61a489e8990f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/9a1efc8c10b86bcedc9233affd10c716b54ca1b7", - "reference": "9a1efc8c10b86bcedc9233affd10c716b54ca1b7", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/52f62836fcb19cd351ef3a2aa9cf61a489e8990f", + "reference": "52f62836fcb19cd351ef3a2aa9cf61a489e8990f", "shasum": "" }, "require": { @@ -4648,7 +4652,7 @@ "require-dev": { "symfony/http-foundation": "^5.4|^6.0|^7.0" }, - "time": "2025-07-10T08:14:14+00:00", + "time": "2025-12-17T22:32:13+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -4676,7 +4680,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v6.4.24" + "source": "https://github.com/symfony/security-csrf/tree/v6.4.31" }, "funding": [ { @@ -4859,17 +4863,17 @@ }, { "name": "symfony/string", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.30", + "version_normalized": "6.4.30.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1" + "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", - "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", + "url": "https://api.github.com/repos/symfony/string/zipball/50590a057841fa6bf69d12eceffce3465b9e32cb", + "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb", "shasum": "" }, "require": { @@ -4883,13 +4887,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": "2025-08-22T12:33:20+00:00", + "time": "2025-11-21T18:03:05+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -4928,7 +4931,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.25" + "source": "https://github.com/symfony/string/tree/v6.4.30" }, "funding": [ { @@ -4952,23 +4955,23 @@ }, { "name": "symfony/translation-contracts", - "version": "v3.6.0", - "version_normalized": "3.6.0.0", + "version": "v3.6.1", + "version_normalized": "3.6.1.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" + "reference": "65a8bc82080447fae78373aa10f8d13b38338977" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", + "reference": "65a8bc82080447fae78373aa10f8d13b38338977", "shasum": "" }, "require": { "php": ">=8.1" }, - "time": "2024-09-27T08:32:26+00:00", + "time": "2025-07-15T13:41:35+00:00", "type": "library", "extra": { "thanks": { @@ -5013,7 +5016,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1" }, "funding": [ { @@ -5024,6 +5027,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" @@ -5033,17 +5040,17 @@ }, { "name": "symfony/twig-bridge", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "9d13e87591c9de3221c8d6f23cd9a2b5958607bf" + "reference": "1dcf980dd4f79885b986befdeb1c1bc0d6aedfc8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/9d13e87591c9de3221c8d6f23cd9a2b5958607bf", - "reference": "9d13e87591c9de3221c8d6f23cd9a2b5958607bf", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/1dcf980dd4f79885b986befdeb1c1bc0d6aedfc8", + "reference": "1dcf980dd4f79885b986befdeb1c1bc0d6aedfc8", "shasum": "" }, "require": { @@ -5056,7 +5063,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/console": "<5.4", - "symfony/form": "<6.3", + "symfony/form": "<6.4.32|>7,<7.3.10|>7.4,<7.4.4", "symfony/http-foundation": "<5.4", "symfony/http-kernel": "<6.4", "symfony/mime": "<6.2", @@ -5074,7 +5081,7 @@ "symfony/dependency-injection": "^5.4|^6.0|^7.0", "symfony/expression-language": "^5.4|^6.0|^7.0", "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/form": "^6.4.20|^7.2.5", + "symfony/form": "^6.4.32|~7.3.10|^7.4.4", "symfony/html-sanitizer": "^6.1|^7.0", "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/http-kernel": "^6.4|^7.0", @@ -5097,7 +5104,7 @@ "twig/inky-extra": "^2.12|^3", "twig/markdown-extra": "^2.12|^3" }, - "time": "2025-08-13T09:41:44+00:00", + "time": "2026-01-03T23:03:08+00:00", "type": "symfony-bridge", "installation-source": "dist", "autoload": { @@ -5125,7 +5132,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.4.25" + "source": "https://github.com/symfony/twig-bridge/tree/v6.4.32" }, "funding": [ { @@ -5149,17 +5156,17 @@ }, { "name": "symfony/twig-bundle", - "version": "v6.4.24", - "version_normalized": "6.4.24.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "3b48b6e8225495c6d2438828982b4d219ca565ba" + "reference": "a5c8dcc11a5bf9c96320da20070d2e158a4e0b30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/3b48b6e8225495c6d2438828982b4d219ca565ba", - "reference": "3b48b6e8225495c6d2438828982b4d219ca565ba", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/a5c8dcc11a5bf9c96320da20070d2e158a4e0b30", + "reference": "a5c8dcc11a5bf9c96320da20070d2e158a4e0b30", "shasum": "" }, "require": { @@ -5188,7 +5195,7 @@ "symfony/web-link": "^5.4|^6.0|^7.0", "symfony/yaml": "^5.4|^6.0|^7.0" }, - "time": "2025-07-10T08:14:14+00:00", + "time": "2026-01-05T12:44:39+00:00", "type": "symfony-bundle", "installation-source": "dist", "autoload": { @@ -5216,7 +5223,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v6.4.24" + "source": "https://github.com/symfony/twig-bundle/tree/v6.4.32" }, "funding": [ { @@ -5240,17 +5247,17 @@ }, { "name": "symfony/validator", - "version": "v6.4.29", - "version_normalized": "6.4.29.0", + "version": "v6.4.33", + "version_normalized": "6.4.33.0", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "99df8a769e64e399f510166141ea74f450e8dd1d" + "reference": "da1a40418439c0483ca7e0d4ae4c4f744f6b8536" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/99df8a769e64e399f510166141ea74f450e8dd1d", - "reference": "99df8a769e64e399f510166141ea74f450e8dd1d", + "url": "https://api.github.com/repos/symfony/validator/zipball/da1a40418439c0483ca7e0d4ae4c4f744f6b8536", + "reference": "da1a40418439c0483ca7e0d4ae4c4f744f6b8536", "shasum": "" }, "require": { @@ -5291,7 +5298,7 @@ "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", "symfony/yaml": "^5.4|^6.0|^7.0" }, - "time": "2025-11-06T20:26:06+00:00", + "time": "2026-01-26T16:20:53+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -5320,7 +5327,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v6.4.29" + "source": "https://github.com/symfony/validator/tree/v6.4.33" }, "funding": [ { @@ -5344,17 +5351,17 @@ }, { "name": "symfony/var-dumper", - "version": "v6.4.26", - "version_normalized": "6.4.26.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a" + "reference": "131fc9915e0343052af5ed5040401b481ca192aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/cfae1497a2f1eaad78dbc0590311c599c7178d4a", - "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/131fc9915e0343052af5ed5040401b481ca192aa", + "reference": "131fc9915e0343052af5ed5040401b481ca192aa", "shasum": "" }, "require": { @@ -5373,7 +5380,7 @@ "symfony/uid": "^5.4|^6.0|^7.0", "twig/twig": "^2.13|^3.0.4" }, - "time": "2025-09-25T15:37:27+00:00", + "time": "2026-01-01T13:34:06+00:00", "bin": [ "Resources/bin/var-dump-server" ], @@ -5411,7 +5418,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.26" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.32" }, "funding": [ { @@ -5519,17 +5526,17 @@ }, { "name": "symfony/web-profiler-bundle", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.32", + "version_normalized": "6.4.32.0", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "4c1754d6b3ffe52e9eaed0d9a392eb43a60fc910" + "reference": "011f59e3f3d20f60d11b4e78b8dc63504f56e145" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/4c1754d6b3ffe52e9eaed0d9a392eb43a60fc910", - "reference": "4c1754d6b3ffe52e9eaed0d9a392eb43a60fc910", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/011f59e3f3d20f60d11b4e78b8dc63504f56e145", + "reference": "011f59e3f3d20f60d11b4e78b8dc63504f56e145", "shasum": "" }, "require": { @@ -5553,7 +5560,7 @@ "symfony/css-selector": "^5.4|^6.0|^7.0", "symfony/stopwatch": "^5.4|^6.0|^7.0" }, - "time": "2025-08-07T12:02:05+00:00", + "time": "2026-01-06T09:13:42+00:00", "type": "symfony-bundle", "installation-source": "dist", "autoload": { @@ -5584,7 +5591,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.25" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.32" }, "funding": [ { @@ -5608,17 +5615,17 @@ }, { "name": "symfony/yaml", - "version": "v6.4.25", - "version_normalized": "6.4.25.0", + "version": "v6.4.30", + "version_normalized": "6.4.30.0", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e54b060bc9c3dc3d4258bf0d165d0064e755f565" + "reference": "8207ae83da19ee3748d6d4f567b4d9a7c656e331" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e54b060bc9c3dc3d4258bf0d165d0064e755f565", - "reference": "e54b060bc9c3dc3d4258bf0d165d0064e755f565", + "url": "https://api.github.com/repos/symfony/yaml/zipball/8207ae83da19ee3748d6d4f567b4d9a7c656e331", + "reference": "8207ae83da19ee3748d6d4f567b4d9a7c656e331", "shasum": "" }, "require": { @@ -5632,7 +5639,7 @@ "require-dev": { "symfony/console": "^5.4|^6.0|^7.0" }, - "time": "2025-08-26T16:59:00+00:00", + "time": "2025-12-02T11:50:18+00:00", "bin": [ "Resources/bin/yaml-lint" ], @@ -5663,7 +5670,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.25" + "source": "https://github.com/symfony/yaml/tree/v6.4.30" }, "funding": [ { @@ -5824,17 +5831,17 @@ }, { "name": "twig/twig", - "version": "v3.21.1", - "version_normalized": "3.21.1.0", + "version": "v3.23.0", + "version_normalized": "3.23.0.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d" + "reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d", - "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", + "reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", "shasum": "" }, "require": { @@ -5848,7 +5855,7 @@ "psr/container": "^1.0|^2.0", "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, - "time": "2025-05-03T07:21:55+00:00", + "time": "2026-01-23T21:00:41+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -5890,7 +5897,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.21.1" + "source": "https://github.com/twigphp/Twig/tree/v3.23.0" }, "funding": [ { diff --git a/lib/composer/installed.php b/lib/composer/installed.php index 458ae0d688..d05367ff10 100644 --- a/lib/composer/installed.php +++ b/lib/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'combodo/itop', 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => '2b828f8a22d238f2221cc9e157c83d8d2ebd0696', + 'reference' => '0f11fd9919aab579586a6f52e1c74f317518040c', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -22,7 +22,7 @@ 'combodo/itop' => array( 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => '2b828f8a22d238f2221cc9e157c83d8d2ebd0696', + 'reference' => '0f11fd9919aab579586a6f52e1c74f317518040c', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -310,9 +310,9 @@ 'dev_requirement' => false, ), 'symfony/cache' => array( - 'pretty_version' => 'v6.4.12', - 'version' => '6.4.12.0', - 'reference' => 'a463451b7f6ac4a47b98dbfc78ec2d3560c759d8', + 'pretty_version' => 'v6.4.33', + 'version' => '6.4.33.0', + 'reference' => '5b088fa41eb9568748dc255c45e4054c387ba73b', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/cache', 'aliases' => array(), @@ -334,18 +334,18 @@ ), ), 'symfony/config' => array( - 'pretty_version' => 'v6.4.24', - 'version' => '6.4.24.0', - 'reference' => '80e2cf005cf17138c97193be0434cdcfd1b2212e', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => 'd445badf0ad2c2a492e38c0378c39997a56ef97b', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/config', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/console' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => '273fd29ff30ba0a88ca5fb83f7cf1ab69306adae', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), @@ -361,9 +361,9 @@ 'dev_requirement' => false, ), 'symfony/dependency-injection' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => '900da8a42eceeb4a13a0ec34caa7db49328daff3', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => 'b17882e933c4c606620247b6708ab53aa3b88753', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/dependency-injection', 'aliases' => array(), @@ -379,27 +379,27 @@ 'dev_requirement' => false, ), 'symfony/dotenv' => array( - 'pretty_version' => 'v6.4.24', - 'version' => '6.4.24.0', - 'reference' => '234b6c602f12b00693f4b0d1054386fb30dfc8ff', + 'pretty_version' => 'v6.4.30', + 'version' => '6.4.30.0', + 'reference' => '924edbc9631b75302def0258ed1697948b17baf6', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/dotenv', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/error-handler' => array( - 'pretty_version' => 'v6.4.24', - 'version' => '6.4.24.0', - 'reference' => '30fd0b3cf0e972e82636038ce4db0e4fe777112c', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '8c18400784fcb014dc73c8d5601a9576af7f8ad4', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/error-handler', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/event-dispatcher' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => 'b0cf3162020603587363f0551cd3be43958611ff', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '99d7e101826e6610606b9433248f80c1997cd20b', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/event-dispatcher', 'aliases' => array(), @@ -421,90 +421,90 @@ ), ), 'symfony/filesystem' => array( - 'pretty_version' => 'v6.4.24', - 'version' => '6.4.24.0', - 'reference' => '75ae2edb7cdcc0c53766c30b0a2512b8df574bd8', + 'pretty_version' => 'v6.4.30', + 'version' => '6.4.30.0', + 'reference' => '441c6b69f7222aadae7cbf5df588496d5ee37789', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/filesystem', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/finder' => array( - 'pretty_version' => 'v6.4.24', - 'version' => '6.4.24.0', - 'reference' => '73089124388c8510efb8d2d1689285d285937b08', + 'pretty_version' => 'v6.4.33', + 'version' => '6.4.33.0', + 'reference' => '24965ca011dac87431729640feef8bcf7b5523e0', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/finder', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/form' => array( - 'pretty_version' => 'v6.4.26', - 'version' => '6.4.26.0', - 'reference' => 'b40cdbe70be9274ea807ef61da7d0f8d1c70dc51', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => 'b758162fb45024f898640ec27f4ac90be0dbfb8f', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/form', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/framework-bundle' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => '1d6a764b58e4f780df00f71c20ba3a61095ea447', + 'pretty_version' => 'v6.4.33', + 'version' => '6.4.33.0', + 'reference' => '9ef2d0b63b9e855ba351e770a603d89699115801', 'type' => 'symfony-bundle', 'install_path' => __DIR__ . '/../symfony/framework-bundle', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/http-foundation' => array( - 'pretty_version' => 'v6.4.29', - 'version' => '6.4.29.0', - 'reference' => 'b03d11e015552a315714c127d8d1e0f9e970ec88', + 'pretty_version' => 'v6.4.33', + 'version' => '6.4.33.0', + 'reference' => 'f1a490cc9d595ba7ebe684220e625d1e472ad278', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-foundation', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/http-kernel' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => 'a0ee3cea5cabf4ed960fd2ef57668ceeacdb6e15', + 'pretty_version' => 'v6.4.33', + 'version' => '6.4.33.0', + 'reference' => '73fa5c999d7f741ca544a97d3c791cc97890ae4d', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-kernel', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/mailer' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => '628b43b45a3e6b15c8a633fb22df547ed9b492a2', + 'pretty_version' => 'v6.4.31', + 'version' => '6.4.31.0', + 'reference' => '8835f93333474780fda1b987cae37e33c3e026ca', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/mailer', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/mime' => array( - 'pretty_version' => 'v6.4.24', - 'version' => '6.4.24.0', - 'reference' => '664d5e844a2de5e11c8255d0aef6bc15a9660ac7', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '7409686879ca36c09fc970a5fa8ff6e93504dba4', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/mime', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/options-resolver' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => 'd28e7e2db8a73e9511df892d36445f61314bbebe', + 'pretty_version' => 'v6.4.30', + 'version' => '6.4.30.0', + 'reference' => 'eeaa8cabe54c7b3516938c72a4a161c0cc80a34f', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/options-resolver', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/password-hasher' => array( - 'pretty_version' => 'v6.4.24', - 'version' => '6.4.24.0', - 'reference' => 'dcab5ac87450aaed26483ba49c2ce86808da7557', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => 'fbdfa5a2ca218ec8bb9029517426df2d780bdba9', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/password-hasher', 'aliases' => array(), @@ -574,45 +574,45 @@ 'dev_requirement' => false, ), 'symfony/property-access' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => 'fedc771326d4978a7d3167fa009a509b06a2e168', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '6dfa655ac9e9860c05cabb287f34da86b18c237e', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/property-access', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/property-info' => array( - 'pretty_version' => 'v6.4.24', - 'version' => '6.4.24.0', - 'reference' => '1056ae3621eeddd78d7c5ec074f1c1784324eec6', + 'pretty_version' => 'v6.4.33', + 'version' => '6.4.33.0', + 'reference' => '7d961dbb543fcfaa57fa55e555edd466e90160be', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/property-info', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/routing' => array( - 'pretty_version' => 'v6.4.24', - 'version' => '6.4.24.0', - 'reference' => 'e4f94e625c8e6f910aa004a0042f7b2d398278f5', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '0dc6253e864e71b486e8ba4970a56ab849106ebe', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/routing', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/security-core' => array( - 'pretty_version' => 'v6.4.26', - 'version' => '6.4.26.0', - 'reference' => '8b7c95bf04d82fcd0c06a918b2d849bfb2ab9cc0', + 'pretty_version' => 'v6.4.31', + 'version' => '6.4.31.0', + 'reference' => 'fa269ad61a021cc54329dc96e57bed78ba720bfe', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/security-core', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/security-csrf' => array( - 'pretty_version' => 'v6.4.24', - 'version' => '6.4.24.0', - 'reference' => '9a1efc8c10b86bcedc9233affd10c716b54ca1b7', + 'pretty_version' => 'v6.4.31', + 'version' => '6.4.31.0', + 'reference' => '52f62836fcb19cd351ef3a2aa9cf61a489e8990f', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/security-csrf', 'aliases' => array(), @@ -643,54 +643,54 @@ 'dev_requirement' => true, ), 'symfony/string' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => '7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1', + '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-contracts' => array( - 'pretty_version' => 'v3.6.0', - 'version' => '3.6.0.0', - 'reference' => 'df210c7a2573f1913b2d17cc95f90f53a73d8f7d', + 'pretty_version' => 'v3.6.1', + 'version' => '3.6.1.0', + 'reference' => '65a8bc82080447fae78373aa10f8d13b38338977', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/translation-contracts', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/twig-bridge' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => '9d13e87591c9de3221c8d6f23cd9a2b5958607bf', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '1dcf980dd4f79885b986befdeb1c1bc0d6aedfc8', 'type' => 'symfony-bridge', 'install_path' => __DIR__ . '/../symfony/twig-bridge', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/twig-bundle' => array( - 'pretty_version' => 'v6.4.24', - 'version' => '6.4.24.0', - 'reference' => '3b48b6e8225495c6d2438828982b4d219ca565ba', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => 'a5c8dcc11a5bf9c96320da20070d2e158a4e0b30', 'type' => 'symfony-bundle', 'install_path' => __DIR__ . '/../symfony/twig-bundle', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/validator' => array( - 'pretty_version' => 'v6.4.29', - 'version' => '6.4.29.0', - 'reference' => '99df8a769e64e399f510166141ea74f450e8dd1d', + 'pretty_version' => 'v6.4.33', + 'version' => '6.4.33.0', + 'reference' => 'da1a40418439c0483ca7e0d4ae4c4f744f6b8536', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/validator', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/var-dumper' => array( - 'pretty_version' => 'v6.4.26', - 'version' => '6.4.26.0', - 'reference' => 'cfae1497a2f1eaad78dbc0590311c599c7178d4a', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '131fc9915e0343052af5ed5040401b481ca192aa', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/var-dumper', 'aliases' => array(), @@ -706,18 +706,18 @@ 'dev_requirement' => false, ), 'symfony/web-profiler-bundle' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => '4c1754d6b3ffe52e9eaed0d9a392eb43a60fc910', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '011f59e3f3d20f60d11b4e78b8dc63504f56e145', 'type' => 'symfony-bundle', 'install_path' => __DIR__ . '/../symfony/web-profiler-bundle', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/yaml' => array( - 'pretty_version' => 'v6.4.25', - 'version' => '6.4.25.0', - 'reference' => 'e54b060bc9c3dc3d4258bf0d165d0064e755f565', + 'pretty_version' => 'v6.4.30', + 'version' => '6.4.30.0', + 'reference' => '8207ae83da19ee3748d6d4f567b4d9a7c656e331', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/yaml', 'aliases' => array(), @@ -742,9 +742,9 @@ 'dev_requirement' => false, ), 'twig/twig' => array( - 'pretty_version' => 'v3.21.1', - 'version' => '3.21.1.0', - 'reference' => '285123877d4dd97dd7c11842ac5fb7e86e60d81d', + 'pretty_version' => 'v3.23.0', + 'version' => '3.23.0.0', + 'reference' => 'a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9', 'type' => 'library', 'install_path' => __DIR__ . '/../twig/twig', 'aliases' => array(), diff --git a/lib/symfony/cache/Adapter/AbstractAdapter.php b/lib/symfony/cache/Adapter/AbstractAdapter.php index 7525fe0394..bf04ae08cb 100644 --- a/lib/symfony/cache/Adapter/AbstractAdapter.php +++ b/lib/symfony/cache/Adapter/AbstractAdapter.php @@ -40,7 +40,7 @@ protected function __construct(string $namespace = '', int $defaultLifetime = 0) $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).static::NS_SEPARATOR; $this->defaultLifetime = $defaultLifetime; if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { - throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace)); + throw new InvalidArgumentException(\sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace)); } self::$createCacheItem ??= \Closure::bind( static function ($key, $value, $isHit) { @@ -155,7 +155,7 @@ public function commit(): bool $ok = false; $v = $values[$id]; $type = get_debug_type($v); - $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + $message = \sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); } } else { @@ -178,7 +178,7 @@ public function commit(): bool } $ok = false; $type = get_debug_type($v); - $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + $message = \sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); } } diff --git a/lib/symfony/cache/Adapter/AbstractTagAwareAdapter.php b/lib/symfony/cache/Adapter/AbstractTagAwareAdapter.php index ef62b4fb21..a1af6141b9 100644 --- a/lib/symfony/cache/Adapter/AbstractTagAwareAdapter.php +++ b/lib/symfony/cache/Adapter/AbstractTagAwareAdapter.php @@ -42,7 +42,7 @@ protected function __construct(string $namespace = '', int $defaultLifetime = 0) $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; $this->defaultLifetime = $defaultLifetime; if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { - throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace)); + throw new InvalidArgumentException(\sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace)); } self::$createCacheItem ??= \Closure::bind( static function ($key, $value, $isHit) { @@ -194,7 +194,7 @@ public function commit(): bool $ok = false; $v = $values[$id]; $type = get_debug_type($v); - $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + $message = \sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); } } else { @@ -218,7 +218,7 @@ public function commit(): bool } $ok = false; $type = get_debug_type($v); - $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + $message = \sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null, 'cache-adapter' => get_debug_type($this)]); } } diff --git a/lib/symfony/cache/Adapter/ApcuAdapter.php b/lib/symfony/cache/Adapter/ApcuAdapter.php index 2eddb49a7f..50ce8448e3 100644 --- a/lib/symfony/cache/Adapter/ApcuAdapter.php +++ b/lib/symfony/cache/Adapter/ApcuAdapter.php @@ -82,7 +82,7 @@ protected function doHave(string $id): bool protected function doClear(string $namespace): bool { return isset($namespace[0]) && class_exists(\APCUIterator::class, false) && ('cli' !== \PHP_SAPI || filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOL)) - ? apcu_delete(new \APCUIterator(sprintf('/^%s/', preg_quote($namespace, '/')), \APC_ITER_KEY)) + ? apcu_delete(new \APCUIterator(\sprintf('/^%s/', preg_quote($namespace, '/')), \APC_ITER_KEY)) : apcu_clear_cache(); } @@ -101,19 +101,10 @@ protected function doSave(array $values, int $lifetime): array|bool return $failed; } - try { - if (false === $failures = apcu_store($values, null, $lifetime)) { - $failures = $values; - } - - return array_keys($failures); - } catch (\Throwable $e) { - if (1 === \count($values)) { - // Workaround https://github.com/krakjoe/apcu/issues/170 - apcu_delete(array_key_first($values)); - } - - throw $e; + if (false === $failures = apcu_store($values, null, $lifetime)) { + $failures = $values; } + + return array_keys($failures); } } diff --git a/lib/symfony/cache/Adapter/ArrayAdapter.php b/lib/symfony/cache/Adapter/ArrayAdapter.php index 660a52646e..38e19cbddd 100644 --- a/lib/symfony/cache/Adapter/ArrayAdapter.php +++ b/lib/symfony/cache/Adapter/ArrayAdapter.php @@ -46,11 +46,11 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true, float $maxLifetime = 0, int $maxItems = 0) { if (0 > $maxLifetime) { - throw new InvalidArgumentException(sprintf('Argument $maxLifetime must be positive, %F passed.', $maxLifetime)); + throw new InvalidArgumentException(\sprintf('Argument $maxLifetime must be positive, %F passed.', $maxLifetime)); } if (0 > $maxItems) { - throw new InvalidArgumentException(sprintf('Argument $maxItems must be a positive integer, %d passed.', $maxItems)); + throw new InvalidArgumentException(\sprintf('Argument $maxItems must be a positive integer, %d passed.', $maxItems)); } $this->defaultLifetime = $defaultLifetime; @@ -312,9 +312,11 @@ private function freeze($value, string $key): string|int|float|bool|array|\UnitE try { $serialized = serialize($value); } catch (\Exception $e) { - unset($this->values[$key], $this->tags[$key]); + if (!isset($this->expiries[$key])) { + unset($this->values[$key]); + } $type = get_debug_type($value); - $message = sprintf('Failed to save key "{key}" of type %s: %s', $type, $e->getMessage()); + $message = \sprintf('Failed to save key "{key}" of type %s: %s', $type, $e->getMessage()); CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]); return null; diff --git a/lib/symfony/cache/Adapter/ChainAdapter.php b/lib/symfony/cache/Adapter/ChainAdapter.php index 221b1fb5de..1d187f65cf 100644 --- a/lib/symfony/cache/Adapter/ChainAdapter.php +++ b/lib/symfony/cache/Adapter/ChainAdapter.php @@ -51,7 +51,7 @@ public function __construct(array $adapters, int $defaultLifetime = 0) foreach ($adapters as $adapter) { if (!$adapter instanceof CacheItemPoolInterface) { - throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', get_debug_type($adapter), CacheItemPoolInterface::class)); + throw new InvalidArgumentException(\sprintf('The class "%s" does not implement the "%s" interface.', get_debug_type($adapter), CacheItemPoolInterface::class)); } if ('cli' === \PHP_SAPI && $adapter instanceof ApcuAdapter && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOL)) { continue; // skip putting APCu in the chain when the backend is disabled @@ -76,7 +76,7 @@ static function ($sourceItem, $item, $defaultLifetime, $sourceMetadata = null) { $item->metadata = $item->newMetadata = $sourceItem->metadata = $sourceMetadata; if (isset($item->metadata[CacheItem::METADATA_EXPIRY])) { - $item->expiresAt(\DateTimeImmutable::createFromFormat('U.u', sprintf('%.6F', $item->metadata[CacheItem::METADATA_EXPIRY]))); + $item->expiresAt(\DateTimeImmutable::createFromFormat('U.u', \sprintf('%.6F', $item->metadata[CacheItem::METADATA_EXPIRY]))); } elseif (0 < $defaultLifetime) { $item->expiresAfter($defaultLifetime); } @@ -106,7 +106,7 @@ public function get(string $key, callable $callback, ?float $beta = null, ?array $callback = $wrap; $beta = \INF === $beta ? \INF : 0; } - if ($adapter instanceof CacheInterface) { + if ($adapter instanceof CacheInterface && $i !== $this->adapterCount) { $value = $adapter->get($key, $callback, $beta, $metadata); } else { $value = $this->doGet($adapter, $key, $callback, $beta, $metadata); diff --git a/lib/symfony/cache/Adapter/DoctrineDbalAdapter.php b/lib/symfony/cache/Adapter/DoctrineDbalAdapter.php index 9d02be3aa2..1866083b48 100644 --- a/lib/symfony/cache/Adapter/DoctrineDbalAdapter.php +++ b/lib/symfony/cache/Adapter/DoctrineDbalAdapter.php @@ -62,7 +62,7 @@ class DoctrineDbalAdapter extends AbstractAdapter implements PruneableInterface public function __construct(Connection|string $connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], ?MarshallerInterface $marshaller = null) { if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) { - throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0])); + throw new InvalidArgumentException(\sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0])); } if ($connOrDsn instanceof Connection) { @@ -151,7 +151,7 @@ public function prune(): bool if ('' !== $this->namespace) { $deleteSql .= " AND $this->idCol LIKE ?"; - $params[] = sprintf('%s%%', $this->namespace); + $params[] = \sprintf('%s%%', $this->namespace); $paramTypes[] = ParameterType::STRING; } diff --git a/lib/symfony/cache/Adapter/MemcachedAdapter.php b/lib/symfony/cache/Adapter/MemcachedAdapter.php index 0efa152ee3..9f983f0ad7 100644 --- a/lib/symfony/cache/Adapter/MemcachedAdapter.php +++ b/lib/symfony/cache/Adapter/MemcachedAdapter.php @@ -25,7 +25,7 @@ class MemcachedAdapter extends AbstractAdapter /** * We are replacing characters that are illegal in Memcached keys with reserved characters from * {@see \Symfony\Contracts\Cache\ItemInterface::RESERVED_CHARACTERS} that are legal in Memcached. - * Note: don’t use {@see \Symfony\Component\Cache\Adapter\AbstractAdapter::NS_SEPARATOR}. + * Note: don’t use {@see AbstractAdapter::NS_SEPARATOR}. */ private const RESERVED_MEMCACHED = " \n\r\t\v\f\0"; private const RESERVED_PSR6 = '@()\{}/'; @@ -314,7 +314,7 @@ private function getClient(): \Memcached throw new CacheException('MemcachedAdapter: "serializer" option must be "php" or "igbinary".'); } if ('' !== $prefix = (string) $this->lazyClient->getOption(\Memcached::OPT_PREFIX_KEY)) { - throw new CacheException(sprintf('MemcachedAdapter: "prefix_key" option must be empty when using proxified connections, "%s" given.', $prefix)); + throw new CacheException(\sprintf('MemcachedAdapter: "prefix_key" option must be empty when using proxified connections, "%s" given.', $prefix)); } return $this->client = $this->lazyClient; diff --git a/lib/symfony/cache/Adapter/ParameterNormalizer.php b/lib/symfony/cache/Adapter/ParameterNormalizer.php index a6896402f7..483df1c0bc 100644 --- a/lib/symfony/cache/Adapter/ParameterNormalizer.php +++ b/lib/symfony/cache/Adapter/ParameterNormalizer.php @@ -29,7 +29,7 @@ public static function normalizeDuration(string $duration): int try { return \DateTimeImmutable::createFromFormat('U', 0)->add(new \DateInterval($duration))->getTimestamp(); } catch (\Exception $e) { - throw new \InvalidArgumentException(sprintf('Cannot parse date interval "%s".', $duration), 0, $e); + throw new \InvalidArgumentException(\sprintf('Cannot parse date interval "%s".', $duration), 0, $e); } } } diff --git a/lib/symfony/cache/Adapter/PdoAdapter.php b/lib/symfony/cache/Adapter/PdoAdapter.php index c79b739594..f5865993d2 100644 --- a/lib/symfony/cache/Adapter/PdoAdapter.php +++ b/lib/symfony/cache/Adapter/PdoAdapter.php @@ -57,16 +57,16 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface public function __construct(#[\SensitiveParameter] \PDO|string $connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], ?MarshallerInterface $marshaller = null) { if (\is_string($connOrDsn) && str_contains($connOrDsn, '://')) { - throw new InvalidArgumentException(sprintf('Usage of Doctrine DBAL URL with "%s" is not supported. Use a PDO DSN or "%s" instead.', __CLASS__, DoctrineDbalAdapter::class)); + throw new InvalidArgumentException(\sprintf('Usage of Doctrine DBAL URL with "%s" is not supported. Use a PDO DSN or "%s" instead.', __CLASS__, DoctrineDbalAdapter::class)); } if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) { - throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0])); + throw new InvalidArgumentException(\sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0])); } if ($connOrDsn instanceof \PDO) { if (\PDO::ERRMODE_EXCEPTION !== $connOrDsn->getAttribute(\PDO::ATTR_ERRMODE)) { - throw new InvalidArgumentException(sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)).', __CLASS__)); + throw new InvalidArgumentException(\sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)).', __CLASS__)); } $this->conn = $connOrDsn; @@ -108,12 +108,12 @@ public function createTable() // - trailing space removal // - case-insensitivity // - language processing like é == e - 'mysql' => "CREATE TABLE $this->table ($this->idCol VARBINARY(255) NOT NULL PRIMARY KEY, $this->dataCol MEDIUMBLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8mb4_bin, ENGINE = InnoDB", + 'mysql' => "CREATE TABLE $this->table ($this->idCol VARBINARY(255) NOT NULL PRIMARY KEY, $this->dataCol MEDIUMBLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED, $this->timeCol INTEGER UNSIGNED NOT NULL), ENGINE = InnoDB", 'sqlite' => "CREATE TABLE $this->table ($this->idCol TEXT NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", 'pgsql' => "CREATE TABLE $this->table ($this->idCol VARCHAR(255) NOT NULL PRIMARY KEY, $this->dataCol BYTEA NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", 'oci' => "CREATE TABLE $this->table ($this->idCol VARCHAR2(255) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", 'sqlsrv' => "CREATE TABLE $this->table ($this->idCol VARCHAR(255) NOT NULL PRIMARY KEY, $this->dataCol VARBINARY(MAX) NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", - default => throw new \DomainException(sprintf('Creating the cache table is currently not implemented for PDO driver "%s".', $driver)), + default => throw new \DomainException(\sprintf('Creating the cache table is currently not implemented for PDO driver "%s".', $driver)), }; $this->getConnection()->exec($sql); @@ -137,7 +137,7 @@ public function prune(): bool $delete->bindValue(':time', time(), \PDO::PARAM_INT); if ('' !== $this->namespace) { - $delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), \PDO::PARAM_STR); + $delete->bindValue(':namespace', \sprintf('%s%%', $this->namespace), \PDO::PARAM_STR); } try { return $delete->execute(); @@ -314,7 +314,17 @@ protected function doSave(array $values, int $lifetime): array|bool $insertStmt->bindValue(':time', $now, \PDO::PARAM_INT); } + if ('sqlsrv' === $driver) { + $dataStream = fopen('php://memory', 'r+'); + } foreach ($values as $id => $data) { + if ('sqlsrv' === $driver) { + rewind($dataStream); + fwrite($dataStream, $data); + ftruncate($dataStream, \strlen($data)); + rewind($dataStream); + $data = $dataStream; + } try { $stmt->execute(); } catch (\PDOException $e) { diff --git a/lib/symfony/cache/Adapter/PhpArrayAdapter.php b/lib/symfony/cache/Adapter/PhpArrayAdapter.php index 0cda1cce8d..6c3d707245 100644 --- a/lib/symfony/cache/Adapter/PhpArrayAdapter.php +++ b/lib/symfony/cache/Adapter/PhpArrayAdapter.php @@ -17,6 +17,7 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\CachedValueInterface; use Symfony\Component\Cache\Traits\ContractsTrait; use Symfony\Component\Cache\Traits\ProxyTrait; use Symfony\Component\VarExporter\VarExporter; @@ -96,22 +97,21 @@ public function get(string $key, callable $callback, ?float $beta = null, ?array if ('N;' === $value) { return null; } + if (!$value instanceof CachedValueInterface) { + return $value; + } try { - if ($value instanceof \Closure) { - return $value(); - } + return $value->getValue(); } catch (\Throwable) { unset($this->keys[$key]); goto get_from_pool; } - - return $value; } public function getItem(mixed $key): CacheItem { if (!\is_string($key)) { - throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + throw new InvalidArgumentException(\sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); } if (!isset($this->values)) { $this->initialize(); @@ -125,9 +125,9 @@ public function getItem(mixed $key): CacheItem if ('N;' === $value) { $value = null; - } elseif ($value instanceof \Closure) { + } elseif ($value instanceof CachedValueInterface) { try { - $value = $value(); + $value = $value->getValue(); } catch (\Throwable) { $value = null; $isHit = false; @@ -141,7 +141,7 @@ public function getItems(array $keys = []): iterable { foreach ($keys as $key) { if (!\is_string($key)) { - throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + throw new InvalidArgumentException(\sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); } } if (!isset($this->values)) { @@ -154,7 +154,7 @@ public function getItems(array $keys = []): iterable public function hasItem(mixed $key): bool { if (!\is_string($key)) { - throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + throw new InvalidArgumentException(\sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); } if (!isset($this->values)) { $this->initialize(); @@ -166,7 +166,7 @@ public function hasItem(mixed $key): bool public function deleteItem(mixed $key): bool { if (!\is_string($key)) { - throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + throw new InvalidArgumentException(\sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); } if (!isset($this->values)) { $this->initialize(); @@ -182,7 +182,7 @@ public function deleteItems(array $keys): bool foreach ($keys as $key) { if (!\is_string($key)) { - throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + throw new InvalidArgumentException(\sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); } if (isset($this->keys[$key])) { @@ -250,21 +250,21 @@ public function warmUp(array $values): array { if (file_exists($this->file)) { if (!is_file($this->file)) { - throw new InvalidArgumentException(sprintf('Cache path exists and is not a file: "%s".', $this->file)); + throw new InvalidArgumentException(\sprintf('Cache path exists and is not a file: "%s".', $this->file)); } if (!is_writable($this->file)) { - throw new InvalidArgumentException(sprintf('Cache file is not writable: "%s".', $this->file)); + throw new InvalidArgumentException(\sprintf('Cache file is not writable: "%s".', $this->file)); } } else { $directory = \dirname($this->file); if (!is_dir($directory) && !@mkdir($directory, 0777, true)) { - throw new InvalidArgumentException(sprintf('Cache directory does not exist and cannot be created: "%s".', $directory)); + throw new InvalidArgumentException(\sprintf('Cache directory does not exist and cannot be created: "%s".', $directory)); } if (!is_writable($directory)) { - throw new InvalidArgumentException(sprintf('Cache directory is not writable: "%s".', $directory)); + throw new InvalidArgumentException(\sprintf('Cache directory is not writable: "%s".', $directory)); } } @@ -291,7 +291,7 @@ public function warmUp(array $values): array try { $value = VarExporter::export($value, $isStaticValue, $preload); } catch (\Exception $e) { - throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value)), 0, $e); + throw new InvalidArgumentException(\sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value)), 0, $e); } } elseif (\is_string($value)) { // Wrap "N;" in a closure to not confuse it with an encoded `null` @@ -300,14 +300,13 @@ public function warmUp(array $values): array } $value = var_export($value, true); } elseif (!\is_scalar($value)) { - throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value))); + throw new InvalidArgumentException(\sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value))); } else { $value = var_export($value, true); } if (!$isStaticValue) { - $value = str_replace("\n", "\n ", $value); - $value = "static function () {\n return {$value};\n}"; + $value = 'new class() implements \\'.CachedValueInterface::class." { public function getValue(): mixed { return {$value}; } }"; } $hash = hash('xxh128', $value); @@ -368,9 +367,9 @@ private function generateItems(array $keys): \Generator if ('N;' === $value) { yield $key => $f($key, null, true); - } elseif ($value instanceof \Closure) { + } elseif ($value instanceof CachedValueInterface) { try { - yield $key => $f($key, $value(), true); + yield $key => $f($key, $value->getValue(), true); } catch (\Throwable) { yield $key => $f($key, null, false); } diff --git a/lib/symfony/cache/Adapter/PhpFilesAdapter.php b/lib/symfony/cache/Adapter/PhpFilesAdapter.php index e550276df4..70d0894451 100644 --- a/lib/symfony/cache/Adapter/PhpFilesAdapter.php +++ b/lib/symfony/cache/Adapter/PhpFilesAdapter.php @@ -14,6 +14,7 @@ use Symfony\Component\Cache\Exception\CacheException; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\Traits\CachedValueInterface; use Symfony\Component\Cache\Traits\FilesystemCommonTrait; use Symfony\Component\VarExporter\VarExporter; @@ -114,8 +115,10 @@ protected function doFetch(array $ids): iterable $values[$id] = null; } elseif (!\is_object($value)) { $values[$id] = $value; + } elseif ($value instanceof CachedValueInterface) { + $values[$id] = $value->getValue(); } elseif (!$value instanceof LazyValue) { - $values[$id] = $value(); + $values[$id] = $value; } elseif (false === $values[$id] = include $value->file) { unset($values[$id], $this->values[$id]); $missingIds[] = $id; @@ -152,7 +155,7 @@ protected function doFetch(array $ids): iterable if ($now >= $expiresAt) { unset($this->values[$id], $missingIds[$k], self::$valuesCache[$file]); } - } catch (\ErrorException $e) { + } catch (\ErrorException) { unset($missingIds[$k]); } } @@ -217,7 +220,7 @@ protected function doSave(array $values, int $lifetime): array|bool try { $value = VarExporter::export($value, $isStaticValue); } catch (\Exception $e) { - throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value)), 0, $e); + throw new InvalidArgumentException(\sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value)), 0, $e); } } elseif (\is_string($value)) { // Wrap "N;" in a closure to not confuse it with an encoded `null` @@ -226,7 +229,7 @@ protected function doSave(array $values, int $lifetime): array|bool } $value = var_export($value, true); } elseif (!\is_scalar($value)) { - throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value))); + throw new InvalidArgumentException(\sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value))); } else { $value = var_export($value, true); } @@ -236,7 +239,7 @@ protected function doSave(array $values, int $lifetime): array|bool if ($isStaticValue) { $value = "return [{$expiry}, {$value}];"; } elseif ($this->appendOnly) { - $value = "return [{$expiry}, static fn () => {$value}];"; + $value = "return [{$expiry}, new class() implements \\".CachedValueInterface::class." { public function getValue(): mixed { return {$value}; } }];"; } else { // We cannot use a closure here because of https://bugs.php.net/76982 $value = str_replace('\Symfony\Component\VarExporter\Internal\\', '', $value); @@ -255,7 +258,7 @@ protected function doSave(array $values, int $lifetime): array|bool } if (!$ok && !is_writable($this->directory)) { - throw new CacheException(sprintf('Cache directory is not writable (%s).', $this->directory)); + throw new CacheException(\sprintf('Cache directory is not writable (%s).', $this->directory)); } return $ok; diff --git a/lib/symfony/cache/Adapter/ProxyAdapter.php b/lib/symfony/cache/Adapter/ProxyAdapter.php index c022dd5fa9..5621226069 100644 --- a/lib/symfony/cache/Adapter/ProxyAdapter.php +++ b/lib/symfony/cache/Adapter/ProxyAdapter.php @@ -73,7 +73,7 @@ static function ($key, $innerItem, $poolHash) { self::$setInnerItem ??= \Closure::bind( static function (CacheItemInterface $innerItem, CacheItem $item, $expiry = null) { $innerItem->set($item->pack()); - $innerItem->expiresAt(($expiry ?? $item->expiry) ? \DateTimeImmutable::createFromFormat('U.u', sprintf('%.6F', $expiry ?? $item->expiry)) : null); + $innerItem->expiresAt(($expiry ?? $item->expiry) ? \DateTimeImmutable::createFromFormat('U.u', \sprintf('%.6F', $expiry ?? $item->expiry)) : null); }, null, CacheItem::class diff --git a/lib/symfony/cache/Adapter/RedisTagAwareAdapter.php b/lib/symfony/cache/Adapter/RedisTagAwareAdapter.php index a44ef986dc..9aa959add2 100644 --- a/lib/symfony/cache/Adapter/RedisTagAwareAdapter.php +++ b/lib/symfony/cache/Adapter/RedisTagAwareAdapter.php @@ -14,6 +14,7 @@ use Predis\Connection\Aggregate\ClusterInterface; use Predis\Connection\Aggregate\PredisCluster; use Predis\Connection\Aggregate\ReplicationInterface; +use Predis\Connection\Replication\ReplicationInterface as Predis2ReplicationInterface; use Predis\Response\ErrorInterface; use Predis\Response\Status; use Relay\Relay; @@ -63,7 +64,7 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter public function __construct(\Redis|Relay|\RedisArray|\RedisCluster|\Predis\ClientInterface $redis, string $namespace = '', int $defaultLifetime = 0, ?MarshallerInterface $marshaller = null) { if ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof ClusterInterface && !$redis->getConnection() instanceof PredisCluster) { - throw new InvalidArgumentException(sprintf('Unsupported Predis cluster connection: only "%s" is, "%s" given.', PredisCluster::class, get_debug_type($redis->getConnection()))); + throw new InvalidArgumentException(\sprintf('Unsupported Predis cluster connection: only "%s" is, "%s" given.', PredisCluster::class, get_debug_type($redis->getConnection()))); } $isRelay = $redis instanceof Relay; @@ -72,7 +73,7 @@ public function __construct(\Redis|Relay|\RedisArray|\RedisCluster|\Predis\Clien foreach (\is_array($compression) ? $compression : [$compression] as $c) { if ($isRelay ? Relay::COMPRESSION_NONE : \Redis::COMPRESSION_NONE !== $c) { - throw new InvalidArgumentException(sprintf('redis compression must be disabled when using "%s", use "%s" instead.', static::class, DeflateMarshaller::class)); + throw new InvalidArgumentException(\sprintf('redis compression must be disabled when using "%s", use "%s" instead.', static::class, DeflateMarshaller::class)); } } } @@ -85,7 +86,7 @@ protected function doSave(array $values, int $lifetime, array $addTagData = [], { $eviction = $this->getRedisEvictionPolicy(); if ('noeviction' !== $eviction && !str_starts_with($eviction, 'volatile-')) { - throw new LogicException(sprintf('Redis maxmemory-policy setting "%s" is *not* supported by RedisTagAwareAdapter, use "noeviction" or "volatile-*" eviction policies.', $eviction)); + throw new LogicException(\sprintf('Redis maxmemory-policy setting "%s" is *not* supported by RedisTagAwareAdapter, use "noeviction" or "volatile-*" eviction policies.', $eviction)); } // serialize values @@ -286,9 +287,16 @@ private function getRedisEvictionPolicy(): string $hosts = $this->getHosts(); $host = reset($hosts); - if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) { + if ($host instanceof \Predis\Client) { + $connection = $host->getConnection(); + // Predis supports info command only on the master in replication environments - $hosts = [$host->getClientFor('master')]; + if ($connection instanceof ReplicationInterface) { + $hosts = [$host->getClientFor('master')]; + } elseif ($connection instanceof Predis2ReplicationInterface) { + $connection->switchToMaster(); + $hosts = [$host]; + } } foreach ($hosts as $host) { diff --git a/lib/symfony/cache/Adapter/TagAwareAdapter.php b/lib/symfony/cache/Adapter/TagAwareAdapter.php index 539ef1697f..a12e908ad7 100644 --- a/lib/symfony/cache/Adapter/TagAwareAdapter.php +++ b/lib/symfony/cache/Adapter/TagAwareAdapter.php @@ -294,15 +294,12 @@ public function reset() $this->tags instanceof ResettableInterface && $this->tags->reset(); } - 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__); } @@ -366,7 +363,7 @@ private function getTagVersions(array $tagsByKey, bool $persistTags): array (self::$saveTags)($this->tags, $newTags); } - while ($now > ($this->knownTagVersions[$tag = array_key_first($this->knownTagVersions)][0] ?? \INF)) { + while ($now > ($this->knownTagVersions[$tag = array_key_first($this->knownTagVersions) ?? ''][0] ?? \INF)) { unset($this->knownTagVersions[$tag]); } diff --git a/lib/symfony/cache/Adapter/TraceableAdapter.php b/lib/symfony/cache/Adapter/TraceableAdapter.php index 8569fa2831..1e99295419 100644 --- a/lib/symfony/cache/Adapter/TraceableAdapter.php +++ b/lib/symfony/cache/Adapter/TraceableAdapter.php @@ -38,7 +38,7 @@ public function __construct(AdapterInterface $pool) public function get(string $key, callable $callback, ?float $beta = null, ?array &$metadata = null): mixed { if (!$this->pool instanceof CacheInterface) { - throw new \BadMethodCallException(sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', get_debug_type($this->pool), CacheInterface::class)); + throw new \BadMethodCallException(\sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', get_debug_type($this->pool), CacheInterface::class)); } $isHit = true; diff --git a/lib/symfony/cache/CacheItem.php b/lib/symfony/cache/CacheItem.php index 1a81706da9..1aa5bcdced 100644 --- a/lib/symfony/cache/CacheItem.php +++ b/lib/symfony/cache/CacheItem.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache; +use Psr\Cache\CacheItemInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Exception\LogicException; @@ -30,7 +31,7 @@ final class CacheItem implements ItemInterface protected float|int|null $expiry = null; protected array $metadata = []; protected array $newMetadata = []; - protected ?ItemInterface $innerItem = null; + protected ?CacheItemInterface $innerItem = null; protected ?string $poolHash = null; protected bool $isTaggable = false; @@ -81,7 +82,7 @@ public function expiresAfter(mixed $time): static } elseif (\is_int($time)) { $this->expiry = $time + microtime(true); } else { - throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', get_debug_type($time))); + throw new InvalidArgumentException(\sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', get_debug_type($time))); } return $this; @@ -90,14 +91,14 @@ public function expiresAfter(mixed $time): static public function tag(mixed $tags): static { if (!$this->isTaggable) { - throw new LogicException(sprintf('Cache item "%s" comes from a non tag-aware pool: you cannot tag it.', $this->key)); + throw new LogicException(\sprintf('Cache item "%s" comes from a non tag-aware pool: you cannot tag it.', $this->key)); } if (!\is_array($tags) && !$tags instanceof \Traversable) { // don't use is_iterable(), it's slow $tags = [$tags]; } foreach ($tags as $tag) { if (!\is_string($tag) && !$tag instanceof \Stringable) { - throw new InvalidArgumentException(sprintf('Cache tag must be string or object that implements __toString(), "%s" given.', get_debug_type($tag))); + throw new InvalidArgumentException(\sprintf('Cache tag must be string or object that implements __toString(), "%s" given.', get_debug_type($tag))); } $tag = (string) $tag; if (isset($this->newMetadata[self::METADATA_TAGS][$tag])) { @@ -107,7 +108,7 @@ public function tag(mixed $tags): static throw new InvalidArgumentException('Cache tag length must be greater than zero.'); } if (false !== strpbrk($tag, self::RESERVED_CHARACTERS)) { - throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters "%s".', $tag, self::RESERVED_CHARACTERS)); + throw new InvalidArgumentException(\sprintf('Cache tag "%s" contains reserved characters "%s".', $tag, self::RESERVED_CHARACTERS)); } $this->newMetadata[self::METADATA_TAGS][$tag] = $tag; } @@ -130,13 +131,13 @@ public function getMetadata(): array public static function validateKey($key): string { if (!\is_string($key)) { - throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); + throw new InvalidArgumentException(\sprintf('Cache key must be string, "%s" given.', get_debug_type($key))); } if ('' === $key) { throw new InvalidArgumentException('Cache key length must be greater than zero.'); } if (false !== strpbrk($key, self::RESERVED_CHARACTERS)) { - throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS)); + throw new InvalidArgumentException(\sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS)); } return $key; @@ -196,3 +197,5 @@ private function unpack(): bool return true; } } + +// @php-cs-fixer-ignore protected_to_private Friend-level scope access relies on protected properties diff --git a/lib/symfony/cache/DataCollector/CacheDataCollector.php b/lib/symfony/cache/DataCollector/CacheDataCollector.php index b9bcdaf132..73886cb4d7 100644 --- a/lib/symfony/cache/DataCollector/CacheDataCollector.php +++ b/lib/symfony/cache/DataCollector/CacheDataCollector.php @@ -38,15 +38,7 @@ public function addInstance(string $name, TraceableAdapter $instance): void public function collect(Request $request, Response $response, ?\Throwable $exception = null): void { - $empty = ['calls' => [], 'adapters' => [], 'config' => [], 'options' => [], 'statistics' => []]; - $this->data = ['instances' => $empty, 'total' => $empty]; - foreach ($this->instances as $name => $instance) { - $this->data['instances']['calls'][$name] = $instance->getCalls(); - $this->data['instances']['adapters'][$name] = get_debug_type($instance->getPool()); - } - - $this->data['instances']['statistics'] = $this->calculateStatistics(); - $this->data['total']['statistics'] = $this->calculateTotalStatistics(); + $this->lateCollect(); } public function reset(): void @@ -59,6 +51,15 @@ public function reset(): void public function lateCollect(): void { + $empty = ['calls' => [], 'adapters' => [], 'config' => [], 'options' => [], 'statistics' => []]; + $this->data = ['instances' => $empty, 'total' => $empty]; + foreach ($this->instances as $name => $instance) { + $this->data['instances']['calls'][$name] = $instance->getCalls(); + $this->data['instances']['adapters'][$name] = get_debug_type($instance->getPool()); + } + + $this->data['instances']['statistics'] = $this->calculateStatistics(); + $this->data['total']['statistics'] = $this->calculateTotalStatistics(); $this->data['instances']['calls'] = $this->cloneVar($this->data['instances']['calls']); } @@ -142,6 +143,8 @@ private function calculateStatistics(): array } } elseif ('save' === $call->name) { ++$statistics[$name]['writes']; + } elseif ('saveDeferred' === $call->name) { + ++$statistics[$name]['writes']; } elseif ('deleteItem' === $call->name) { ++$statistics[$name]['deletes']; } diff --git a/lib/symfony/cache/DependencyInjection/CachePoolPass.php b/lib/symfony/cache/DependencyInjection/CachePoolPass.php index f6622f27bd..9d2273d905 100644 --- a/lib/symfony/cache/DependencyInjection/CachePoolPass.php +++ b/lib/symfony/cache/DependencyInjection/CachePoolPass.php @@ -16,7 +16,9 @@ use Symfony\Component\Cache\Adapter\ChainAdapter; use Symfony\Component\Cache\Adapter\NullAdapter; use Symfony\Component\Cache\Adapter\ParameterNormalizer; +use Symfony\Component\Cache\Adapter\TagAwareAdapter; use Symfony\Component\Cache\Messenger\EarlyExpirationDispatcher; +use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -51,6 +53,7 @@ public function process(ContainerBuilder $container) 'default_lifetime', 'early_expiration_message_bus', 'reset', + 'pruneable', ]; foreach ($container->findTaggedServiceIds('cache.pool') as $id => $tags) { $adapter = $pool = $container->getDefinition($id); @@ -58,9 +61,11 @@ public function process(ContainerBuilder $container) continue; } $class = $adapter->getClass(); + $providers = $adapter->getArguments(); while ($adapter instanceof ChildDefinition) { $adapter = $container->findDefinition($adapter->getParent()); $class = $class ?: $adapter->getClass(); + $providers += $adapter->getArguments(); if ($t = $adapter->getTag('cache.pool')) { $tags[0] += $t[0]; } @@ -88,11 +93,13 @@ public function process(ContainerBuilder $container) $tags[0]['provider'] = new Reference(static::getServiceProvider($container, $tags[0]['provider'])); } + $pruneable = $tags[0]['pruneable'] ?? $container->getReflectionClass($class, false)?->implementsInterface(PruneableInterface::class) ?? false; + if (ChainAdapter::class === $class) { $adapters = []; - foreach ($adapter->getArgument(0) as $provider => $adapter) { + foreach ($providers['index_0'] ?? $providers[0] as $provider => $adapter) { if ($adapter instanceof ChildDefinition) { - $chainedPool = $adapter; + $chainedPool = clone $adapter; } else { $chainedPool = $adapter = new ChildDefinition($adapter); } @@ -109,7 +116,7 @@ public function process(ContainerBuilder $container) } if (ChainAdapter::class === $chainedClass) { - throw new InvalidArgumentException(sprintf('Invalid service "%s": chain of adapters cannot reference another chain, found "%s".', $id, $chainedPool->getParent())); + throw new InvalidArgumentException(\sprintf('Invalid service "%s": chain of adapters cannot reference another chain, found "%s".', $id, $chainedPool->getParent())); } $i = 0; @@ -154,7 +161,9 @@ public function process(ContainerBuilder $container) ), ]); $pool->addTag('container.reversible'); - } elseif ('namespace' !== $attr || !\in_array($class, [ArrayAdapter::class, NullAdapter::class], true)) { + } elseif ('pruneable' === $attr) { + // no-op + } elseif ('namespace' !== $attr || !\in_array($class, [ArrayAdapter::class, NullAdapter::class, TagAwareAdapter::class], true)) { $argument = $tags[0][$attr]; if ('default_lifetime' === $attr && !is_numeric($argument)) { @@ -167,13 +176,17 @@ public function process(ContainerBuilder $container) unset($tags[0][$attr]); } if (!empty($tags[0])) { - throw new InvalidArgumentException(sprintf('Invalid "cache.pool" tag for service "%s": accepted attributes are "clearer", "provider", "name", "namespace", "default_lifetime", "early_expiration_message_bus" and "reset", found "%s".', $id, implode('", "', array_keys($tags[0])))); + throw new InvalidArgumentException(\sprintf('Invalid "cache.pool" tag for service "%s": accepted attributes are "clearer", "provider", "name", "namespace", "default_lifetime", "early_expiration_message_bus", "reset" and "pruneable", found "%s".', $id, implode('", "', array_keys($tags[0])))); } if (null !== $clearer) { $clearers[$clearer][$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE); } + $poolTags = $pool->getTags(); + $poolTags['cache.pool'][0]['pruneable'] ??= $pruneable; + $pool->setTags($poolTags); + $allPools[$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE); } @@ -197,10 +210,6 @@ public function process(ContainerBuilder $container) $clearer->setArgument(0, $pools); } $clearer->addTag('cache.pool.clearer'); - - if ('cache.system_clearer' === $id) { - $clearer->addTag('kernel.cache_clearer'); - } } $allPoolsKeys = array_keys($allPools); diff --git a/lib/symfony/cache/DependencyInjection/CachePoolPrunerPass.php b/lib/symfony/cache/DependencyInjection/CachePoolPrunerPass.php index 00e912686b..8700231414 100644 --- a/lib/symfony/cache/DependencyInjection/CachePoolPrunerPass.php +++ b/lib/symfony/cache/DependencyInjection/CachePoolPrunerPass.php @@ -15,7 +15,6 @@ use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; /** @@ -35,14 +34,8 @@ public function process(ContainerBuilder $container) $services = []; foreach ($container->findTaggedServiceIds('cache.pool') as $id => $tags) { - $class = $container->getParameterBag()->resolveValue($container->getDefinition($id)->getClass()); - - if (!$reflection = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); - } - - if ($reflection->implementsInterface(PruneableInterface::class)) { - $services[$id] = new Reference($id); + if ($tags[0]['pruneable'] ?? $container->getReflectionClass($container->getDefinition($id)->getClass(), false)?->implementsInterface(PruneableInterface::class) ?? false) { + $services[$tags[0]['name'] ?? $id] = new Reference($id); } } diff --git a/lib/symfony/cache/LockRegistry.php b/lib/symfony/cache/LockRegistry.php index c5c5fde898..31ec51ced9 100644 --- a/lib/symfony/cache/LockRegistry.php +++ b/lib/symfony/cache/LockRegistry.php @@ -83,7 +83,7 @@ public static function setFiles(array $files): array return $previousFiles; } - public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, ?\Closure $setMetadata = null, ?LoggerInterface $logger = null): mixed + public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, ?\Closure $setMetadata = null, ?LoggerInterface $logger = null, ?float $beta = null): mixed { if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedFiles) { // disable locking on Windows by default @@ -105,7 +105,7 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s $locked = flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock); if ($locked || !$wouldBlock) { - $logger?->info(sprintf('Lock %s, now computing item "{key}"', $locked ? 'acquired' : 'not supported'), ['key' => $item->getKey()]); + $logger?->info(\sprintf('Lock %s, now computing item "{key}"', $locked ? 'acquired' : 'not supported'), ['key' => $item->getKey()]); self::$lockedFiles[$key] = true; $value = $callback($item, $save); @@ -124,6 +124,11 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s // if we failed the race, retry locking in blocking mode to wait for the winner $logger?->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]); flock($lock, \LOCK_SH); + + if (\INF === $beta) { + $logger?->info('Force-recomputing item "{key}"', ['key' => $item->getKey()]); + continue; + } } finally { flock($lock, \LOCK_UN); unset(self::$lockedFiles[$key]); diff --git a/lib/symfony/cache/Messenger/EarlyExpirationDispatcher.php b/lib/symfony/cache/Messenger/EarlyExpirationDispatcher.php index 8fe0f2515d..5c8cf8d679 100644 --- a/lib/symfony/cache/Messenger/EarlyExpirationDispatcher.php +++ b/lib/symfony/cache/Messenger/EarlyExpirationDispatcher.php @@ -37,13 +37,13 @@ public function __construct(MessageBusInterface $bus, ReverseContainer $reverseC /** * @return mixed */ - public function __invoke(callable $callback, CacheItem $item, bool &$save, AdapterInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger = null) + public function __invoke(callable $callback, CacheItem $item, bool &$save, AdapterInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger = null, ?float $beta = null) { if (!$item->isHit() || null === $message = EarlyExpirationMessage::create($this->reverseContainer, $callback, $item, $pool)) { // The item is stale or the callback cannot be reversed: we must compute the value now $logger?->info('Computing item "{key}" online: '.($item->isHit() ? 'callback cannot be reversed' : 'item is stale'), ['key' => $item->getKey()]); - return null !== $this->callbackWrapper ? ($this->callbackWrapper)($callback, $item, $save, $pool, $setMetadata, $logger) : $callback($item, $save); + return null !== $this->callbackWrapper ? ($this->callbackWrapper)($callback, $item, $save, $pool, $setMetadata, $logger, $beta) : $callback($item, $save); } $envelope = $this->bus->dispatch($message); diff --git a/lib/symfony/cache/Messenger/EarlyExpirationMessage.php b/lib/symfony/cache/Messenger/EarlyExpirationMessage.php index 6056ebab46..99cca0499e 100644 --- a/lib/symfony/cache/Messenger/EarlyExpirationMessage.php +++ b/lib/symfony/cache/Messenger/EarlyExpirationMessage.php @@ -35,6 +35,11 @@ public static function create(ReverseContainer $reverseContainer, callable $call $pool = $reverseContainer->getId($pool); + if ($callback instanceof \Closure && !str_contains(($r = new \ReflectionFunction($callback))->name, '{closure')) { + $callback = [$r->getClosureThis() ?? (\PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass())?->name, $r->name]; + $callback[0] ?: $callback = $r->name; + } + if (\is_object($callback)) { if (null === $id = $reverseContainer->getId($callback)) { return null; diff --git a/lib/symfony/cache/Psr16Cache.php b/lib/symfony/cache/Psr16Cache.php index f21384fee9..01494d7142 100644 --- a/lib/symfony/cache/Psr16Cache.php +++ b/lib/symfony/cache/Psr16Cache.php @@ -135,7 +135,7 @@ public function getMultiple($keys, $default = null): iterable if ($keys instanceof \Traversable) { $keys = iterator_to_array($keys, false); } elseif (!\is_array($keys)) { - throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', get_debug_type($keys))); + throw new InvalidArgumentException(\sprintf('Cache keys must be array or Traversable, "%s" given.', get_debug_type($keys))); } try { @@ -166,7 +166,7 @@ public function setMultiple($values, $ttl = null): bool { $valuesIsArray = \is_array($values); if (!$valuesIsArray && !$values instanceof \Traversable) { - throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given.', get_debug_type($values))); + throw new InvalidArgumentException(\sprintf('Cache values must be array or Traversable, "%s" given.', get_debug_type($values))); } $items = []; @@ -215,7 +215,7 @@ public function deleteMultiple($keys): bool if ($keys instanceof \Traversable) { $keys = iterator_to_array($keys, false); } elseif (!\is_array($keys)) { - throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', get_debug_type($keys))); + throw new InvalidArgumentException(\sprintf('Cache keys must be array or Traversable, "%s" given.', get_debug_type($keys))); } try { diff --git a/lib/symfony/cache/Traits/AbstractAdapterTrait.php b/lib/symfony/cache/Traits/AbstractAdapterTrait.php index 4ab2537db9..c5b5e4a91a 100644 --- a/lib/symfony/cache/Traits/AbstractAdapterTrait.php +++ b/lib/symfony/cache/Traits/AbstractAdapterTrait.php @@ -276,15 +276,12 @@ public function reset(): void $this->ids = []; } - 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__); } @@ -303,7 +300,7 @@ private function generateItems(iterable $items, array &$keys): \Generator try { foreach ($items as $id => $value) { if (!isset($keys[$id])) { - throw new InvalidArgumentException(sprintf('Could not match value id "%s" to keys "%s".', $id, implode('", "', $keys))); + throw new InvalidArgumentException(\sprintf('Could not match value id "%s" to keys "%s".', $id, implode('", "', $keys))); } $key = $keys[$id]; unset($keys[$id]); diff --git a/lib/symfony/cache/Traits/CachedValueInterface.php b/lib/symfony/cache/Traits/CachedValueInterface.php new file mode 100644 index 0000000000..8e95f60b07 --- /dev/null +++ b/lib/symfony/cache/Traits/CachedValueInterface.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +/** + * @internal + */ +interface CachedValueInterface +{ + public function getValue(): mixed; +} diff --git a/lib/symfony/cache/Traits/ContractsTrait.php b/lib/symfony/cache/Traits/ContractsTrait.php index 8d830f0abf..c93256ebae 100644 --- a/lib/symfony/cache/Traits/ContractsTrait.php +++ b/lib/symfony/cache/Traits/ContractsTrait.php @@ -54,7 +54,7 @@ public function setCallbackWrapper(?callable $callbackWrapper): callable } $previousWrapper = $this->callbackWrapper; - $this->callbackWrapper = $callbackWrapper ?? static fn (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) => $callback($item, $save); + $this->callbackWrapper = $callbackWrapper ?? static fn (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger, ?float $beta = null) => $callback($item, $save); return $previousWrapper; } @@ -62,7 +62,7 @@ public function setCallbackWrapper(?callable $callbackWrapper): callable private function doGet(AdapterInterface $pool, string $key, callable $callback, ?float $beta, ?array &$metadata = null): mixed { if (0 > $beta ??= 1.0) { - throw new InvalidArgumentException(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)); + throw new InvalidArgumentException(\sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)); } static $setMetadata; @@ -82,7 +82,7 @@ static function (CacheItem $item, float $startTime, ?array &$metadata) { $this->callbackWrapper ??= LockRegistry::compute(...); - return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata, $key) { + return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata, $key, $beta) { // don't wrap nor save recursive calls if (isset($this->computing[$key])) { $value = $callback($item, $save); @@ -101,7 +101,7 @@ static function (CacheItem $item, float $startTime, ?array &$metadata) { try { $value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { $setMetadata($item, $startTime, $metadata); - }, $this->logger ?? null); + }, $this->logger ?? null, $beta); $setMetadata($item, $startTime, $metadata); return $value; diff --git a/lib/symfony/cache/Traits/FilesystemCommonTrait.php b/lib/symfony/cache/Traits/FilesystemCommonTrait.php index 3b976b66f6..09e8e26fdd 100644 --- a/lib/symfony/cache/Traits/FilesystemCommonTrait.php +++ b/lib/symfony/cache/Traits/FilesystemCommonTrait.php @@ -32,7 +32,7 @@ private function init(string $namespace, ?string $directory): void } if (isset($namespace[0])) { if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) { - throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0])); + throw new InvalidArgumentException(\sprintf('Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0])); } $directory .= \DIRECTORY_SEPARATOR.$namespace; } else { @@ -44,7 +44,7 @@ private function init(string $namespace, ?string $directory): void $directory .= \DIRECTORY_SEPARATOR; // On Windows the whole path is limited to 258 chars if ('\\' === \DIRECTORY_SEPARATOR && \strlen($directory) > 234) { - throw new InvalidArgumentException(sprintf('Cache directory too long (%s).', $directory)); + throw new InvalidArgumentException(\sprintf('Cache directory too long (%s).', $directory)); } $this->directory = $directory; @@ -172,15 +172,12 @@ private function scanHashDir(string $directory): \Generator } } - 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/lib/symfony/cache/Traits/FilesystemTrait.php b/lib/symfony/cache/Traits/FilesystemTrait.php index 47e9b838ff..05fa10e964 100644 --- a/lib/symfony/cache/Traits/FilesystemTrait.php +++ b/lib/symfony/cache/Traits/FilesystemTrait.php @@ -92,7 +92,7 @@ protected function doSave(array $values, int $lifetime): array|bool } if ($failed && !is_writable($this->directory)) { - throw new CacheException(sprintf('Cache directory is not writable (%s).', $this->directory)); + throw new CacheException(\sprintf('Cache directory is not writable (%s).', $this->directory)); } return $failed; diff --git a/lib/symfony/cache/Traits/Redis6ProxyTrait.php b/lib/symfony/cache/Traits/Redis61ProxyTrait.php similarity index 98% rename from lib/symfony/cache/Traits/Redis6ProxyTrait.php rename to lib/symfony/cache/Traits/Redis61ProxyTrait.php index 34f60cb102..0ec7b57625 100644 --- a/lib/symfony/cache/Traits/Redis6ProxyTrait.php +++ b/lib/symfony/cache/Traits/Redis61ProxyTrait.php @@ -15,7 +15,7 @@ /** * @internal */ - trait Redis6ProxyTrait + trait Redis61ProxyTrait { public function dump($key): \Redis|string|false { @@ -51,7 +51,7 @@ public function waitaof($numlocal, $numreplicas, $timeout): \Redis|array|false /** * @internal */ - trait Redis6ProxyTrait + trait Redis61ProxyTrait { public function dump($key): \Redis|string { diff --git a/lib/symfony/cache/Traits/Redis62ProxyTrait.php b/lib/symfony/cache/Traits/Redis62ProxyTrait.php new file mode 100644 index 0000000000..4ea807220e --- /dev/null +++ b/lib/symfony/cache/Traits/Redis62ProxyTrait.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +if (version_compare(phpversion('redis'), '6.2.0', '>=')) { + /** + * @internal + */ + trait Redis62ProxyTrait + { + public function expiremember($key, $field, $ttl, $unit = null): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expiremember(...\func_get_args()); + } + + public function expirememberat($key, $field, $timestamp): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expirememberat(...\func_get_args()); + } + + public function getWithMeta($key): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getWithMeta(...\func_get_args()); + } + + public function serverName(): false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->serverName(...\func_get_args()); + } + + public function serverVersion(): false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->serverVersion(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait Redis62ProxyTrait + { + } +} diff --git a/lib/symfony/cache/Traits/Redis63ProxyTrait.php b/lib/symfony/cache/Traits/Redis63ProxyTrait.php new file mode 100644 index 0000000000..6f6b370173 --- /dev/null +++ b/lib/symfony/cache/Traits/Redis63ProxyTrait.php @@ -0,0 +1,162 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +if (version_compare(phpversion('redis'), '6.3.0', '>=')) { + /** + * @internal + */ + trait Redis63ProxyTrait + { + public function delifeq($key, $value): \Redis|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->delifeq(...\func_get_args()); + } + + public function hexpire($key, $ttl, $fields, $mode = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpire(...\func_get_args()); + } + + public function hexpireat($key, $time, $fields, $mode = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpireat(...\func_get_args()); + } + + public function hexpiretime($key, $fields): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpiretime(...\func_get_args()); + } + + public function hgetdel($key, $fields): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetdel(...\func_get_args()); + } + + public function hgetex($key, $fields, $expiry = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetex(...\func_get_args()); + } + + public function hGetWithMeta($key, $member): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hGetWithMeta(...\func_get_args()); + } + + public function hpersist($key, $fields): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpersist(...\func_get_args()); + } + + public function hpexpire($key, $ttl, $fields, $mode = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpire(...\func_get_args()); + } + + public function hpexpireat($key, $mstime, $fields, $mode = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpireat(...\func_get_args()); + } + + public function hpexpiretime($key, $fields): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpiretime(...\func_get_args()); + } + + public function hpttl($key, $fields): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpttl(...\func_get_args()); + } + + public function hsetex($key, $fields, $expiry = null): \Redis|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hsetex(...\func_get_args()); + } + + public function httl($key, $fields): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->httl(...\func_get_args()); + } + + public function vadd($key, $values, $element, $options = null): \Redis|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vadd(...\func_get_args()); + } + + public function vcard($key): \Redis|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vcard(...\func_get_args()); + } + + public function vdim($key): \Redis|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vdim(...\func_get_args()); + } + + public function vemb($key, $member, $raw = false): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vemb(...\func_get_args()); + } + + public function vgetattr($key, $member, $decode = true): \Redis|array|string|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vgetattr(...\func_get_args()); + } + + public function vinfo($key): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vinfo(...\func_get_args()); + } + + public function vismember($key, $member): \Redis|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vismember(...\func_get_args()); + } + + public function vlinks($key, $member, $withscores = false): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vlinks(...\func_get_args()); + } + + public function vrandmember($key, $count = 0): \Redis|array|string|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vrandmember(...\func_get_args()); + } + + public function vrange($key, $min, $max, $count = -1): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vrange(...\func_get_args()); + } + + public function vrem($key, $member): \Redis|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vrem(...\func_get_args()); + } + + public function vsetattr($key, $member, $attributes): \Redis|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vsetattr(...\func_get_args()); + } + + public function vsim($key, $member, $options = null): \Redis|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vsim(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait Redis63ProxyTrait + { + } +} diff --git a/lib/symfony/cache/Traits/Redis6Proxy.php b/lib/symfony/cache/Traits/Redis6Proxy.php index c841d4269b..e321fee624 100644 --- a/lib/symfony/cache/Traits/Redis6Proxy.php +++ b/lib/symfony/cache/Traits/Redis6Proxy.php @@ -25,7 +25,9 @@ class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class); */ class Redis6Proxy extends \Redis implements ResetInterface, LazyObjectInterface { - use Redis6ProxyTrait; + use Redis61ProxyTrait; + use Redis62ProxyTrait; + use Redis63ProxyTrait; use LazyProxyTrait { resetLazyObject as reset; } diff --git a/lib/symfony/cache/Traits/RedisCluster6ProxyTrait.php b/lib/symfony/cache/Traits/RedisCluster61ProxyTrait.php similarity index 95% rename from lib/symfony/cache/Traits/RedisCluster6ProxyTrait.php rename to lib/symfony/cache/Traits/RedisCluster61ProxyTrait.php index 9c3169e323..9ff5b19da5 100644 --- a/lib/symfony/cache/Traits/RedisCluster6ProxyTrait.php +++ b/lib/symfony/cache/Traits/RedisCluster61ProxyTrait.php @@ -15,7 +15,7 @@ /** * @internal */ - trait RedisCluster6ProxyTrait + trait RedisCluster61ProxyTrait { public function getex($key, $options = []): \RedisCluster|string|false { @@ -36,7 +36,7 @@ public function waitaof($key_or_address, $numlocal, $numreplicas, $timeout): \Re /** * @internal */ - trait RedisCluster6ProxyTrait + trait RedisCluster61ProxyTrait { public function publish($channel, $message): \RedisCluster|bool { diff --git a/lib/symfony/cache/Traits/RedisCluster62ProxyTrait.php b/lib/symfony/cache/Traits/RedisCluster62ProxyTrait.php new file mode 100644 index 0000000000..e8f864a05f --- /dev/null +++ b/lib/symfony/cache/Traits/RedisCluster62ProxyTrait.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +if (version_compare(phpversion('redis'), '6.2.0', '>=')) { + /** + * @internal + */ + trait RedisCluster62ProxyTrait + { + public function expiremember($key, $field, $ttl, $unit = null): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expiremember(...\func_get_args()); + } + + public function expirememberat($key, $field, $timestamp): \Redis|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->expirememberat(...\func_get_args()); + } + + public function getdel($key): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getdel(...\func_get_args()); + } + + public function getWithMeta($key): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getWithMeta(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait RedisCluster62ProxyTrait + { + } +} diff --git a/lib/symfony/cache/Traits/RedisCluster63ProxyTrait.php b/lib/symfony/cache/Traits/RedisCluster63ProxyTrait.php new file mode 100644 index 0000000000..374f96214b --- /dev/null +++ b/lib/symfony/cache/Traits/RedisCluster63ProxyTrait.php @@ -0,0 +1,162 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +if (version_compare(phpversion('redis'), '6.3.0', '>=')) { + /** + * @internal + */ + trait RedisCluster63ProxyTrait + { + public function delifeq($key, $value): \RedisCluster|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->delifeq(...\func_get_args()); + } + + public function hexpire($key, $ttl, $fields, $mode = null): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpire(...\func_get_args()); + } + + public function hexpireat($key, $time, $fields, $mode = null): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpireat(...\func_get_args()); + } + + public function hexpiretime($key, $fields): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpiretime(...\func_get_args()); + } + + public function hgetdel($key, $fields): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetdel(...\func_get_args()); + } + + public function hgetex($key, $fields, $expiry = null): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetex(...\func_get_args()); + } + + public function hgetWithMeta($key, $member): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetWithMeta(...\func_get_args()); + } + + public function hpersist($key, $fields): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpersist(...\func_get_args()); + } + + public function hpexpire($key, $ttl, $fields, $mode = null): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpire(...\func_get_args()); + } + + public function hpexpireat($key, $mstime, $fields, $mode = null): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpireat(...\func_get_args()); + } + + public function hpexpiretime($key, $fields): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpiretime(...\func_get_args()); + } + + public function hpttl($key, $fields): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpttl(...\func_get_args()); + } + + public function hsetex($key, $fields, $expiry = null): \RedisCluster|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hsetex(...\func_get_args()); + } + + public function httl($key, $fields): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->httl(...\func_get_args()); + } + + public function vadd($key, $values, $element, $options = null): \RedisCluster|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vadd(...\func_get_args()); + } + + public function vcard($key): \RedisCluster|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vcard(...\func_get_args()); + } + + public function vdim($key): \RedisCluster|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vdim(...\func_get_args()); + } + + public function vemb($key, $member, $raw = false): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vemb(...\func_get_args()); + } + + public function vgetattr($key, $member, $decode = true): \RedisCluster|array|string|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vgetattr(...\func_get_args()); + } + + public function vinfo($key): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vinfo(...\func_get_args()); + } + + public function vismember($key, $member): \RedisCluster|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vismember(...\func_get_args()); + } + + public function vlinks($key, $member, $withscores = false): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vlinks(...\func_get_args()); + } + + public function vrandmember($key, $count = 0): \RedisCluster|array|string|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vrandmember(...\func_get_args()); + } + + public function vrange($key, $min, $max, $count = -1): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vrange(...\func_get_args()); + } + + public function vrem($key, $member): \RedisCluster|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vrem(...\func_get_args()); + } + + public function vsetattr($key, $member, $attributes): \RedisCluster|int|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vsetattr(...\func_get_args()); + } + + public function vsim($key, $member, $options = null): \RedisCluster|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vsim(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait RedisCluster63ProxyTrait + { + } +} diff --git a/lib/symfony/cache/Traits/RedisCluster6Proxy.php b/lib/symfony/cache/Traits/RedisCluster6Proxy.php index c19aa1620a..1ea025dd0f 100644 --- a/lib/symfony/cache/Traits/RedisCluster6Proxy.php +++ b/lib/symfony/cache/Traits/RedisCluster6Proxy.php @@ -25,7 +25,9 @@ class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class); */ class RedisCluster6Proxy extends \RedisCluster implements ResetInterface, LazyObjectInterface { - use RedisCluster6ProxyTrait; + use RedisCluster61ProxyTrait; + use RedisCluster62ProxyTrait; + use RedisCluster63ProxyTrait; use LazyProxyTrait { resetLazyObject as reset; } diff --git a/lib/symfony/cache/Traits/RedisTrait.php b/lib/symfony/cache/Traits/RedisTrait.php index 2a1fa39216..c3fc689909 100644 --- a/lib/symfony/cache/Traits/RedisTrait.php +++ b/lib/symfony/cache/Traits/RedisTrait.php @@ -17,6 +17,7 @@ use Predis\Connection\Aggregate\ReplicationInterface; use Predis\Connection\Cluster\ClusterInterface as Predis2ClusterInterface; use Predis\Connection\Cluster\RedisCluster as Predis2RedisCluster; +use Predis\Connection\Replication\ReplicationInterface as Predis2ReplicationInterface; use Predis\Response\ErrorInterface; use Predis\Response\Status; use Relay\Relay; @@ -36,6 +37,7 @@ trait RedisTrait { private static array $defaultConnectionOptions = [ 'class' => null, + 'auth' => null, 'persistent' => 0, 'persistent_id' => null, 'timeout' => 30, @@ -57,7 +59,7 @@ private function init(\Redis|Relay|\RedisArray|\RedisCluster|\Predis\ClientInter parent::__construct($namespace, $defaultLifetime); if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) { - throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0])); + throw new InvalidArgumentException(\sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0])); } if ($redis instanceof \Predis\ClientInterface && $redis->getOptions()->exceptions) { @@ -94,10 +96,11 @@ public static function createConnection(#[\SensitiveParameter] string $dsn, arra throw new InvalidArgumentException('Invalid Redis DSN: it does not start with "redis[s]:".'); } - if (!\extension_loaded('redis') && !class_exists(\Predis\Client::class)) { - throw new CacheException('Cannot find the "redis" extension nor the "predis/predis" package.'); + if (!\extension_loaded('redis') && !\extension_loaded('relay') && !class_exists(\Predis\Client::class)) { + throw new CacheException('Cannot find the "redis" extension nor the "relay" extension nor the "predis/predis" package.'); } + $auth = null; $params = preg_replace_callback('#^'.$scheme.':(//)?(?:(?:(?[^:@]*+):)?(?[^@]*+)@)?#', function ($m) use (&$auth) { if (isset($m['password'])) { if (\in_array($m['user'], ['', 'default'], true)) { @@ -172,6 +175,7 @@ public static function createConnection(#[\SensitiveParameter] string $dsn, arra } $params += $query + $options + self::$defaultConnectionOptions; + $params['auth'] ??= $auth; if (isset($params['redis_sentinel']) && !class_exists(\Predis\Client::class) && !class_exists(\RedisSentinel::class) && !class_exists(Sentinel::class)) { throw new CacheException('Redis Sentinel support requires one of: "predis/predis", "ext-redis >= 5.2", "ext-relay".'); @@ -200,7 +204,7 @@ public static function createConnection(#[\SensitiveParameter] string $dsn, arra }; if (isset($params['redis_sentinel']) && !is_a($class, \Predis\Client::class, true) && !class_exists(\RedisSentinel::class) && !class_exists(Sentinel::class)) { - throw new CacheException(sprintf('Cannot use Redis Sentinel: class "%s" does not extend "Predis\Client" and neither ext-redis >= 5.2 nor ext-relay have been found.', $class)); + throw new CacheException(\sprintf('Cannot use Redis Sentinel: class "%s" does not extend "Predis\Client" and neither ext-redis >= 5.2 nor ext-relay have been found.', $class)); } $isRedisExt = is_a($class, \Redis::class, true); @@ -216,7 +220,7 @@ public static function createConnection(#[\SensitiveParameter] string $dsn, arra do { $host = $hosts[$hostIndex]['host'] ?? $hosts[$hostIndex]['path']; $port = $hosts[$hostIndex]['port'] ?? 0; - $passAuth = isset($params['auth']) && (!$isRedisExt || \defined('Redis::OPT_NULL_MULTIBULK_AS_NULL')); + $passAuth = null !== $params['auth'] && (!$isRedisExt || \defined('Redis::OPT_NULL_MULTIBULK_AS_NULL')); $address = false; if (isset($hosts[$hostIndex]['host']) && $tls) { @@ -228,7 +232,7 @@ public static function createConnection(#[\SensitiveParameter] string $dsn, arra } try { - if (version_compare(phpversion('redis'), '6.0.0', '>=') && $isRedisExt) { + if ($isRedisExt && version_compare(phpversion('redis'), '6.0.0', '>=')) { $options = [ 'host' => $host, 'port' => $port, @@ -246,10 +250,10 @@ public static function createConnection(#[\SensitiveParameter] string $dsn, arra } else { $extra = $passAuth ? [$params['auth']] : []; - $sentinel = new $sentinelClass($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...$extra); + $sentinel = @new $sentinelClass($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...$extra); } - if ($address = $sentinel->getMasterAddrByName($params['redis_sentinel'])) { + if ($address = @$sentinel->getMasterAddrByName($params['redis_sentinel'])) { [$host, $port] = $address; } } catch (\RedisException|\Relay\Exception $redisException) { @@ -257,7 +261,7 @@ public static function createConnection(#[\SensitiveParameter] string $dsn, arra } while (++$hostIndex < \count($hosts) && !$address); if (isset($params['redis_sentinel']) && !$address) { - throw new InvalidArgumentException(sprintf('Failed to retrieve master information from sentinel "%s".', $params['redis_sentinel']), previous: $redisException ?? null); + throw new InvalidArgumentException(\sprintf('Failed to retrieve master information from sentinel "%s".', $params['redis_sentinel']), previous: $redisException ?? null); } try { @@ -280,7 +284,7 @@ public static function createConnection(#[\SensitiveParameter] string $dsn, arra } } - if (isset($params['auth'])) { + if (null !== $params['auth']) { $extra['auth'] = $params['auth']; } @$redis->{$connect}($host, $port, (float) $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...\defined('Redis::SCAN_PREFIX') || !$isRedisExt ? [$extra] : []); @@ -292,23 +296,19 @@ public static function createConnection(#[\SensitiveParameter] string $dsn, arra restore_error_handler(); } if (!$isConnected) { - $error = preg_match('/^Redis::p?connect\(\): (.*)/', $error ?? $redis->getLastError() ?? '', $error) ? sprintf(' (%s)', $error[1]) : ''; + $error = preg_match('/^Redis::p?connect\(\): (.*)/', $error ?? $redis->getLastError() ?? '', $error) ? \sprintf(' (%s)', $error[1]) : ''; throw new InvalidArgumentException('Redis connection failed: '.$error.'.'); } - if ((null !== $auth && !$redis->auth($auth)) - // Due to a bug in phpredis we must always select the dbindex if persistent pooling is enabled - // @see https://github.com/phpredis/phpredis/issues/1920 - // @see https://github.com/symfony/symfony/issues/51578 - || (($params['dbindex'] || ('pconnect' === $connect && '0' !== \ini_get('redis.pconnect.pooling_enabled'))) && !$redis->select($params['dbindex'])) - ) { + if (0 < $params['tcp_keepalive'] && (!$isRedisExt || \defined('Redis::OPT_TCP_KEEPALIVE'))) { + $redis->setOption($isRedisExt ? \Redis::OPT_TCP_KEEPALIVE : Relay::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']); + } + + if ((!\defined('Redis::SCAN_PREFIX') && null !== $auth && $isRedisExt && !$redis->auth($auth)) || !$redis->select($params['dbindex'])) { $e = preg_replace('/^ERR /', '', $redis->getLastError()); throw new InvalidArgumentException('Redis connection failed: '.$e.'.'); } - if (0 < $params['tcp_keepalive'] && (!$isRedisExt || \defined('Redis::OPT_TCP_KEEPALIVE'))) { - $redis->setOption($isRedisExt ? \Redis::OPT_TCP_KEEPALIVE : Relay::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']); - } } catch (\RedisException|\Relay\Exception $e) { throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage()); } @@ -388,14 +388,12 @@ public static function createConnection(#[\SensitiveParameter] string $dsn, arra if ($params['dbindex']) { $params['parameters']['database'] = $params['dbindex']; } - if (null !== $auth) { - if (\is_array($auth)) { - // ACL - $params['parameters']['username'] = $auth[0]; - $params['parameters']['password'] = $auth[1]; - } else { - $params['parameters']['password'] = $auth; - } + if (\is_array($params['auth'])) { + // ACL + $params['parameters']['username'] = $params['auth'][0]; + $params['parameters']['password'] = $params['auth'][1]; + } elseif (null !== $params['auth']) { + $params['parameters']['password'] = $params['auth']; } if (isset($params['ssl'])) { @@ -417,9 +415,9 @@ public static function createConnection(#[\SensitiveParameter] string $dsn, arra $redis->getConnection()->setSentinelTimeout($params['timeout']); } } elseif (class_exists($class, false)) { - throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis", "RedisArray", "RedisCluster", "Relay\Relay" nor "Predis\ClientInterface".', $class)); + throw new InvalidArgumentException(\sprintf('"%s" is not a subclass of "Redis", "RedisArray", "RedisCluster", "Relay\Relay" nor "Predis\ClientInterface".', $class)); } else { - throw new InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); + throw new InvalidArgumentException(\sprintf('Class "%s" does not exist.', $class)); } return $redis; @@ -433,7 +431,7 @@ protected function doFetch(array $ids): iterable $result = []; - if ($this->redis instanceof \Predis\ClientInterface && ($this->redis->getConnection() instanceof ClusterInterface || $this->redis->getConnection() instanceof Predis2ClusterInterface)) { + if (($this->redis instanceof \Predis\ClientInterface && ($this->redis->getConnection() instanceof ClusterInterface || $this->redis->getConnection() instanceof Predis2ClusterInterface)) || $this->redis instanceof RelayCluster) { $values = $this->pipeline(function () use ($ids) { foreach ($ids as $id) { yield 'get' => [$id]; @@ -473,9 +471,16 @@ protected function doClear(string $namespace): bool $cleared = true; $hosts = $this->getHosts(); $host = reset($hosts); - if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) { - // Predis supports info command only on the master in replication environments - $hosts = [$host->getClientFor('master')]; + if ($host instanceof \Predis\Client) { + $connection = $host->getConnection(); + + if ($connection instanceof ReplicationInterface) { + $hosts = [$host->getClientFor('master')]; + } elseif ($connection instanceof Predis2ReplicationInterface) { + $connection->switchToMaster(); + + $hosts = [$host]; + } } foreach ($hosts as $host) { @@ -508,7 +513,7 @@ protected function doClear(string $namespace): bool $cursor = null; do { - $keys = $host instanceof \Predis\ClientInterface ? $host->scan($cursor, 'MATCH', $pattern, 'COUNT', 1000) : $host->scan($cursor, $pattern, 1000); + $keys = $host instanceof \Predis\ClientInterface ? $host->scan($cursor ?? 0, 'MATCH', $pattern, 'COUNT', 1000) : $host->scan($cursor, $pattern, 1000); if (isset($keys[1]) && \is_array($keys[1])) { $cursor = $keys[0]; $keys = $keys[1]; diff --git a/lib/symfony/cache/Traits/Relay/BgsaveTrait.php b/lib/symfony/cache/Traits/Relay/BgsaveTrait.php new file mode 100644 index 0000000000..367f82f7bb --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/BgsaveTrait.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.11', '>=')) { + /** + * @internal + */ + trait BgsaveTrait + { + public function bgsave($arg = null): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgsave(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait BgsaveTrait + { + public function bgsave($schedule = false): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgsave(...\func_get_args()); + } + } +} diff --git a/lib/symfony/cache/Traits/Relay/CopyTrait.php b/lib/symfony/cache/Traits/Relay/CopyTrait.php new file mode 100644 index 0000000000..a271a9d103 --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/CopyTrait.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.8.1', '>=')) { + /** + * @internal + */ + trait CopyTrait + { + public function copy($src, $dst, $options = null): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->copy(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait CopyTrait + { + public function copy($src, $dst, $options = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->copy(...\func_get_args()); + } + } +} diff --git a/lib/symfony/cache/Traits/Relay/FtTrait.php b/lib/symfony/cache/Traits/Relay/FtTrait.php new file mode 100644 index 0000000000..1abf0455bf --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/FtTrait.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.9.0', '>=')) { + /** + * @internal + */ + trait FtTrait + { + public function ftAggregate($index, $query, $options = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftAggregate(...\func_get_args()); + } + + public function ftAliasAdd($index, $alias): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftAliasAdd(...\func_get_args()); + } + + public function ftAliasDel($alias): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftAliasDel(...\func_get_args()); + } + + public function ftAliasUpdate($index, $alias): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftAliasUpdate(...\func_get_args()); + } + + public function ftAlter($index, $schema, $skipinitialscan = false): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftAlter(...\func_get_args()); + } + + public function ftConfig($operation, $option, $value = null): \Relay\Relay|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftConfig(...\func_get_args()); + } + + public function ftCreate($index, $schema, $options = null): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftCreate(...\func_get_args()); + } + + public function ftCursor($operation, $index, $cursor, $options = null): \Relay\Relay|array|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftCursor(...\func_get_args()); + } + + public function ftDictAdd($dict, $term, ...$other_terms): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftDictAdd(...\func_get_args()); + } + + public function ftDictDel($dict, $term, ...$other_terms): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftDictDel(...\func_get_args()); + } + + public function ftDictDump($dict): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftDictDump(...\func_get_args()); + } + + public function ftDropIndex($index, $dd = false): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftDropIndex(...\func_get_args()); + } + + public function ftExplain($index, $query, $dialect = 0): \Relay\Relay|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftExplain(...\func_get_args()); + } + + public function ftExplainCli($index, $query, $dialect = 0): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftExplainCli(...\func_get_args()); + } + + public function ftInfo($index): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftInfo(...\func_get_args()); + } + + public function ftProfile($index, $command, $query, $limited = false): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftProfile(...\func_get_args()); + } + + public function ftSearch($index, $query, $options = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftSearch(...\func_get_args()); + } + + public function ftSpellCheck($index, $query, $options = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftSpellCheck(...\func_get_args()); + } + + public function ftSynDump($index): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftSynDump(...\func_get_args()); + } + + public function ftSynUpdate($index, $synonym, $term_or_terms, $skipinitialscan = false): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftSynUpdate(...\func_get_args()); + } + + public function ftTagVals($index, $tag): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftTagVals(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait FtTrait + { + } +} diff --git a/lib/symfony/cache/Traits/Relay/GeosearchTrait.php b/lib/symfony/cache/Traits/Relay/GeosearchTrait.php new file mode 100644 index 0000000000..88ed1e9d30 --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/GeosearchTrait.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.9.0', '>=')) { + /** + * @internal + */ + trait GeosearchTrait + { + public function geosearch($key, $position, $shape, $unit, $options = []): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geosearch(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait GeosearchTrait + { + public function geosearch($key, $position, $shape, $unit, $options = []): \Relay\Relay|array + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geosearch(...\func_get_args()); + } + } +} diff --git a/lib/symfony/cache/Traits/Relay/GetWithMetaTrait.php b/lib/symfony/cache/Traits/Relay/GetWithMetaTrait.php new file mode 100644 index 0000000000..d0643c339e --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/GetWithMetaTrait.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.10.1', '>=')) { + /** + * @internal + */ + trait GetWithMetaTrait + { + public function getWithMeta($key): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getWithMeta(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait GetWithMetaTrait + { + } +} diff --git a/lib/symfony/cache/Traits/Relay/GetrangeTrait.php b/lib/symfony/cache/Traits/Relay/GetrangeTrait.php new file mode 100644 index 0000000000..4522d20b59 --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/GetrangeTrait.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.9.0', '>=')) { + /** + * @internal + */ + trait GetrangeTrait + { + public function getrange($key, $start, $end): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getrange(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait GetrangeTrait + { + public function getrange($key, $start, $end): \Relay\Relay|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getrange(...\func_get_args()); + } + } +} diff --git a/lib/symfony/cache/Traits/Relay/HsetTrait.php b/lib/symfony/cache/Traits/Relay/HsetTrait.php new file mode 100644 index 0000000000..a7cb8fff07 --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/HsetTrait.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.9.0', '>=')) { + /** + * @internal + */ + trait HsetTrait + { + public function hset($key, ...$keys_and_vals): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hset(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait HsetTrait + { + public function hset($key, $mem, $val, ...$kvals): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hset(...\func_get_args()); + } + } +} diff --git a/lib/symfony/cache/Traits/Relay/IsTrackedTrait.php b/lib/symfony/cache/Traits/Relay/IsTrackedTrait.php new file mode 100644 index 0000000000..8055e2e92c --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/IsTrackedTrait.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.11.1', '>=')) { + /** + * @internal + */ + trait IsTrackedTrait + { + public function isTracked($key): bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->isTracked(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait IsTrackedTrait + { + } +} diff --git a/lib/symfony/cache/Traits/Relay/MoveTrait.php b/lib/symfony/cache/Traits/Relay/MoveTrait.php new file mode 100644 index 0000000000..358e52f616 --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/MoveTrait.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.9.0', '>=')) { + /** + * @internal + */ + trait MoveTrait + { + public function blmove($srckey, $dstkey, $srcpos, $dstpos, $timeout): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blmove(...\func_get_args()); + } + + public function lmove($srckey, $dstkey, $srcpos, $dstpos): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lmove(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait MoveTrait + { + public function blmove($srckey, $dstkey, $srcpos, $dstpos, $timeout): \Relay\Relay|false|string|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blmove(...\func_get_args()); + } + + public function lmove($srckey, $dstkey, $srcpos, $dstpos): \Relay\Relay|false|string|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lmove(...\func_get_args()); + } + } +} diff --git a/lib/symfony/cache/Traits/Relay/NullableReturnTrait.php b/lib/symfony/cache/Traits/Relay/NullableReturnTrait.php new file mode 100644 index 0000000000..0b7409045d --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/NullableReturnTrait.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.9.0', '>=')) { + /** + * @internal + */ + trait NullableReturnTrait + { + public function dump($key): \Relay\Relay|false|string|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dump(...\func_get_args()); + } + + public function geodist($key, $src, $dst, $unit = null): \Relay\Relay|false|float|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geodist(...\func_get_args()); + } + + public function hrandfield($hash, $options = null): \Relay\Relay|array|false|string|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hrandfield(...\func_get_args()); + } + + public function xadd($key, $id, $values, $maxlen = 0, $approx = false, $nomkstream = false): \Relay\Relay|false|string|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xadd(...\func_get_args()); + } + + public function zrank($key, $rank, $withscore = false): \Relay\Relay|array|false|int|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrank(...\func_get_args()); + } + + public function zrevrank($key, $rank, $withscore = false): \Relay\Relay|array|false|int|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrank(...\func_get_args()); + } + + public function zscore($key, $member): \Relay\Relay|false|float|null + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscore(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait NullableReturnTrait + { + public function dump($key): \Relay\Relay|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dump(...\func_get_args()); + } + + public function geodist($key, $src, $dst, $unit = null): \Relay\Relay|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geodist(...\func_get_args()); + } + + public function hrandfield($hash, $options = null): \Relay\Relay|array|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hrandfield(...\func_get_args()); + } + + public function xadd($key, $id, $values, $maxlen = 0, $approx = false, $nomkstream = false): \Relay\Relay|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xadd(...\func_get_args()); + } + + public function zrank($key, $rank, $withscore = false): \Relay\Relay|array|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrank(...\func_get_args()); + } + + public function zrevrank($key, $rank, $withscore = false): \Relay\Relay|array|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrank(...\func_get_args()); + } + + public function zscore($key, $member): \Relay\Relay|false|float + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscore(...\func_get_args()); + } + } +} diff --git a/lib/symfony/cache/Traits/Relay/PfcountTrait.php b/lib/symfony/cache/Traits/Relay/PfcountTrait.php new file mode 100644 index 0000000000..340db8af75 --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/PfcountTrait.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.9.0', '>=')) { + /** + * @internal + */ + trait PfcountTrait + { + public function pfcount($key_or_keys): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfcount(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait PfcountTrait + { + public function pfcount($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfcount(...\func_get_args()); + } + } +} diff --git a/lib/symfony/cache/Traits/Relay/Relay11Trait.php b/lib/symfony/cache/Traits/Relay/Relay11Trait.php new file mode 100644 index 0000000000..289d8faa07 --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/Relay11Trait.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.11.0', '>=')) { + /** + * @internal + */ + trait Relay11Trait + { + public function cmsIncrBy($key, $field, $value, ...$fields_and_falues): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsIncrBy(...\func_get_args()); + } + + public function cmsInfo($key): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsInfo(...\func_get_args()); + } + + public function cmsInitByDim($key, $width, $depth): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsInitByDim(...\func_get_args()); + } + + public function cmsInitByProb($key, $error, $probability): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsInitByProb(...\func_get_args()); + } + + public function cmsMerge($dstkey, $keys, $weights = []): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsMerge(...\func_get_args()); + } + + public function cmsQuery($key, ...$fields): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsQuery(...\func_get_args()); + } + + public function commandlog($subcmd, ...$args): \Relay\Relay|array|bool|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->commandlog(...\func_get_args()); + } + + public function hexpire($hash, $ttl, $fields, $mode = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpire(...\func_get_args()); + } + + public function hexpireat($hash, $ttl, $fields, $mode = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpireat(...\func_get_args()); + } + + public function hexpiretime($hash, $fields): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpiretime(...\func_get_args()); + } + + public function hgetdel($key, $fields): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetdel(...\func_get_args()); + } + + public function hgetex($hash, $fields, $expiry = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetex(...\func_get_args()); + } + + public function hpersist($hash, $fields): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpersist(...\func_get_args()); + } + + public function hpexpire($hash, $ttl, $fields, $mode = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpire(...\func_get_args()); + } + + public function hpexpireat($hash, $ttl, $fields, $mode = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpireat(...\func_get_args()); + } + + public function hpexpiretime($hash, $fields): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpiretime(...\func_get_args()); + } + + public function hpttl($hash, $fields): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpttl(...\func_get_args()); + } + + public function hsetex($key, $fields, $expiry = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hsetex(...\func_get_args()); + } + + public function httl($hash, $fields): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->httl(...\func_get_args()); + } + + public function serverName(): false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->serverName(...\func_get_args()); + } + + public function serverVersion(): false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->serverVersion(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait Relay11Trait + { + } +} diff --git a/lib/symfony/cache/Traits/Relay/Relay121Trait.php b/lib/symfony/cache/Traits/Relay/Relay121Trait.php new file mode 100644 index 0000000000..da222ba8f4 --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/Relay121Trait.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.12.1', '>=')) { + /** + * @internal + */ + trait Relay121Trait + { + public function hgetWithMeta($hash, $member): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetWithMeta(...\func_get_args()); + } + + public function select($db): \Relay\Relay|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->select(...\func_get_args()); + } + + public function watch($key, ...$other_keys): \Relay\Relay|bool|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->watch(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait Relay121Trait + { + public function select($db): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->select(...\func_get_args()); + } + + public function watch($key, ...$other_keys): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->watch(...\func_get_args()); + } + } +} diff --git a/lib/symfony/cache/Traits/Relay/Relay12Trait.php b/lib/symfony/cache/Traits/Relay/Relay12Trait.php new file mode 100644 index 0000000000..26df3211fe --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/Relay12Trait.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.12.0', '>=')) { + /** + * @internal + */ + trait Relay12Trait + { + public function delifeq($key, $value): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->delifeq(...\func_get_args()); + } + + public function vadd($key, $values, $element, $options = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vadd(...\func_get_args()); + } + + public function vcard($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vcard(...\func_get_args()); + } + + public function vdim($key): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vdim(...\func_get_args()); + } + + public function vemb($key, $element, $raw = false): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vemb(...\func_get_args()); + } + + public function vgetattr($key, $element, $raw = false): \Relay\Relay|array|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vgetattr(...\func_get_args()); + } + + public function vinfo($key): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vinfo(...\func_get_args()); + } + + public function vismember($key, $element): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vismember(...\func_get_args()); + } + + public function vlinks($key, $element, $withscores): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vlinks(...\func_get_args()); + } + + public function vrandmember($key, $count = 0): \Relay\Relay|array|false|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vrandmember(...\func_get_args()); + } + + public function vrange($key, $min, $max, $count = -1): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vrange(...\func_get_args()); + } + + public function vrem($key, $element): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vrem(...\func_get_args()); + } + + public function vsetattr($key, $element, $attributes): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vsetattr(...\func_get_args()); + } + + public function vsim($key, $member, $options = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->vsim(...\func_get_args()); + } + + public function xdelex($key, $ids, $mode = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xdelex(...\func_get_args()); + } + + public function xackdel($key, $group, $ids, $mode = null): \Relay\Relay|array|false + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xackdel(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait Relay12Trait + { + } +} diff --git a/lib/symfony/cache/Traits/Relay/Relay20Trait.php b/lib/symfony/cache/Traits/Relay/Relay20Trait.php new file mode 100644 index 0000000000..b062ca9a68 --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/Relay20Trait.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.20.0', '>=')) { + /** + * @internal + */ + trait Relay20Trait + { + public function _digest($value): string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->_digest(...\func_get_args()); + } + + public function delex($key, $options = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->delex(...\func_get_args()); + } + + public function digest($key): \Relay\Relay|false|null|string + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->digest(...\func_get_args()); + } + + public function msetex($kvals, $ttl = null): \Relay\Relay|false|int + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->msetx(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait Relay20Trait + { + } +} diff --git a/lib/symfony/cache/Traits/Relay/SwapdbTrait.php b/lib/symfony/cache/Traits/Relay/SwapdbTrait.php new file mode 100644 index 0000000000..8ae0a079d6 --- /dev/null +++ b/lib/symfony/cache/Traits/Relay/SwapdbTrait.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits\Relay; + +if (version_compare(phpversion('relay'), '0.9.0', '>=')) { + /** + * @internal + */ + trait SwapdbTrait + { + public function swapdb($index1, $index2): \Relay\Relay|bool + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->swapdb(...\func_get_args()); + } + } +} else { + /** + * @internal + */ + trait SwapdbTrait + { + } +} diff --git a/lib/symfony/cache/Traits/RelayProxy.php b/lib/symfony/cache/Traits/RelayProxy.php index 96d7d19b46..8933e93ac7 100644 --- a/lib/symfony/cache/Traits/RelayProxy.php +++ b/lib/symfony/cache/Traits/RelayProxy.php @@ -11,6 +11,22 @@ namespace Symfony\Component\Cache\Traits; +use Symfony\Component\Cache\Traits\Relay\BgsaveTrait; +use Symfony\Component\Cache\Traits\Relay\CopyTrait; +use Symfony\Component\Cache\Traits\Relay\FtTrait; +use Symfony\Component\Cache\Traits\Relay\GeosearchTrait; +use Symfony\Component\Cache\Traits\Relay\GetrangeTrait; +use Symfony\Component\Cache\Traits\Relay\GetWithMetaTrait; +use Symfony\Component\Cache\Traits\Relay\HsetTrait; +use Symfony\Component\Cache\Traits\Relay\IsTrackedTrait; +use Symfony\Component\Cache\Traits\Relay\MoveTrait; +use Symfony\Component\Cache\Traits\Relay\NullableReturnTrait; +use Symfony\Component\Cache\Traits\Relay\PfcountTrait; +use Symfony\Component\Cache\Traits\Relay\Relay11Trait; +use Symfony\Component\Cache\Traits\Relay\Relay121Trait; +use Symfony\Component\Cache\Traits\Relay\Relay12Trait; +use Symfony\Component\Cache\Traits\Relay\Relay20Trait; +use Symfony\Component\Cache\Traits\Relay\SwapdbTrait; use Symfony\Component\VarExporter\LazyObjectInterface; use Symfony\Component\VarExporter\LazyProxyTrait; use Symfony\Contracts\Service\ResetInterface; @@ -25,10 +41,26 @@ class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class); */ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInterface { + use BgsaveTrait; + use CopyTrait; + use FtTrait; + use GeosearchTrait; + use GetrangeTrait; + use GetWithMetaTrait; + use HsetTrait; + use IsTrackedTrait; use LazyProxyTrait { resetLazyObject as reset; } + use MoveTrait; + use NullableReturnTrait; + use PfcountTrait; use RelayProxyTrait; + use Relay11Trait; + use Relay12Trait; + use Relay121Trait; + use Relay20Trait; + use SwapdbTrait; private const LAZY_OBJECT_PROPERTY_SCOPES = []; @@ -222,11 +254,6 @@ public function rawCommand($cmd, ...$args): mixed return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->rawCommand(...\func_get_args()); } - public function select($db): \Relay\Relay|bool - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->select(...\func_get_args()); - } - public function auth(#[\SensitiveParameter] $auth): bool { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->auth(...\func_get_args()); @@ -267,11 +294,6 @@ public function dbsize(): \Relay\Relay|false|int return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dbsize(...\func_get_args()); } - public function dump($key): \Relay\Relay|false|string - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->dump(...\func_get_args()); - } - public function replicaof($host = null, $port = 0): \Relay\Relay|bool { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->replicaof(...\func_get_args()); @@ -332,11 +354,6 @@ public function lcs($key1, $key2, $options = null): mixed return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lcs(...\func_get_args()); } - public function bgsave($schedule = false): \Relay\Relay|bool - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->bgsave(...\func_get_args()); - } - public function save(): \Relay\Relay|bool { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->save(...\func_get_args()); @@ -392,11 +409,6 @@ public function geoadd($key, $lng, $lat, $member, ...$other_triples_and_options) return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geoadd(...\func_get_args()); } - public function geodist($key, $src, $dst, $unit = null): \Relay\Relay|false|float - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geodist(...\func_get_args()); - } - public function geohash($key, $member, ...$other_members): \Relay\Relay|array|false { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geohash(...\func_get_args()); @@ -422,11 +434,6 @@ public function georadius_ro($key, $lng, $lat, $radius, $unit, $options = []): m return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->georadius_ro(...\func_get_args()); } - public function geosearch($key, $position, $shape, $unit, $options = []): \Relay\Relay|array - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geosearch(...\func_get_args()); - } - public function geosearchstore($dst, $src, $position, $shape, $unit, $options = []): \Relay\Relay|false|int { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->geosearchstore(...\func_get_args()); @@ -442,11 +449,6 @@ public function getset($key, $value): mixed return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getset(...\func_get_args()); } - public function getrange($key, $start, $end): \Relay\Relay|false|string - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getrange(...\func_get_args()); - } - public function setrange($key, $start, $value): \Relay\Relay|false|int { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->setrange(...\func_get_args()); @@ -527,11 +529,6 @@ public function pfadd($key, $elements): \Relay\Relay|false|int return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfadd(...\func_get_args()); } - public function pfcount($key): \Relay\Relay|false|int - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfcount(...\func_get_args()); - } - public function pfmerge($dst, $srckeys): \Relay\Relay|bool { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pfmerge(...\func_get_args()); @@ -642,16 +639,6 @@ public function type($key): \Relay\Relay|bool|int|string return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->type(...\func_get_args()); } - public function lmove($srckey, $dstkey, $srcpos, $dstpos): \Relay\Relay|false|null|string - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lmove(...\func_get_args()); - } - - public function blmove($srckey, $dstkey, $srcpos, $dstpos, $timeout): \Relay\Relay|false|null|string - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->blmove(...\func_get_args()); - } - public function lrange($key, $start, $stop): \Relay\Relay|array|false { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->lrange(...\func_get_args()); @@ -807,11 +794,6 @@ public function hmget($hash, $members): \Relay\Relay|array|false return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hmget(...\func_get_args()); } - public function hrandfield($hash, $options = null): \Relay\Relay|array|false|string - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hrandfield(...\func_get_args()); - } - public function hmset($hash, $members): \Relay\Relay|bool { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hmset(...\func_get_args()); @@ -827,11 +809,6 @@ public function hsetnx($hash, $member, $value): \Relay\Relay|bool return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hsetnx(...\func_get_args()); } - public function hset($key, $mem, $val, ...$kvals): \Relay\Relay|false|int - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hset(...\func_get_args()); - } - public function hdel($key, $mem, ...$mems): \Relay\Relay|false|int { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hdel(...\func_get_args()); @@ -962,11 +939,6 @@ public function wait($replicas, $timeout): \Relay\Relay|false|int return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->wait(...\func_get_args()); } - public function watch($key, ...$other_keys): \Relay\Relay|bool - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->watch(...\func_get_args()); - } - public function unwatch(): \Relay\Relay|bool { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->unwatch(...\func_get_args()); @@ -1097,11 +1069,6 @@ public function xack($key, $group, $ids): \Relay\Relay|false|int return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xack(...\func_get_args()); } - public function xadd($key, $id, $values, $maxlen = 0, $approx = false, $nomkstream = false): \Relay\Relay|false|string - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xadd(...\func_get_args()); - } - public function xclaim($key, $group, $consumer, $min_idle, $ids, $options): \Relay\Relay|array|bool { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->xclaim(...\func_get_args()); @@ -1207,16 +1174,6 @@ public function zrevrangebylex($key, $max, $min, $offset = -1, $count = -1): \Re return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrangebylex(...\func_get_args()); } - public function zrank($key, $rank, $withscore = false): \Relay\Relay|array|false|int - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrank(...\func_get_args()); - } - - public function zrevrank($key, $rank, $withscore = false): \Relay\Relay|array|false|int - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrevrank(...\func_get_args()); - } - public function zrem($key, ...$args): \Relay\Relay|false|int { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zrem(...\func_get_args()); @@ -1272,11 +1229,6 @@ public function zmscore($key, ...$mems): \Relay\Relay|array|false return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zmscore(...\func_get_args()); } - public function zscore($key, $member): \Relay\Relay|false|float - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscore(...\func_get_args()); - } - public function zinter($keys, $weights = null, $options = null): \Relay\Relay|array|false { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zinter(...\func_get_args()); diff --git a/lib/symfony/cache/Traits/RelayProxyTrait.php b/lib/symfony/cache/Traits/RelayProxyTrait.php index a1d252b96d..c35b5fa017 100644 --- a/lib/symfony/cache/Traits/RelayProxyTrait.php +++ b/lib/symfony/cache/Traits/RelayProxyTrait.php @@ -17,11 +17,6 @@ */ trait RelayProxyTrait { - public function copy($src, $dst, $options = null): \Relay\Relay|bool - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->copy(...\func_get_args()); - } - public function jsonArrAppend($key, $value_or_array, $path = null): \Relay\Relay|array|false { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->jsonArrAppend(...\func_get_args()); @@ -148,9 +143,5 @@ public function jsonType($key, $path = null): \Relay\Relay|array|false */ trait RelayProxyTrait { - public function copy($src, $dst, $options = null): \Relay\Relay|false|int - { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->copy(...\func_get_args()); - } } } diff --git a/lib/symfony/config/Definition/Builder/ArrayNodeDefinition.php b/lib/symfony/config/Definition/Builder/ArrayNodeDefinition.php index ec0e12ab6f..e4938352c3 100644 --- a/lib/symfony/config/Definition/Builder/ArrayNodeDefinition.php +++ b/lib/symfony/config/Definition/Builder/ArrayNodeDefinition.php @@ -331,7 +331,7 @@ public function normalizeKeys(bool $bool): static public function append(NodeDefinition $node): static { - $this->children[$node->name] = $node->setParent($this); + $this->children[$node->name ?? ''] = $node->setParent($this); return $this; } diff --git a/lib/symfony/config/Definition/Dumper/YamlReferenceDumper.php b/lib/symfony/config/Definition/Dumper/YamlReferenceDumper.php index 0813ab1e59..7840ef4093 100644 --- a/lib/symfony/config/Definition/Dumper/YamlReferenceDumper.php +++ b/lib/symfony/config/Definition/Dumper/YamlReferenceDumper.php @@ -249,6 +249,6 @@ private function getPrototypeChildren(PrototypedArrayNode $node): array } $keyNode->setInfo($info); - return [$key => $keyNode]; + return [$key ?? '' => $keyNode]; } } diff --git a/lib/symfony/config/Resource/ClassExistenceResource.php b/lib/symfony/config/Resource/ClassExistenceResource.php index aa9177d29b..49a6074dac 100644 --- a/lib/symfony/config/Resource/ClassExistenceResource.php +++ b/lib/symfony/config/Resource/ClassExistenceResource.php @@ -101,23 +101,23 @@ public function isFresh(int $timestamp): bool return $this->exists[0] xor !$exists[0]; } - /** - * @internal - */ - public function __sleep(): array + public function __serialize(): array { if (null === $this->exists) { $this->isFresh(0); } - return ['resource', 'exists']; + return [ + 'resource' => $this->resource, + 'exists' => $this->exists, + ]; } - /** - * @internal - */ - public function __wakeup(): void + public function __unserialize(array $data): void { + $this->resource = array_shift($data); + $this->exists = array_shift($data); + if (\is_bool($this->exists)) { $this->exists = [$this->exists, null]; } diff --git a/lib/symfony/config/Resource/GlobResource.php b/lib/symfony/config/Resource/GlobResource.php index 3e381a4115..f00e1c8b95 100644 --- a/lib/symfony/config/Resource/GlobResource.php +++ b/lib/symfony/config/Resource/GlobResource.php @@ -77,21 +77,28 @@ public function isFresh(int $timestamp): bool return $this->hash === $hash; } - /** - * @internal - */ - public function __sleep(): array + public function __serialize(): array { $this->hash ??= $this->computeHash(); - return ['prefix', 'pattern', 'recursive', 'hash', 'forExclusion', 'excludedPrefixes']; + return [ + 'prefix' => $this->prefix, + 'pattern' => $this->pattern, + 'recursive' => $this->recursive, + 'hash' => $this->hash, + 'forExclusion' => $this->forExclusion, + 'excludedPrefixes' => $this->excludedPrefixes, + ]; } - /** - * @internal - */ - public function __wakeup(): void + public function __unserialize(array $data): void { + $this->prefix = array_shift($data); + $this->pattern = array_shift($data); + $this->recursive = array_shift($data); + $this->hash = array_shift($data); + $this->forExclusion = array_shift($data); + $this->excludedPrefixes = array_shift($data); $this->globBrace = \defined('GLOB_BRACE') ? \GLOB_BRACE : 0; } @@ -111,7 +118,7 @@ public function getIterator(): \Traversable if (class_exists(Finder::class)) { $regex = Glob::toRegex($pattern); if ($this->recursive) { - $regex = substr_replace($regex, '(/|$)', -2, 1); + $regex = substr_replace($regex, str_ends_with($pattern, '/') ? '' : '(/|$)', -2, 1); } } else { $regex = null; diff --git a/lib/symfony/config/Resource/ReflectionClassResource.php b/lib/symfony/config/Resource/ReflectionClassResource.php index cfd96135d1..8b7bfba820 100644 --- a/lib/symfony/config/Resource/ReflectionClassResource.php +++ b/lib/symfony/config/Resource/ReflectionClassResource.php @@ -60,17 +60,19 @@ public function __toString(): string return 'reflection.'.$this->className; } - /** - * @internal - */ - public function __sleep(): array + public function __serialize(): array { if (!isset($this->hash)) { $this->hash = $this->computeHash(); $this->loadFiles($this->classReflector); } - return ['files', 'className', 'hash']; + return [ + 'files' => $this->files, + 'className' => $this->className, + 'excludedVendors' => $this->excludedVendors, + 'hash' => $this->hash, + ]; } private function loadFiles(\ReflectionClass $class): void diff --git a/lib/symfony/console/Application.php b/lib/symfony/console/Application.php index c18d482b47..f61761df52 100644 --- a/lib/symfony/console/Application.php +++ b/lib/symfony/console/Application.php @@ -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; + } } /** @@ -723,15 +732,14 @@ public function find(string $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)); @@ -779,9 +787,9 @@ public function find(string $name) } } - $command = $this->get(reset($commands)); + $command = $commands ? $this->get(reset($commands)) : null; - if ($command->isHidden()) { + if (!$command || $command->isHidden()) { throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); } @@ -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); diff --git a/lib/symfony/console/Helper/QuestionHelper.php b/lib/symfony/console/Helper/QuestionHelper.php index 593b01b39d..d652a05ef5 100644 --- a/lib/symfony/console/Helper/QuestionHelper.php +++ b/lib/symfony/console/Helper/QuestionHelper.php @@ -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,12 +311,12 @@ 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]; // Echo out remaining chars for current match - $remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)))); + $remainingCharacters = substr($ret, \strlen($this->mostRecentlyEnteredValue($fullChoice))); $output->write($remainingCharacters); $fullChoice .= $remainingCharacters; $i = (false === $encoding = mb_detect_encoding($fullChoice, null, true)) ? \strlen($fullChoice) : mb_strlen($fullChoice, $encoding); @@ -376,14 +370,14 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu if ($numMatches > 0 && -1 !== $ofs) { $cursor->savePosition(); // Write highlighted text, complete the partially entered response - $charactersEntered = \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))); + $charactersEntered = \strlen($this->mostRecentlyEnteredValue($fullChoice)); $output->write(''.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).''); $cursor->restorePosition(); } } - // 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,14 +516,8 @@ private function readInput($inputStream, Question $question): string|false return false; } - $ret = ''; $cp = $this->setIOCodepage(); - while (false !== ($char = fgetc($multiLineStreamReader))) { - if ("\x4" === $char || \PHP_EOL === "{$ret}{$char}") { - break; - } - $ret .= $char; - } + $ret = $this->doReadInput($multiLineStreamReader, "\x4"); if (stream_get_meta_data($inputStream)['seekable']) { fseek($inputStream, ftell($multiLineStreamReader)); @@ -601,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/lib/symfony/console/Helper/SymfonyQuestionHelper.php b/lib/symfony/console/Helper/SymfonyQuestionHelper.php index 11b4e42388..634550d3ce 100644 --- a/lib/symfony/console/Helper/SymfonyQuestionHelper.php +++ b/lib/symfony/console/Helper/SymfonyQuestionHelper.php @@ -34,7 +34,7 @@ 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($output)); } switch (true) { @@ -98,9 +98,9 @@ protected function writeError(OutputInterface $output, \Exception $error) parent::writeError($output, $error); } - private function getEofShortcut(): string + private function getEofShortcut(OutputInterface $output): string { - if ('Windows' === \PHP_OS_FAMILY) { + if ('\\' === \DIRECTORY_SEPARATOR && !$output->isDecorated()) { return 'Ctrl+Z then Enter'; } diff --git a/lib/symfony/console/Helper/TableStyle.php b/lib/symfony/console/Helper/TableStyle.php index be956c109e..b0c94deb77 100644 --- a/lib/symfony/console/Helper/TableStyle.php +++ b/lib/symfony/console/Helper/TableStyle.php @@ -77,10 +77,11 @@ public function getPaddingChar(): string * * * ╔═══════════════╤══════════════════════════╤══════════════════╗ - * 1 ISBN 2 Title │ Author ║ - * ╠═══════════════╪══════════════════════════╪══════════════════╣ + * ║ ISBN │ Title │ Author ║ + * ╠═══════1═══════╪══════════════════════════╪══════════════════╣ * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ + * ╟───────2───────┼──────────────────────────┼──────────────────╢ * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ * ╚═══════════════╧══════════════════════════╧══════════════════╝ @@ -101,11 +102,10 @@ public function setHorizontalBorderChars(string $outside, ?string $inside = null * * * ╔═══════════════╤══════════════════════════╤══════════════════╗ - * ║ ISBN │ Title │ Author ║ - * ╠═══════1═══════╪══════════════════════════╪══════════════════╣ + * 1 ISBN 2 Title │ Author ║ + * ╠═══════════════╪══════════════════════════╪══════════════════╣ * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ - * ╟───────2───────┼──────────────────────────┼──────────────────╢ * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ * ╚═══════════════╧══════════════════════════╧══════════════════╝ diff --git a/lib/symfony/console/Helper/TerminalInputHelper.php b/lib/symfony/console/Helper/TerminalInputHelper.php new file mode 100644 index 0000000000..d6f07db8b3 --- /dev/null +++ b/lib/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/lib/symfony/console/Input/ArgvInput.php b/lib/symfony/console/Input/ArgvInput.php index a33092aee8..b5f8666897 100644 --- a/lib/symfony/console/Input/ArgvInput.php +++ b/lib/symfony/console/Input/ArgvInput.php @@ -176,7 +176,7 @@ 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]); } diff --git a/lib/symfony/console/Question/ChoiceQuestion.php b/lib/symfony/console/Question/ChoiceQuestion.php index 9445ccc0c5..bcfe4dc45f 100644 --- a/lib/symfony/console/Question/ChoiceQuestion.php +++ b/lib/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 { diff --git a/lib/symfony/console/Resources/completion.bash b/lib/symfony/console/Resources/completion.bash index 64c6a338fc..2befe76cba 100644 --- a/lib/symfony/console/Resources/completion.bash +++ b/lib/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/lib/symfony/console/SignalRegistry/SignalRegistry.php b/lib/symfony/console/SignalRegistry/SignalRegistry.php index ef2e5f04e1..ac8851b061 100644 --- a/lib/symfony/console/SignalRegistry/SignalRegistry.php +++ b/lib/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/lib/symfony/console/Tester/TesterTrait.php b/lib/symfony/console/Tester/TesterTrait.php index 127556d1db..238c7b7ebb 100644 --- a/lib/symfony/console/Tester/TesterTrait.php +++ b/lib/symfony/console/Tester/TesterTrait.php @@ -168,10 +168,10 @@ 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_contains($input, \PHP_EOL)) { - fwrite($stream, "\x4"); + if (!str_ends_with($input, "\x4")) { + fwrite($stream, \PHP_EOL); } } diff --git a/lib/symfony/dependency-injection/Attribute/Autowire.php b/lib/symfony/dependency-injection/Attribute/Autowire.php index 8740926578..c2d6c56c5b 100644 --- a/lib/symfony/dependency-injection/Attribute/Autowire.php +++ b/lib/symfony/dependency-injection/Attribute/Autowire.php @@ -52,7 +52,7 @@ public function __construct( if (null !== $value && null !== $service) { throw new LogicException('#[Autowire] attribute cannot declare $value and $service at the same time.'); } - } elseif (!(null !== $value xor null !== $service xor null !== $expression xor null !== $env xor null !== $param)) { + } elseif (1 !== (null !== $value) + (null !== $service) + (null !== $expression) + (null !== $env) + (null !== $param)) { throw new LogicException('#[Autowire] attribute must declare exactly one of $service, $expression, $env, $param or $value.'); } diff --git a/lib/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php b/lib/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php index 4fea73217c..ea1986ce94 100644 --- a/lib/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php +++ b/lib/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php @@ -41,6 +41,7 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass private bool $lazy; private bool $byConstructor; private bool $byFactory; + private bool $byMultiUseArgument; private array $definitions; private array $aliases; @@ -67,6 +68,7 @@ public function process(ContainerBuilder $container) $this->lazy = false; $this->byConstructor = false; $this->byFactory = false; + $this->byMultiUseArgument = false; $this->definitions = $container->getDefinitions(); $this->aliases = $container->getAliases(); @@ -89,7 +91,12 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed if ($value instanceof ArgumentInterface) { $this->lazy = !$this->byFactory || !$value instanceof IteratorArgument; + $byMultiUseArgument = $this->byMultiUseArgument; + if ($value instanceof IteratorArgument) { + $this->byMultiUseArgument = true; + } parent::processValue($value->getValues()); + $this->byMultiUseArgument = $byMultiUseArgument; $this->lazy = $lazy; return $value; @@ -106,7 +113,8 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed $value, $this->lazy || ($this->hasProxyDumper && $targetDefinition?->isLazy()), ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior(), - $this->byConstructor + $this->byConstructor, + $this->byMultiUseArgument ); if ($inExpression) { @@ -117,7 +125,9 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed $targetDefinition, $value, $this->lazy || $targetDefinition?->isLazy(), - true + true, + $this->byConstructor, + $this->byMultiUseArgument ); } diff --git a/lib/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php b/lib/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php index 90ef098898..0d185ac527 100644 --- a/lib/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php +++ b/lib/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php @@ -40,6 +40,10 @@ class CheckDefinitionValidityPass implements CompilerPassInterface public function process(ContainerBuilder $container) { foreach ($container->getDefinitions() as $id => $definition) { + if ($definition->hasErrors()) { + continue; + } + // synthetic service is public if ($definition->isSynthetic() && !$definition->isPublic()) { throw new RuntimeException(\sprintf('A synthetic service ("%s") must be public.', $id)); diff --git a/lib/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php b/lib/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php index 9965262400..b783a21f31 100644 --- a/lib/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php +++ b/lib/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php @@ -79,7 +79,7 @@ public function __construct(bool $autoload = false, array $skippedIds = []) protected function processValue(mixed $value, bool $isRoot = false): mixed { - if (isset($this->skippedIds[$this->currentId])) { + if (isset($this->skippedIds[$this->currentId ?? ''])) { return $value; } @@ -142,13 +142,14 @@ private function checkTypeDeclarations(Definition $checkedDefinition, \Reflectio if (!$p->hasType() || $p->isVariadic()) { continue; } + $key = $i; if (\array_key_exists($p->name, $values)) { - $i = $p->name; + $key = $p->name; } elseif (!\array_key_exists($i, $values)) { continue; } - $this->checkType($checkedDefinition, $values[$i], $p, $envPlaceholderUniquePrefix); + $this->checkType($checkedDefinition, $values[$key], $p, $envPlaceholderUniquePrefix); } if ($reflectionFunction->isVariadic() && ($lastParameter = end($reflectionParameters))->hasType()) { diff --git a/lib/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php b/lib/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php index 204401cd2c..251f26ef23 100644 --- a/lib/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php +++ b/lib/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php @@ -69,9 +69,9 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior() || ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior() ) { - $this->sourceReferences[$targetId][$this->currentId] ??= true; + $this->sourceReferences[$targetId][$this->currentId ?? ''] ??= true; } else { - $this->sourceReferences[$targetId][$this->currentId] = false; + $this->sourceReferences[$targetId][$this->currentId ?? ''] = false; } return $value; @@ -81,7 +81,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed return parent::processValue($value, $isRoot); } - $this->erroredDefinitions[$this->currentId] = $value; + $this->erroredDefinitions[$this->currentId ?? ''] = $value; return parent::processValue($value); } diff --git a/lib/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php b/lib/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php index 9b75fea390..0909cf3f91 100644 --- a/lib/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php +++ b/lib/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php @@ -146,7 +146,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed $this->container->log($this, \sprintf('Inlined service "%s" to "%s".', $id, $this->currentId)); $this->inlinedIds[$id] = $definition->isPublic() || !$definition->isShared(); - $this->notInlinedIds[$this->currentId] = true; + $this->notInlinedIds[$this->currentId ?? ''] = true; if ($definition->isShared()) { return $definition; diff --git a/lib/symfony/dependency-injection/Compiler/PassConfig.php b/lib/symfony/dependency-injection/Compiler/PassConfig.php index 677f2f6106..369ff47a98 100644 --- a/lib/symfony/dependency-injection/Compiler/PassConfig.php +++ b/lib/symfony/dependency-injection/Compiler/PassConfig.php @@ -97,7 +97,8 @@ public function __construct() new AliasDeprecatedPublicServicesPass(), ], // Let build parameters be available as late as possible - -2048 => [new RemoveBuildParametersPass()], + // Don't remove array parameters since ResolveParameterPlaceHoldersPass doesn't resolve them + -2048 => [new RemoveBuildParametersPass(true)], ]; } diff --git a/lib/symfony/dependency-injection/Compiler/RemoveBuildParametersPass.php b/lib/symfony/dependency-injection/Compiler/RemoveBuildParametersPass.php index 72df1efb16..c2cf2903cb 100644 --- a/lib/symfony/dependency-injection/Compiler/RemoveBuildParametersPass.php +++ b/lib/symfony/dependency-injection/Compiler/RemoveBuildParametersPass.php @@ -20,6 +20,11 @@ class RemoveBuildParametersPass implements CompilerPassInterface */ private array $removedParameters = []; + public function __construct( + private bool $preserveArrays = false, + ) { + } + /** * @return void */ @@ -29,7 +34,7 @@ public function process(ContainerBuilder $container) $this->removedParameters = []; foreach ($parameterBag->all() as $name => $value) { - if ('.' === ($name[0] ?? '')) { + if ('.' === ($name[0] ?? '') && (!$this->preserveArrays || !\is_array($value))) { $this->removedParameters[$name] = $value; $parameterBag->remove($name); diff --git a/lib/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php b/lib/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php index 3a0d07bbe5..d6377bb9b6 100644 --- a/lib/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php +++ b/lib/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php @@ -41,7 +41,15 @@ public function process(ContainerBuilder $container) $seenAliasTargets = []; $replacements = []; - foreach ($container->getAliases() as $definitionId => $target) { + // Sort aliases so non-deprecated ones come first. This ensures that when + // multiple aliases point to the same private definition, non-deprecated + // aliases get priority for renaming. Otherwise, the definition might be + // renamed to a deprecated alias ID, causing the original service ID to + // become an alias to the deprecated one (inverting the alias chain). + $aliases = $container->getAliases(); + uasort($aliases, static fn ($a, $b) => $a->isDeprecated() <=> $b->isDeprecated()); + + foreach ($aliases as $definitionId => $target) { $targetId = (string) $target; // Special case: leave this target alone if ('service_container' === $targetId) { diff --git a/lib/symfony/dependency-injection/Compiler/ResolveBindingsPass.php b/lib/symfony/dependency-injection/Compiler/ResolveBindingsPass.php index 404709585f..9fa6178226 100644 --- a/lib/symfony/dependency-injection/Compiler/ResolveBindingsPass.php +++ b/lib/symfony/dependency-injection/Compiler/ResolveBindingsPass.php @@ -121,10 +121,10 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed foreach ($bindings as $key => $binding) { [$bindingValue, $bindingId, $used, $bindingType, $file] = $binding->getValues(); if ($used) { - $this->usedBindings[$bindingId] = true; - unset($this->unusedBindings[$bindingId]); - } elseif (!isset($this->usedBindings[$bindingId])) { - $this->unusedBindings[$bindingId] = [$key, $this->currentId, $bindingType, $file]; + $this->usedBindings[$bindingId ?? ''] = true; + unset($this->unusedBindings[$bindingId ?? '']); + } elseif (!isset($this->usedBindings[$bindingId ?? ''])) { + $this->unusedBindings[$bindingId ?? ''] = [$key, $this->currentId, $bindingType, $file]; } if (preg_match('/^(?:(?:array|bool|float|int|string|iterable|([^ $]++)) )\$/', $key, $m)) { @@ -263,8 +263,8 @@ private function getBindingValue(BoundArgument $binding): mixed { [$bindingValue, $bindingId] = $binding->getValues(); - $this->usedBindings[$bindingId] = true; - unset($this->unusedBindings[$bindingId]); + $this->usedBindings[$bindingId ?? ''] = true; + unset($this->unusedBindings[$bindingId ?? '']); return $bindingValue; } diff --git a/lib/symfony/dependency-injection/Compiler/ResolveClassPass.php b/lib/symfony/dependency-injection/Compiler/ResolveClassPass.php index 761f4067b5..23d711ca5a 100644 --- a/lib/symfony/dependency-injection/Compiler/ResolveClassPass.php +++ b/lib/symfony/dependency-injection/Compiler/ResolveClassPass.php @@ -26,15 +26,17 @@ class ResolveClassPass implements CompilerPassInterface public function process(ContainerBuilder $container) { foreach ($container->getDefinitions() as $id => $definition) { - if ($definition->isSynthetic() || null !== $definition->getClass()) { + if ($definition->isSynthetic() + || $definition->hasErrors() + || null !== $definition->getClass() + || !preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $id) + ) { continue; } - if (preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $id)) { - if ($definition instanceof ChildDefinition && !class_exists($id)) { - throw new InvalidArgumentException(\sprintf('Service definition "%s" has a parent but no class, and its name looks like an FQCN. Either the class is missing or you want to inherit it from the parent service. To resolve this ambiguity, please rename this service to a non-FQCN (e.g. using dots), or create the missing class.', $id)); - } - $definition->setClass($id); + if ($definition instanceof ChildDefinition && !class_exists($id)) { + throw new InvalidArgumentException(\sprintf('Service definition "%s" has a parent but no class, and its name looks like an FQCN. Either the class is missing or you want to inherit it from the parent service. To resolve this ambiguity, please rename this service to a non-FQCN (e.g. using dots), or create the missing class.', $id)); } + $definition->setClass($id); } } } diff --git a/lib/symfony/dependency-injection/Compiler/ResolveHotPathPass.php b/lib/symfony/dependency-injection/Compiler/ResolveHotPathPass.php index 705bb837b9..59d87b3946 100644 --- a/lib/symfony/dependency-injection/Compiler/ResolveHotPathPass.php +++ b/lib/symfony/dependency-injection/Compiler/ResolveHotPathPass.php @@ -51,7 +51,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed return $value->clearTag('container.hot_path'); } - $this->resolvedIds[$this->currentId] = true; + $this->resolvedIds[$this->currentId ?? ''] = true; if (!$value->hasTag('container.hot_path')) { return $value; diff --git a/lib/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php b/lib/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php index 16d0e9fcb0..015db9d1c4 100644 --- a/lib/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php +++ b/lib/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php @@ -36,7 +36,11 @@ public function process(ContainerBuilder $container) $this->currentId = $id; if ($aliasId !== $defId = $this->getDefinitionId($aliasId, $container)) { - $container->setAlias($id, $defId)->setPublic($alias->isPublic()); + $newAlias = $container->setAlias($id, $defId)->setPublic($alias->isPublic()); + + if ($alias->isDeprecated()) { + $newAlias->setDeprecated(...array_values($alias->getDeprecation('%alias_id%'))); + } } } } diff --git a/lib/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php b/lib/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php index 2544cde954..97f9398e1b 100644 --- a/lib/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php +++ b/lib/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php @@ -74,7 +74,7 @@ public function clear(): void /** * Connects 2 nodes together in the Graph. */ - public function connect(?string $sourceId, mixed $sourceValue, ?string $destId, mixed $destValue = null, ?Reference $reference = null, bool $lazy = false, bool $weak = false, bool $byConstructor = false): void + public function connect(?string $sourceId, mixed $sourceValue, ?string $destId, mixed $destValue = null, ?Reference $reference = null, bool $lazy = false, bool $weak = false, bool $byConstructor = false, bool $byMultiUseArgument = false): void { if (null === $sourceId || null === $destId) { return; @@ -82,7 +82,7 @@ public function connect(?string $sourceId, mixed $sourceValue, ?string $destId, $sourceNode = $this->createNode($sourceId, $sourceValue); $destNode = $this->createNode($destId, $destValue); - $edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference, $lazy, $weak, $byConstructor); + $edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference, $lazy, $weak, $byConstructor, $byMultiUseArgument); $sourceNode->addOutEdge($edge); $destNode->addInEdge($edge); diff --git a/lib/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php b/lib/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php index b607164a6d..1fad566668 100644 --- a/lib/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php +++ b/lib/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php @@ -26,8 +26,9 @@ class ServiceReferenceGraphEdge private bool $lazy; private bool $weak; private bool $byConstructor; + private bool $byMultiUseArgument; - public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, mixed $value = null, bool $lazy = false, bool $weak = false, bool $byConstructor = false) + public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, mixed $value = null, bool $lazy = false, bool $weak = false, bool $byConstructor = false, bool $byMultiUseArgument = false) { $this->sourceNode = $sourceNode; $this->destNode = $destNode; @@ -35,6 +36,7 @@ public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceRefere $this->lazy = $lazy; $this->weak = $weak; $this->byConstructor = $byConstructor; + $this->byMultiUseArgument = $byMultiUseArgument; } /** @@ -84,4 +86,9 @@ public function isReferencedByConstructor(): bool { return $this->byConstructor; } + + public function isFromMultiUseArgument(): bool + { + return $this->byMultiUseArgument; + } } diff --git a/lib/symfony/dependency-injection/ContainerBuilder.php b/lib/symfony/dependency-injection/ContainerBuilder.php index fdbd290baf..bca4356310 100644 --- a/lib/symfony/dependency-injection/ContainerBuilder.php +++ b/lib/symfony/dependency-injection/ContainerBuilder.php @@ -207,7 +207,7 @@ public function registerExtension(ExtensionInterface $extension) $this->extensions[$extension->getAlias()] = $extension; if (false !== $extension->getNamespace()) { - $this->extensionsByNs[$extension->getNamespace()] = $extension; + $this->extensionsByNs[$extension->getNamespace() ?? ''] = $extension; } } diff --git a/lib/symfony/dependency-injection/Dumper/PhpDumper.php b/lib/symfony/dependency-injection/Dumper/PhpDumper.php index b897cb2fce..d55a5a1005 100644 --- a/lib/symfony/dependency-injection/Dumper/PhpDumper.php +++ b/lib/symfony/dependency-injection/Dumper/PhpDumper.php @@ -458,7 +458,7 @@ private function collectCircularReferences(string $sourceId, array $edges, array foreach ($edges as $edge) { $node = $edge->getDestNode(); $id = $node->getId(); - if ($sourceId === $id || !$node->getValue() instanceof Definition || $edge->isWeak()) { + if (($sourceId === $id && !$edge->isLazy()) || !$node->getValue() instanceof Definition || $edge->isWeak()) { continue; } @@ -699,7 +699,6 @@ private function addServiceInstance(string $id, Definition $definition, bool $is $asGhostObject = false; $isProxyCandidate = $this->isProxyCandidate($definition, $asGhostObject, $id); - $instantiation = ''; $lastWitherIndex = null; foreach ($definition->getMethodCalls() as $k => $call) { @@ -708,20 +707,26 @@ private function addServiceInstance(string $id, Definition $definition, bool $is } } - if (!$isProxyCandidate && $definition->isShared() && !isset($this->singleUsePrivateIds[$id]) && null === $lastWitherIndex) { - $instantiation = \sprintf('$container->%s[%s] = %s', $this->container->getDefinition($id)->isPublic() ? 'services' : 'privates', $this->doExport($id), $isSimpleInstance ? '' : '$instance'); - } elseif (!$isSimpleInstance) { - $instantiation = '$instance'; - } + $shouldShareInline = !$isProxyCandidate && $definition->isShared() && !isset($this->singleUsePrivateIds[$id]) && null === $lastWitherIndex; + $serviceAccessor = \sprintf('$container->%s[%s]', $this->container->getDefinition($id)->isPublic() ? 'services' : 'privates', $this->doExport($id)); + $return = match (true) { + $shouldShareInline && !isset($this->circularReferences[$id]) && $isSimpleInstance => 'return '.$serviceAccessor.' = ', + $shouldShareInline && !isset($this->circularReferences[$id]) => $serviceAccessor.' = $instance = ', + $shouldShareInline || !$isSimpleInstance => '$instance = ', + default => 'return ', + }; - $return = ''; - if ($isSimpleInstance) { - $return = 'return '; - } else { - $instantiation .= ' = '; + $code = $this->addNewInstance($definition, ' '.$return, $id, $asGhostObject); + + if ($shouldShareInline && isset($this->circularReferences[$id])) { + $code .= \sprintf( + "\n if (isset(%s)) {\n return %1\$s;\n }\n\n %s%1\$s = \$instance;\n", + $serviceAccessor, + $isSimpleInstance ? 'return ' : '' + ); } - return $this->addNewInstance($definition, ' '.$return.$instantiation, $id, $asGhostObject); + return $code; } private function isTrivialInstance(Definition $definition): bool @@ -1055,7 +1060,7 @@ private function addInlineService(string $id, Definition $definition, ?Definitio $code = ''; if ($isSimpleInstance = $isRootInstance = null === $inlineDef) { - foreach ($this->serviceCalls as $targetId => [$callCount, $behavior, $byConstructor]) { + foreach ($this->serviceCalls as $targetId => [, , $byConstructor]) { if ($byConstructor && isset($this->circularReferences[$id][$targetId]) && !$this->circularReferences[$id][$targetId] && !($this->hasProxyDumper && $definition->isLazy())) { $code .= $this->addInlineReference($id, $definition, $targetId, $forConstructor); } @@ -1208,6 +1213,7 @@ private function addNewInstance(Definition $definition, string $return = '', ?st || ($callable[0] instanceof Definition && !$this->definitionVariables->offsetExists($callable[0])) ))) { $initializer = 'fn () => '.$this->dumpValue($callable[0]); + $this->preload[LazyClosure::class] = LazyClosure::class; return $return.LazyClosure::getCode($initializer, $callable, $class, $this->container, $id).$tail; } @@ -1610,27 +1616,28 @@ public function getParameter(string $name): array|bool|string|int|float|\UnitEnu trigger_deprecation(...self::DEPRECATED_PARAMETERS[$name]); } - if (isset($this->buildParameters[$name])) { + if (\array_key_exists($name, $this->buildParameters)) { return $this->buildParameters[$name]; } - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || \array_key_exists($name, $this->parameters))) { - throw new ParameterNotFoundException($name); - } if (isset($this->loadedDynamicParameters[$name])) { return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); } + if (!\array_key_exists($name, $this->parameters) || '.' === ($name[0] ?? '')) { + throw new ParameterNotFoundException($name); + } + return $this->parameters[$name]; } public function hasParameter(string $name): bool { - if (isset($this->buildParameters[$name])) { + if (\array_key_exists($name, $this->buildParameters)) { return true; } - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || \array_key_exists($name, $this->parameters); + return \array_key_exists($name, $this->parameters) || isset($this->loadedDynamicParameters[$name]); } public function setParameter(string $name, $value): void @@ -1843,7 +1850,15 @@ private function dumpValue(mixed $value, bool $interpolate = true): string $returnedType = ''; if ($value instanceof TypedReference) { - $returnedType = \sprintf(': %s\%s', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $value->getInvalidBehavior() ? '' : '?', str_replace(['|', '&'], ['|\\', '&\\'], $value->getType())); + $type = $value->getType(); + $nullable = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $value->getInvalidBehavior() ? '' : '?'; + + if ('?' === ($type[0] ?? '')) { + $type = substr($type, 1); + $nullable = '?'; + } + + $returnedType = \sprintf(': %s\%s', $nullable, str_replace(['|', '&'], ['|\\', '&\\'], $type)); } $attribute = ''; @@ -2180,7 +2195,7 @@ private function isSingleUsePrivateNode(ServiceReferenceGraphNode $node): bool if (!$value = $edge->getSourceNode()->getValue()) { continue; } - if ($edge->isLazy() || !$value instanceof Definition || !$value->isShared()) { + if ($edge->isLazy() || !$value instanceof Definition || !$value->isShared() || $edge->isFromMultiUseArgument()) { return false; } diff --git a/lib/symfony/dependency-injection/EnvVarProcessor.php b/lib/symfony/dependency-injection/EnvVarProcessor.php index 07fae98719..b5bf0b22c6 100644 --- a/lib/symfony/dependency-injection/EnvVarProcessor.php +++ b/lib/symfony/dependency-injection/EnvVarProcessor.php @@ -325,7 +325,7 @@ public function getEnv(string $prefix, string $name, \Closure $getEnv): mixed } if ('query_string' === $prefix) { - $queryString = parse_url($env, \PHP_URL_QUERY) ?: $env; + $queryString = parse_url($env, \PHP_URL_QUERY) ?: (parse_url($env, \PHP_URL_SCHEME) ? '' : $env); parse_str($queryString, $result); return $result; diff --git a/lib/symfony/dependency-injection/Loader/Configurator/AbstractConfigurator.php b/lib/symfony/dependency-injection/Loader/Configurator/AbstractConfigurator.php index 5be4a2672a..d96eacb6dc 100644 --- a/lib/symfony/dependency-injection/Loader/Configurator/AbstractConfigurator.php +++ b/lib/symfony/dependency-injection/Loader/Configurator/AbstractConfigurator.php @@ -46,15 +46,12 @@ public function __call(string $method, array $args) throw new \BadMethodCallException(\sprintf('Call to undefined method "%s::%s()".', static::class, $method)); } - 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/lib/symfony/dependency-injection/Loader/FileLoader.php b/lib/symfony/dependency-injection/Loader/FileLoader.php index 0a54c43445..1b6cd6c2c2 100644 --- a/lib/symfony/dependency-injection/Loader/FileLoader.php +++ b/lib/symfony/dependency-injection/Loader/FileLoader.php @@ -166,12 +166,12 @@ public function registerClasses(Definition $prototype, string $namespace, string $this->interfaces[] = $class; } else { $this->setDefinition($class, $definition = $getPrototype()); + $definition->setClass($class); if (null !== $errorMessage) { $definition->addError($errorMessage); continue; } - $definition->setClass($class); $interfaces = []; foreach (class_implements($class, false) as $interface) { diff --git a/lib/symfony/dependency-injection/Loader/PhpFileLoader.php b/lib/symfony/dependency-injection/Loader/PhpFileLoader.php index f01cf39d7c..fb6cc81f7c 100644 --- a/lib/symfony/dependency-injection/Loader/PhpFileLoader.php +++ b/lib/symfony/dependency-injection/Loader/PhpFileLoader.php @@ -57,6 +57,9 @@ public function load(mixed $resource, ?string $type = null): mixed return include $path; }, $this, ProtectedPhpFileLoader::class); + $instanceof = $this->instanceof; + $this->instanceof = []; + try { $callback = $load($path, $this->env); @@ -64,7 +67,7 @@ public function load(mixed $resource, ?string $type = null): mixed $this->executeCallback($callback, new ContainerConfigurator($this->container, $this, $this->instanceof, $path, $resource, $this->env), $path); } } finally { - $this->instanceof = []; + $this->instanceof = $instanceof; $this->registerAliasesForSinglyImplementedInterfaces(); } diff --git a/lib/symfony/dotenv/Command/DotenvDumpCommand.php b/lib/symfony/dotenv/Command/DotenvDumpCommand.php index 49495b7063..815c8e422e 100644 --- a/lib/symfony/dotenv/Command/DotenvDumpCommand.php +++ b/lib/symfony/dotenv/Command/DotenvDumpCommand.php @@ -23,7 +23,13 @@ /** * A console command to compile .env files into a PHP-optimized file called .env.local.php. * - * @internal + * To use this command, first register it explicitly as a service, e.g in your services.yaml file: + * + * ```yaml + * services: + * # [...] + * Symfony\Component\Dotenv\Command\DotenvDumpCommand: ~ + * ``` */ #[Autoconfigure(bind: ['$projectDir' => '%kernel.project_dir%', '$defaultEnv' => '%kernel.environment%'])] #[AsCommand(name: 'dotenv:dump', description: 'Compile .env files to .env.local.php')] diff --git a/lib/symfony/error-handler/BufferingLogger.php b/lib/symfony/error-handler/BufferingLogger.php index 3fc741e3ea..ddd0863f8f 100644 --- a/lib/symfony/error-handler/BufferingLogger.php +++ b/lib/symfony/error-handler/BufferingLogger.php @@ -35,15 +35,12 @@ public function cleanLogs(): array return $logs; } - 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/lib/symfony/error-handler/DebugClassLoader.php b/lib/symfony/error-handler/DebugClassLoader.php index 9773345519..078f8af56a 100644 --- a/lib/symfony/error-handler/DebugClassLoader.php +++ b/lib/symfony/error-handler/DebugClassLoader.php @@ -1216,7 +1216,7 @@ private function parsePhpDoc(\Reflector $reflector): array $static = 'static' === $parts[0]; for ($i = $static ? 2 : 0; null !== $p = $parts[$i] ?? null; $i += 2) { - if (\in_array($p, ['', '|', '&', 'callable'], true) || \in_array(substr($returnType, -1), ['|', '&'], true)) { + if (\in_array($p, ['', 'callable'], true) || \in_array(substr($returnType, -1), ['|', '&'], true) || \in_array($p[0], ['|', '&'], true)) { $returnType .= trim($parts[$i - 1] ?? '').$p; continue; } diff --git a/lib/symfony/error-handler/ErrorRenderer/FileLinkFormatter.php b/lib/symfony/error-handler/ErrorRenderer/FileLinkFormatter.php index ca793b0752..48f3a0a9df 100644 --- a/lib/symfony/error-handler/ErrorRenderer/FileLinkFormatter.php +++ b/lib/symfony/error-handler/ErrorRenderer/FileLinkFormatter.php @@ -67,14 +67,11 @@ public function format(string $file, int $line): string|bool return false; } - /** - * @internal - */ - public function __sleep(): array + public function __serialize(): array { $this->fileLinkFormat = $this->getFileLinkFormat(); - return ['fileLinkFormat']; + return ['fileLinkFormat' => $this->fileLinkFormat]; } /** diff --git a/lib/symfony/finder/Finder.php b/lib/symfony/finder/Finder.php index 51d2b48e72..83e5d2a8b6 100644 --- a/lib/symfony/finder/Finder.php +++ b/lib/symfony/finder/Finder.php @@ -57,8 +57,10 @@ class Finder implements \IteratorAggregate, \Countable private bool $reverseSorting = false; private \Closure|int|false $sort = false; private int $ignore = 0; + /** @var list */ private array $dirs = []; private array $dates = []; + /** @var list> */ private array $iterators = []; private array $contains = []; private array $notContains = []; @@ -666,27 +668,33 @@ public function in(string|array $dirs): static */ public function getIterator(): \Iterator { - if (0 === \count($this->dirs) && 0 === \count($this->iterators)) { + if (!$this->dirs && !$this->iterators) { throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.'); } - if (1 === \count($this->dirs) && 0 === \count($this->iterators)) { + if (1 === \count($this->dirs) && !$this->iterators) { $iterator = $this->searchInDirectory($this->dirs[0]); - - if ($this->sort || $this->reverseSorting) { - $iterator = (new SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); + } else { + $iterator = new \AppendIterator(); + foreach ($this->dirs as $dir) { + $iterator->append(new \IteratorIterator(new LazyIterator(fn () => $this->searchInDirectory($dir)))); } - return $iterator; - } - - $iterator = new \AppendIterator(); - foreach ($this->dirs as $dir) { - $iterator->append(new \IteratorIterator(new LazyIterator(fn () => $this->searchInDirectory($dir)))); - } - - foreach ($this->iterators as $it) { - $iterator->append($it); + foreach ($this->iterators as $it) { + $iterator->append(new \IteratorIterator(new LazyIterator(static function () use ($it) { + foreach ($it as $file) { + if (!$file instanceof \SplFileInfo) { + $file = new \SplFileInfo($file); + } + $key = $file->getPathname(); + if (!$file instanceof SplFileInfo) { + $file = new SplFileInfo($key, $file->getPath(), $key); + } + + yield $key => $file; + } + }))); + } } if ($this->sort || $this->reverseSorting) { @@ -701,26 +709,13 @@ public function getIterator(): \Iterator * * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array. * - * @return $this + * @param iterable $iterator * - * @throws \InvalidArgumentException when the given argument is not iterable + * @return $this */ public function append(iterable $iterator): static { - if ($iterator instanceof \IteratorAggregate) { - $this->iterators[] = $iterator->getIterator(); - } elseif ($iterator instanceof \Iterator) { - $this->iterators[] = $iterator; - } elseif (is_iterable($iterator)) { - $it = new \ArrayIterator(); - foreach ($iterator as $file) { - $file = $file instanceof \SplFileInfo ? $file : new \SplFileInfo($file); - $it[$file->getPathname()] = $file; - } - $this->iterators[] = $it; - } else { - throw new \InvalidArgumentException('Finder::append() method wrong argument type.'); - } + $this->iterators[] = $iterator; return $this; } diff --git a/lib/symfony/finder/Glob.php b/lib/symfony/finder/Glob.php index 7fe8b1a86c..d950e48fc7 100644 --- a/lib/symfony/finder/Glob.php +++ b/lib/symfony/finder/Glob.php @@ -44,6 +44,9 @@ public static function toRegex(string $glob, bool $strictLeadingDot = true, bool $escaping = false; $inCurlies = 0; $regex = ''; + if ($unanchored = str_starts_with($glob, '**/')) { + $glob = '/'.$glob; + } $sizeGlob = \strlen($glob); for ($i = 0; $i < $sizeGlob; ++$i) { $car = $glob[$i]; @@ -104,6 +107,10 @@ public static function toRegex(string $glob, bool $strictLeadingDot = true, bool $escaping = false; } + if ($unanchored) { + $regex = substr_replace($regex, '?', 1 + ('/' === $delimiter) + ($strictLeadingDot ? \strlen('(?=[^\.])') : 0), 0); + } + return $delimiter.'^'.$regex.'$'.$delimiter; } } diff --git a/lib/symfony/form/AbstractRendererEngine.php b/lib/symfony/form/AbstractRendererEngine.php index 3f1ab79c26..e81155b469 100644 --- a/lib/symfony/form/AbstractRendererEngine.php +++ b/lib/symfony/form/AbstractRendererEngine.php @@ -50,6 +50,11 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface, Re */ private array $resourceHierarchyLevels = []; + /** + * @var array> + */ + private array $resourceInheritability = []; + /** * Creates a new renderer engine. * @@ -75,7 +80,17 @@ public function setTheme(FormView $view, mixed $themes, bool $useDefaultThemes = // Unset instead of resetting to an empty array, in order to allow // implementations (like TwigRendererEngine) to check whether $cacheKey // is set at all. - unset($this->resources[$cacheKey], $this->resourceHierarchyLevels[$cacheKey]); + unset($this->resources[$cacheKey], $this->resourceHierarchyLevels[$cacheKey], $this->resourceInheritability[$cacheKey]); + } + + protected function setResourceInheritability(string $cacheKey, string $blockName, bool $inheritable): void + { + $this->resourceInheritability[$cacheKey][$blockName] = $inheritable; + } + + protected function isResourceInheritable(string $cacheKey, string $blockName): bool + { + return $this->resourceInheritability[$cacheKey][$blockName] ?? false; } public function getResourceForBlockName(FormView $view, string $blockName): mixed @@ -144,6 +159,7 @@ private function loadResourceForBlockNameHierarchy(string $cacheKey, FormView $v // cache. The only missing thing is to set the hierarchy level at which // the template was found. $this->resourceHierarchyLevels[$cacheKey][$blockName] = $hierarchyLevel; + $this->setResourceInheritability($cacheKey, $blockName, true); return true; } @@ -167,6 +183,7 @@ private function loadResourceForBlockNameHierarchy(string $cacheKey, FormView $v // Cache the shortcuts for further accesses $this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName]; $this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName]; + $this->setResourceInheritability($cacheKey, $blockName, false); return true; } @@ -175,6 +192,7 @@ private function loadResourceForBlockNameHierarchy(string $cacheKey, FormView $v // Cache the shortcuts for further accesses $this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName]; $this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName]; + $this->setResourceInheritability($cacheKey, $blockName, false); return true; } @@ -183,6 +201,7 @@ private function loadResourceForBlockNameHierarchy(string $cacheKey, FormView $v // Cache the result for further accesses $this->resources[$cacheKey][$blockName] = false; $this->resourceHierarchyLevels[$cacheKey][$blockName] = false; + $this->setResourceInheritability($cacheKey, $blockName, true); return false; } @@ -193,5 +212,6 @@ public function reset(): void $this->useDefaultThemes = []; $this->resources = []; $this->resourceHierarchyLevels = []; + $this->resourceInheritability = []; } } diff --git a/lib/symfony/form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/lib/symfony/form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php index 5a07147912..d83ea3eceb 100644 --- a/lib/symfony/form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php +++ b/lib/symfony/form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php @@ -24,6 +24,15 @@ */ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer { + /** + * Unicode whitespace characters used by ICU in formatted date strings. + * + * @see https://unicode-org.atlassian.net/browse/CLDR-14032 + */ + private const NO_BREAK_SPACE = "\u{00A0}"; + private const NARROW_NO_BREAK_SPACE = "\u{202F}"; // Used by ICU 72+ before AM/PM + private const THIN_SPACE = "\u{2009}"; + private int $dateFormat; private int $timeFormat; private ?string $pattern; @@ -86,7 +95,7 @@ public function transform(mixed $dateTime): string throw new TransformationFailedException(intl_get_error_message()); } - return $value; + return self::normalizeWhitespace($value); } /** @@ -112,11 +121,7 @@ public function reverseTransform(mixed $value): ?\DateTime $dateOnly = $this->isPatternDateOnly(); $dateFormatter = $this->getIntlDateFormatter($dateOnly); - try { - $timestamp = @$dateFormatter->parse($value); - } catch (\IntlException $e) { - throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); - } + $timestamp = $this->parse($dateFormatter, $value); if (0 != intl_get_error_code()) { throw new TransformationFailedException(intl_get_error_message(), intl_get_error_code()); @@ -194,4 +199,47 @@ protected function isPatternDateOnly(): bool // check for the absence of time-related placeholders return 0 === preg_match('#[ahHkKmsSAzZOvVxX]#', $pattern); } + + /** + * Normalizes various Unicode whitespace characters to regular ASCII spaces. + * + * ICU 72+ uses special Unicode whitespace characters (such as narrow no-break space U+202F) + * in formatted date strings. This method ensures consistent handling regardless of ICU version + * by normalizing these characters to regular ASCII spaces (U+0020). + */ + private static function normalizeWhitespace(string $string): string + { + return str_replace([self::NO_BREAK_SPACE, self::NARROW_NO_BREAK_SPACE, self::THIN_SPACE], ' ', $string); + } + + /** + * Parses a localized date string, handling ICU version differences in whitespace. + * + * ICU 72+ uses special Unicode whitespace characters (such as narrow no-break space U+202F) + * that users typically don't type. This method first tries parsing the input as-is, then + * tries with whitespace normalization to ensure compatibility across ICU versions. + * + * @throws TransformationFailedException When the input cannot be parsed + */ + private function parse(\IntlDateFormatter $dateFormatter, string $value): int|float|false + { + try { + $timestamp = @$dateFormatter->parse($value); + } catch (\IntlException $e) { + throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); + } + + // If parsing failed and the value contains regular spaces, try with ICU 72+ whitespace + if ((false === $timestamp || 0 !== intl_get_error_code()) && str_contains($value, ' ')) { + $icuValue = str_replace(' ', self::NARROW_NO_BREAK_SPACE, $value); + + try { + $timestamp = @$dateFormatter->parse($icuValue); + } catch (\IntlException) { + // Ignore, we'll use the original error below + } + } + + return $timestamp; + } } diff --git a/lib/symfony/form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/lib/symfony/form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index 6e9db3e091..2d71f7bced 100644 --- a/lib/symfony/form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/lib/symfony/form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -177,7 +177,7 @@ protected function getNumberFormatter(): \NumberFormatter */ protected function castParsedValue(int|float $value): int|float { - if (\is_int($value) && $value === (int) $float = (float) $value) { + if (\is_int($value) && (($float = (float) $value) < \PHP_INT_MAX) && $value === (int) $float) { return $float; } diff --git a/lib/symfony/form/Extension/Core/Type/EnumType.php b/lib/symfony/form/Extension/Core/Type/EnumType.php index bfede9c04d..106cb341d7 100644 --- a/lib/symfony/form/Extension/Core/Type/EnumType.php +++ b/lib/symfony/form/Extension/Core/Type/EnumType.php @@ -30,7 +30,17 @@ public function configureOptions(OptionsResolver $resolver): void ->setAllowedTypes('class', 'string') ->setAllowedValues('class', enum_exists(...)) ->setDefault('choices', static fn (Options $options): array => $options['class']::cases()) - ->setDefault('choice_label', static fn (\UnitEnum $choice) => $choice instanceof TranslatableInterface ? $choice : $choice->name) + ->setDefault('choice_label', static function (Options $options) { + return static function (\UnitEnum $choice, int|string $key): string|TranslatableInterface { + if (\is_int($key)) { + // Key is an integer, use the enum's name (or translatable) + return $choice instanceof TranslatableInterface ? $choice : $choice->name; + } + + // Key is a string, use it as the label + return $key; + }; + }) ->setDefault('choice_value', static function (Options $options): ?\Closure { if (!is_a($options['class'], \BackedEnum::class, true)) { return null; diff --git a/lib/symfony/form/Extension/Core/Type/MoneyType.php b/lib/symfony/form/Extension/Core/Type/MoneyType.php index 9c9e5b4d7c..f4909e23be 100644 --- a/lib/symfony/form/Extension/Core/Type/MoneyType.php +++ b/lib/symfony/form/Extension/Core/Type/MoneyType.php @@ -51,6 +51,12 @@ public function buildView(FormView $view, FormInterface $form, array $options) if ($options['html5']) { $view->vars['type'] = 'number'; + + if (!isset($view->vars['attr']['step'])) { + $view->vars['attr']['step'] = 'any'; + } + } else { + $view->vars['attr']['inputmode'] = 0 === $options['scale'] ? 'numeric' : 'decimal'; } } diff --git a/lib/symfony/form/Extension/Core/Type/TextareaType.php b/lib/symfony/form/Extension/Core/Type/TextareaType.php index 40e7580d80..3c485b83af 100644 --- a/lib/symfony/form/Extension/Core/Type/TextareaType.php +++ b/lib/symfony/form/Extension/Core/Type/TextareaType.php @@ -12,11 +12,22 @@ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\DataTransformerInterface; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; +use Symfony\Component\Form\Util\StringUtil; -class TextareaType extends AbstractType +class TextareaType extends AbstractType implements DataTransformerInterface { + /** + * @return void + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->addViewTransformer($this); + } + /** * @return void */ @@ -35,4 +46,26 @@ public function getBlockPrefix(): string { return 'textarea'; } + + public function transform(mixed $value): mixed + { + if (null === $value) { + return ''; + } + + return $value; + } + + public function reverseTransform(mixed $value): mixed + { + if (!\is_string($value)) { + return $value; + } + + if ('' === $value) { + return null; + } + + return StringUtil::normalizeNewlines($value); + } } diff --git a/lib/symfony/form/FormBuilder.php b/lib/symfony/form/FormBuilder.php index beabdd03c8..3c0f4e2179 100644 --- a/lib/symfony/form/FormBuilder.php +++ b/lib/symfony/form/FormBuilder.php @@ -26,192 +26,192 @@ */ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormBuilderInterface { - /** - * The children of the form builder. - * - * @var FormBuilderInterface[] - */ - private array $children = []; + /** + * The children of the form builder. + * + * @var FormBuilderInterface[] + */ + private array $children = []; - /** - * The data of children who haven't been converted to form builders yet. - */ - private array $unresolvedChildren = []; - - public function __construct(?string $name, ?string $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory, array $options = []) - { - parent::__construct($name, $dataClass, $dispatcher, $options); - - $this->setFormFactory($factory); - } + /** + * The data of children who haven't been converted to form builders yet. + */ + private array $unresolvedChildren = []; + + public function __construct(?string $name, ?string $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory, array $options = []) + { + parent::__construct($name, $dataClass, $dispatcher, $options); + + $this->setFormFactory($factory); + } - public function add(FormBuilderInterface|string $child, ?string $type = null, array $options = []): static - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } - - if ($child instanceof FormBuilderInterface) { - $this->children[$child->getName()] = $child; - - // In case an unresolved child with the same name exists - unset($this->unresolvedChildren[$child->getName()]); + public function add(FormBuilderInterface|string $child, ?string $type = null, array $options = []): static + { + if ($this->locked) { + throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); + } + + if ($child instanceof FormBuilderInterface) { + $this->children[$child->getName()] = $child; + + // In case an unresolved child with the same name exists + unset($this->unresolvedChildren[$child->getName()]); - return $this; - } - - if (!\is_string($child) && !\is_int($child)) { - throw new UnexpectedTypeException($child, 'string or Symfony\Component\Form\FormBuilderInterface'); - } + return $this; + } + + if (!\is_string($child) && !\is_int($child)) { + throw new UnexpectedTypeException($child, 'string or Symfony\Component\Form\FormBuilderInterface'); + } - // Add to "children" to maintain order - $this->children[$child] = null; - $this->unresolvedChildren[$child] = [$type, $options]; + // Add to "children" to maintain order + $this->children[$child] = null; + $this->unresolvedChildren[$child] = [$type, $options]; - return $this; - } + return $this; + } - public function create(string $name, ?string $type = null, array $options = []): FormBuilderInterface - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } + public function create(string $name, ?string $type = null, array $options = []): FormBuilderInterface + { + if ($this->locked) { + throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); + } - if (null === $type && null === $this->getDataClass()) { - $type = TextType::class; - } + if (null === $type && null === $this->getDataClass()) { + $type = TextType::class; + } - if (null !== $type) { - return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options); - } - - return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options); - } - - public function get(string $name): FormBuilderInterface - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } - - if (isset($this->unresolvedChildren[$name])) { - return $this->resolveChild($name); - } - - if (isset($this->children[$name])) { - return $this->children[$name]; - } - - throw new InvalidArgumentException(\sprintf('The child with the name "%s" does not exist.', $name)); - } - - public function remove(string $name): static - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } - - unset($this->unresolvedChildren[$name], $this->children[$name]); - - return $this; - } - - public function has(string $name): bool - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } - - return isset($this->unresolvedChildren[$name]) || isset($this->children[$name]); - } - - public function all(): array - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } - - $this->resolveChildren(); - - return $this->children; - } - - public function count(): int - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } - - return \count($this->children); - } - - public function getFormConfig(): FormConfigInterface - { - /** @var self $config */ - $config = parent::getFormConfig(); - - $config->children = []; - $config->unresolvedChildren = []; - - return $config; - } - - public function getForm(): FormInterface - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } - - $this->resolveChildren(); - - $form = new Form($this->getFormConfig()); - - foreach ($this->children as $child) { - // Automatic initialization is only supported on root forms - $form->add($child->setAutoInitialize(false)->getForm()); - } - - if ($this->getAutoInitialize()) { - // Automatically initialize the form if it is configured so - $form->initialize(); - } - - return $form; - } - - /** - * @return \Traversable - */ - public function getIterator(): \Traversable - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } - - return new \ArrayIterator($this->all()); - } - - /** - * Converts an unresolved child into a {@link FormBuilderInterface} instance. - */ - private function resolveChild(string $name): FormBuilderInterface - { - [$type, $options] = $this->unresolvedChildren[$name]; - - unset($this->unresolvedChildren[$name]); - - return $this->children[$name] = $this->create($name, $type, $options); - } - - /** - * Converts all unresolved children into {@link FormBuilder} instances. - */ - private function resolveChildren(): void - { - foreach ($this->unresolvedChildren as $name => $info) { - $this->children[$name] = $this->create($name, $info[0], $info[1]); - } - - $this->unresolvedChildren = []; - } + if (null !== $type) { + return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options); + } + + return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options); + } + + public function get(string $name): FormBuilderInterface + { + if ($this->locked) { + throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); + } + + if (isset($this->unresolvedChildren[$name])) { + return $this->resolveChild($name); + } + + if (isset($this->children[$name])) { + return $this->children[$name]; + } + + throw new InvalidArgumentException(\sprintf('The child with the name "%s" does not exist.', $name)); + } + + public function remove(string $name): static + { + if ($this->locked) { + throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); + } + + unset($this->unresolvedChildren[$name], $this->children[$name]); + + return $this; + } + + public function has(string $name): bool + { + if ($this->locked) { + throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); + } + + return isset($this->unresolvedChildren[$name]) || isset($this->children[$name]); + } + + public function all(): array + { + if ($this->locked) { + throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); + } + + $this->resolveChildren(); + + return $this->children; + } + + public function count(): int + { + if ($this->locked) { + throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); + } + + return \count($this->children); + } + + public function getFormConfig(): FormConfigInterface + { + /** @var self $config */ + $config = parent::getFormConfig(); + + $config->children = []; + $config->unresolvedChildren = []; + + return $config; + } + + public function getForm(): FormInterface + { + if ($this->locked) { + throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); + } + + $this->resolveChildren(); + + $form = new Form($this->getFormConfig()); + + foreach ($this->children as $child) { + // Automatic initialization is only supported on root forms + $form->add($child->setAutoInitialize(false)->getForm()); + } + + if ($this->getAutoInitialize()) { + // Automatically initialize the form if it is configured so + $form->initialize(); + } + + return $form; + } + + /** + * @return \Traversable + */ + public function getIterator(): \Traversable + { + if ($this->locked) { + throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); + } + + return new \ArrayIterator($this->all()); + } + + /** + * Converts an unresolved child into a {@link FormBuilderInterface} instance. + */ + private function resolveChild(string $name): FormBuilderInterface + { + [$type, $options] = $this->unresolvedChildren[$name]; + + unset($this->unresolvedChildren[$name]); + + return $this->children[$name] = $this->create($name, $type, $options); + } + + /** + * Converts all unresolved children into {@link FormBuilder} instances. + */ + private function resolveChildren(): void + { + foreach ($this->unresolvedChildren as $name => $info) { + $this->children[$name] = $this->create($name, $info[0], $info[1]); + } + + $this->unresolvedChildren = []; + } } diff --git a/lib/symfony/form/Resources/translations/validators.nb.xlf b/lib/symfony/form/Resources/translations/validators.nb.xlf index 193306b719..0dd82d3f39 100644 --- a/lib/symfony/form/Resources/translations/validators.nb.xlf +++ b/lib/symfony/form/Resources/translations/validators.nb.xlf @@ -12,7 +12,7 @@ The CSRF token is invalid. Please try to resubmit the form. - CSRF-tokenen er ugyldig. Vennligst prøv å sende inn skjemaet på nytt. + CSRF-tokenen er ugyldig. Vennligst prøv å sende inn skjemaet på nytt. This value is not a valid HTML5 color. diff --git a/lib/symfony/form/Resources/translations/validators.no.xlf b/lib/symfony/form/Resources/translations/validators.no.xlf index 193306b719..0dd82d3f39 100644 --- a/lib/symfony/form/Resources/translations/validators.no.xlf +++ b/lib/symfony/form/Resources/translations/validators.no.xlf @@ -12,7 +12,7 @@ The CSRF token is invalid. Please try to resubmit the form. - CSRF-tokenen er ugyldig. Vennligst prøv å sende inn skjemaet på nytt. + CSRF-tokenen er ugyldig. Vennligst prøv å sende inn skjemaet på nytt. This value is not a valid HTML5 color. diff --git a/lib/symfony/form/Util/OrderedHashMap.php b/lib/symfony/form/Util/OrderedHashMap.php index f92be10a4b..a6409b7346 100644 --- a/lib/symfony/form/Util/OrderedHashMap.php +++ b/lib/symfony/form/Util/OrderedHashMap.php @@ -120,16 +120,11 @@ public function offsetGet(mixed $key): mixed public function offsetSet(mixed $key, mixed $value): void { - if (null === $key || !isset($this->elements[$key])) { - if (null === $key) { - $key = [] === $this->orderedKeys - // If the array is empty, use 0 as key - ? 0 - // Imitate PHP behavior of generating a key that equals - // the highest existing integer key + 1 - : 1 + (int) max($this->orderedKeys); - } - + if (null === $key) { + $this->elements[] = $value; + $key = array_key_last($this->elements); + $this->orderedKeys[] = (string) $key; + } elseif (!\array_key_exists($key, $this->elements)) { $this->orderedKeys[] = (string) $key; } diff --git a/lib/symfony/form/Util/StringUtil.php b/lib/symfony/form/Util/StringUtil.php index 45a50c1adc..2a12ac83c3 100644 --- a/lib/symfony/form/Util/StringUtil.php +++ b/lib/symfony/form/Util/StringUtil.php @@ -36,6 +36,14 @@ public static function trim(string $string): string return trim($string); } + /** + * Converts both CRLF and CR to LF. + */ + public static function normalizeNewlines(string $string): string + { + return str_replace(["\r\n", "\r"], "\n", $string); + } + /** * Converts a fully-qualified class name to a block prefix. * diff --git a/lib/symfony/framework-bundle/CHANGELOG.md b/lib/symfony/framework-bundle/CHANGELOG.md index 949aad31c3..639fe721d2 100644 --- a/lib/symfony/framework-bundle/CHANGELOG.md +++ b/lib/symfony/framework-bundle/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Add `HttpClientAssertionsTrait` * Add `AbstractController::renderBlock()` and `renderBlockView()` + * Remove call to `renderView()` in `AbstractController::render()` * Add native return type to `Translator` and to `Application::reset()` * Deprecate the integration of Doctrine annotations, either uninstall the `doctrine/annotations` package or disable the integration by setting `framework.annotations` to `false` * Enable `json_decode_detailed_errors` context for Serializer by default if `kernel.debug` is true and the `seld/jsonlint` package is installed diff --git a/lib/symfony/framework-bundle/Command/CachePoolPruneCommand.php b/lib/symfony/framework-bundle/Command/CachePoolPruneCommand.php index 208e8123c6..ff90a9dbad 100644 --- a/lib/symfony/framework-bundle/Command/CachePoolPruneCommand.php +++ b/lib/symfony/framework-bundle/Command/CachePoolPruneCommand.php @@ -53,14 +53,21 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); + $exitCode = Command::SUCCESS; foreach ($this->pools as $name => $pool) { $io->comment(\sprintf('Pruning cache pool: %s', $name)); - $pool->prune(); + + if (!$pool->prune()) { + $io->error(\sprintf('Cache pool "%s" could not be pruned.', $name)); + $exitCode = Command::FAILURE; + } } - $io->success('Successfully pruned cache pool(s).'); + if (Command::SUCCESS === $exitCode) { + $io->success('Successfully pruned cache pool(s).'); + } - return 0; + return $exitCode; } } diff --git a/lib/symfony/framework-bundle/Command/ConfigDebugCommand.php b/lib/symfony/framework-bundle/Command/ConfigDebugCommand.php index fb79b39bf4..fcef7c1d6c 100644 --- a/lib/symfony/framework-bundle/Command/ConfigDebugCommand.php +++ b/lib/symfony/framework-bundle/Command/ConfigDebugCommand.php @@ -161,7 +161,7 @@ private function getConfigForPath(array $config, string $path, string $alias): m $steps = explode('.', $path); foreach ($steps as $step) { - if (!\array_key_exists($step, $config)) { + if (!\is_array($config) || !\array_key_exists($step, $config)) { throw new LogicException(\sprintf('Unable to find configuration for "%s.%s".', $alias, $path)); } diff --git a/lib/symfony/framework-bundle/Command/SecretsEncryptFromLocalCommand.php b/lib/symfony/framework-bundle/Command/SecretsEncryptFromLocalCommand.php index 46e0baffc9..0eba8956c0 100644 --- a/lib/symfony/framework-bundle/Command/SecretsEncryptFromLocalCommand.php +++ b/lib/symfony/framework-bundle/Command/SecretsEncryptFromLocalCommand.php @@ -61,14 +61,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int } foreach ($this->vault->list(true) as $name => $value) { - $localValue = $this->localVault->reveal($name); + if (null === $localValue = $this->localVault->reveal($name)) { + continue; + } - if (null !== $localValue && $value !== $localValue) { + if ($value !== $localValue) { $this->vault->seal($name, $localValue); - } elseif (null !== $message = $this->localVault->getLastMessage()) { - $io->error($message); - - return 1; + $io->note($this->vault->getLastMessage()); } } diff --git a/lib/symfony/framework-bundle/Controller/AbstractController.php b/lib/symfony/framework-bundle/Controller/AbstractController.php index a5ab48b59b..b474498168 100644 --- a/lib/symfony/framework-bundle/Controller/AbstractController.php +++ b/lib/symfony/framework-bundle/Controller/AbstractController.php @@ -157,6 +157,10 @@ protected function json(mixed $data, int $status = 200, array $headers = [], arr return new JsonResponse($json, $status, $headers, true); } + if (null === $data) { + return new JsonResponse('null', $status, $headers, true); + } + return new JsonResponse($data, $status, $headers); } diff --git a/lib/symfony/framework-bundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php b/lib/symfony/framework-bundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php index 6e7669a710..428137ff82 100644 --- a/lib/symfony/framework-bundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php +++ b/lib/symfony/framework-bundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php @@ -34,7 +34,10 @@ public function process(ContainerBuilder $container) $definitions = $container->getDefinitions(); foreach ($definitions as $id => $definition) { - if ($id && '.' !== $id[0] && (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag('container.private')) && !$definition->hasErrors() && !$definition->isAbstract()) { + if ($inner = $definition->getTag('container.decorator')[0]['inner'] ?? null) { + $privateServices[$inner] = new Reference($inner, ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE); + } + if ($id && '.' !== $id[0] && ($definition->isPrivate() || $definition->hasTag('container.private')) && !$definition->hasErrors() && !$definition->isAbstract()) { $privateServices[$id] = new Reference($id, ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE); } } diff --git a/lib/symfony/framework-bundle/DependencyInjection/Configuration.php b/lib/symfony/framework-bundle/DependencyInjection/Configuration.php index 78ed8b3ac8..7fe754e3df 100644 --- a/lib/symfony/framework-bundle/DependencyInjection/Configuration.php +++ b/lib/symfony/framework-bundle/DependencyInjection/Configuration.php @@ -358,7 +358,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void ->arrayNode('workflows') ->canBeEnabled() ->beforeNormalization() - ->always(function ($v) { + ->always(static function ($v) { if (\is_array($v) && true === $v['enabled']) { $workflows = $v; unset($workflows['enabled']); @@ -367,7 +367,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void $workflows = []; } - if (1 === \count($workflows) && isset($workflows['workflows']) && !array_is_list($workflows['workflows']) && array_diff(array_keys($workflows['workflows']), ['audit_trail', 'type', 'marking_store', 'supports', 'support_strategy', 'initial_marking', 'places', 'transitions'])) { + if (1 === \count($workflows) && isset($workflows['workflows']) && !array_is_list($workflows['workflows']) && array_diff_key($workflows['workflows'], ['audit_trail' => 1, 'type' => 1, 'marking_store' => 1, 'supports' => 1, 'support_strategy' => 1, 'initial_marking' => 1, 'places' => 1, 'transitions' => 1])) { $workflows = $workflows['workflows']; } @@ -473,27 +473,16 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void throw new InvalidConfigurationException('The "places" option must be an array in workflow configuration.'); } - // It's an indexed array of shape ['place1', 'place2'] - if (isset($places[0]) && \is_string($places[0])) { - return array_map(function (string $place) { - return ['name' => $place]; - }, $places); - } - - // It's an indexed array, we let the validation occur - if (isset($places[0]) && \is_array($places[0])) { - return $places; - } - - foreach ($places as $name => $place) { - if (\is_array($place) && \array_key_exists('name', $place)) { - continue; + $normalizedPlaces = []; + foreach ($places as $key => $value) { + if (!\is_array($value)) { + $value = ['name' => $value]; } - $place['name'] = $name; - $places[$name] = $place; + $value['name'] ??= $key; + $normalizedPlaces[] = $value; } - return array_values($places); + return $normalizedPlaces; }) ->end() ->isRequired() @@ -516,26 +505,26 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void ->end() ->arrayNode('transitions') ->beforeNormalization() - ->always() - ->then(function ($transitions) { + ->always(static function ($transitions) { if (!\is_array($transitions)) { throw new InvalidConfigurationException('The "transitions" option must be an array in workflow configuration.'); } - // It's an indexed array, we let the validation occur - if (isset($transitions[0]) && \is_array($transitions[0])) { - return $transitions; - } - - foreach ($transitions as $name => $transition) { - if (\is_array($transition) && \array_key_exists('name', $transition)) { - continue; + $normalizedTransitions = []; + foreach ($transitions as $key => $transition) { + if (\is_array($transition)) { + if (\is_string($key = $transition['key'] ?? $key)) { + $transition['name'] ??= $key; + } + if (!($transition['name'] ?? false)) { + throw new InvalidConfigurationException('The "name" option is required for each transition in workflow configuration.'); + } + unset($transition['key']); } - $transition['name'] = $name; - $transitions[$name] = $transition; + $normalizedTransitions[$key] = $transition; } - return $transitions; + return $normalizedTransitions; }) ->end() ->isRequired() @@ -552,6 +541,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void ->example('is_fully_authenticated() and is_granted(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'') ->end() ->arrayNode('from') + ->performNoDeepMerging() ->beforeNormalization() ->ifString() ->then(fn ($v) => [$v]) @@ -562,6 +552,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void ->end() ->end() ->arrayNode('to') + ->performNoDeepMerging() ->beforeNormalization() ->ifString() ->then(fn ($v) => [$v]) @@ -1866,6 +1857,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e ->end() ->arrayNode('vars') ->info('Associative array: the default vars used to expand the templated URI.') + ->useAttributeAsKey('name') ->normalizeKeys(false) ->variablePrototype()->end() ->end() @@ -1946,6 +1938,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e ->end() ->arrayNode('extra') ->info('Extra options for specific HTTP client') + ->useAttributeAsKey('name') ->normalizeKeys(false) ->variablePrototype()->end() ->end() @@ -2097,6 +2090,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e ->end() ->arrayNode('extra') ->info('Extra options for specific HTTP client') + ->useAttributeAsKey('name') ->normalizeKeys(false) ->variablePrototype()->end() ->end() diff --git a/lib/symfony/framework-bundle/DependencyInjection/FrameworkExtension.php b/lib/symfony/framework-bundle/DependencyInjection/FrameworkExtension.php index 2071c13c3c..a8ef96b659 100644 --- a/lib/symfony/framework-bundle/DependencyInjection/FrameworkExtension.php +++ b/lib/symfony/framework-bundle/DependencyInjection/FrameworkExtension.php @@ -163,6 +163,7 @@ use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader; use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader; +use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Serializer; @@ -920,11 +921,11 @@ private function registerProfilerConfiguration(array $config, ContainerBuilder $ $container->getDefinition('profiler_listener') ->addArgument($config['collect_parameter']); - if (!$container->getParameter('kernel.debug') || !class_exists(CliRequest::class) || !$container->has('debug.stopwatch')) { + if (!$container->getParameter('kernel.debug') || !$this->hasConsole() || !$container->has('debug.stopwatch') || !class_exists(CliRequest::class)) { $container->removeDefinition('console_profiler_listener'); } - if (!class_exists(CommandDataCollector::class)) { + if (!$this->hasConsole() || !class_exists(CommandDataCollector::class)) { $container->removeDefinition('.data_collector.command'); } } @@ -972,16 +973,16 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ $transitionCounter = 0; foreach ($workflow['transitions'] as $transition) { if ('workflow' === $type) { - $transitionDefinition = new Definition(Workflow\Transition::class, [$transition['name'], $transition['from'], $transition['to']]); $transitionId = \sprintf('.%s.transition.%s', $workflowId, $transitionCounter++); - $container->setDefinition($transitionId, $transitionDefinition); + $container->register($transitionId, Workflow\Transition::class) + ->setArguments([$transition['name'], $transition['from'], $transition['to']]); $transitions[] = new Reference($transitionId); if (isset($transition['guard'])) { - $configuration = new Definition(Workflow\EventListener\GuardExpression::class); - $configuration->addArgument(new Reference($transitionId)); - $configuration->addArgument($transition['guard']); $eventName = \sprintf('workflow.%s.guard.%s', $name, $transition['name']); - $guardsConfiguration[$eventName][] = $configuration; + $guardsConfiguration[$eventName][] = new Definition( + Workflow\EventListener\GuardExpression::class, + [new Reference($transitionId), $transition['guard']] + ); } if ($transition['metadata']) { $transitionsMetadataDefinition->addMethodCall('offsetSet', [ @@ -992,16 +993,16 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ } elseif ('state_machine' === $type) { foreach ($transition['from'] as $from) { foreach ($transition['to'] as $to) { - $transitionDefinition = new Definition(Workflow\Transition::class, [$transition['name'], $from, $to]); $transitionId = \sprintf('.%s.transition.%s', $workflowId, $transitionCounter++); - $container->setDefinition($transitionId, $transitionDefinition); + $container->register($transitionId, Workflow\Transition::class) + ->setArguments([$transition['name'], $from, $to]); $transitions[] = new Reference($transitionId); if (isset($transition['guard'])) { - $configuration = new Definition(Workflow\EventListener\GuardExpression::class); - $configuration->addArgument(new Reference($transitionId)); - $configuration->addArgument($transition['guard']); $eventName = \sprintf('workflow.%s.guard.%s', $name, $transition['name']); - $guardsConfiguration[$eventName][] = $configuration; + $guardsConfiguration[$eventName][] = new Definition( + Workflow\EventListener\GuardExpression::class, + [new Reference($transitionId), $transition['guard']] + ); } if ($transition['metadata']) { $transitionsMetadataDefinition->addMethodCall('offsetSet', [ @@ -1622,11 +1623,11 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder foreach ($config['providers'] as $provider) { if ($provider['locales']) { - $locales += $provider['locales']; + $locales = array_merge($locales, $provider['locales']); } } - $locales = array_unique($locales); + $locales = array_values(array_unique($locales)); $container->getDefinition('console.command.translation_pull') ->replaceArgument(4, array_merge($transPaths, [$config['default_path']])) @@ -1954,7 +1955,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder if (isset($config['enable_attributes']) && $config['enable_attributes']) { $annotationLoader = new Definition( AttributeLoader::class, - [new Reference('annotation_reader', ContainerInterface::NULL_ON_INVALID_REFERENCE)] + interface_exists(CacheableSupportsMethodInterface::class) ? [new Reference('annotation_reader', ContainerInterface::NULL_ON_INVALID_REFERENCE)] : [], ); $serializerLoaders[] = $annotationLoader; diff --git a/lib/symfony/framework-bundle/Resources/config/schema/symfony-1.0.xsd b/lib/symfony/framework-bundle/Resources/config/schema/symfony-1.0.xsd index bcf3a4f9e6..4a650af6bc 100644 --- a/lib/symfony/framework-bundle/Resources/config/schema/symfony-1.0.xsd +++ b/lib/symfony/framework-bundle/Resources/config/schema/symfony-1.0.xsd @@ -471,7 +471,8 @@ - + + diff --git a/lib/symfony/framework-bundle/Test/KernelTestCase.php b/lib/symfony/framework-bundle/Test/KernelTestCase.php index c64b0e25f9..5c337b7300 100644 --- a/lib/symfony/framework-bundle/Test/KernelTestCase.php +++ b/lib/symfony/framework-bundle/Test/KernelTestCase.php @@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; +use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Contracts\Service\ResetInterface; @@ -82,6 +83,18 @@ protected static function bootKernel(array $options = []): KernelInterface static::$kernel = $kernel; static::$booted = true; + // If the cache warmer is registered, it means that the cache has been + // warmed up, so the current container is not fresh anymore. Let's + // reboot a fresh one. + if (self::getContainer()->initialized('cache_warmer')) { + static::ensureKernelShutdown(); + + $kernel = static::createKernel($options); + $kernel->boot(); + static::$kernel = $kernel; + static::$booted = true; + } + return static::$kernel; } @@ -135,6 +148,11 @@ protected static function ensureKernelShutdown() static::$kernel->boot(); $container = static::$kernel->getContainer(); + $httpCacheDir = null; + if ($container->has('http_cache')) { + $httpCacheDir = static::$kernel->getCacheDir().'/http_cache'; + } + if ($container->has('services_resetter')) { // Instantiate the service because Container::reset() only resets services that have been used $container->get('services_resetter'); @@ -146,6 +164,10 @@ protected static function ensureKernelShutdown() if ($container instanceof ResetInterface) { $container->reset(); } + + if (null !== $httpCacheDir && is_dir($httpCacheDir)) { + (new Filesystem())->remove($httpCacheDir); + } } } } diff --git a/lib/symfony/framework-bundle/Test/TestContainer.php b/lib/symfony/framework-bundle/Test/TestContainer.php index 77135fa066..288fd76e8a 100644 --- a/lib/symfony/framework-bundle/Test/TestContainer.php +++ b/lib/symfony/framework-bundle/Test/TestContainer.php @@ -71,15 +71,11 @@ public function set(string $id, mixed $service): void $container = $this->getPublicContainer(); $renamedId = $this->renamedIds[$id] ?? $id; - try { + if (!$this->getPrivateContainer()->has($renamedId)) { $container->set($renamedId, $service); - } catch (InvalidArgumentException $e) { - if (!str_starts_with($e->getMessage(), "The \"$renamedId\" service is private")) { - throw $e; - } - if (isset($container->privates[$renamedId])) { - throw new InvalidArgumentException(\sprintf('The "%s" service is already initialized, you cannot replace it.', $id)); - } + } elseif (isset($container->privates[$renamedId])) { + throw new InvalidArgumentException(\sprintf('The "%s" service is already initialized, you cannot replace it.', $id)); + } else { $container->privates[$renamedId] = $service; } } diff --git a/lib/symfony/http-foundation/AcceptHeader.php b/lib/symfony/http-foundation/AcceptHeader.php index 853c000e00..e735c75647 100644 --- a/lib/symfony/http-foundation/AcceptHeader.php +++ b/lib/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/lib/symfony/http-foundation/Request.php b/lib/symfony/http-foundation/Request.php index a66312c8ed..8a497a77c3 100644 --- a/lib/symfony/http-foundation/Request.php +++ b/lib/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/lib/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php b/lib/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php index 48c219a7aa..8d757f03f1 100644 --- a/lib/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/lib/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php @@ -194,7 +194,6 @@ public function configureSchema(Schema $schema, ?\Closure $isSameDatabase = null $table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true); $table->addColumn($this->lifetimeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true); $table->addColumn($this->timeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true); - $table->addOption('collate', 'utf8mb4_bin'); $table->addOption('engine', 'InnoDB'); break; case 'sqlite': @@ -252,7 +251,7 @@ public function createTable() // - trailing space removal // - case-insensitivity // - language processing like é == e - 'mysql' => "CREATE TABLE $this->table ($this->idCol VARBINARY(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED NOT NULL, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8mb4_bin, ENGINE = InnoDB", + 'mysql' => "CREATE TABLE $this->table ($this->idCol VARBINARY(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED NOT NULL, $this->timeCol INTEGER UNSIGNED NOT NULL), ENGINE = InnoDB", 'sqlite' => "CREATE TABLE $this->table ($this->idCol TEXT NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)", 'pgsql' => "CREATE TABLE $this->table ($this->idCol VARCHAR(128) NOT NULL PRIMARY KEY, $this->dataCol BYTEA NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)", 'oci' => "CREATE TABLE $this->table ($this->idCol VARCHAR2(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)", @@ -795,6 +794,12 @@ private function getInsertStatement(#[\SensitiveParameter] string $sessionId, st rewind($data); $sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, EMPTY_BLOB(), :expiry, :time) RETURNING $this->dataCol into :data"; break; + case 'sqlsrv': + $data = fopen('php://memory', 'r+'); + fwrite($data, $sessionData); + rewind($data); + $sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time)"; + break; default: $data = $sessionData; $sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time)"; @@ -822,6 +827,12 @@ private function getUpdateStatement(#[\SensitiveParameter] string $sessionId, st rewind($data); $sql = "UPDATE $this->table SET $this->dataCol = EMPTY_BLOB(), $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id RETURNING $this->dataCol into :data"; break; + case 'sqlsrv': + $data = fopen('php://memory', 'r+'); + fwrite($data, $sessionData); + rewind($data); + $sql = "UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id"; + break; default: $data = $sessionData; $sql = "UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id"; @@ -869,12 +880,16 @@ private function getMergeStatement(#[\SensitiveParameter] string $sessionId, str $mergeStmt = $this->pdo->prepare($mergeSql); if ('sqlsrv' === $this->driver) { + $dataStream = fopen('php://memory', 'r+'); + fwrite($dataStream, $data); + rewind($dataStream); + $mergeStmt->bindParam(1, $sessionId, \PDO::PARAM_STR); $mergeStmt->bindParam(2, $sessionId, \PDO::PARAM_STR); - $mergeStmt->bindParam(3, $data, \PDO::PARAM_LOB); + $mergeStmt->bindParam(3, $dataStream, \PDO::PARAM_LOB); $mergeStmt->bindValue(4, time() + $maxlifetime, \PDO::PARAM_INT); $mergeStmt->bindValue(5, time(), \PDO::PARAM_INT); - $mergeStmt->bindParam(6, $data, \PDO::PARAM_LOB); + $mergeStmt->bindParam(6, $dataStream, \PDO::PARAM_LOB); $mergeStmt->bindValue(7, time() + $maxlifetime, \PDO::PARAM_INT); $mergeStmt->bindValue(8, time(), \PDO::PARAM_INT); } else { diff --git a/lib/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php b/lib/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php index 43a9eb84e2..e41d035392 100644 --- a/lib/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php +++ b/lib/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php @@ -62,6 +62,7 @@ public static function createHandler(object|string $connection, array $options = throw new \InvalidArgumentException('Unsupported Redis or Memcached DSN. Try running "composer require symfony/cache".'); } $handlerClass = str_starts_with($connection, 'memcached:') ? MemcachedSessionHandler::class : RedisSessionHandler::class; + $connection = preg_replace('/([?&])prefix=[^&]*+&?/', '\1', $connection); $connection = AbstractAdapter::createConnection($connection, ['lazy' => true]); return new $handlerClass($connection, array_intersect_key($options, ['prefix' => 1, 'ttl' => 1])); diff --git a/lib/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php b/lib/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php index 996eacf06f..0fb42944f9 100644 --- a/lib/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php +++ b/lib/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php @@ -168,6 +168,10 @@ private function mapQueryString(Request $request, string $type, MapQueryString $ private function mapRequestPayload(Request $request, string $type, MapRequestPayload $attribute): ?object { + if ('' === $data = $request->request->all() ?: $request->getContent()) { + return null; + } + if (null === $format = $request->getContentTypeFormat()) { throw new HttpException(Response::HTTP_UNSUPPORTED_MEDIA_TYPE, 'Unsupported format.'); } @@ -176,14 +180,10 @@ private function mapRequestPayload(Request $request, string $type, MapRequestPay throw new HttpException(Response::HTTP_UNSUPPORTED_MEDIA_TYPE, \sprintf('Unsupported format, expects "%s", but "%s" given.', implode('", "', (array) $attribute->acceptFormat), $format)); } - if ($data = $request->request->all()) { + if (\is_array($data)) { return $this->serializer->denormalize($data, $type, 'csv', $attribute->serializationContext + self::CONTEXT_DENORMALIZE); } - if ('' === $data = $request->getContent()) { - return null; - } - if ('form' === $format) { throw new HttpException(Response::HTTP_BAD_REQUEST, 'Request payload contains invalid "form" data.'); } diff --git a/lib/symfony/http-kernel/DataCollector/DumpDataCollector.php b/lib/symfony/http-kernel/DataCollector/DumpDataCollector.php index 2300acf914..8c45b42792 100644 --- a/lib/symfony/http-kernel/DataCollector/DumpDataCollector.php +++ b/lib/symfony/http-kernel/DataCollector/DumpDataCollector.php @@ -143,10 +143,7 @@ public function reset(): void $this->clonesIndex = 0; } - /** - * @internal - */ - public function __sleep(): array + public function __serialize(): array { if (!$this->dataCount) { $this->data = []; @@ -161,16 +158,12 @@ public function __sleep(): array $this->dataCount = 0; $this->isCollected = true; - return parent::__sleep(); + return ['data' => $this->data]; } - /** - * @internal - */ - public function __wakeup(): void + public function __unserialize(array $data): void { - parent::__wakeup(); - + $this->data = array_pop($data) ?? []; $charset = array_pop($this->data); $fileLinkFormat = array_pop($this->data); $this->dataCount = \count($this->data); @@ -180,7 +173,7 @@ public function __wakeup(): void } } - self::__construct($this->stopwatch, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \is_string($charset) ? $charset : null); + self::__construct($this->stopwatch ?? null, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \is_string($charset) ? $charset : null); } public function getDumpsCount(): int diff --git a/lib/symfony/http-kernel/EventListener/CacheAttributeListener.php b/lib/symfony/http-kernel/EventListener/CacheAttributeListener.php index 723e758cd0..310e7f25a4 100644 --- a/lib/symfony/http-kernel/EventListener/CacheAttributeListener.php +++ b/lib/symfony/http-kernel/EventListener/CacheAttributeListener.php @@ -13,6 +13,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; +use Symfony\Component\HttpFoundation\HeaderBag; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Attribute\Cache; @@ -123,10 +124,23 @@ public function onKernelResponse(ResponseEvent $event) unset($this->lastModified[$request]); unset($this->etags[$request]); - $hasVary = $response->headers->has('Vary'); + // Check if the response has a Vary header that should be considered, ignoring cases where + // it's only 'Accept-Language' and the request has the '_vary_by_language' attribute + $hasVary = ['Accept-Language'] === $response->getVary() ? !$request->attributes->get('_vary_by_language') : $response->hasVary(); + //Check if cache-control directive was set manually in cacheControl (not auto computed) + $hasCacheControlDirective = new class($response->headers) extends HeaderBag { + public function __construct(private parent $headerBag) + { + } + + public function __invoke(string $key): bool + { + return \array_key_exists($key, $this->headerBag->cacheControl); + } + }; foreach (array_reverse($attributes) as $cache) { - if (null !== $cache->smaxage && !$response->headers->hasCacheControlDirective('s-maxage')) { + if (null !== $cache->smaxage && !$hasCacheControlDirective('s-maxage')) { $response->setSharedMaxAge($this->toSeconds($cache->smaxage)); } @@ -134,19 +148,19 @@ public function onKernelResponse(ResponseEvent $event) $response->headers->addCacheControlDirective('must-revalidate'); } - if (null !== $cache->maxage && !$response->headers->hasCacheControlDirective('max-age')) { + if (null !== $cache->maxage && !$hasCacheControlDirective('max-age')) { $response->setMaxAge($this->toSeconds($cache->maxage)); } - if (null !== $cache->maxStale && !$response->headers->hasCacheControlDirective('max-stale')) { + if (null !== $cache->maxStale && !$hasCacheControlDirective('max-stale')) { $response->headers->addCacheControlDirective('max-stale', $this->toSeconds($cache->maxStale)); } - if (null !== $cache->staleWhileRevalidate && !$response->headers->hasCacheControlDirective('stale-while-revalidate')) { + if (null !== $cache->staleWhileRevalidate && !$hasCacheControlDirective('stale-while-revalidate')) { $response->headers->addCacheControlDirective('stale-while-revalidate', $this->toSeconds($cache->staleWhileRevalidate)); } - if (null !== $cache->staleIfError && !$response->headers->hasCacheControlDirective('stale-if-error')) { + if (null !== $cache->staleIfError && !$hasCacheControlDirective('stale-if-error')) { $response->headers->addCacheControlDirective('stale-if-error', $this->toSeconds($cache->staleIfError)); } @@ -159,12 +173,14 @@ public function onKernelResponse(ResponseEvent $event) } } + $hasPublicOrPrivateCacheControlDirective = $hasCacheControlDirective('public') || $hasCacheControlDirective('private'); + foreach ($attributes as $cache) { - if (true === $cache->public) { + if (true === $cache->public && !$hasPublicOrPrivateCacheControlDirective) { $response->setPublic(); } - if (false === $cache->public) { + if (false === $cache->public && !$hasPublicOrPrivateCacheControlDirective) { $response->setPrivate(); } } diff --git a/lib/symfony/http-kernel/HttpCache/Store.php b/lib/symfony/http-kernel/HttpCache/Store.php index 473537d85b..4eba39337d 100644 --- a/lib/symfony/http-kernel/HttpCache/Store.php +++ b/lib/symfony/http-kernel/HttpCache/Store.php @@ -211,13 +211,9 @@ public function write(Request $request, Response $response): string // read existing cache entries, remove non-varying, and add this one to the list $entries = []; - $vary = $response->headers->get('vary'); + $vary = implode(', ', $response->headers->all('vary')); foreach ($this->getMetadata($key) as $entry) { - if (!isset($entry[1]['vary'][0])) { - $entry[1]['vary'] = ['']; - } - - if ($entry[1]['vary'][0] != $vary || !$this->requestsMatch($vary ?? '', $entry[0], $storedEnv)) { + if (!$this->requestsMatch($vary ?? '', $entry[0], $storedEnv)) { $entries[] = $entry; } } @@ -285,7 +281,7 @@ public function invalidate(Request $request) */ private function requestsMatch(?string $vary, array $env1, array $env2): bool { - if (empty($vary)) { + if ('' === ($vary ?? '')) { return true; } diff --git a/lib/symfony/http-kernel/Kernel.php b/lib/symfony/http-kernel/Kernel.php index a04739505f..a2bf0f8270 100644 --- a/lib/symfony/http-kernel/Kernel.php +++ b/lib/symfony/http-kernel/Kernel.php @@ -70,17 +70,18 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private ?string $warmupDir = null; private int $requestStackSize = 0; private bool $resetServices = false; + private bool $handlingHttpCache = false; /** * @var array */ private static array $freshCache = []; - public const VERSION = '6.4.25'; - public const VERSION_ID = 60425; + public const VERSION = '6.4.33'; + public const VERSION_ID = 60433; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 25; + public const RELEASE_VERSION = 33; public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2026'; @@ -101,6 +102,7 @@ public function __clone() $this->container = null; $this->requestStackSize = 0; $this->resetServices = false; + $this->handlingHttpCache = false; } /** @@ -108,7 +110,7 @@ public function __clone() */ public function boot() { - if (true === $this->booted) { + if ($this->booted) { if (!$this->requestStackSize && $this->resetServices) { if ($this->container->has('services_resetter')) { $this->container->get('services_resetter')->reset(); @@ -122,7 +124,7 @@ public function boot() return; } - if (null === $this->container) { + if (!$this->container) { $this->preBoot(); } @@ -149,7 +151,7 @@ public function reboot(?string $warmupDir) */ public function terminate(Request $request, Response $response) { - if (false === $this->booted) { + if (!$this->booted) { return; } @@ -163,7 +165,7 @@ public function terminate(Request $request, Response $response) */ public function shutdown() { - if (false === $this->booted) { + if (!$this->booted) { return; } @@ -181,17 +183,26 @@ public function shutdown() public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response { - if (!$this->booted) { - $container = $this->container ?? $this->preBoot(); + if (!$this->container) { + $this->preBoot(); + } - if ($container->has('http_cache')) { - return $container->get('http_cache')->handle($request, $type, $catch); + if (HttpKernelInterface::MAIN_REQUEST === $type && !$this->handlingHttpCache && $this->container->has('http_cache')) { + $this->handlingHttpCache = true; + + try { + return $this->container->get('http_cache')->handle($request, $type, $catch); + } finally { + $this->handlingHttpCache = false; + $this->resetServices = true; } } $this->boot(); ++$this->requestStackSize; - $this->resetServices = true; + if (!$this->handlingHttpCache) { + $this->resetServices = true; + } try { return $this->getHttpKernel()->handle($request, $type, $catch); @@ -603,7 +614,7 @@ protected function buildContainer(): ContainerBuilder { foreach (['cache' => $this->getCacheDir(), 'build' => $this->warmupDir ?: $this->getBuildDir(), 'logs' => $this->getLogDir()] as $name => $dir) { if (!is_dir($dir)) { - if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) { + if (!@mkdir($dir, 0o777, true) && !is_dir($dir)) { throw new \RuntimeException(\sprintf('Unable to create the "%s" directory (%s).', $name, $dir)); } } elseif (!is_writable($dir)) { diff --git a/lib/symfony/mailer/Transport/Smtp/SmtpTransport.php b/lib/symfony/mailer/Transport/Smtp/SmtpTransport.php index ee37516e10..2570e3fc25 100644 --- a/lib/symfony/mailer/Transport/Smtp/SmtpTransport.php +++ b/lib/symfony/mailer/Transport/Smtp/SmtpTransport.php @@ -154,18 +154,7 @@ 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 @@ -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/lib/symfony/mime/Email.php b/lib/symfony/mime/Email.php index 8183c7899e..c5a65641b6 100644 --- a/lib/symfony/mime/Email.php +++ b/lib/symfony/mime/Email.php @@ -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/lib/symfony/mime/Encoder/QpContentEncoder.php b/lib/symfony/mime/Encoder/QpContentEncoder.php index 777a6a96c3..c425b6759d 100644 --- a/lib/symfony/mime/Encoder/QpContentEncoder.php +++ b/lib/symfony/mime/Encoder/QpContentEncoder.php @@ -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/lib/symfony/mime/Encoder/QpEncoder.php b/lib/symfony/mime/Encoder/QpEncoder.php index 160dde3297..76ec445a31 100644 --- a/lib/symfony/mime/Encoder/QpEncoder.php +++ b/lib/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/lib/symfony/mime/MimeTypes.php b/lib/symfony/mime/MimeTypes.php index 19628b0b17..fd9881b72e 100644 --- a/lib/symfony/mime/MimeTypes.php +++ b/lib/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/lib/symfony/mime/Part/MessagePart.php b/lib/symfony/mime/Part/MessagePart.php index 9d30544ae9..704211e468 100644 --- a/lib/symfony/mime/Part/MessagePart.php +++ b/lib/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/lib/symfony/mime/Resources/bin/update_mime_types.php b/lib/symfony/mime/Resources/bin/update_mime_types.php index b707d458e9..6811a7b253 100644 --- a/lib/symfony/mime/Resources/bin/update_mime_types.php +++ b/lib/symfony/mime/Resources/bin/update_mime_types.php @@ -80,7 +80,7 @@ 'html' => ['text/html'], 'jar' => ['application/x-java-archive'], 'jpg' => ['image/jpeg'], - 'js' => ['text/javascript'], + 'js' => ['text/javascript', 'application/javascript', 'application/x-javascript'], 'keynote' => ['application/vnd.apple.keynote'], 'key' => ['application/vnd.apple.keynote'], 'm3u' => ['audio/x-mpegurl'], diff --git a/lib/symfony/options-resolver/OptionsResolver.php b/lib/symfony/options-resolver/OptionsResolver.php index da7553cfb2..3a232a3802 100644 --- a/lib/symfony/options-resolver/OptionsResolver.php +++ b/lib/symfony/options-resolver/OptionsResolver.php @@ -803,7 +803,7 @@ public function remove(string|array $optionNames): static foreach ((array) $optionNames as $option) { unset($this->defined[$option], $this->defaults[$option], $this->required[$option], $this->resolved[$option]); - unset($this->lazy[$option], $this->normalizers[$option], $this->allowedTypes[$option], $this->allowedValues[$option], $this->info[$option]); + unset($this->lazy[$option], $this->normalizers[$option], $this->allowedTypes[$option], $this->allowedValues[$option], $this->info[$option], $this->deprecated[$option]); } return $this; @@ -964,6 +964,11 @@ public function offsetGet(mixed $option, bool $triggerDeprecation = true): mixed $resolver = new self(); $resolver->prototype = false; $resolver->parentsOptions = $this->parentsOptions; + + if ($this->prototype && null !== $this->prototypeIndex && null !== ($parentOptionKey = array_key_last($resolver->parentsOptions))) { + $resolver->parentsOptions[$parentOptionKey] .= \sprintf('[%s]', $this->prototypeIndex); + } + $resolver->parentsOptions[] = $option; foreach ($this->nested[$option] as $closure) { $closure($resolver, $this); diff --git a/lib/symfony/property-access/composer.json b/lib/symfony/property-access/composer.json index ce7710cfe1..4d51197e2c 100644 --- a/lib/symfony/property-access/composer.json +++ b/lib/symfony/property-access/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/property-info": "^5.4|^6.0|^7.0" + "symfony/property-info": "^6.4.32|~7.3.10|^7.4.4" }, "require-dev": { "symfony/cache": "^5.4|^6.0|^7.0" diff --git a/lib/symfony/property-info/Extractor/PhpDocExtractor.php b/lib/symfony/property-info/Extractor/PhpDocExtractor.php index e1b42eec5c..2907b6b51a 100644 --- a/lib/symfony/property-info/Extractor/PhpDocExtractor.php +++ b/lib/symfony/property-info/Extractor/PhpDocExtractor.php @@ -12,6 +12,8 @@ namespace Symfony\Component\PropertyInfo\Extractor; use phpDocumentor\Reflection\DocBlock; +use phpDocumentor\Reflection\DocBlock\Tags\Factory\StaticMethod; +use phpDocumentor\Reflection\DocBlock\Tags\Generic; use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag; use phpDocumentor\Reflection\DocBlockFactory; use phpDocumentor\Reflection\DocBlockFactoryInterface; @@ -36,7 +38,7 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property public const MUTATOR = 2; /** - * @var array + * @var array */ private array $docBlocks = []; @@ -63,6 +65,10 @@ public function __construct(?DocBlockFactoryInterface $docBlockFactory = null, ? throw new \LogicException(\sprintf('Unable to use the "%s" class as the "phpdocumentor/reflection-docblock" package is not installed. Try running composer require "phpdocumentor/reflection-docblock".', __CLASS__)); } + if (!is_subclass_of(Generic::class, StaticMethod::class)) { + throw new \LogicException('symfony/property-info v6 does not support phpdocumentor/reflection-docblock v6. Please stick to ^5.2 in your composer.json file.'); + } + $this->docBlockFactory = $docBlockFactory ?: DocBlockFactory::createInstance(); $this->contextFactory = new ContextFactory(); $this->phpDocTypeHelper = new PhpDocTypeHelper(); @@ -114,7 +120,7 @@ public function getLongDescription(string $class, string $property, array $conte public function getTypes(string $class, string $property, array $context = []): ?array { /** @var DocBlock $docBlock */ - [$docBlock, $source, $prefix] = $this->getDocBlock($class, $property); + [$docBlock, $source, $prefix, $declaringClass] = $this->getDocBlock($class, $property); if (!$docBlock) { return null; } @@ -133,12 +139,15 @@ public function getTypes(string $class, string $property, array $context = []): foreach ($this->phpDocTypeHelper->getTypes($tag->getType()) as $type) { switch ($type->getClassName()) { case 'self': + $resolvedClass = $declaringClass ?? $class; + break; + case 'static': $resolvedClass = $class; break; case 'parent': - if (false !== $resolvedClass = $parentClass ??= get_parent_class($class)) { + if (false !== $resolvedClass = $parentClass ??= get_parent_class($declaringClass ?? $class)) { break; } // no break @@ -217,7 +226,7 @@ private function filterDocBlockParams(DocBlock $docBlock, string $allowedParam): } /** - * @return array{DocBlock|null, int|null, string|null} + * @return array{DocBlock|null, int|null, string|null, string|null} */ private function getDocBlock(string $class, string $property): array { @@ -236,31 +245,36 @@ private function getDocBlock(string $class, string $property): array $ucFirstProperty = ucfirst($property); switch (true) { - case $reflectionProperty?->isPromoted() && $docBlock = $this->getDocBlockFromConstructor($class, $property): - $data = [$docBlock, self::MUTATOR, null]; + case $reflectionProperty?->isPromoted() && $docBlock = $this->getDocBlockFromConstructor($reflectionProperty->class, $property): + $data = [$docBlock, self::MUTATOR, null, $reflectionProperty->class]; break; - case $docBlock = $this->getDocBlockFromProperty($class, $property): - $data = [$docBlock, self::PROPERTY, null]; + case [$docBlock, $declaringClass] = $this->getDocBlockFromProperty($class, $property): + $data = [$docBlock, self::PROPERTY, null, $declaringClass]; break; - case [$docBlock] = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::ACCESSOR): - $data = [$docBlock, self::ACCESSOR, null]; + case [$docBlock, , $declaringClass] = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::ACCESSOR): + $data = [$docBlock, self::ACCESSOR, null, $declaringClass]; break; - case [$docBlock, $prefix] = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::MUTATOR): - $data = [$docBlock, self::MUTATOR, $prefix]; + case [$docBlock, $prefix, $declaringClass] = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::MUTATOR): + $data = [$docBlock, self::MUTATOR, $prefix, $declaringClass]; break; default: - $data = [null, null, null]; + $data = [null, null, null, null]; } return $this->docBlocks[$propertyHash] = $data; } - private function getDocBlockFromProperty(string $class, string $property): ?DocBlock + /** + * @return array{DocBlock, string}|null + */ + private function getDocBlockFromProperty(string $class, string $property, ?string $originalClass = null): ?array { + $originalClass ??= $class; + // Use a ReflectionProperty instead of $class to get the parent class if applicable try { $reflectionProperty = new \ReflectionProperty($class, $property); @@ -272,37 +286,45 @@ private function getDocBlockFromProperty(string $class, string $property): ?DocB foreach ($reflector->getTraits() as $trait) { if ($trait->hasProperty($property)) { - return $this->getDocBlockFromProperty($trait->getName(), $property); + return $this->getDocBlockFromProperty($trait->getName(), $property, $reflector->isTrait() ? $originalClass : $reflector->getName()); } } try { - return $this->docBlockFactory->create($reflectionProperty, $this->createFromReflector($reflector)); + $declaringClass = $reflector->isTrait() ? $originalClass : $reflector->getName(); + + return [$this->docBlockFactory->create($reflectionProperty, $this->createFromReflector($reflector)), $declaringClass]; } catch (\InvalidArgumentException|\RuntimeException) { return null; } } /** - * @return array{DocBlock, string}|null + * @return array{DocBlock, string, string}|null */ - private function getDocBlockFromMethod(string $class, string $ucFirstProperty, int $type): ?array + private function getDocBlockFromMethod(string $class, string $ucFirstProperty, int $type, ?string $originalClass = null): ?array { + $originalClass ??= $class; $prefixes = self::ACCESSOR === $type ? $this->accessorPrefixes : $this->mutatorPrefixes; $prefix = null; + $method = null; foreach ($prefixes as $prefix) { $methodName = $prefix.$ucFirstProperty; try { - $reflectionMethod = new \ReflectionMethod($class, $methodName); - if ($reflectionMethod->isStatic()) { + $method = new \ReflectionMethod($class, $methodName); + if ($method->isStatic()) { + continue; + } + + if (self::ACCESSOR === $type && \in_array((string) $method->getReturnType(), ['void', 'never'], true)) { continue; } if ( - (self::ACCESSOR === $type && 0 === $reflectionMethod->getNumberOfRequiredParameters()) - || (self::MUTATOR === $type && $reflectionMethod->getNumberOfParameters() >= 1) + (self::ACCESSOR === $type && !$method->getNumberOfRequiredParameters()) + || (self::MUTATOR === $type && $method->getNumberOfParameters() >= 1) ) { break; } @@ -311,20 +333,22 @@ private function getDocBlockFromMethod(string $class, string $ucFirstProperty, i } } - if (!isset($reflectionMethod)) { + if (!$method) { return null; } - $reflector = $reflectionMethod->getDeclaringClass(); + $reflector = $method->getDeclaringClass(); foreach ($reflector->getTraits() as $trait) { if ($trait->hasMethod($methodName)) { - return $this->getDocBlockFromMethod($trait->getName(), $ucFirstProperty, $type); + return $this->getDocBlockFromMethod($trait->getName(), $ucFirstProperty, $type, $reflector->isTrait() ? $originalClass : $reflector->getName()); } } try { - return [$this->docBlockFactory->create($reflectionMethod, $this->createFromReflector($reflector)), $prefix]; + $declaringClass = $reflector->isTrait() ? $originalClass : $reflector->getName(); + + return [$this->docBlockFactory->create($method, $this->createFromReflector($reflector)), $prefix, $declaringClass]; } catch (\InvalidArgumentException|\RuntimeException) { return null; } diff --git a/lib/symfony/property-info/Extractor/PhpStanExtractor.php b/lib/symfony/property-info/Extractor/PhpStanExtractor.php index d79a6a10a6..93a306d33e 100644 --- a/lib/symfony/property-info/Extractor/PhpStanExtractor.php +++ b/lib/symfony/property-info/Extractor/PhpStanExtractor.php @@ -154,7 +154,7 @@ public function getTypes(string $class, string $property, array $context = []): public function getTypesFromConstructor(string $class, string $property): ?array { if (null === $tagDocNode = $this->getDocBlockFromConstructor($class, $property)) { - return null; + return $this->getTypes($class, $property); } $types = []; @@ -278,19 +278,24 @@ private function getDocBlockFromMethod(string $class, string $ucFirstProperty, i { $prefixes = self::ACCESSOR === $type ? $this->accessorPrefixes : $this->mutatorPrefixes; $prefix = null; + $method = null; foreach ($prefixes as $prefix) { $methodName = $prefix.$ucFirstProperty; try { - $reflectionMethod = new \ReflectionMethod($class, $methodName); - if ($reflectionMethod->isStatic()) { + $method = new \ReflectionMethod($class, $methodName); + if ($method->isStatic()) { + continue; + } + + if (self::ACCESSOR === $type && \in_array((string) $method->getReturnType(), ['void', 'never'], true)) { continue; } if ( - (self::ACCESSOR === $type && 0 === $reflectionMethod->getNumberOfRequiredParameters()) - || (self::MUTATOR === $type && $reflectionMethod->getNumberOfParameters() >= 1) + (self::ACCESSOR === $type && !$method->getNumberOfRequiredParameters()) + || (self::MUTATOR === $type && $method->getNumberOfParameters() >= 1) ) { break; } @@ -299,17 +304,17 @@ private function getDocBlockFromMethod(string $class, string $ucFirstProperty, i } } - if (!isset($reflectionMethod)) { + if (!$method) { return null; } - if (null === $rawDocNode = $reflectionMethod->getDocComment() ?: null) { + if (null === $rawDocNode = $method->getDocComment() ?: null) { return null; } $phpDocNode = $this->getPhpDocNode($rawDocNode); - return [$phpDocNode, $prefix, $reflectionMethod->class]; + return [$phpDocNode, $prefix, $method->class]; } private function getPhpDocNode(string $rawDocNode): PhpDocNode diff --git a/lib/symfony/property-info/Extractor/ReflectionExtractor.php b/lib/symfony/property-info/Extractor/ReflectionExtractor.php index 6311c55fd3..e59a9ac409 100644 --- a/lib/symfony/property-info/Extractor/ReflectionExtractor.php +++ b/lib/symfony/property-info/Extractor/ReflectionExtractor.php @@ -261,17 +261,13 @@ public function getReadInfo(string $class, string $property, array $context = [] foreach ($this->accessorPrefixes as $prefix) { $methodName = $prefix.$camelProp; - if ($reflClass->hasMethod($methodName) && $reflClass->getMethod($methodName)->getModifiers() & $this->methodReflectionFlags && !$reflClass->getMethod($methodName)->getNumberOfRequiredParameters()) { - $method = $reflClass->getMethod($methodName); - - return new PropertyReadInfo(PropertyReadInfo::TYPE_METHOD, $methodName, $this->getReadVisiblityForMethod($method), $method->isStatic(), false); + if ($reflClass->hasMethod($methodName) && ($m = $reflClass->getMethod($methodName))->getModifiers() & $this->methodReflectionFlags && !$m->getNumberOfRequiredParameters() && !\in_array((string) $m->getReturnType(), ['void', 'never'], true)) { + return new PropertyReadInfo(PropertyReadInfo::TYPE_METHOD, $methodName, $this->getReadVisibilityForMethod($m), $m->isStatic(), false); } } - if ($allowGetterSetter && $reflClass->hasMethod($getsetter) && ($reflClass->getMethod($getsetter)->getModifiers() & $this->methodReflectionFlags)) { - $method = $reflClass->getMethod($getsetter); - - return new PropertyReadInfo(PropertyReadInfo::TYPE_METHOD, $getsetter, $this->getReadVisiblityForMethod($method), $method->isStatic(), false); + if ($allowGetterSetter && $reflClass->hasMethod($getsetter) && ($m = $reflClass->getMethod($getsetter))->getModifiers() & $this->methodReflectionFlags && !$m->getNumberOfRequiredParameters() && !\in_array((string) $m->getReturnType(), ['void', 'never'], true)) { + return new PropertyReadInfo(PropertyReadInfo::TYPE_METHOD, $getsetter, $this->getReadVisibilityForMethod($m), $m->isStatic(), false); } if ($allowMagicGet && $reflClass->hasMethod('__get') && (($r = $reflClass->getMethod('__get'))->getModifiers() & $this->methodReflectionFlags)) { @@ -279,7 +275,7 @@ public function getReadInfo(string $class, string $property, array $context = [] } if ($hasProperty && (($r = $reflClass->getProperty($property))->getModifiers() & $this->propertyReflectionFlags)) { - return new PropertyReadInfo(PropertyReadInfo::TYPE_PROPERTY, $property, $this->getReadVisiblityForProperty($r), $r->isStatic(), true); + return new PropertyReadInfo(PropertyReadInfo::TYPE_PROPERTY, $property, $this->getReadVisibilityForProperty($r), $r->isStatic(), true); } if ($allowMagicCall && $reflClass->hasMethod('__call') && ($reflClass->getMethod('__call')->getModifiers() & $this->methodReflectionFlags)) { @@ -305,6 +301,7 @@ public function getWriteInfo(string $class, string $property, array $context = [ $allowAdderRemover = $context['enable_adder_remover_extraction'] ?? true; $camelized = $this->camelize($property); + $nonCamelized = ucfirst($property); $constructor = $reflClass->getConstructor(); $singulars = $this->inflector->singularize($camelized); $errors = []; @@ -323,8 +320,8 @@ public function getWriteInfo(string $class, string $property, array $context = [ $removerMethod = $reflClass->getMethod($removerAccessName); $mutator = new PropertyWriteInfo(PropertyWriteInfo::TYPE_ADDER_AND_REMOVER); - $mutator->setAdderInfo(new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD, $adderAccessName, $this->getWriteVisiblityForMethod($adderMethod), $adderMethod->isStatic())); - $mutator->setRemoverInfo(new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD, $removerAccessName, $this->getWriteVisiblityForMethod($removerMethod), $removerMethod->isStatic())); + $mutator->setAdderInfo(new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD, $adderAccessName, $this->getWriteVisibilityForMethod($adderMethod), $adderMethod->isStatic())); + $mutator->setRemoverInfo(new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD, $removerAccessName, $this->getWriteVisibilityForMethod($removerMethod), $removerMethod->isStatic())); return $mutator; } @@ -343,27 +340,56 @@ public function getWriteInfo(string $class, string $property, array $context = [ $method = $reflClass->getMethod($methodName); if (!\in_array($mutatorPrefix, $this->arrayMutatorPrefixes, true)) { - return new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD, $methodName, $this->getWriteVisiblityForMethod($method), $method->isStatic()); + return new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD, $methodName, $this->getWriteVisibilityForMethod($method), $method->isStatic()); + } + } + + if ($camelized !== $nonCamelized) { + foreach ($this->mutatorPrefixes as $mutatorPrefix) { + $methodName = $mutatorPrefix.$nonCamelized; + + [$accessible, $methodAccessibleErrors] = $this->isMethodAccessible($reflClass, $methodName, 1); + if (!$accessible) { + $errors[] = $methodAccessibleErrors; + continue; + } + + $method = $reflClass->getMethod($methodName); + + if (!\in_array($mutatorPrefix, $this->arrayMutatorPrefixes, true)) { + return new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD, $methodName, $this->getWriteVisibilityForMethod($method), $method->isStatic()); + } } } $getsetter = lcfirst($camelized); + $getsetterNonCamelized = lcfirst($nonCamelized); if ($allowGetterSetter) { [$accessible, $methodAccessibleErrors] = $this->isMethodAccessible($reflClass, $getsetter, 1); if ($accessible) { $method = $reflClass->getMethod($getsetter); - return new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD, $getsetter, $this->getWriteVisiblityForMethod($method), $method->isStatic()); + return new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD, $getsetter, $this->getWriteVisibilityForMethod($method), $method->isStatic()); } $errors[] = $methodAccessibleErrors; + + if ($getsetter !== $getsetterNonCamelized) { + [$accessible, $methodAccessibleErrors] = $this->isMethodAccessible($reflClass, $getsetterNonCamelized, 1); + if ($accessible) { + $method = $reflClass->getMethod($getsetterNonCamelized); + + return new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD, $getsetterNonCamelized, $this->getWriteVisibilityForMethod($method), $method->isStatic()); + } + $errors[] = $methodAccessibleErrors; + } } if ($reflClass->hasProperty($property) && ($reflClass->getProperty($property)->getModifiers() & $this->propertyReflectionFlags)) { $reflProperty = $reflClass->getProperty($property); if (!$reflProperty->isReadOnly()) { - return new PropertyWriteInfo(PropertyWriteInfo::TYPE_PROPERTY, $property, $this->getWriteVisiblityForProperty($reflProperty), $reflProperty->isStatic()); + return new PropertyWriteInfo(PropertyWriteInfo::TYPE_PROPERTY, $property, $this->getWriteVisibilityForProperty($reflProperty), $reflProperty->isStatic()); } $errors[] = [\sprintf('The property "%s" in class "%s" is a promoted readonly property.', $property, $reflClass->getName())]; @@ -757,6 +783,10 @@ private function isMethodAccessible(\ReflectionClass $class, string $methodName, */ private function camelize(string $string): string { + if ('' === ltrim($string, '_')) { + return $string; + } + return str_replace(' ', '', ucwords(str_replace('_', ' ', $string))); } @@ -804,7 +834,7 @@ private function getPropertyFlags(int $accessFlags): int return $propertyFlags; } - private function getReadVisiblityForProperty(\ReflectionProperty $reflectionProperty): string + private function getReadVisibilityForProperty(\ReflectionProperty $reflectionProperty): string { if ($reflectionProperty->isPrivate()) { return PropertyReadInfo::VISIBILITY_PRIVATE; @@ -817,7 +847,7 @@ private function getReadVisiblityForProperty(\ReflectionProperty $reflectionProp return PropertyReadInfo::VISIBILITY_PUBLIC; } - private function getReadVisiblityForMethod(\ReflectionMethod $reflectionMethod): string + private function getReadVisibilityForMethod(\ReflectionMethod $reflectionMethod): string { if ($reflectionMethod->isPrivate()) { return PropertyReadInfo::VISIBILITY_PRIVATE; @@ -830,7 +860,7 @@ private function getReadVisiblityForMethod(\ReflectionMethod $reflectionMethod): return PropertyReadInfo::VISIBILITY_PUBLIC; } - private function getWriteVisiblityForProperty(\ReflectionProperty $reflectionProperty): string + private function getWriteVisibilityForProperty(\ReflectionProperty $reflectionProperty): string { if (\PHP_VERSION_ID >= 80400) { if ($reflectionProperty->isVirtual() && !$reflectionProperty->hasHook(\PropertyHookType::Set)) { @@ -857,7 +887,7 @@ private function getWriteVisiblityForProperty(\ReflectionProperty $reflectionPro return PropertyWriteInfo::VISIBILITY_PUBLIC; } - private function getWriteVisiblityForMethod(\ReflectionMethod $reflectionMethod): string + private function getWriteVisibilityForMethod(\ReflectionMethod $reflectionMethod): string { if ($reflectionMethod->isPrivate()) { return PropertyWriteInfo::VISIBILITY_PRIVATE; diff --git a/lib/symfony/property-info/Util/PhpDocTypeHelper.php b/lib/symfony/property-info/Util/PhpDocTypeHelper.php index 686ea00136..a4d171ef07 100644 --- a/lib/symfony/property-info/Util/PhpDocTypeHelper.php +++ b/lib/symfony/property-info/Util/PhpDocTypeHelper.php @@ -21,6 +21,7 @@ use phpDocumentor\Reflection\Types\Integer; use phpDocumentor\Reflection\Types\Null_; use phpDocumentor\Reflection\Types\Nullable; +use phpDocumentor\Reflection\Types\Scalar; use phpDocumentor\Reflection\Types\String_; use Symfony\Component\PropertyInfo\Type; @@ -56,6 +57,15 @@ public function getTypes(DocType $varType): array $varType = $varType->getActualType(); } + if ($varType instanceof Scalar) { + return [ + new Type(Type::BUILTIN_TYPE_BOOL), + new Type(Type::BUILTIN_TYPE_FLOAT), + new Type(Type::BUILTIN_TYPE_INT), + new Type(Type::BUILTIN_TYPE_STRING), + ]; + } + if (!$varType instanceof Compound) { if ($varType instanceof Null_) { $nullable = true; @@ -109,6 +119,10 @@ private function createType(DocType $type, bool $nullable): ?Type { $docType = (string) $type; + if ('mixed[]' === $docType) { + $docType = 'array'; + } + if ($type instanceof Collection) { $fqsen = $type->getFqsen(); if ($fqsen && 'list' === $fqsen->getName() && !class_exists(List_::class, false) && !class_exists((string) $fqsen)) { @@ -152,21 +166,28 @@ private function createType(DocType $type, bool $nullable): ?Type return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, $collectionKeyTypes, $collectionValueTypes); } + $docType = $this->normalizeType($docType); + [$phpType, $class] = $this->getPhpTypeAndClass($docType); + + if ('array' === $docType) { + return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, null, null); + } + + if (null === $class) { + return new Type($phpType, $nullable, $class); + } + if ($type instanceof PseudoType) { if ($type->underlyingType() instanceof Integer) { return new Type(Type::BUILTIN_TYPE_INT, $nullable, null); } elseif ($type->underlyingType() instanceof String_) { return new Type(Type::BUILTIN_TYPE_STRING, $nullable, null); + } else { + // It's safer to fall back to other extractors here, as resolving pseudo types correctly is not easy at the moment + return null; } } - $docType = $this->normalizeType($docType); - [$phpType, $class] = $this->getPhpTypeAndClass($docType); - - if ('array' === $docType) { - return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, null, null); - } - return new Type($phpType, $nullable, $class); } diff --git a/lib/symfony/property-info/composer.json b/lib/symfony/property-info/composer.json index 495b51dc50..b2e571ef16 100644 --- a/lib/symfony/property-info/composer.json +++ b/lib/symfony/property-info/composer.json @@ -36,7 +36,7 @@ }, "conflict": { "doctrine/annotations": "<1.12", - "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/reflection-docblock": "<5.2|>=6", "phpdocumentor/type-resolver": "<1.5.1", "symfony/dependency-injection": "<5.4|>=6.0,<6.4", "symfony/cache": "<5.4", diff --git a/lib/symfony/routing/Loader/Configurator/CollectionConfigurator.php b/lib/symfony/routing/Loader/Configurator/CollectionConfigurator.php index fdb659cab9..fe4cab4a27 100644 --- a/lib/symfony/routing/Loader/Configurator/CollectionConfigurator.php +++ b/lib/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__); } diff --git a/lib/symfony/routing/Loader/Configurator/ImportConfigurator.php b/lib/symfony/routing/Loader/Configurator/ImportConfigurator.php index 9c92a7d722..ad0c6d1314 100644 --- a/lib/symfony/routing/Loader/Configurator/ImportConfigurator.php +++ b/lib/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/lib/symfony/routing/Loader/Configurator/Traits/PrefixTrait.php b/lib/symfony/routing/Loader/Configurator/Traits/PrefixTrait.php index 9777c6490a..9f2284c5c2 100644 --- a/lib/symfony/routing/Loader/Configurator/Traits/PrefixTrait.php +++ b/lib/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,6 +45,9 @@ 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)); diff --git a/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php b/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php index 9deb012561..f71264ce9b 100644 --- a/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php +++ b/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php @@ -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); } } diff --git a/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php b/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php index db754e6de0..5177c269ae 100644 --- a/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php +++ b/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php @@ -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; @@ -73,8 +73,8 @@ public function match(string $pathinfo): array 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/lib/symfony/routing/Matcher/RedirectableUrlMatcher.php b/lib/symfony/routing/Matcher/RedirectableUrlMatcher.php index 8d1ad4f90a..3e7b78b5e6 100644 --- a/lib/symfony/routing/Matcher/RedirectableUrlMatcher.php +++ b/lib/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/lib/symfony/routing/Matcher/TraceableUrlMatcher.php b/lib/symfony/routing/Matcher/TraceableUrlMatcher.php index 20fb064687..8ff018309c 100644 --- a/lib/symfony/routing/Matcher/TraceableUrlMatcher.php +++ b/lib/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(); diff --git a/lib/symfony/routing/Matcher/UrlMatcher.php b/lib/symfony/routing/Matcher/UrlMatcher.php index ec281fde73..f3ab414f04 100644 --- a/lib/symfony/routing/Matcher/UrlMatcher.php +++ b/lib/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; } @@ -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(); diff --git a/lib/symfony/routing/Route.php b/lib/symfony/routing/Route.php index 70798e5420..e34dcb75ea 100644 --- a/lib/symfony/routing/Route.php +++ b/lib/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 diff --git a/lib/symfony/routing/RouteCollection.php b/lib/symfony/routing/RouteCollection.php index 7032b3e1a0..a253bc56d6 100644 --- a/lib/symfony/routing/RouteCollection.php +++ b/lib/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; diff --git a/lib/symfony/security-core/Resources/translations/security.da.xlf b/lib/symfony/security-core/Resources/translations/security.da.xlf index 564f0eee99..1f338806a8 100644 --- a/lib/symfony/security-core/Resources/translations/security.da.xlf +++ b/lib/symfony/security-core/Resources/translations/security.da.xlf @@ -76,7 +76,7 @@ Too many failed login attempts, please try again in %minutes% minutes. - For mange mislykkede loginforsøg, prøv igen om %minutes% minutter. + For mange mislykkede loginforsøg, prøv igen om %minutes% minutter. diff --git a/lib/symfony/security-core/Resources/translations/security.fi.xlf b/lib/symfony/security-core/Resources/translations/security.fi.xlf index 7df4a19347..8e74dec187 100644 --- a/lib/symfony/security-core/Resources/translations/security.fi.xlf +++ b/lib/symfony/security-core/Resources/translations/security.fi.xlf @@ -4,7 +4,7 @@ An authentication exception occurred. - Autentikointi poikkeus tapahtui. + Autentikointipoikkeus tapahtui. Authentication credentials could not be found. @@ -20,7 +20,7 @@ Cookie has already been used by someone else. - Eväste on jo jonkin muun käytössä. + Eväste on jo jonkun muun käytössä. Not privileged to request the resource. @@ -28,11 +28,11 @@ Invalid CSRF token. - Virheellinen CSRF tunnus. + Virheellinen CSRF-tunnus. No authentication provider found to support the authentication token. - Autentikointi tunnukselle ei löydetty tuettua autentikointi tarjoajaa. + Autentikointitunnukselle ei löydetty tuettua autentikoinnintarjoajaa. No session available, it either timed out or cookies are not enabled. @@ -44,7 +44,7 @@ Username could not be found. - Käyttäjätunnusta ei löydetty. + Käyttäjätunnusta ei löytynyt. Account has expired. @@ -76,7 +76,7 @@ Too many failed login attempts, please try again in %minutes% minutes. - Liian monta epäonnistunutta kirjautumisyritystä, yritä uudelleen %minutes% minuutin kuluttua. + Liian monta epäonnistunutta kirjautumisyritystä, yritä uudelleen %minutes% minuutin kuluttua. diff --git a/lib/symfony/security-core/Resources/translations/security.gl.xlf b/lib/symfony/security-core/Resources/translations/security.gl.xlf index 49f48dbed9..f868a2e2db 100644 --- a/lib/symfony/security-core/Resources/translations/security.gl.xlf +++ b/lib/symfony/security-core/Resources/translations/security.gl.xlf @@ -76,7 +76,7 @@ Too many failed login attempts, please try again in %minutes% minutes. - Demasiados intentos fallidos de inicio de sesión, inténtao de novo en %minutes% minutos. + Demasiados intentos errados de inicio de sesión, inténtao de novo en %minutes% minutos. diff --git a/lib/symfony/security-core/Resources/translations/security.lb.xlf b/lib/symfony/security-core/Resources/translations/security.lb.xlf index 181ef2444f..6ff4c984bc 100644 --- a/lib/symfony/security-core/Resources/translations/security.lb.xlf +++ b/lib/symfony/security-core/Resources/translations/security.lb.xlf @@ -76,7 +76,7 @@ Too many failed login attempts, please try again in %minutes% minutes. - Ze vill Feeler beim Umellen, versicht weg erëm an %minutes% Minutten. + Ze vill Feeler beim Umellen, versicht weg erëm an %minutes% Minutten. diff --git a/lib/symfony/security-core/Resources/translations/security.nb.xlf b/lib/symfony/security-core/Resources/translations/security.nb.xlf index 9ace014112..9f960cd1d8 100644 --- a/lib/symfony/security-core/Resources/translations/security.nb.xlf +++ b/lib/symfony/security-core/Resources/translations/security.nb.xlf @@ -76,7 +76,7 @@ Too many failed login attempts, please try again in %minutes% minutes. - For mange mislykkede påloggingsforsøk, prøv igjen om %minutes% minutter. + For mange mislykkede påloggingsforsøk, prøv igjen om %minutes% minutter. diff --git a/lib/symfony/security-core/Resources/translations/security.no.xlf b/lib/symfony/security-core/Resources/translations/security.no.xlf index 9ace014112..9f960cd1d8 100644 --- a/lib/symfony/security-core/Resources/translations/security.no.xlf +++ b/lib/symfony/security-core/Resources/translations/security.no.xlf @@ -76,7 +76,7 @@ Too many failed login attempts, please try again in %minutes% minutes. - For mange mislykkede påloggingsforsøk, prøv igjen om %minutes% minutter. + For mange mislykkede påloggingsforsøk, prøv igjen om %minutes% minutter. diff --git a/lib/symfony/security-core/Resources/translations/security.sv.xlf b/lib/symfony/security-core/Resources/translations/security.sv.xlf index dffe36df63..a61036fd19 100644 --- a/lib/symfony/security-core/Resources/translations/security.sv.xlf +++ b/lib/symfony/security-core/Resources/translations/security.sv.xlf @@ -76,7 +76,7 @@ Too many failed login attempts, please try again in %minutes% minutes. - För många misslyckade inloggningsförsök, vänligen försök igen om %minutes% minuter. + För många misslyckade inloggningsförsök, försök igen om %minutes% minuter. diff --git a/lib/symfony/string/Inflector/EnglishInflector.php b/lib/symfony/string/Inflector/EnglishInflector.php index b9d74c004e..5583669965 100644 --- a/lib/symfony/string/Inflector/EnglishInflector.php +++ b/lib/symfony/string/Inflector/EnglishInflector.php @@ -25,6 +25,13 @@ 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'], @@ -205,6 +212,12 @@ 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'], diff --git a/lib/symfony/string/Slugger/AsciiSlugger.php b/lib/symfony/string/Slugger/AsciiSlugger.php index d0c338682e..d4d4e942a6 100644 --- a/lib/symfony/string/Slugger/AsciiSlugger.php +++ b/lib/symfony/string/Slugger/AsciiSlugger.php @@ -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/lib/symfony/string/UnicodeString.php b/lib/symfony/string/UnicodeString.php index 75af2da42d..f416ee1b24 100644 --- a/lib/symfony/string/UnicodeString.php +++ b/lib/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/lib/symfony/string/composer.json b/lib/symfony/string/composer.json index 56c1368828..1a2b41ec6d 100644 --- a/lib/symfony/string/composer.json +++ b/lib/symfony/string/composer.json @@ -23,9 +23,8 @@ "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/intl": "^6.2|^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" }, diff --git a/lib/symfony/translation-contracts/TranslatorTrait.php b/lib/symfony/translation-contracts/TranslatorTrait.php index 06210b0ed3..afedd9928b 100644 --- a/lib/symfony/translation-contracts/TranslatorTrait.php +++ b/lib/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); } diff --git a/lib/symfony/twig-bridge/Form/TwigRendererEngine.php b/lib/symfony/twig-bridge/Form/TwigRendererEngine.php index f6cb5239b0..3bde82141b 100644 --- a/lib/symfony/twig-bridge/Form/TwigRendererEngine.php +++ b/lib/symfony/twig-bridge/Form/TwigRendererEngine.php @@ -71,6 +71,7 @@ protected function loadResourceForBlockName(string $cacheKey, FormView $view, st // $this->resources[$cacheKey][$block] is not set. Since the themes are // already loaded, it can only be a non-existing block. $this->resources[$cacheKey][$blockName] = false; + $this->setResourceInheritability($cacheKey, $blockName, true); return false; } @@ -108,8 +109,9 @@ protected function loadResourceForBlockName(string $cacheKey, FormView $view, st // EAGER CACHE POPULATION (see doc comment) foreach ($this->resources[$parentCacheKey] as $nestedBlockName => $resource) { - if (!isset($this->resources[$cacheKey][$nestedBlockName])) { + if (!isset($this->resources[$cacheKey][$nestedBlockName]) && $this->isResourceInheritable($parentCacheKey, $nestedBlockName)) { $this->resources[$cacheKey][$nestedBlockName] = $resource; + $this->setResourceInheritability($cacheKey, $nestedBlockName, true); } } } @@ -119,6 +121,7 @@ protected function loadResourceForBlockName(string $cacheKey, FormView $view, st if (!isset($this->resources[$cacheKey][$blockName])) { // Cache that we didn't find anything to speed up further accesses $this->resources[$cacheKey][$blockName] = false; + $this->setResourceInheritability($cacheKey, $blockName, true); } return false !== $this->resources[$cacheKey][$blockName]; @@ -162,6 +165,7 @@ protected function loadResourcesFromTheme(string $cacheKey, mixed &$theme) // The resource given back is the key to the bucket that // contains this block. $this->resources[$cacheKey][$block] = $blockData; + $this->setResourceInheritability($cacheKey, $block, true); } } } while (false !== $currentTheme = $currentTheme->getParent($context)); diff --git a/lib/symfony/twig-bridge/composer.json b/lib/symfony/twig-bridge/composer.json index f663de11da..1996595dc1 100644 --- a/lib/symfony/twig-bridge/composer.json +++ b/lib/symfony/twig-bridge/composer.json @@ -29,7 +29,7 @@ "symfony/asset-mapper": "^6.3|^7.0", "symfony/dependency-injection": "^5.4|^6.0|^7.0", "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/form": "^6.4.20|^7.2.5", + "symfony/form": "^6.4.32|~7.3.10|^7.4.4", "symfony/html-sanitizer": "^6.1|^7.0", "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/http-kernel": "^6.4|^7.0", @@ -58,7 +58,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/console": "<5.4", - "symfony/form": "<6.3", + "symfony/form": "<6.4.32|>7,<7.3.10|>7.4,<7.4.4", "symfony/http-foundation": "<5.4", "symfony/http-kernel": "<6.4", "symfony/mime": "<6.2", diff --git a/lib/symfony/twig-bundle/TemplateIterator.php b/lib/symfony/twig-bundle/TemplateIterator.php index bd42f1ac07..75f48558bd 100644 --- a/lib/symfony/twig-bundle/TemplateIterator.php +++ b/lib/symfony/twig-bundle/TemplateIterator.php @@ -64,6 +64,12 @@ public function getIterator(): \Traversable if (null !== $this->defaultPath) { $templates[] = $this->findTemplatesInDirectory($this->defaultPath.'/bundles/'.$bundle->getName(), $name); } + + /* + * The bundle's own templates are also registered with the "!" prefix namespace - this matches + * @see \Symfony\Bundle\TwigBundle\DependencyInjection\TwigExtension::load() + */ + $templates[] = $this->findTemplatesInDirectory($bundleTemplatesDir, '!'.$name); } foreach ($this->paths as $dir => $namespace) { diff --git a/lib/symfony/validator/Resources/translations/validators.be.xlf b/lib/symfony/validator/Resources/translations/validators.be.xlf index 13c6d43a23..448a2e9e4f 100644 --- a/lib/symfony/validator/Resources/translations/validators.be.xlf +++ b/lib/symfony/validator/Resources/translations/validators.be.xlf @@ -548,11 +548,11 @@ The image has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels. - Малюнак мае занадта шмат пікселяў ({{ pixels }}). Максімальная дапушчальная колькасць {{ max_pixels }}. + Малюнак мае занадта шмат пікселяў ({{ pixels }}). Максімальная дапушчальная колькасць {{ max_pixels }}. This filename does not match the expected charset. - Гэта назва файла не адпавядае чаканаму набору знакаў. + Гэта назва файла не адпавядае чаканаму набору знакаў. diff --git a/lib/symfony/validator/Resources/translations/validators.el.xlf b/lib/symfony/validator/Resources/translations/validators.el.xlf index dc5f1a961d..7ec30d5fa6 100644 --- a/lib/symfony/validator/Resources/translations/validators.el.xlf +++ b/lib/symfony/validator/Resources/translations/validators.el.xlf @@ -20,7 +20,7 @@ The value you selected is not a valid choice. - Η τιμή που επιλέχθηκε δεν αντιστοιχεί σε έγκυρη επιλογή. + Η τιμή που επιλέξατε δεν αντιστοιχεί σε έγκυρη επιλογή. You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. @@ -40,19 +40,19 @@ This field is missing. - Λείπει αυτό το πεδίο. + Αυτό το πεδίο λείπει. This value is not a valid date. - Η τιμή δεν αντιστοιχεί σε έγκυρη ημερομηνία. + Αυτή τιμή δεν αντιστοιχεί σε έγκυρη ημερομηνία. This value is not a valid datetime. - Η τιμή δεν αντιστοιχεί σε έγκυρη ημερομηνία και ώρα. + Αυτή η τιμή δεν αντιστοιχεί σε έγκυρη ημερομηνία και ώρα. This value is not a valid email address. - Η τιμή δεν αντιστοιχεί σε έγκυρο email. + Αυτή η τιμή δεν αντιστοιχεί σε έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομίου. The file could not be found. @@ -72,19 +72,19 @@ This value should be {{ limit }} or less. - Αυτή η τιμή θα έπρεπε να είναι {{ limit }} ή λιγότερο. + Αυτή η τιμή πρέπει να είναι {{ limit }} ή λιγότερο. This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Αυτή η τιμή είναι πολύ μεγάλη. Θα έπρεπε να έχει {{ limit }} χαρακτήρα ή λιγότερο.|Αυτή η τιμή είναι πολύ μεγάλη. Θα έπρεπε να έχει {{ limit }} χαρακτήρες ή λιγότερο. + Αυτή η τιμή είναι πολύ μεγάλη. Πρέπει να έχει {{ limit }} χαρακτήρα ή λιγότερο.|Αυτή η τιμή είναι πολύ μεγάλη. Πρέπει να έχει {{ limit }} χαρακτήρες ή λιγότερο. This value should be {{ limit }} or more. - Αυτή η τιμή θα έπρεπε να είναι {{ limit }} ή περισσότερο. + Αυτή η τιμή πρέπει να είναι {{ limit }} ή περισσότερο. This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Αυτή η τιμή είναι πολύ μικρή. Θα έπρεπε να έχει {{ limit }} χαρακτήρα ή περισσότερο.|Αυτή η τιμή είναι πολύ μικρή. Θα έπρεπε να έχει {{ limit }} χαρακτήρες ή περισσότερο. + Αυτή η τιμή είναι πολύ μικρή. Πρέπει να έχει {{ limit }} χαρακτήρα ή περισσότερο.|Αυτή η τιμή είναι πολύ μικρή. Πρέπει να έχει {{ limit }} χαρακτήρες ή περισσότερο. This value should not be blank. @@ -108,11 +108,11 @@ This value is not a valid URL. - Αυτή η τιμή δεν αντιστοιχεί σε έγκυρο URL. + Αυτή η τιμή δεν αντιστοιχεί σε έγκυρο σύνδεσμο. The two values should be equal. - Οι δύο τιμές θα πρέπει να είναι ίδιες. + Οι δύο τιμές θα πρέπει να είναι ίσες. The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. @@ -124,11 +124,11 @@ The file could not be uploaded. - Το αρχείο δε μπορεί να ανέβει. + Το αρχείο δε μπορεί να μεταφορτωθεί. This value should be a valid number. - Αυτή η τιμή θα πρέπει να είναι ένας έγκυρος αριθμός. + Αυτή η τιμή πρέπει να είναι ένας έγκυρος αριθμός. This file is not a valid image. @@ -144,7 +144,7 @@ This value is not a valid locale. - Αυτή η τιμή δεν αντιστοιχεί σε έγκυρο κωδικό τοποθεσίας. + Αυτή η τιμή δεν αντιστοιχεί σε έγκυρη τοποθεσία. This value is not a valid country. @@ -176,23 +176,23 @@ This value should be the user's current password. - Αυτή η τιμή θα έπρεπε να είναι ο τρέχων κωδικός. + Αυτή η τιμή πρέπει να είναι ο τρέχων κωδικός του χρήστη. This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. - Αυτή η τιμή θα έπρεπε να έχει ακριβώς {{ limit }} χαρακτήρα.|Αυτή η τιμή θα έπρεπε να έχει ακριβώς {{ limit }} χαρακτήρες. + Αυτή η τιμή πρέπει να έχει ακριβώς {{ limit }} χαρακτήρα.|Αυτή η τιμή πρέπει να έχει ακριβώς {{ limit }} χαρακτήρες. The file was only partially uploaded. - Το αρχείο δεν ανέβηκε ολόκληρο. + Το αρχείο δεν μεταφορτώθηκε ολόκληρο. No file was uploaded. - Δεν ανέβηκε κανένα αρχείο. + Δεν μεταφορτώθηκε κανένα αρχείο. No temporary folder was configured in php.ini, or the configured folder does not exist. - Δεν έχει ρυθμιστεί προσωρινός φάκελος στο php.ini, ή ο ρυθμισμένος φάκελος δεν υπάρχει. + Δεν έχει ρυθμιστεί προσωρινός φάκελος στο php.ini ή ο ρυθμισμένος φάκελος δεν υπάρχει. Cannot write temporary file to disk. @@ -204,15 +204,15 @@ This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. - Αυτή η συλλογή θα πρέπει να περιέχει {{ limit }} στοιχείο ή περισσότερα.|Αυτή η συλλογή θα πρέπει να περιέχει {{ limit }} στοιχεία ή περισσότερα. + Αυτή η συλλογή πρέπει να περιέχει {{ limit }} στοιχείο ή περισσότερα.|Αυτή η συλλογή πρέπει να περιέχει {{ limit }} στοιχεία ή περισσότερα. This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. - Αυτή η συλλογή θα πρέπει να περιέχει {{ limit }} στοιχείo ή λιγότερα.|Αυτή η συλλογή θα πρέπει να περιέχει {{ limit }} στοιχεία ή λιγότερα. + Αυτή η συλλογή πρέπει να περιέχει {{ limit }} στοιχείo ή λιγότερα.|Αυτή η συλλογή πρέπει να περιέχει {{ limit }} στοιχεία ή λιγότερα. This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. - Αυτή η συλλογή θα πρέπει να περιέχει ακριβώς {{ limit }} στοιχείo.|Αυτή η συλλογή θα πρέπει να περιέχει ακριβώς {{ limit }} στοιχεία. + Αυτή η συλλογή πρέπει να περιέχει ακριβώς {{ limit }} στοιχείo.|Αυτή η συλλογή πρέπει να περιέχει ακριβώς {{ limit }} στοιχεία. Invalid card number. @@ -228,23 +228,23 @@ This value is not a valid ISBN-10. - Αυτό δεν είναι έγκυρος κωδικός ISBN-10. + Αυτός δεν είναι έγκυρος κωδικός ISBN-10. This value is not a valid ISBN-13. - Αυτό δεν είναι έγκυρος κωδικός ISBN-13. + Αυτός δεν είναι έγκυρος κωδικός ISBN-13. This value is neither a valid ISBN-10 nor a valid ISBN-13. - Αυτό δεν είναι ούτε έγκυρος κωδικός ISBN-10 ούτε έγκυρος κωδικός ISBN-13. + Αυτός δεν είναι ούτε ένας έγκυρος κωδικός ISBN-10 ούτε έγκυρος κωδικός ISBN-13. This value is not a valid ISSN. - Αυτό δεν είναι έγκυρος κωδικός ISSN. + Αυτός δεν είναι έγκυρος κωδικός ISSN. This value is not a valid currency. - Αυτό δεν αντιστοιχεί σε έγκυρο νόμισμα. + Αυτή η τιμή δεν αντιστοιχεί σε έγκυρο νόμισμα. This value should be equal to {{ compared_value }}. @@ -260,7 +260,7 @@ This value should be identical to {{ compared_value_type }} {{ compared_value }}. - Αυτή η τιμή θα πρέπει να είναι πανομοιότυπη με {{ compared_value_type }} {{ compared_value }}. + Αυτή η τιμή θα πρέπει να είναι ίδια με {{ compared_value_type }} {{ compared_value }}. This value should be less than {{ compared_value }}. @@ -276,15 +276,15 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. - Αυτή η τιμή δεν πρέπει να είναι πανομοιότυπη με {{ compared_value_type }} {{ compared_value }}. + Αυτή η τιμή δεν πρέπει να είναι ίδια με {{ compared_value_type }} {{ compared_value }}. The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. - Η αναλογία πλάτους-ύψους της εικόνας είναι πολύ μεγάλη ({{ ratio }}). Μέγιστη επιτρεπτή αναλογία {{ max_ratio }}. + Η αναλογία της εικόνας είναι πολύ μεγάλη ({{ ratio }}). Μέγιστη επιτρεπτή αναλογία {{ max_ratio }}. The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. - Η αναλογία πλάτους-ύψους της εικόνας είναι πολύ μικρή ({{ ratio }}). Ελάχιστη επιτρεπτή αναλογία {{ min_ratio }}. + Η αναλογία της εικόνας είναι πολύ μικρή ({{ ratio }}). Ελάχιστη επιτρεπτή αναλογία {{ min_ratio }}. The image is square ({{ width }}x{{ height }}px). Square images are not allowed. @@ -304,7 +304,7 @@ The host could not be resolved. - Η διεύθυνση δεν μπόρεσε να επιλυθεί. + Δεν ήταν δυνατή η επίλυση του κεντρικού υπολογιστή. This value does not match the expected {{ charset }} charset. @@ -324,7 +324,7 @@ This value should be a multiple of {{ compared_value }}. - Αυτή η τιμή θα έπρεπε να είναι πολλαπλάσιο του {{ compared_value }}. + Αυτή η τιμή πρέπει να είναι πολλαπλάσιο του {{ compared_value }}. This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. @@ -332,31 +332,31 @@ This value should be valid JSON. - Αυτή η τιμή θα πρέπει να είναι έγκυρο JSON. + Αυτή η τιμή πρέπει να είναι έγκυρο JSON. This collection should contain only unique elements. - Αυτή η συλλογή θα πρέπει να περιέχει μόνο μοναδικά στοιχεία. + Αυτή η συλλογή πρέπει να περιέχει μόνο μοναδικά στοιχεία. This value should be positive. - Αυτή η τιμή θα πρέπει να είναι θετική. + Αυτή η τιμή πρέπει να είναι θετική. This value should be either positive or zero. - Αυτή η τιμή θα πρέπει να είναι θετική ή μηδενική. + Αυτή η τιμή πρέπει να είναι θετική ή μηδενική. This value should be negative. - Αυτή η τιμή θα πρέπει να είναι αρνητική. + Αυτή η τιμή πρέπει να είναι αρνητική. This value should be either negative or zero. - Αυτή η τιμή θα πρέπει να είναι αρνητική ή μηδενική. + Αυτή η τιμή πρέπει να είναι αρνητική ή μηδενική. This value is not a valid timezone. - Αυτή η τιμή θα δεν είναι έγκυρη ζώνη ώρας. + Αυτή η τιμή δεν είναι έγκυρη ζώνη ώρας. This password has been leaked in a data breach, it must not be used. Please use another password. @@ -364,27 +364,27 @@ This value should be between {{ min }} and {{ max }}. - Αυτή η τιμή θα πρέπει να είναι μεταξύ {{ min }} και {{ max }}. + Αυτή η τιμή πρέπει να είναι μεταξύ {{ min }} και {{ max }}. This value is not a valid hostname. - Αυτή η τιμή δεν είναι έγκυρο όνομα υποδοχής. + Αυτή η τιμή δεν είναι έγκυρο όνομα κεντρικού υπολογιστή. The number of elements in this collection should be a multiple of {{ compared_value }}. - Το νούμερο των στοιχείων σε αυτή τη συλλογή θα πρέπει να είναι πολλαπλάσιο του {{ compared_value }}. + Το νούμερο των στοιχείων σε αυτή τη συλλογή πρέπει να είναι πολλαπλάσιο του {{ compared_value }}. This value should satisfy at least one of the following constraints: - Αυτή η τιμή θα πρέπει να ικανοποιεί τουλάχιστον έναν από τους παρακάτω περιορισμούς: + Αυτή η τιμή πρέπει να ικανοποιεί τουλάχιστον έναν από τους παρακάτω περιορισμούς: Each element of this collection should satisfy its own set of constraints. - Κάθε στοιχείο σε αυτή τη συλλογή θα πρέπει να ικανοποιεί το δικό του σύνολο περιορισμών. + Κάθε στοιχείο σε αυτή τη συλλογή πρέπει να ικανοποιεί το δικό του σύνολο περιορισμών. This value is not a valid International Securities Identification Number (ISIN). - Αυτή η τιμή δεν είναι έγκυρο International Securities Identification Number (ISIN). + Αυτή η τιμή δεν είναι έγκυρος Διεθνής Αριθμός Αναγνώρισης Τίτλων (ISIN). This value should be a valid expression. @@ -396,7 +396,7 @@ This value is not a valid CIDR notation. - Αυτή η τιμή δεν είναι έγκυρη CIDR σημειογραφία. + Αυτή η τιμή δεν είναι έγκυρη σημειογραφία CIDR. The value of the netmask should be between {{ min }} and {{ max }}. @@ -440,19 +440,19 @@ This URL is missing a top-level domain. - Αυτή η διεύθυνση URL λείπει ένας τομέας ανώτατου επιπέδου. + Λείπει ένας τομέας ανώτατου επιπέδου απο τον σύνδεσμο. This value is too short. It should contain at least one word.|This value is too short. It should contain at least {{ min }} words. - Αυτή η τιμή είναι πολύ σύντομη. Πρέπει να περιέχει τουλάχιστον μία λέξη.|Αυτή η τιμή είναι πολύ σύντομη. Πρέπει να περιέχει τουλάχιστον {{ min }} λέξεις. + Αυτή η τιμή είναι πολύ σύντομη. Πρέπει να περιέχει τουλάχιστον μία λέξη.|Αυτή η τιμή είναι πολύ σύντομη. Πρέπει να περιέχει τουλάχιστον {{ min }} λέξεις. This value is too long. It should contain one word.|This value is too long. It should contain {{ max }} words or less. - Αυτή η τιμή είναι πολύ μεγάλη. Πρέπει να περιέχει μόνο μία λέξη.|Αυτή η τιμή είναι πολύ μεγάλη. Πρέπει να περιέχει {{ max }} λέξεις ή λιγότερες. + Αυτή η τιμή είναι πολύ μεγάλη. Πρέπει να περιέχει μόνο μία λέξη.|Αυτή η τιμή είναι πολύ μεγάλη. Πρέπει να περιέχει {{ max }} λέξεις ή λιγότερες. This value does not represent a valid week in the ISO 8601 format. - Αυτή η τιμή δεν αντιπροσωπεύει έγκυρη εβδομάδα στη μορφή ISO 8601. + Αυτή η τιμή δεν αντιπροσωπεύει έγκυρη εβδομάδα στη μορφή ISO 8601. This value is not a valid week. @@ -468,91 +468,91 @@ This value is not a valid Twig template. - Αυτή η τιμή δεν είναι έγκυρο πρότυπο Twig. + Αυτή η τιμή δεν είναι έγκυρο πρότυπο Twig. This file is not a valid video. - Αυτό το αρχείο δεν είναι έγκυρο βίντεο. + Αυτό το αρχείο δεν είναι έγκυρο βίντεο. The size of the video could not be detected. - Δεν ήταν δυνατός ο εντοπισμός του μεγέθους του βίντεο. + Δεν ήταν δυνατή η ανίχνευση του μεγέθους του βίντεο. The video width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - Το πλάτος του βίντεο είναι πολύ μεγάλο ({{ width }}px). Το επιτρεπόμενο μέγιστο πλάτος είναι {{ max_width }}px. + Το πλάτος του βίντεο είναι πολύ μεγάλο ({{ width }}px). Το επιτρεπόμενο μέγιστο πλάτος είναι {{ max_width }}px. The video width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - Το πλάτος του βίντεο είναι πολύ μικρό ({{ width }}px). Το ελάχιστο αναμενόμενο πλάτος είναι {{ min_width }}px. + Το πλάτος του βίντεο είναι πολύ μικρό ({{ width }}px). Το ελάχιστο αναμενόμενο πλάτος είναι {{ min_width }}px. The video height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. - Το ύψος του βίντεο είναι πολύ μεγάλο ({{ height }}px). Το επιτρεπόμενο μέγιστο ύψος είναι {{ max_height }}px. + Το ύψος του βίντεο είναι πολύ μεγάλο ({{ height }}px). Το επιτρεπόμενο μέγιστο ύψος είναι {{ max_height }}px. The video height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - Το ύψος του βίντεο είναι πολύ μικρό ({{ height }}px). Το αναμενόμενο ελάχιστο ύψος είναι {{ min_height }}px. + Το ύψος του βίντεο είναι πολύ μικρό ({{ height }}px). Το αναμενόμενο ελάχιστο ύψος είναι {{ min_height }}px. The video has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels. - Το βίντεο έχει πολύ λίγα εικονοστοιχεία ({{ pixels }}). Η ελάχιστη αναμενόμενη ποσότητα είναι {{ min_pixels }}. + Το βίντεο έχει πολύ λίγα εικονοστοιχεία ({{ pixels }}). Η ελάχιστη αναμενόμενη ποσότητα είναι {{ min_pixels }}. The video has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels. - Το βίντεο έχει πάρα πολλά εικονοστοιχεία ({{ pixels }}). Η μέγιστη αναμενόμενη ποσότητα είναι {{ max_pixels }}. + Το βίντεο έχει πάρα πολλά εικονοστοιχεία ({{ pixels }}). Η μέγιστη αναμενόμενη ποσότητα είναι {{ max_pixels }}. The video ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. - Η αναλογία του βίντεο είναι πολύ μεγάλη ({{ ratio }}). Η μέγιστη επιτρεπτή αναλογία είναι {{ max_ratio }}. + Η αναλογία του βίντεο είναι πολύ μεγάλη ({{ ratio }}). Η μέγιστη επιτρεπτή αναλογία είναι {{ max_ratio }}. The video ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. - Η αναλογία βίντεο είναι πολύ μικρή ({{ ratio }}). Η ελάχιστη αναμενόμενη αναλογία είναι {{ min_ratio }}. + Η αναλογία βίντεο είναι πολύ μικρή ({{ ratio }}). Η ελάχιστη αναμενόμενη αναλογία είναι {{ min_ratio }}. The video is square ({{ width }}x{{ height }}px). Square videos are not allowed. - Το βίντεο είναι τετράγωνο ({{ width }}x{{ height }}px). Τα τετράγωνα βίντεο δεν επιτρέπονται. + Το βίντεο είναι τετράγωνο ({{ width }}x{{ height }}px). Τα τετράγωνα βίντεο δεν επιτρέπονται. The video is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented videos are not allowed. - Το βίντεο είναι σε οριζόντιο προσανατολισμό ({{ width }}x{{ height }} px). Τα οριζόντια βίντεο δεν επιτρέπονται. + Το βίντεο είναι σε οριζόντιο προσανατολισμό ({{ width }}x{{ height }} px). Τα οριζόντια βίντεο δεν επιτρέπονται. The video is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented videos are not allowed. - Το βίντεο είναι σε κατακόρυφο προσανατολισμό ({{ width }}x{{ height }}px). Βίντεο κάθετου προσανατολισμού δεν επιτρέπονται. + Το βίντεο είναι σε κάθετο προσανατολισμό ({{ width }}x{{ height }}px). Βίντεο κάθετου προσανατολισμού δεν επιτρέπονται. The video file is corrupted. - Το αρχείο βίντεο είναι κατεστραμμένο. + Το αρχείο του βίντεο είναι κατεστραμμένο. The video contains multiple streams. Only one stream is allowed. - Το βίντεο περιέχει πολλαπλά ρεύματα. Επιτρέπεται μόνο ένα ρεύμα. + Το βίντεο περιέχει πολλαπλά ρεύματα. Επιτρέπεται μόνο ένα ρεύμα. Unsupported video codec "{{ codec }}". - Μη υποστηριζόμενος κωδικοποιητής βίντεο «{{ codec }}». + Μη υποστηριζόμενος κωδικοποιητής βίντεο «{{ codec }}». Unsupported video container "{{ container }}". - Μη υποστηριζόμενο κοντέινερ βίντεο "{{ container }}". + Μη υποστηριζόμενος περιέκτης βίντεο "{{ container }}". The image file is corrupted. - Το αρχείο εικόνας είναι κατεστραμμένο. + Το αρχείο της εικόνας είναι κατεστραμμένο. The image has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels. - Η εικόνα έχει πολύ λίγα εικονοστοιχεία ({{ pixels }}). Η αναμενόμενη ελάχιστη ποσότητα είναι {{ min_pixels }}. + Η εικόνα έχει πολύ λίγα εικονοστοιχεία ({{ pixels }}). Η αναμενόμενη ελάχιστη ποσότητα είναι {{ min_pixels }}. The image has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels. - Η εικόνα έχει πάρα πολλούς εικονοστοιχείους ({{ pixels }}). Ο μέγιστος αναμενόμενος αριθμός είναι {{ max_pixels }}. + Η εικόνα έχει πάρα πολλούς εικονοστοιχείους ({{ pixels }}). Ο μέγιστος αναμενόμενος αριθμός είναι {{ max_pixels }}. This filename does not match the expected charset. - Αυτό το όνομα αρχείου δεν αντιστοιχεί στο αναμενόμενο σύνολο χαρακτήρων. + Αυτό το όνομα αρχείου δεν αντιστοιχεί στο αναμενόμενο σύνολο χαρακτήρων. diff --git a/lib/symfony/validator/Resources/translations/validators.es.xlf b/lib/symfony/validator/Resources/translations/validators.es.xlf index c2bdb7c4e5..2685ed1748 100644 --- a/lib/symfony/validator/Resources/translations/validators.es.xlf +++ b/lib/symfony/validator/Resources/translations/validators.es.xlf @@ -160,11 +160,11 @@ The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - El ancho de la imagen es demasiado grande ({{ width }}px). El ancho máximo permitido es de {{ max_width }}px. + La anchura de la imagen es demasiado grande ({{ width }}px). La anchura máxima permitida es de {{ max_width }}px. The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - El ancho de la imagen es demasiado pequeño ({{ width }}px). El ancho mínimo requerido es {{ min_width }}px. + La anchura de la imagen es demasiado pequeña ({{ width }}px). La anchura mínima requerida es de {{ min_width }}px. The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. @@ -472,87 +472,87 @@ This file is not a valid video. - Este archivo no es un video válido. + Este archivo no es un vídeo válido. The size of the video could not be detected. - No se pudo detectar el tamaño del video. + No se pudo detectar el tamaño del vídeo. The video width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - El ancho del vídeo es demasiado grande ({{ width }}px). El ancho máximo permitido es {{ max_width }}px. + La anchura del vídeo es demasiado grande ({{ width }}px). La anchura máxima permitida es de {{ max_width }}px. The video width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - El ancho del video es demasiado pequeño ({{ width }}px). El ancho mínimo esperado es {{ min_width }}px. + La anchura del vídeo es demasiado pequeña ({{ width }}px). La anchura mínima requerida es de {{ min_width }}px. The video height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. - La altura del video es demasiado grande ({{ height }}px). La altura máxima permitida es {{ max_height }}px. + La altura del vídeo es demasiado grande ({{ height }}px). La altura máxima permitida es de {{ max_height }}px. The video height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - La altura del video es demasiado pequeña ({{ height }}px). La altura mínima esperada es {{ min_height }}px. + La altura del vídeo es demasiado pequeña ({{ height }}px). La altura mínima requerida es de {{ min_height }}px. The video has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels. - El vídeo tiene muy pocos píxeles ({{ pixels }}). La cantidad mínima esperada es {{ min_pixels }}. + El vídeo no tiene suficientes píxeles ({{ pixels }}). La cantidad mínima requerida es de {{ min_pixels }}px. The video has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels. - El vídeo tiene demasiados píxeles ({{ pixels }}). La cantidad máxima esperada es {{ max_pixels }}. + El vídeo tiene demasiados píxeles ({{ pixels }}). La cantidad máxima permitida es de {{ max_pixels }}px. The video ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. - La relación del video es demasiado grande ({{ ratio }}). La relación máxima permitida es {{ max_ratio }}. + La relación de aspecto del vídeo es demasiado grande ({{ ratio }}). La máxima relación de aspecto permitida es de {{ max_ratio }}. The video ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. - La relación del video es demasiado pequeña ({{ ratio }}). La relación mínima esperada es {{ min_ratio }}. + La relación de aspecto del vídeo es demasiado pequeña ({{ ratio }}). La mínima relación de aspecto permitida es de {{ min_ratio }}. The video is square ({{ width }}x{{ height }}px). Square videos are not allowed. - El video es cuadrado ({{ width }}x{{ height }}px). No se permiten videos cuadrados. + El vídeo es cuadrado ({{ width }}x{{ height }}px). Los vídeos cuadrados no están permitidos. The video is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented videos are not allowed. - El video tiene orientación horizontal ({{ width }}x{{ height }} px). No se permiten videos en formato horizontal. + El vídeo está orientado horizontalmente ({{ width }}x{{ height }}px). Los vídeos orientados horizontalmente no están permitidos. The video is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented videos are not allowed. - El video tiene orientación vertical ({{ width }}x{{ height }} px). No se permiten videos en orientación vertical. + El vídeo está orientado verticalmente ({{ width }}x{{ height }}px). Los vídeos orientados verticalmente no están permitidos. The video file is corrupted. - El archivo de video está dañado. + El archivo de vídeo está dañado. The video contains multiple streams. Only one stream is allowed. - El video contiene múltiples flujos. Solo se permite un flujo. + El vídeo contiene múltiples flujos. Solo se permite un flujo. Unsupported video codec "{{ codec }}". - Códec de vídeo no compatible «{{ codec }}». + El códec de vídeo "{{ codec }}" no es compatible. Unsupported video container "{{ container }}". - Contenedor de vídeo no compatible "{{ container }}". + El contenedor de vídeo "{{ container }}" no es compatible. The image file is corrupted. - El archivo de imagen está dañado. + El archivo de imagen está dañado. The image has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels. - La imagen tiene muy pocos píxeles ({{ pixels }}). La cantidad mínima esperada es {{ min_pixels }}. + La imagen no tiene suficientes píxeles ({{ pixels }}). La cantidad mínima requerida es de {{ min_pixels }}px. The image has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels. - La imagen tiene demasiados píxeles ({{ pixels }}). La cantidad máxima esperada es {{ max_pixels }}. + La imagen tiene demasiados píxeles ({{ pixels }}). La cantidad máxima permitida es de {{ max_pixels }}px. This filename does not match the expected charset. - Este nombre de archivo no coincide con el conjunto de caracteres esperado. + El nombre de este archivo no utiliza el conjunto de caracteres esperado. diff --git a/lib/symfony/validator/Resources/translations/validators.fa.xlf b/lib/symfony/validator/Resources/translations/validators.fa.xlf index 2e75167995..91b5d894a5 100644 --- a/lib/symfony/validator/Resources/translations/validators.fa.xlf +++ b/lib/symfony/validator/Resources/translations/validators.fa.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - این مقدار یه آدرس آی‌پی معتبر نمی‌باشد. + این مقدار یک آدرس آی‌پی معتبر نمی‌باشد. This value is not a valid language. @@ -472,87 +472,87 @@ This file is not a valid video. - این فایل یک ویدیوی معتبر نیست. + این فایل یک ویدئوی معتبر نیست. The size of the video could not be detected. - اندازه ویدئو قابل تشخیص نبود. + اندازه ویدئو قابل تشخیص نبود. The video width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - عرض ویدئو خیلی زیاد است ({{ width }}px). حداکثر عرض مجاز {{ max_width }}px است. + عرض ویدئو خیلی زیاد است ({{ width }}px). حداکثر عرض مجاز {{ max_width }}px می‌باشد. The video width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - عرض ویدئو خیلی کم است ({{ width }}px). حداقل عرض مورد انتظار {{ min_width }} پیکسل است. + عرض ویدئو خیلی کم است ({{ width }}px). حداقل عرض مورد انتظار {{ min_width }}px می‌باشد. The video height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. - ارتفاع ویدیو خیلی زیاد است ({{ height }}px). حداکثر ارتفاع مجاز {{ max_height }}px است. + ارتفاع ویدئو خیلی زیاد است ({{ height }}px). حداکثر ارتفاع مجاز {{ max_height }}px می‌باشد. The video height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - ارتفاع ویدیو خیلی کم است ({{ height }}px). حداقل ارتفاع مورد انتظار {{ min_height }}px است. + ارتفاع ویدئو خیلی کم است ({{ height }}px). حداقل ارتفاع مورد انتظار {{ min_height }}px می‌باشد. The video has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels. - ویدیو پیکسل‌های بسیار کمی دارد ({{ pixels }}). حداقل مقدار مورد انتظار {{ min_pixels }} است. + مقدار پیکسل‌های ویدئو خیلی کم است ({{ pixels }}px). حداقل مقدار مورد انتظار {{ min_pixels }}px می‌باشد. The video has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels. - ویدئو پیکسل‌های زیادی دارد ({{ pixels }}). حداکثر مقدار مورد انتظار {{ max_pixels }} است. + مقدار پیکسل‌های ویدئو خیلی زیاد است ({{ pixels }}px). حداکثر مقدار مورد انتظار {{ max_pixels }}px می‌باشد. The video ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. - نسبت ویدیو خیلی بزرگ است ({{ ratio }}). حداکثر نسبت مجاز {{ max_ratio }} است. + نسبت ویدئو خیلی بزرگ است ({{ ratio }}). حداکثر نسبت مجاز {{ max_ratio }} است. The video ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. - نسبت ویدیو خیلی کوچک است ({{ ratio }}). نسبت حداقل مورد انتظار {{ min_ratio }} است. + نسبت ویدئو خیلی کوچک است ({{ ratio }}). نسبت حداقل مورد انتظار {{ min_ratio }} است. The video is square ({{ width }}x{{ height }}px). Square videos are not allowed. - ویدئو مربعی است ({{ width }}x{{ height }}px). ویدئوهای مربعی مجاز نیستند. + ویدئو مربعی است ({{ width }}x{{ height }}px). ویدئوهای مربعی مجاز نیستند. The video is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented videos are not allowed. - ویدیو به صورت افقی است ({{ width }}x{{ height }} پیکسل). ویدیوهای افقی مجاز نیستند. + ویدئو به صورت افقی است ({{ width }}x{{ height }} پیکسل). ویدئوهای افقی مجاز نیستند. The video is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented videos are not allowed. - ویدیو با جهت عمودی است ({{ width }}x{{ height }}px). ویدیوهای با جهت عمودی مجاز نیستند. + ویدئو به صورت عمودی است ({{ width }}x{{ height }}px). ویدئوهای عمودی مجاز نیستند. The video file is corrupted. - فایل ویدیو خراب است. + فایل ویدئو خراب است. The video contains multiple streams. Only one stream is allowed. - ویدئو شامل چندین استریم است. فقط یک استریم مجاز است. + ویدئو شامل چندین استریم است. در صورتی که فقط یک استریم مجاز است. Unsupported video codec "{{ codec }}". - کُدک ویدیویی پشتیبانی نمی‌شود «{{ codec }}». + قالب (کُدک) ویدئویی پشتیبانی نمی‌شود «{{ codec }}». Unsupported video container "{{ container }}". - ظرف ویدئو پشتیبانی نمی‌شود "{{ container }}". + فرمت ویدئو پشتیبانی نمی‌شود "{{ container }}". The image file is corrupted. - فایل تصویر خراب است. + فایل تصویر خراب است. The image has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels. - تصویر پیکسل‌های بسیار کمی دارد ({{ pixels }}). حداقل مقدار مورد انتظار {{ min_pixels }} است. + تصویر پیکسل‌های خیلی کمی دارد ({{ pixels }}px). حداقل مقدار مورد انتظار {{ min_pixels }}px می‌باشد. The image has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels. - تصویر پیکسل‌های زیادی دارد ({{ pixels }}). حداکثر مقدار مورد انتظار {{ max_pixels }} است. + تصویر پیکسل‌های خیلی زیادی دارد ({{ pixels }}px). حداکثر مقدار مورد انتظار {{ max_pixels }}px می‌باشد. This filename does not match the expected charset. - نام این فایل با مجموعه نویسه‌های مورد انتظار مطابقت ندارد. + نام فایل مجاز نیست. diff --git a/lib/symfony/validator/Resources/translations/validators.zh_CN.xlf b/lib/symfony/validator/Resources/translations/validators.zh_CN.xlf index 70f2a34c07..8db05f9b96 100644 --- a/lib/symfony/validator/Resources/translations/validators.zh_CN.xlf +++ b/lib/symfony/validator/Resources/translations/validators.zh_CN.xlf @@ -468,91 +468,91 @@ This value is not a valid Twig template. - 该值不是有效的 Twig 模板。 + 该值不是有效的 Twig 模板。 This file is not a valid video. - 此文件不是有效的视频。 + 此文件不是有效的视频。 The size of the video could not be detected. - 无法检测到视频的大小。 + 无法检测到视频的大小。 The video width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - 视频宽度过大({{ width }}px)。允许的最大宽度为 {{ max_width }}px。 + 视频宽度过大({{ width }}px)。允许的最大宽度为 {{ max_width }}px。 The video width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - 视频宽度太小({{ width }}px)。预期的最小宽度为 {{ min_width }} 像素。 + 视频宽度太小({{ width }}px)。预期的最小宽度为 {{ min_width }} 像素。 The video height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. - 视频高度过大({{ height }}px)。允许的最大高度为 {{ max_height }}px。 + 视频高度过大({{ height }}px)。允许的最大高度为 {{ max_height }}px。 The video height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - 视频高度太小({{ height }}px)。期望的最小高度为 {{ min_height }}px。 + 视频高度太小({{ height }}px)。期望的最小高度为 {{ min_height }}px。 The video has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels. - 该视频像素过少 ({{ pixels }}). 期望的最小值为 {{ min_pixels }}。 + 该视频像素过少 ({{ pixels }}). 期望的最小值为 {{ min_pixels }}。 The video has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels. - 该视频的像素过多({{ pixels }})。预期的最大数量为 {{ max_pixels }}。 + 该视频的像素过多({{ pixels }})。预期的最大数量为 {{ max_pixels }}。 The video ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. - 视频纵横比过大({{ ratio }})。允许的最大纵横比为 {{ max_ratio }}。 + 视频纵横比过大({{ ratio }})。允许的最大纵横比为 {{ max_ratio }}。 The video ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. - 视频纵横比过小({{ ratio }})。预期的最低比例为 {{ min_ratio }}。 + 视频纵横比过小({{ ratio }})。预期的最低比例为 {{ min_ratio }}。 The video is square ({{ width }}x{{ height }}px). Square videos are not allowed. - 视频为正方形 ({{ width }}x{{ height }}px)。不允许正方形视频。 + 视频为正方形 ({{ width }}x{{ height }}px)。不允许正方形视频。 The video is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented videos are not allowed. - 视频为横向({{ width }}x{{ height }} 像素)。不允许横向视频。 + 视频为横向({{ width }}x{{ height }} 像素)。不允许横向视频。 The video is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented videos are not allowed. - 该视频为竖屏方向({{ width }}x{{ height }}px)。不允许竖屏视频。 + 该视频为竖屏方向({{ width }}x{{ height }}px)。不允许竖屏视频。 The video file is corrupted. - 视频文件已损坏。 + 视频文件已损坏。 The video contains multiple streams. Only one stream is allowed. - 该视频包含多个流。只允许一个流。 + 该视频包含多个流。只允许一个流。 Unsupported video codec "{{ codec }}". - 不支持的视频编解码器“{{ codec }}”。 + 不支持的视频编解码器“{{ codec }}”。 Unsupported video container "{{ container }}". - 不支持的视频容器 "{{ container }}". + 不支持的视频容器 "{{ container }}". The image file is corrupted. - 图像文件已损坏。 + 图像文件已损坏。 The image has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels. - 图像的像素太少({{ pixels }})。预期的最小数量为 {{ min_pixels }}。 + 图像的像素太少({{ pixels }})。预期的最小数量为 {{ min_pixels }}。 The image has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels. - 图像的像素过多 ({{ pixels }}). 预期的最大数量为 {{ max_pixels }}. + 图像的像素过多 ({{ pixels }}). 预期的最大数量为 {{ max_pixels }}. This filename does not match the expected charset. - 该文件名与预期的字符集不匹配。 + 该文件名与预期的字符集不匹配。 diff --git a/lib/symfony/web-profiler-bundle/Resources/views/Profiler/toolbar_js.html.twig b/lib/symfony/web-profiler-bundle/Resources/views/Profiler/toolbar_js.html.twig index 6d2930ff83..53e24f15ee 100644 --- a/lib/symfony/web-profiler-bundle/Resources/views/Profiler/toolbar_js.html.twig +++ b/lib/symfony/web-profiler-bundle/Resources/views/Profiler/toolbar_js.html.twig @@ -429,7 +429,7 @@ var pending = pendingRequests; for (var i = 0; i < requestStack.length; i++) { startAjaxRequest(i); - if (requestStack[i].duration) { + if (requestStack[i].duration || requestStack[i].error) { finishAjaxRequest(i); } } diff --git a/lib/symfony/yaml/Inline.php b/lib/symfony/yaml/Inline.php index 827e9a1cd3..8feecea158 100644 --- a/lib/symfony/yaml/Inline.php +++ b/lib/symfony/yaml/Inline.php @@ -701,6 +701,10 @@ private static function evaluateScalar(string $scalar, int $flags, array &$refer switch (true) { case ctype_digit($scalar): case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)): + if ($scalar < \PHP_INT_MIN || \PHP_INT_MAX < $scalar) { + return $scalar; + } + $cast = (int) $scalar; return ($scalar === (string) $cast) ? $cast : $scalar; diff --git a/lib/symfony/yaml/Parser.php b/lib/symfony/yaml/Parser.php index 40702ed639..744181f734 100644 --- a/lib/symfony/yaml/Parser.php +++ b/lib/symfony/yaml/Parser.php @@ -769,6 +769,14 @@ private function parseValue(string $value, int $flags, string $context): mixed break; } + if ($this->isCurrentLineComment()) { + break; + } + + if ('mapping' === $context && str_contains($this->currentLine, ': ') && !$this->isCurrentLineComment()) { + throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); + } + $lines[] = trim($this->currentLine); } diff --git a/lib/twig/twig/CHANGELOG b/lib/twig/twig/CHANGELOG index cf202b044b..cf47a76043 100644 --- a/lib/twig/twig/CHANGELOG +++ b/lib/twig/twig/CHANGELOG @@ -1,3 +1,34 @@ +# 3.23.0 (2026-01-23) + + * Add `=` assignment operator (allows to set variables in expression or to replace the short-form of the set tag) + * Add sequence, mapping, and object destructuring + * Add `?.` null-safe operator + * Add `===` and `!==` operators (equivalent to the `same as` and `not same as` tests) + * Fix opcache preload warning for unlinked anonymous class + * Fix spread operator behavior + +# 3.22.2 (2025-12-14) + + * Fix "cycle" with non-countable ArrayAccess + Traversable objects + * Use "getShareDir" as an indicator of Symfony version in Symfony bundle + * Fix escaper compatibility with PHP 8.5 + +# 3.22.1 (2025-11-16) + + * Add support for Symfony 8 + +# 3.22.0 (2025-10-29) + + * Add support for two words test in guard tag + * Add `Environment::registerUndefinedTestCallback()` + * Fix compatibility with Symfony 8 + * Fix accessing arrays with stringable objects as key + * Avoid errors when failing to guess the template info for an error + * Fix expression parser compatibility layer + * Fix compiling 'index' with repr (not string) in EmbedNode + * Update configuration keys + allow extra keys for CommonMark extensions + * Allow usage of other Markdown converters than CommonMark in LeagueMarkdown + # 3.21.1 (2025-05-03) * Fix ExtensionSet usage of BinaryOperatorExpressionParser @@ -44,6 +75,7 @@ # 3.18.0 (2024-12-29) + * Support for invoking closures * Fix unary operator precedence change * Ignore `SyntaxError` exceptions from undefined handlers when using the `guard` tag * Add a way to stream template rendering (`TemplateWrapper::stream()` and `TemplateWrapper::streamBlock()`) @@ -52,7 +84,6 @@ * Fix the null coalescing operator when the test returns null * Fix the Elvis operator when used as '? :' instead of '?:' - * Support for invoking closures # 3.17.0 (2024-12-10) diff --git a/lib/twig/twig/phpstan-baseline.neon b/lib/twig/twig/phpstan-baseline.neon deleted file mode 100644 index 131ed97b4f..0000000000 --- a/lib/twig/twig/phpstan-baseline.neon +++ /dev/null @@ -1,25 +0,0 @@ -parameters: - ignoreErrors: - - # The method is dynamically generated by the CheckSecurityNode - message: '#^Call to an undefined method Twig\\Template\:\:checkSecurity\(\)\.$#' - identifier: method.notFound - count: 1 - path: src/Extension/CoreExtension.php - - - # 2 parameters will be required - message: '#^Method Twig\\Node\\IncludeNode\:\:addGetTemplate\(\) invoked with 2 parameters, 1 required\.$#' - identifier: arguments.count - count: 1 - path: src/Node/IncludeNode.php - - - # int|string will be supported in 4.x - message: '#^PHPDoc tag @param for parameter $name with type int|string is not subtype of native type string\.$#' - identifier: parameter.phpDocType - count: 5 - path: src/Node/Node.php - - - # Adding 0 to the string representation of a number is valid and what we want here - message: '#^Binary operation "\+" between 0 and string results in an error\.$#' - identifier: binaryOp.invalid - count: 1 - path: src/Lexer.php diff --git a/lib/twig/twig/phpstan.neon.dist b/lib/twig/twig/phpstan.neon.dist deleted file mode 100644 index 6d94e41092..0000000000 --- a/lib/twig/twig/phpstan.neon.dist +++ /dev/null @@ -1,9 +0,0 @@ -includes: - - phpstan-baseline.neon - -parameters: - level: 3 - paths: - - src - excludePaths: - - src/Test diff --git a/lib/twig/twig/splitsh.json b/lib/twig/twig/splitsh.json new file mode 100644 index 0000000000..f415dd8d4e --- /dev/null +++ b/lib/twig/twig/splitsh.json @@ -0,0 +1,15 @@ +{ + "subtrees": { + "twig-extra-bundle": "extra/twig-extra-bundle", + "cache-extra": "extra/cache-extra", + "cssinliner-extra": "extra/cssinliner-extra", + "html-extra": "extra/html-extra", + "inky-extra": "extra/inky-extra", + "intl-extra": "extra/intl-extra", + "markdown-extra": "extra/markdown-extra", + "string-extra": "extra/string-extra" + }, + "defaults": { + "git_constraint": "<1.8.2" + } +} diff --git a/lib/twig/twig/src/Attribute/AsTwigFilter.php b/lib/twig/twig/src/Attribute/AsTwigFilter.php index 395531d865..09f8f01de4 100644 --- a/lib/twig/twig/src/Attribute/AsTwigFilter.php +++ b/lib/twig/twig/src/Attribute/AsTwigFilter.php @@ -31,15 +31,15 @@ final class AsTwigFilter { /** - * @param non-empty-string $name The name of the filter in Twig. - * @param bool|null $needsCharset Whether the filter needs the charset passed as the first argument. - * @param bool|null $needsEnvironment Whether the filter needs the environment passed as the first argument, or after the charset. - * @param bool|null $needsContext Whether the filter needs the context array passed as the first argument, or after the charset and the environment. - * @param string[]|null $isSafe List of formats in which you want the raw output to be printed unescaped. - * @param string|array|null $isSafeCallback Function called at compilation time to determine if the filter is safe. - * @param string|null $preEscape Some filters may need to work on input that is already escaped or safe - * @param string[]|null $preservesSafety Preserves the safety of the value that the filter is applied to. - * @param DeprecatedCallableInfo|null $deprecationInfo Information about the deprecation + * @param non-empty-string $name The name of the filter in Twig + * @param bool|null $needsCharset Whether the filter needs the charset passed as the first argument + * @param bool|null $needsEnvironment Whether the filter needs the environment passed as the first argument, or after the charset + * @param bool|null $needsContext Whether the filter needs the context array passed as the first argument, or after the charset and the environment + * @param string[]|null $isSafe List of formats in which you want the raw output to be printed unescaped + * @param string|array|null $isSafeCallback Function called at compilation time to determine if the filter is safe + * @param string|null $preEscape Some filters may need to work on input that is already escaped or safe + * @param string[]|null $preservesSafety Preserves the safety of the value that the filter is applied to + * @param DeprecatedCallableInfo|null $deprecationInfo Information about the deprecation */ public function __construct( public string $name, diff --git a/lib/twig/twig/src/Attribute/AsTwigFunction.php b/lib/twig/twig/src/Attribute/AsTwigFunction.php index 9229d128ef..d161f06f46 100644 --- a/lib/twig/twig/src/Attribute/AsTwigFunction.php +++ b/lib/twig/twig/src/Attribute/AsTwigFunction.php @@ -31,13 +31,13 @@ final class AsTwigFunction { /** - * @param non-empty-string $name The name of the function in Twig. - * @param bool|null $needsCharset Whether the function needs the charset passed as the first argument. - * @param bool|null $needsEnvironment Whether the function needs the environment passed as the first argument, or after the charset. - * @param bool|null $needsContext Whether the function needs the context array passed as the first argument, or after the charset and the environment. - * @param string[]|null $isSafe List of formats in which you want the raw output to be printed unescaped. - * @param string|array|null $isSafeCallback Function called at compilation time to determine if the function is safe. - * @param DeprecatedCallableInfo|null $deprecationInfo Information about the deprecation + * @param non-empty-string $name The name of the function in Twig + * @param bool|null $needsCharset Whether the function needs the charset passed as the first argument + * @param bool|null $needsEnvironment Whether the function needs the environment passed as the first argument, or after the charset + * @param bool|null $needsContext Whether the function needs the context array passed as the first argument, or after the charset and the environment + * @param string[]|null $isSafe List of formats in which you want the raw output to be printed unescaped + * @param string|array|null $isSafeCallback Function called at compilation time to determine if the function is safe + * @param DeprecatedCallableInfo|null $deprecationInfo Information about the deprecation */ public function __construct( public string $name, diff --git a/lib/twig/twig/src/Attribute/AsTwigTest.php b/lib/twig/twig/src/Attribute/AsTwigTest.php index 40eddf83e3..1ce2658b49 100644 --- a/lib/twig/twig/src/Attribute/AsTwigTest.php +++ b/lib/twig/twig/src/Attribute/AsTwigTest.php @@ -31,11 +31,11 @@ final class AsTwigTest { /** - * @param non-empty-string $name The name of the test in Twig. - * @param bool|null $needsCharset Whether the test needs the charset passed as the first argument. - * @param bool|null $needsEnvironment Whether the test needs the environment passed as the first argument, or after the charset. - * @param bool|null $needsContext Whether the test needs the context array passed as the first argument, or after the charset and the environment. - * @param DeprecatedCallableInfo|null $deprecationInfo Information about the deprecation + * @param non-empty-string $name The name of the test in Twig + * @param bool|null $needsCharset Whether the test needs the charset passed as the first argument + * @param bool|null $needsEnvironment Whether the test needs the environment passed as the first argument, or after the charset + * @param bool|null $needsContext Whether the test needs the context array passed as the first argument, or after the charset and the environment + * @param DeprecatedCallableInfo|null $deprecationInfo Information about the deprecation */ public function __construct( public string $name, diff --git a/lib/twig/twig/src/Environment.php b/lib/twig/twig/src/Environment.php index ff3f0c588b..2af6476111 100644 --- a/lib/twig/twig/src/Environment.php +++ b/lib/twig/twig/src/Environment.php @@ -43,11 +43,11 @@ */ class Environment { - public const VERSION = '3.21.1'; - public const VERSION_ID = 32101; + public const VERSION = '3.23.0'; + public const VERSION_ID = 32300; public const MAJOR_VERSION = 3; - public const MINOR_VERSION = 21; - public const RELEASE_VERSION = 1; + public const MINOR_VERSION = 23; + public const RELEASE_VERSION = 0; public const EXTRA_VERSION = ''; private $charset; @@ -827,6 +827,14 @@ public function getTest(string $name): ?TwigTest return $this->extensionSet->getTest($name); } + /** + * @param callable(string): (TwigTest|false) $callable + */ + public function registerUndefinedTestCallback(callable $callable): void + { + $this->extensionSet->registerUndefinedTestCallback($callable); + } + /** * @return void */ diff --git a/lib/twig/twig/src/Error/Error.php b/lib/twig/twig/src/Error/Error.php index 015085e32b..97ed2df991 100644 --- a/lib/twig/twig/src/Error/Error.php +++ b/lib/twig/twig/src/Error/Error.php @@ -148,6 +148,10 @@ private function guessTemplateInfo(): void } } + if (null === $template) { + return; // Impossible to guess the info as the template was not found in the backtrace + } + $r = new \ReflectionObject($template); $file = $r->getFileName(); @@ -158,7 +162,7 @@ private function guessTemplateInfo(): void while ($e = array_pop($exceptions)) { $traces = $e->getTrace(); - array_unshift($traces, ['file' => $e instanceof Error ? $e->phpFile : $e->getFile(), 'line' => $e instanceof Error ? $e->phpLine : $e->getLine()]); + array_unshift($traces, ['file' => $e instanceof self ? $e->phpFile : $e->getFile(), 'line' => $e instanceof self ? $e->phpLine : $e->getLine()]); while ($trace = array_shift($traces)) { if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) { continue; diff --git a/lib/twig/twig/src/ExpressionParser.php b/lib/twig/twig/src/ExpressionParser.php index 727cf7eba6..3ba94d076f 100644 --- a/lib/twig/twig/src/ExpressionParser.php +++ b/lib/twig/twig/src/ExpressionParser.php @@ -214,7 +214,7 @@ public function parseArguments() { trigger_deprecation('twig/twig', '3.19', \sprintf('The "%s()" method is deprecated, use "Twig\ExpressionParser\Infix\ArgumentsTrait::parseNamedArguments()" instead.', __METHOD__)); - $parsePrimary = new \ReflectionMethod($this->parser, 'parsePrimary'); + $parsePrimaryExpression = new \ReflectionMethod($this->parser, 'parsePrimaryExpression'); $namedArguments = false; $definition = false; @@ -263,7 +263,7 @@ public function parseArguments() $name = $value->getAttribute('name'); if ($definition) { - $value = $parsePrimary->invoke($this->parser); + $value = $parsePrimaryExpression->invoke($this->parser); if (!$this->checkConstantExpression($value)) { throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping).', $token->getLine(), $stream->getSourceContext()); diff --git a/lib/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php b/lib/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php index 1c2ae49dd3..96bde555d3 100644 --- a/lib/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php +++ b/lib/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php @@ -13,6 +13,7 @@ use Twig\Error\SyntaxError; use Twig\Node\Expression\ArrayExpression; +use Twig\Node\Expression\Binary\SetBinary; use Twig\Node\Expression\Unary\SpreadUnary; use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Expression\Variable\LocalVariable; @@ -58,7 +59,10 @@ private function parseNamedArguments(Parser $parser, bool $parseOpenParenthesis } $name = null; - if (($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) || ($token = $stream->nextIf(Token::PUNCTUATION_TYPE, ':'))) { + if ($value instanceof SetBinary) { + $name = $value->getNode('left')->getAttribute('name'); + $value = $value->getNode('right'); + } elseif (($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) || ($token = $stream->nextIf(Token::PUNCTUATION_TYPE, ':'))) { if (!$value instanceof ContextVariable) { throw new SyntaxError(\sprintf('A parameter name must be a string, "%s" given.', $value::class), $token->getLine(), $stream->getSourceContext()); } diff --git a/lib/twig/twig/src/ExpressionParser/Infix/AssignmentExpressionParser.php b/lib/twig/twig/src/ExpressionParser/Infix/AssignmentExpressionParser.php new file mode 100644 index 0000000000..fa8c4f2b02 --- /dev/null +++ b/lib/twig/twig/src/ExpressionParser/Infix/AssignmentExpressionParser.php @@ -0,0 +1,66 @@ +getLine(), $parser->getStream()->getSourceContext()); + } + $right = $parser->parseExpression(InfixAssociativity::Left === $this->getAssociativity() ? $this->getPrecedence() + 1 : $this->getPrecedence()); + $right = match ($this->getName()) { + '=' => $right, + default => throw new \LogicException(\sprintf('Unknown operator: %s.', $this->getName())), + }; + + if ($left instanceof ArrayExpression) { + if ($left->isSequence()) { + return new SequenceDestructuringSetBinary($left, $right, $token->getLine()); + } else { + return new ObjectDestructuringSetBinary($left, $right, $token->getLine()); + } + } else { + return new SetBinary($left, $right, $token->getLine()); + } + } + + public function getDescription(): string + { + return 'Assignment operator'; + } +} diff --git a/lib/twig/twig/src/ExpressionParser/Infix/DotExpressionParser.php b/lib/twig/twig/src/ExpressionParser/Infix/DotExpressionParser.php index 7d1cf50582..31418b585b 100644 --- a/lib/twig/twig/src/ExpressionParser/Infix/DotExpressionParser.php +++ b/lib/twig/twig/src/ExpressionParser/Infix/DotExpressionParser.php @@ -37,6 +37,7 @@ final class DotExpressionParser extends AbstractExpressionParser implements Infi public function parse(Parser $parser, AbstractExpression $expr, Token $token): AbstractExpression { + $nullSafe = '?.' === $token->getValue(); $stream = $parser->getStream(); $token = $stream->getCurrent(); $lineno = $token->getLine(); @@ -55,7 +56,7 @@ public function parse(Parser $parser, AbstractExpression $expr, Token $token): A ) { $attribute = new ConstantExpression($token->getValue(), $token->getLine()); } else { - throw new SyntaxError(\sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), $token->toEnglish()), $token->getLine(), $stream->getSourceContext()); + throw new SyntaxError(\sprintf('Expected name or number, got value "%s" of type "%s".', $token->getValue(), $token->toEnglish()), $token->getLine(), $stream->getSourceContext()); } } @@ -74,7 +75,7 @@ public function parse(Parser $parser, AbstractExpression $expr, Token $token): A return new MacroReferenceExpression(new TemplateVariable($expr->getAttribute('name'), $expr->getTemplateLine()), 'macro_'.$attribute->getAttribute('value'), $arguments, $expr->getTemplateLine()); } - return new GetAttrExpression($expr, $attribute, $arguments, $type, $lineno); + return new GetAttrExpression($expr, $attribute, $arguments, $type, $lineno, $nullSafe); } public function getName(): string @@ -82,6 +83,11 @@ public function getName(): string return '.'; } + public function getAliases(): array + { + return ['?.']; + } + public function getDescription(): string { return 'Get an attribute on a variable'; diff --git a/lib/twig/twig/src/ExpressionParser/InfixExpressionParserInterface.php b/lib/twig/twig/src/ExpressionParser/InfixExpressionParserInterface.php index 8d0ac674c8..4641ef815a 100644 --- a/lib/twig/twig/src/ExpressionParser/InfixExpressionParserInterface.php +++ b/lib/twig/twig/src/ExpressionParser/InfixExpressionParserInterface.php @@ -11,12 +11,16 @@ namespace Twig\ExpressionParser; +use Twig\Error\SyntaxError; use Twig\Node\Expression\AbstractExpression; use Twig\Parser; use Twig\Token; interface InfixExpressionParserInterface extends ExpressionParserInterface { + /** + * @throws SyntaxError + */ public function parse(Parser $parser, AbstractExpression $left, Token $token): AbstractExpression; public function getAssociativity(): InfixAssociativity; diff --git a/lib/twig/twig/src/ExpressionParser/Prefix/LiteralExpressionParser.php b/lib/twig/twig/src/ExpressionParser/Prefix/LiteralExpressionParser.php index d98c9adf1f..da3805106d 100644 --- a/lib/twig/twig/src/ExpressionParser/Prefix/LiteralExpressionParser.php +++ b/lib/twig/twig/src/ExpressionParser/Prefix/LiteralExpressionParser.php @@ -20,6 +20,7 @@ use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\Binary\ConcatBinary; use Twig\Node\Expression\ConstantExpression; +use Twig\Node\Expression\EmptyExpression; use Twig\Node\Expression\Variable\ContextVariable; use Twig\Parser; use Twig\Token; @@ -100,10 +101,6 @@ public function parse(Parser $parser, Token $token): AbstractExpression return new ContextVariable($token->getValue(), $token->getLine()); } - if ('=' === $token->getValue() && ('==' === $stream->look(-1)->getValue() || '!=' === $stream->look(-1)->getValue())) { - throw new SyntaxError(\sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $stream->getSourceContext()); - } - // no break default: throw new SyntaxError(\sprintf('Unexpected token "%s" of value "%s".', $token->toEnglish(), $token->getValue()), $token->getLine(), $stream->getSourceContext()); @@ -174,7 +171,12 @@ private function parseSequenceExpression(Parser $parser) } $first = false; - $node->addElement($parser->parseExpression()); + // Check for empty slots (comma with no expression) + if ($stream->test(Token::PUNCTUATION_TYPE, ',')) { + $node->addElement(new EmptyExpression($stream->getCurrent()->getLine())); + } else { + $node->addElement($parser->parseExpression()); + } } $stream->expect(Token::PUNCTUATION_TYPE, ']', 'An opened sequence is not properly closed'); diff --git a/lib/twig/twig/src/ExpressionParser/Prefix/UnaryOperatorExpressionParser.php b/lib/twig/twig/src/ExpressionParser/Prefix/UnaryOperatorExpressionParser.php index 35468940a1..801390097b 100644 --- a/lib/twig/twig/src/ExpressionParser/Prefix/UnaryOperatorExpressionParser.php +++ b/lib/twig/twig/src/ExpressionParser/Prefix/UnaryOperatorExpressionParser.php @@ -33,6 +33,7 @@ public function __construct( private ?PrecedenceChange $precedenceChange = null, private ?string $description = null, private array $aliases = [], + private ?int $operandPrecedence = null, ) { } @@ -41,7 +42,7 @@ public function __construct( */ public function parse(Parser $parser, Token $token): AbstractExpression { - return new ($this->nodeClass)($parser->parseExpression($this->precedence), $token->getLine()); + return new ($this->nodeClass)($parser->parseExpression($this->operandPrecedence ?? $this->precedence), $token->getLine()); } public function getName(): string diff --git a/lib/twig/twig/src/ExpressionParser/PrefixExpressionParserInterface.php b/lib/twig/twig/src/ExpressionParser/PrefixExpressionParserInterface.php index 587997c51a..8e39dad37e 100644 --- a/lib/twig/twig/src/ExpressionParser/PrefixExpressionParserInterface.php +++ b/lib/twig/twig/src/ExpressionParser/PrefixExpressionParserInterface.php @@ -11,11 +11,15 @@ namespace Twig\ExpressionParser; +use Twig\Error\SyntaxError; use Twig\Node\Expression\AbstractExpression; use Twig\Parser; use Twig\Token; interface PrefixExpressionParserInterface extends ExpressionParserInterface { + /** + * @throws SyntaxError + */ public function parse(Parser $parser, Token $token): AbstractExpression; } diff --git a/lib/twig/twig/src/Extension/AttributeExtension.php b/lib/twig/twig/src/Extension/AttributeExtension.php index 44e4f3f6bd..74fcbb8570 100644 --- a/lib/twig/twig/src/Extension/AttributeExtension.php +++ b/lib/twig/twig/src/Extension/AttributeExtension.php @@ -104,7 +104,7 @@ private function initFromAttributes(): void ]); if ($callable->getMinimalNumberOfRequiredArguments() > $method->getNumberOfParameters()) { - throw new \LogicException(sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigFilter, but only %d defined.', $reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters())); + throw new \LogicException(\sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigFilter, but only %d defined.', $reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters())); } $filters[$attribute->name] = $callable; @@ -125,14 +125,13 @@ private function initFromAttributes(): void ]); if ($callable->getMinimalNumberOfRequiredArguments() > $method->getNumberOfParameters()) { - throw new \LogicException(sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigFunction, but only %d defined.', $reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters())); + throw new \LogicException(\sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigFunction, but only %d defined.', $reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters())); } $functions[$attribute->name] = $callable; } foreach ($method->getAttributes(AsTwigTest::class) as $reflectionAttribute) { - /** @var AsTwigTest $attribute */ $attribute = $reflectionAttribute->newInstance(); @@ -145,7 +144,7 @@ private function initFromAttributes(): void ]); if ($callable->getMinimalNumberOfRequiredArguments() > $method->getNumberOfParameters()) { - throw new \LogicException(sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigTest, but only %d defined.', $reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters())); + throw new \LogicException(\sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigTest, but only %d defined.', $reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters())); } $tests[$attribute->name] = $callable; diff --git a/lib/twig/twig/src/Extension/CoreExtension.php b/lib/twig/twig/src/Extension/CoreExtension.php index f7e4250ae5..345f406661 100644 --- a/lib/twig/twig/src/Extension/CoreExtension.php +++ b/lib/twig/twig/src/Extension/CoreExtension.php @@ -17,6 +17,7 @@ use Twig\Error\RuntimeError; use Twig\Error\SyntaxError; use Twig\ExpressionParser\Infix\ArrowExpressionParser; +use Twig\ExpressionParser\Infix\AssignmentExpressionParser; use Twig\ExpressionParser\Infix\BinaryOperatorExpressionParser; use Twig\ExpressionParser\Infix\ConditionalTernaryExpressionParser; use Twig\ExpressionParser\Infix\DotExpressionParser; @@ -55,10 +56,12 @@ use Twig\Node\Expression\Binary\MulBinary; use Twig\Node\Expression\Binary\NotEqualBinary; use Twig\Node\Expression\Binary\NotInBinary; +use Twig\Node\Expression\Binary\NotSameAsBinary; use Twig\Node\Expression\Binary\NullCoalesceBinary; use Twig\Node\Expression\Binary\OrBinary; use Twig\Node\Expression\Binary\PowerBinary; use Twig\Node\Expression\Binary\RangeBinary; +use Twig\Node\Expression\Binary\SameAsBinary; use Twig\Node\Expression\Binary\SpaceshipBinary; use Twig\Node\Expression\Binary\StartsWithBinary; use Twig\Node\Expression\Binary\SubBinary; @@ -333,7 +336,7 @@ public function getExpressionParsers(): array return [ // unary operators new UnaryOperatorExpressionParser(NotUnary::class, 'not', 50, new PrecedenceChange('twig/twig', '3.15', 70)), - new UnaryOperatorExpressionParser(SpreadUnary::class, '...', 512, description: 'Spread operator'), + new UnaryOperatorExpressionParser(SpreadUnary::class, '...', 512, description: 'Spread operator', operandPrecedence: 0), new UnaryOperatorExpressionParser(NegUnary::class, '-', 500), new UnaryOperatorExpressionParser(PosUnary::class, '+', 500), @@ -360,6 +363,8 @@ public function getExpressionParsers(): array new BinaryOperatorExpressionParser(EndsWithBinary::class, 'ends with', 20), new BinaryOperatorExpressionParser(HasSomeBinary::class, 'has some', 20), new BinaryOperatorExpressionParser(HasEveryBinary::class, 'has every', 20), + new BinaryOperatorExpressionParser(SameAsBinary::class, '===', 20), + new BinaryOperatorExpressionParser(NotSameAsBinary::class, '!==', 20), new BinaryOperatorExpressionParser(RangeBinary::class, '..', 25), new BinaryOperatorExpressionParser(AddBinary::class, '+', 30), new BinaryOperatorExpressionParser(SubBinary::class, '-', 30), @@ -373,6 +378,9 @@ public function getExpressionParsers(): array // ternary operator new ConditionalTernaryExpressionParser(), + // assignment operator + new AssignmentExpressionParser('='), + // Twig callables new IsExpressionParser(), new IsNotExpressionParser(), @@ -417,10 +425,8 @@ public static function cycle($values, $position): mixed trigger_deprecation('twig/twig', '3.12', 'Passing a non-countable sequence of values to "%s()" is deprecated.', __METHOD__); - return $values; + $values = self::toArray($values, false); } - - $values = self::toArray($values, false); } if (!$count = \count($values)) { @@ -1694,7 +1700,7 @@ public static function getAttribute(Environment $env, Source $source, $object, $ } if (match (true) { - \is_array($object) => \array_key_exists($arrayItem, $object), + \is_array($object) => \array_key_exists($arrayItem = (string) $arrayItem, $object), $object instanceof \ArrayAccess => $object->offsetExists($arrayItem), default => false, }) { @@ -1715,9 +1721,13 @@ public static function getAttribute(Environment $env, Source $source, $object, $ } if ($object instanceof \ArrayAccess) { - $message = \sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, $object::class); + if (\is_object($arrayItem) || \is_array($arrayItem)) { + $message = \sprintf('Key of type "%s" does not exist in ArrayAccess-able object of class "%s".', get_debug_type($arrayItem), get_debug_type($object)); + } else { + $message = \sprintf('Key "%s" does not exist in ArrayAccess-able object of class "%s".', $arrayItem, get_debug_type($object)); + } } elseif (\is_object($object)) { - $message = \sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, $object::class); + $message = \sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, get_debug_type($object)); } elseif (\is_array($object)) { if (!$object) { $message = \sprintf('Key "%s" does not exist as the sequence/mapping is empty.', $arrayItem); @@ -1880,7 +1890,7 @@ public static function getAttribute(Environment $env, Source $source, $object, $ return; } - throw new RuntimeError(\sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()"/"has%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), $lineno, $source); + throw new RuntimeError(\sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()", "is%1$s()", "has%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), $lineno, $source); } if ($sandboxed) { diff --git a/lib/twig/twig/src/Extension/ExtensionInterface.php b/lib/twig/twig/src/Extension/ExtensionInterface.php index 44356f6276..60ca35b4e6 100644 --- a/lib/twig/twig/src/Extension/ExtensionInterface.php +++ b/lib/twig/twig/src/Extension/ExtensionInterface.php @@ -11,8 +11,11 @@ namespace Twig\Extension; +use Twig\ExpressionParser; use Twig\ExpressionParser\ExpressionParserInterface; use Twig\ExpressionParser\PrecedenceChange; +use Twig\Node\Expression\Binary\AbstractBinary; +use Twig\Node\Expression\Unary\AbstractUnary; use Twig\NodeVisitor\NodeVisitorInterface; use Twig\TokenParser\TokenParserInterface; use Twig\TwigFilter; diff --git a/lib/twig/twig/src/ExtensionSet.php b/lib/twig/twig/src/ExtensionSet.php index 85a98cf3c3..7bb62fa781 100644 --- a/lib/twig/twig/src/ExtensionSet.php +++ b/lib/twig/twig/src/ExtensionSet.php @@ -27,6 +27,10 @@ use Twig\NodeVisitor\NodeVisitorInterface; use Twig\TokenParser\TokenParserInterface; +// Help opcache.preload discover always-needed symbols +// @see https://github.com/php/php-src/issues/10131 +class_exists(BinaryOperatorExpressionParser::class); + /** * @author Fabien Potencier * @@ -59,6 +63,8 @@ final class ExtensionSet private $functionCallbacks = []; /** @var array */ private $filterCallbacks = []; + /** @var array */ + private $testCallbacks = []; /** @var array */ private $parserCallbacks = []; private $lastModified = 0; @@ -410,9 +416,23 @@ public function getTest(string $name): ?TwigTest } } + foreach ($this->testCallbacks as $callback) { + if (false !== $test = $callback($name)) { + return $test; + } + } + return null; } + /** + * @param callable(string): (TwigTest|false) $callable + */ + public function registerUndefinedTestCallback(callable $callable): void + { + $this->testCallbacks[] = $callable; + } + public function getExpressionParsers(): ExpressionParsers { if (!$this->initialized) { diff --git a/lib/twig/twig/src/Lexer.php b/lib/twig/twig/src/Lexer.php index 027771accb..508a79c025 100644 --- a/lib/twig/twig/src/Lexer.php +++ b/lib/twig/twig/src/Lexer.php @@ -525,7 +525,7 @@ private function moveCursor($text): void private function getOperatorRegex(): string { - $expressionParsers = ['=']; + $expressionParsers = []; foreach ($this->env->getExpressionParsers() as $expressionParser) { $expressionParsers = array_merge($expressionParsers, [$expressionParser->getName()], $expressionParser->getAliases()); } diff --git a/lib/twig/twig/src/Node/EmbedNode.php b/lib/twig/twig/src/Node/EmbedNode.php index fe4365b571..2de39ebb94 100644 --- a/lib/twig/twig/src/Node/EmbedNode.php +++ b/lib/twig/twig/src/Node/EmbedNode.php @@ -41,7 +41,7 @@ protected function addGetTemplate(Compiler $compiler, string $template = ''): vo ->raw(', ') ->repr($this->getTemplateLine()) ->raw(', ') - ->string($this->getAttribute('index')) + ->repr($this->getAttribute('index')) ->raw(')') ; if ($this->getAttribute('ignore_missing')) { diff --git a/lib/twig/twig/src/Node/Expression/ArrayExpression.php b/lib/twig/twig/src/Node/Expression/ArrayExpression.php index b6f8a6ba48..f9f719dd94 100644 --- a/lib/twig/twig/src/Node/Expression/ArrayExpression.php +++ b/lib/twig/twig/src/Node/Expression/ArrayExpression.php @@ -12,6 +12,7 @@ namespace Twig\Node\Expression; use Twig\Compiler; +use Twig\Error\SyntaxError; use Twig\Node\Expression\Unary\SpreadUnary; use Twig\Node\Expression\Unary\StringCastUnary; use Twig\Node\Expression\Variable\ContextVariable; @@ -60,6 +61,31 @@ public function hasElement(AbstractExpression $key): bool return false; } + /** + * Checks if the array is a sequence (keys are sequential integers starting from 0). + * + * @internal + */ + public function isSequence(): bool + { + foreach ($this->getKeyValuePairs() as $i => $pair) { + $key = $pair['key']; + if ($key instanceof TempNameExpression) { + $keyValue = $key->getAttribute('name'); + } elseif ($key instanceof ConstantExpression) { + $keyValue = $key->getAttribute('value'); + } else { + return false; + } + + if ($keyValue !== $i) { + return false; + } + } + + return true; + } + public function addElement(AbstractExpression $value, ?AbstractExpression $key = null): void { if (null === $key) { @@ -77,6 +103,13 @@ public function compile(Compiler $compiler): void return; } + // Check for empty expressions which are only allowed in destructuring + foreach ($this->getKeyValuePairs() as $pair) { + if ($pair['value'] instanceof EmptyExpression) { + throw new SyntaxError('Empty array elements are only allowed in destructuring assignments.', $pair['value']->getTemplateLine(), $this->getSourceContext()); + } + } + $compiler->raw('['); $isSequence = true; foreach ($this->getKeyValuePairs() as $i => $pair) { diff --git a/lib/twig/twig/src/Node/Expression/Binary/MatchesBinary.php b/lib/twig/twig/src/Node/Expression/Binary/MatchesBinary.php index 32e8d34e45..569dfde05f 100644 --- a/lib/twig/twig/src/Node/Expression/Binary/MatchesBinary.php +++ b/lib/twig/twig/src/Node/Expression/Binary/MatchesBinary.php @@ -13,8 +13,8 @@ use Twig\Compiler; use Twig\Error\SyntaxError; -use Twig\Node\Expression\ReturnBoolInterface; use Twig\Node\Expression\ConstantExpression; +use Twig\Node\Expression\ReturnBoolInterface; use Twig\Node\Node; class MatchesBinary extends AbstractBinary implements ReturnBoolInterface diff --git a/lib/twig/twig/src/Node/Expression/Binary/NotSameAsBinary.php b/lib/twig/twig/src/Node/Expression/Binary/NotSameAsBinary.php new file mode 100644 index 0000000000..ed28c19bb6 --- /dev/null +++ b/lib/twig/twig/src/Node/Expression/Binary/NotSameAsBinary.php @@ -0,0 +1,23 @@ +raw('!=='); + } +} diff --git a/lib/twig/twig/src/Node/Expression/Binary/ObjectDestructuringSetBinary.php b/lib/twig/twig/src/Node/Expression/Binary/ObjectDestructuringSetBinary.php new file mode 100644 index 0000000000..2c0853f655 --- /dev/null +++ b/lib/twig/twig/src/Node/Expression/Binary/ObjectDestructuringSetBinary.php @@ -0,0 +1,71 @@ +getKeyValuePairs() as $pair) { + if (!$pair['value'] instanceof ContextVariable) { + throw new SyntaxError(\sprintf('Cannot assign to "%s", only variables can be assigned in object/mapping destructuring.', $pair['value']::class), $lineno); + } + $this->properties[] = $pair['value']->getAttribute('name'); + } + + parent::__construct($left, $right, $lineno); + } + + public function compile(Compiler $compiler): void + { + $compiler->addDebugInfo($this); + $compiler->raw('['); + foreach ($this->properties as $i => $property) { + if ($i) { + $compiler->raw(', '); + } + $compiler->raw('$context[')->repr($property)->raw(']'); + } + $compiler->raw('] = ['); + foreach ($this->properties as $i => $property) { + if ($i) { + $compiler->raw(', '); + } + $compiler->raw('CoreExtension::getAttribute($this->env, $this->source, ')->subcompile($this->getNode('right'))->raw(', ')->repr($property)->raw(', [], \\Twig\\Template::ANY_CALL, false, false, false, ')->repr($this->getNode('right')->getTemplateLine())->raw(')'); + } + $compiler->raw(']'); + } + + public function operator(Compiler $compiler): Compiler + { + return $compiler->raw('='); + } +} diff --git a/lib/twig/twig/src/Node/Expression/Binary/SameAsBinary.php b/lib/twig/twig/src/Node/Expression/Binary/SameAsBinary.php new file mode 100644 index 0000000000..b08a19072a --- /dev/null +++ b/lib/twig/twig/src/Node/Expression/Binary/SameAsBinary.php @@ -0,0 +1,23 @@ +raw('==='); + } +} diff --git a/lib/twig/twig/src/Node/Expression/Binary/SequenceDestructuringSetBinary.php b/lib/twig/twig/src/Node/Expression/Binary/SequenceDestructuringSetBinary.php new file mode 100644 index 0000000000..a6a873c516 --- /dev/null +++ b/lib/twig/twig/src/Node/Expression/Binary/SequenceDestructuringSetBinary.php @@ -0,0 +1,67 @@ +getKeyValuePairs() as $pair) { + if ($pair['value'] instanceof EmptyExpression) { + $this->variables[] = null; + } elseif ($pair['value'] instanceof ContextVariable) { + $this->variables[] = $pair['value']->getAttribute('name'); + } else { + throw new SyntaxError(\sprintf('Cannot assign to "%s", only variables can be assigned in sequence destructuring.', $pair['value']::class), $lineno); + } + } + + parent::__construct($left, $right, $lineno); + } + + public function compile(Compiler $compiler): void + { + $compiler->addDebugInfo($this); + $compiler->raw('['); + foreach ($this->variables as $i => $name) { + if ($i) { + $compiler->raw(', '); + } + if (null !== $name) { + $compiler->raw('$context[')->repr($name)->raw(']'); + } + } + $compiler->raw('] = array_pad(')->subcompile($this->getNode('right'))->raw(', ')->repr(\count($this->variables))->raw(', null)'); + } + + public function operator(Compiler $compiler): Compiler + { + return $compiler->raw('='); + } +} diff --git a/lib/twig/twig/src/Node/Expression/Binary/SetBinary.php b/lib/twig/twig/src/Node/Expression/Binary/SetBinary.php new file mode 100644 index 0000000000..7b3443298b --- /dev/null +++ b/lib/twig/twig/src/Node/Expression/Binary/SetBinary.php @@ -0,0 +1,44 @@ + + */ +class SetBinary extends AbstractBinary +{ + /** + * @param ContextVariable $left + * @param AbstractExpression $right + */ + public function __construct(Node $left, Node $right, int $lineno) + { + $name = $left->getAttribute('name'); + if (!\is_string($name)) { + throw new \LogicException('The "name" attribute must be a string.'); + } + $left = new AssignContextVariable($name, $left->getTemplateLine()); + + parent::__construct($left, $right, $lineno); + } + + public function operator(Compiler $compiler): Compiler + { + return $compiler->raw('='); + } +} diff --git a/lib/twig/twig/src/Node/Expression/EmptyExpression.php b/lib/twig/twig/src/Node/Expression/EmptyExpression.php new file mode 100644 index 0000000000..768d1d64fa --- /dev/null +++ b/lib/twig/twig/src/Node/Expression/EmptyExpression.php @@ -0,0 +1,33 @@ + $node, 'attribute' => $attribute]; if (null !== $arguments) { @@ -36,7 +36,7 @@ public function __construct(AbstractExpression $node, AbstractExpression $attrib trigger_deprecation('twig/twig', '3.15', \sprintf('Not passing a "%s" instance as the "arguments" argument of the "%s" constructor is deprecated ("%s" given).', ArrayExpression::class, static::class, $arguments::class)); } - parent::__construct($nodes, ['type' => $type, 'ignore_strict_check' => false, 'optimizable' => true], $lineno); + parent::__construct($nodes, ['type' => $type, 'ignore_strict_check' => false, 'optimizable' => !$nullSafe, 'null_safe' => $nullSafe], $lineno); } public function enableDefinedTest(): void @@ -49,6 +49,8 @@ public function compile(Compiler $compiler): void { $env = $compiler->getEnvironment(); $arrayAccessSandbox = false; + $nullSafe = $this->getAttribute('null_safe'); + $objectVar = null; // optimize array calls if ( @@ -93,14 +95,27 @@ public function compile(Compiler $compiler): void ; } - $compiler->raw('CoreExtension::getAttribute($this->env, $this->source, '); - if ($this->getAttribute('ignore_strict_check')) { $this->getNode('node')->setAttribute('ignore_strict_check', true); } + if ($nullSafe) { + $objectVar = '$'.$compiler->getVarName(); + $compiler + ->raw('((null === ('.$objectVar.' = ') + ->subcompile($this->getNode('node')) + ->raw(')) ? null : '); + } + + $compiler->raw('CoreExtension::getAttribute($this->env, $this->source, '); + + if ($nullSafe) { + $compiler->raw($objectVar); + } else { + $compiler->subcompile($this->getNode('node')); + } + $compiler - ->subcompile($this->getNode('node')) ->raw(', ') ->subcompile($this->getNode('attribute')) ; @@ -123,14 +138,18 @@ public function compile(Compiler $compiler): void if ($arrayAccessSandbox) { $compiler->raw(')'); } + + if ($nullSafe) { + $compiler->raw(')'); + } } - private function changeIgnoreStrictCheck(GetAttrExpression $node): void + private function changeIgnoreStrictCheck(self $node): void { $node->setAttribute('optimizable', false); $node->setAttribute('ignore_strict_check', true); - if ($node->getNode('node') instanceof GetAttrExpression) { + if ($node->getNode('node') instanceof self) { $this->changeIgnoreStrictCheck($node->getNode('node')); } } diff --git a/lib/twig/twig/src/Node/Expression/Test/DefinedTest.php b/lib/twig/twig/src/Node/Expression/Test/DefinedTest.php index f17715bc61..d735029901 100644 --- a/lib/twig/twig/src/Node/Expression/Test/DefinedTest.php +++ b/lib/twig/twig/src/Node/Expression/Test/DefinedTest.php @@ -15,16 +15,8 @@ use Twig\Compiler; use Twig\Error\SyntaxError; use Twig\Node\Expression\AbstractExpression; -use Twig\Node\Expression\ArrayExpression; -use Twig\Node\Expression\BlockReferenceExpression; -use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Expression\FunctionExpression; -use Twig\Node\Expression\GetAttrExpression; -use Twig\Node\Expression\MacroReferenceExpression; -use Twig\Node\Expression\MethodCallExpression; use Twig\Node\Expression\SupportDefinedTestInterface; use Twig\Node\Expression\TestExpression; -use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; use Twig\TwigTest; diff --git a/lib/twig/twig/src/Node/TypesNode.php b/lib/twig/twig/src/Node/TypesNode.php index b5949848d1..a182880838 100644 --- a/lib/twig/twig/src/Node/TypesNode.php +++ b/lib/twig/twig/src/Node/TypesNode.php @@ -1,5 +1,14 @@ varNameSalt++); } + /** + * @throws SyntaxError + */ public function parse(TokenStream $stream, $test = null, bool $dropNeedle = false): ModuleNode { $vars = get_object_vars($this); @@ -158,6 +161,9 @@ public function subparseIgnoreUnknownTwigCallables($test, bool $dropNeedle = fal } } + /** + * @throws SyntaxError + */ public function subparse($test, bool $dropNeedle = false): Node { $lineno = $this->getCurrentToken()->getLine(); @@ -494,11 +500,26 @@ public function getTest(int $line): TwigTest // try 2-words tests $name = $name.' '.$this->getCurrentToken()->getValue(); - if ($test = $this->env->getTest($name)) { - $this->stream->next(); + try { + $test = $this->env->getTest($name); + } catch (SyntaxError $e) { + if (!$this->shouldIgnoreUnknownTwigCallables()) { + throw $e; + } + + $test = null; } + $this->stream->next(); } else { - $test = $this->env->getTest($name); + try { + $test = $this->env->getTest($name); + } catch (SyntaxError $e) { + if (!$this->shouldIgnoreUnknownTwigCallables()) { + throw $e; + } + + $test = null; + } } if (!$test) { diff --git a/lib/twig/twig/src/Resources/debug.php b/lib/twig/twig/src/Resources/debug.php index 104b4f4e0d..a0392ff513 100644 --- a/lib/twig/twig/src/Resources/debug.php +++ b/lib/twig/twig/src/Resources/debug.php @@ -1,9 +1,9 @@ + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/lib/twig/twig/src/Resources/string_loader.php b/lib/twig/twig/src/Resources/string_loader.php index 8f0e6492aa..c499e5ec2b 100644 --- a/lib/twig/twig/src/Resources/string_loader.php +++ b/lib/twig/twig/src/Resources/string_loader.php @@ -1,9 +1,9 @@ + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/lib/twig/twig/src/Runtime/EscaperRuntime.php b/lib/twig/twig/src/Runtime/EscaperRuntime.php index 17ed76cc95..f686e19f0c 100644 --- a/lib/twig/twig/src/Runtime/EscaperRuntime.php +++ b/lib/twig/twig/src/Runtime/EscaperRuntime.php @@ -17,7 +17,7 @@ final class EscaperRuntime implements RuntimeExtensionInterface { - /** @var array */ + /** @var array */ private $escapers = []; /** @internal */ @@ -140,6 +140,10 @@ public function escape($string, string $strategy = 'html', ?string $charset = nu case 'html': // see https://www.php.net/htmlspecialchars + if ('UTF-8' === $charset) { + return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8'); + } + // Using a static variable to avoid initializing the array // each time the function is called. Moving the declaration on the // top of the function slow downs other escaping strategies. @@ -195,7 +199,7 @@ public function escape($string, string $strategy = 'html', ?string $charset = nu * Escape sequences supported only by JavaScript, not JSON, are omitted. * \" is also supported but omitted, because the resulting string is not HTML safe. */ - static $shortMap = [ + $short = match ($char) { '\\' => '\\\\', '/' => '\\/', "\x08" => '\b', @@ -203,10 +207,11 @@ public function escape($string, string $strategy = 'html', ?string $charset = nu "\x0A" => '\n', "\x0D" => '\r', "\x09" => '\t', - ]; + default => false, + }; - if (isset($shortMap[$char])) { - return $shortMap[$char]; + if ($short) { + return $short; } $codepoint = mb_ord($char, 'UTF-8'); @@ -267,7 +272,7 @@ public function escape($string, string $strategy = 'html', ?string $charset = nu * @license https://framework.zend.com/license/new-bsd New BSD License */ $chr = $matches[0]; - $ord = \ord($chr); + $ord = \ord($chr[0]); /* * The following replaces characters undefined in HTML with the @@ -288,18 +293,13 @@ public function escape($string, string $strategy = 'html', ?string $charset = nu * entities that XML supports. Using HTML entities would result in this error: * XML Parsing Error: undefined entity */ - static $entityMap = [ + return match ($ord) { 34 => '"', /* quotation mark */ 38 => '&', /* ampersand */ 60 => '<', /* less-than sign */ 62 => '>', /* greater-than sign */ - ]; - - if (isset($entityMap[$ord])) { - return $entityMap[$ord]; - } - - return \sprintf('&#x%02X;', $ord); + default => \sprintf('&#x%02X;', $ord), + }; } /* diff --git a/lib/twig/twig/src/Template.php b/lib/twig/twig/src/Template.php index faf7aee1e0..c372092874 100644 --- a/lib/twig/twig/src/Template.php +++ b/lib/twig/twig/src/Template.php @@ -270,7 +270,7 @@ public function getBlockNames(array $context, array $blocks = []): array /** * @param string|TemplateWrapper|array $template */ - protected function load(string|TemplateWrapper|array $template, int $line, int|null $index = null): self + protected function load(string|TemplateWrapper|array $template, int $line, ?int $index = null): self { try { if (\is_array($template)) { @@ -315,7 +315,7 @@ protected function load(string|TemplateWrapper|array $template, int $line, int|n * * @deprecated since Twig 3.21 and will be removed in 4.0. Use Template::load() instead. */ - protected function loadTemplate($template, $templateName = null, int|null $line = null, int|null $index = null): self|TemplateWrapper + protected function loadTemplate($template, $templateName = null, ?int $line = null, ?int $index = null): self|TemplateWrapper { trigger_deprecation('twig/twig', '3.21', 'The "%s" method is deprecated.', __METHOD__); diff --git a/lib/twig/twig/src/TokenParser/GuardTokenParser.php b/lib/twig/twig/src/TokenParser/GuardTokenParser.php index 656766af51..eb48865795 100644 --- a/lib/twig/twig/src/TokenParser/GuardTokenParser.php +++ b/lib/twig/twig/src/TokenParser/GuardTokenParser.php @@ -32,9 +32,15 @@ public function parse(Token $token): Node $method = 'get'.$typeToken->getValue(); $nameToken = $stream->expect(Token::NAME_TYPE); + $name = $nameToken->getValue(); + if ('test' === $typeToken->getValue() && $stream->test(Token::NAME_TYPE)) { + // try 2-words tests + $name .= ' '.$stream->getCurrent()->getValue(); + $stream->next(); + } try { - $exists = null !== $this->parser->getEnvironment()->$method($nameToken->getValue()); + $exists = null !== $this->parser->getEnvironment()->$method($name); } catch (SyntaxError) { $exists = false; }