diff --git a/composer.lock b/composer.lock index 5a6f85f40..be99d6b17 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 000000000..2b0707968 --- /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 000000000..fa7663748 --- /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 973dc980e..ecfd37d3b 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -1595,6 +1595,8 @@ return array( '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', @@ -1769,22 +1771,43 @@ return array( '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', @@ -1949,6 +1972,7 @@ return array( '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', @@ -2515,6 +2539,13 @@ return array( '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', @@ -2812,6 +2843,9 @@ return array( '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', @@ -2902,6 +2936,13 @@ return array( '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', @@ -3127,6 +3168,7 @@ return array( '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', @@ -3382,6 +3424,7 @@ return array( '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', @@ -3457,6 +3500,7 @@ return array( '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', @@ -3614,6 +3658,7 @@ return array( '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', @@ -3699,10 +3744,15 @@ return array( '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', @@ -3711,6 +3761,7 @@ return array( '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', @@ -3804,6 +3855,8 @@ return array( '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 11f99de31..2f30b308d 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -1981,6 +1981,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', @@ -2155,22 +2157,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', @@ -2335,6 +2358,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', @@ -2901,6 +2925,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', @@ -3198,6 +3229,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', @@ -3288,6 +3322,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', @@ -3513,6 +3554,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', @@ -3768,6 +3810,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', @@ -3843,6 +3886,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', @@ -4000,6 +4044,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', @@ -4085,10 +4130,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', @@ -4097,6 +4147,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', @@ -4190,6 +4241,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 a6a673415..f26be2736 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 458ae0d68..d05367ff1 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 7525fe039..bf04ae08c 100644 --- a/lib/symfony/cache/Adapter/AbstractAdapter.php +++ b/lib/symfony/cache/Adapter/AbstractAdapter.php @@ -40,7 +40,7 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg $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 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg $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 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg } $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 ef62b4fb2..a1af6141b 100644 --- a/lib/symfony/cache/Adapter/AbstractTagAwareAdapter.php +++ b/lib/symfony/cache/Adapter/AbstractTagAwareAdapter.php @@ -42,7 +42,7 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA $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 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA $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 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA } $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 2eddb49a7..50ce8448e 100644 --- a/lib/symfony/cache/Adapter/ApcuAdapter.php +++ b/lib/symfony/cache/Adapter/ApcuAdapter.php @@ -82,7 +82,7 @@ class ApcuAdapter extends AbstractAdapter 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 @@ class ApcuAdapter extends AbstractAdapter 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 660a52646..38e19cbdd 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 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter 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 221b1fb5d..1d187f65c 100644 --- a/lib/symfony/cache/Adapter/ChainAdapter.php +++ b/lib/symfony/cache/Adapter/ChainAdapter.php @@ -51,7 +51,7 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa 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 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa $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 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa $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 9d02be3aa..1866083b4 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 @@ class DoctrineDbalAdapter extends AbstractAdapter implements PruneableInterface 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 0efa152ee..9f983f0ad 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 @@ class MemcachedAdapter extends AbstractAdapter 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 a6896402f..483df1c0b 100644 --- a/lib/symfony/cache/Adapter/ParameterNormalizer.php +++ b/lib/symfony/cache/Adapter/ParameterNormalizer.php @@ -29,7 +29,7 @@ final class ParameterNormalizer 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 c79b73959..f5865993d 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 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface // - 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 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface $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 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface $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 0cda1cce8..6c3d70724 100644 --- a/lib/symfony/cache/Adapter/PhpArrayAdapter.php +++ b/lib/symfony/cache/Adapter/PhpArrayAdapter.php @@ -17,6 +17,7 @@ use Symfony\Component\Cache\CacheItem; 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 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte 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 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte 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 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte { 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 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte 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 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte 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 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte 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 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte { 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 @@ EOF; 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 @@ EOF; } $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 @@ EOF; 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 e550276df..70d089445 100644 --- a/lib/symfony/cache/Adapter/PhpFilesAdapter.php +++ b/lib/symfony/cache/Adapter/PhpFilesAdapter.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Cache\Adapter; 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 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface $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 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface if ($now >= $expiresAt) { unset($this->values[$id], $missingIds[$k], self::$valuesCache[$file]); } - } catch (\ErrorException $e) { + } catch (\ErrorException) { unset($missingIds[$k]); } } @@ -217,7 +220,7 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface 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 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface } $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 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface 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 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface } 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 c022dd5fa..562122606 100644 --- a/lib/symfony/cache/Adapter/ProxyAdapter.php +++ b/lib/symfony/cache/Adapter/ProxyAdapter.php @@ -73,7 +73,7 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa 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 a44ef986d..9aa959add 100644 --- a/lib/symfony/cache/Adapter/RedisTagAwareAdapter.php +++ b/lib/symfony/cache/Adapter/RedisTagAwareAdapter.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Cache\Adapter; 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 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter 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 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter { $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 @@ EOLUA; $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 539ef1697..a12e908ad 100644 --- a/lib/symfony/cache/Adapter/TagAwareAdapter.php +++ b/lib/symfony/cache/Adapter/TagAwareAdapter.php @@ -294,15 +294,12 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac $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 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac (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 8569fa283..1e9929541 100644 --- a/lib/symfony/cache/Adapter/TraceableAdapter.php +++ b/lib/symfony/cache/Adapter/TraceableAdapter.php @@ -38,7 +38,7 @@ class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInt 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 1a81706da..1aa5bcdce 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 @@ final class CacheItem implements ItemInterface } 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 @@ final class CacheItem implements ItemInterface 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 @@ final class CacheItem implements ItemInterface 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 @@ final class CacheItem implements ItemInterface 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 @@ final class CacheItem implements ItemInterface 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 b9bcdaf13..73886cb4d 100644 --- a/lib/symfony/cache/DataCollector/CacheDataCollector.php +++ b/lib/symfony/cache/DataCollector/CacheDataCollector.php @@ -38,15 +38,7 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter 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 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter 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 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter } } 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 f6622f27b..9d2273d90 100644 --- a/lib/symfony/cache/DependencyInjection/CachePoolPass.php +++ b/lib/symfony/cache/DependencyInjection/CachePoolPass.php @@ -16,7 +16,9 @@ use Symfony\Component\Cache\Adapter\ArrayAdapter; 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 @@ class CachePoolPass implements CompilerPassInterface '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 @@ class CachePoolPass implements CompilerPassInterface 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 @@ class CachePoolPass implements CompilerPassInterface $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 @@ class CachePoolPass implements CompilerPassInterface } 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 @@ class CachePoolPass implements CompilerPassInterface ), ]); $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 @@ class CachePoolPass implements CompilerPassInterface 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 @@ class CachePoolPass implements CompilerPassInterface $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 00e912686..870023141 100644 --- a/lib/symfony/cache/DependencyInjection/CachePoolPrunerPass.php +++ b/lib/symfony/cache/DependencyInjection/CachePoolPrunerPass.php @@ -15,7 +15,6 @@ use Symfony\Component\Cache\PruneableInterface; 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 @@ class CachePoolPrunerPass implements CompilerPassInterface $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 c5c5fde89..31ec51ced 100644 --- a/lib/symfony/cache/LockRegistry.php +++ b/lib/symfony/cache/LockRegistry.php @@ -83,7 +83,7 @@ final class LockRegistry 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 @@ final class LockRegistry $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 @@ final class LockRegistry // 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 8fe0f2515..5c8cf8d67 100644 --- a/lib/symfony/cache/Messenger/EarlyExpirationDispatcher.php +++ b/lib/symfony/cache/Messenger/EarlyExpirationDispatcher.php @@ -37,13 +37,13 @@ class EarlyExpirationDispatcher /** * @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 6056ebab4..99cca0499 100644 --- a/lib/symfony/cache/Messenger/EarlyExpirationMessage.php +++ b/lib/symfony/cache/Messenger/EarlyExpirationMessage.php @@ -35,6 +35,11 @@ final class EarlyExpirationMessage $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 f21384fee..01494d714 100644 --- a/lib/symfony/cache/Psr16Cache.php +++ b/lib/symfony/cache/Psr16Cache.php @@ -135,7 +135,7 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf 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 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf { $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 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf 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 4ab2537db..c5b5e4a91 100644 --- a/lib/symfony/cache/Traits/AbstractAdapterTrait.php +++ b/lib/symfony/cache/Traits/AbstractAdapterTrait.php @@ -276,15 +276,12 @@ trait AbstractAdapterTrait $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 @@ trait AbstractAdapterTrait 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 000000000..8e95f60b0 --- /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 8d830f0ab..c93256eba 100644 --- a/lib/symfony/cache/Traits/ContractsTrait.php +++ b/lib/symfony/cache/Traits/ContractsTrait.php @@ -54,7 +54,7 @@ trait ContractsTrait } $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 @@ trait ContractsTrait 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 @@ trait ContractsTrait $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 @@ trait ContractsTrait 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 3b976b66f..09e8e26fd 100644 --- a/lib/symfony/cache/Traits/FilesystemCommonTrait.php +++ b/lib/symfony/cache/Traits/FilesystemCommonTrait.php @@ -32,7 +32,7 @@ trait FilesystemCommonTrait } 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 @@ trait FilesystemCommonTrait $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 @@ trait FilesystemCommonTrait } } - 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 47e9b838f..05fa10e96 100644 --- a/lib/symfony/cache/Traits/FilesystemTrait.php +++ b/lib/symfony/cache/Traits/FilesystemTrait.php @@ -92,7 +92,7 @@ trait FilesystemTrait } 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 34f60cb10..0ec7b5762 100644 --- a/lib/symfony/cache/Traits/Redis6ProxyTrait.php +++ b/lib/symfony/cache/Traits/Redis61ProxyTrait.php @@ -15,7 +15,7 @@ if (version_compare(phpversion('redis'), '6.1.0-dev', '>=')) { /** * @internal */ - trait Redis6ProxyTrait + trait Redis61ProxyTrait { public function dump($key): \Redis|string|false { @@ -51,7 +51,7 @@ if (version_compare(phpversion('redis'), '6.1.0-dev', '>=')) { /** * @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 000000000..4ea807220 --- /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 000000000..6f6b37017 --- /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 c841d4269..e321fee62 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 9c3169e32..9ff5b19da 100644 --- a/lib/symfony/cache/Traits/RedisCluster6ProxyTrait.php +++ b/lib/symfony/cache/Traits/RedisCluster61ProxyTrait.php @@ -15,7 +15,7 @@ if (version_compare(phpversion('redis'), '6.1.0-dev', '>')) { /** * @internal */ - trait RedisCluster6ProxyTrait + trait RedisCluster61ProxyTrait { public function getex($key, $options = []): \RedisCluster|string|false { @@ -36,7 +36,7 @@ if (version_compare(phpversion('redis'), '6.1.0-dev', '>')) { /** * @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 000000000..e8f864a05 --- /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 000000000..374f96214 --- /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 c19aa1620..1ea025dd0 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 2a1fa3921..c3fc68990 100644 --- a/lib/symfony/cache/Traits/RedisTrait.php +++ b/lib/symfony/cache/Traits/RedisTrait.php @@ -17,6 +17,7 @@ use Predis\Connection\Aggregate\RedisCluster; 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 @@ trait RedisTrait 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 @@ trait RedisTrait 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 @@ trait RedisTrait } $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 @@ trait RedisTrait }; 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 @@ trait RedisTrait 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 @@ trait RedisTrait } 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 @@ trait RedisTrait } 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 @@ trait RedisTrait } 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 @@ trait RedisTrait } } - 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 @@ trait RedisTrait 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'])) - ) { - $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']); } + + 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.'.'); + } + } catch (\RedisException|\Relay\Exception $e) { throw new InvalidArgumentException('Redis connection failed: '.$e->getMessage()); } @@ -388,14 +388,12 @@ trait RedisTrait 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 @@ trait RedisTrait $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 @@ trait RedisTrait $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 @@ trait RedisTrait $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 @@ trait RedisTrait $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 000000000..367f82f7b --- /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 000000000..a271a9d10 --- /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 000000000..1abf0455b --- /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 000000000..88ed1e9d3 --- /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 000000000..d0643c339 --- /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 000000000..4522d20b5 --- /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 000000000..a7cb8fff0 --- /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 000000000..8055e2e92 --- /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 000000000..358e52f61 --- /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 000000000..0b7409045 --- /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 000000000..340db8af7 --- /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 000000000..289d8faa0 --- /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 000000000..da222ba8f --- /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 000000000..26df3211f --- /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 000000000..b062ca9a6 --- /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 000000000..8ae0a079d --- /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 96d7d19b4..8933e93ac 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 @@ class RelayProxy extends \Relay\Relay implements ResetInterface, LazyObjectInter 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 a1d252b96..c35b5fa01 100644 --- a/lib/symfony/cache/Traits/RelayProxyTrait.php +++ b/lib/symfony/cache/Traits/RelayProxyTrait.php @@ -17,11 +17,6 @@ if (version_compare(phpversion('relay'), '0.8.1', '>=')) { */ 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 @@ if (version_compare(phpversion('relay'), '0.8.1', '>=')) { */ 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 ec0e12ab6..e4938352c 100644 --- a/lib/symfony/config/Definition/Builder/ArrayNodeDefinition.php +++ b/lib/symfony/config/Definition/Builder/ArrayNodeDefinition.php @@ -331,7 +331,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition 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 0813ab1e5..7840ef409 100644 --- a/lib/symfony/config/Definition/Dumper/YamlReferenceDumper.php +++ b/lib/symfony/config/Definition/Dumper/YamlReferenceDumper.php @@ -249,6 +249,6 @@ class YamlReferenceDumper } $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 aa9177d29..49a6074da 100644 --- a/lib/symfony/config/Resource/ClassExistenceResource.php +++ b/lib/symfony/config/Resource/ClassExistenceResource.php @@ -101,23 +101,23 @@ class ClassExistenceResource implements SelfCheckingResourceInterface 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 3e381a411..f00e1c8b9 100644 --- a/lib/symfony/config/Resource/GlobResource.php +++ b/lib/symfony/config/Resource/GlobResource.php @@ -77,21 +77,28 @@ class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface 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 @@ class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface 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 cfd96135d..8b7bfba82 100644 --- a/lib/symfony/config/Resource/ReflectionClassResource.php +++ b/lib/symfony/config/Resource/ReflectionClassResource.php @@ -60,17 +60,19 @@ class ReflectionClassResource implements SelfCheckingResourceInterface 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 c18d482b4..f61761df5 100644 --- a/lib/symfony/console/Application.php +++ b/lib/symfony/console/Application.php @@ -403,6 +403,15 @@ class Application implements ResetInterface 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 @@ class Application implements ResetInterface $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 @@ class Application implements ResetInterface } } - $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 @@ class Application implements ResetInterface } } + $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 @@ class Application implements ResetInterface } 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 @@ class Application implements ResetInterface 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 593b01b39..d652a05ef 100644 --- a/lib/symfony/console/Helper/QuestionHelper.php +++ b/lib/symfony/console/Helper/QuestionHelper.php @@ -258,11 +258,7 @@ class QuestionHelper extends Helper $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 @@ class QuestionHelper extends Helper // 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 @@ class QuestionHelper extends Helper $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 @@ class QuestionHelper extends Helper 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 @@ class QuestionHelper extends Helper 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 @@ class QuestionHelper extends Helper { if (!$question->isMultiline()) { $cp = $this->setIOCodepage(); - $ret = fgets($inputStream, 4096); + $ret = $this->doReadInput($inputStream); return $this->resetIOCodepage($cp, $ret); } @@ -524,14 +516,8 @@ class QuestionHelper extends Helper 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 @@ class QuestionHelper extends Helper 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 11b4e4238..634550d3c 100644 --- a/lib/symfony/console/Helper/SymfonyQuestionHelper.php +++ b/lib/symfony/console/Helper/SymfonyQuestionHelper.php @@ -34,7 +34,7 @@ class SymfonyQuestionHelper extends QuestionHelper $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 @@ class SymfonyQuestionHelper extends QuestionHelper 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 be956c109..b0c94deb7 100644 --- a/lib/symfony/console/Helper/TableStyle.php +++ b/lib/symfony/console/Helper/TableStyle.php @@ -77,10 +77,11 @@ class TableStyle * * * ╔═══════════════╤══════════════════════════╤══════════════════╗ - * 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 @@ class TableStyle * * * ╔═══════════════╤══════════════════════════╤══════════════════╗ - * ║ 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 000000000..d6f07db8b --- /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 a33092aee..b5f866689 100644 --- a/lib/symfony/console/Input/ArgvInput.php +++ b/lib/symfony/console/Input/ArgvInput.php @@ -176,7 +176,7 @@ class ArgvInput extends Input } 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 9445ccc0c..bcfe4dc45 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 @@ class ChoiceQuestion extends Question } /** - * 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 64c6a338f..2befe76cb 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 ef2e5f04e..ac8851b06 100644 --- a/lib/symfony/console/SignalRegistry/SignalRegistry.php +++ b/lib/symfony/console/SignalRegistry/SignalRegistry.php @@ -13,8 +13,21 @@ namespace Symfony\Component\Console\SignalRegistry; 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 @@ final class SignalRegistry 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 (\is_callable($previousCallback)) { - $this->signalHandlers[$signal][] = $previousCallback; + if (!isset($this->originalHandlers[$signal])) { + $this->originalHandlers[$signal] = $previous; + } + + 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 @@ final class SignalRegistry $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 127556d1d..238c7b7eb 100644 --- a/lib/symfony/console/Tester/TesterTrait.php +++ b/lib/symfony/console/Tester/TesterTrait.php @@ -168,10 +168,10 @@ trait TesterTrait $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 874092657..c2d6c56c5 100644 --- a/lib/symfony/dependency-injection/Attribute/Autowire.php +++ b/lib/symfony/dependency-injection/Attribute/Autowire.php @@ -52,7 +52,7 @@ class Autowire 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 4fea73217..ea1986ce9 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 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass $this->lazy = false; $this->byConstructor = false; $this->byFactory = false; + $this->byMultiUseArgument = false; $this->definitions = $container->getDefinitions(); $this->aliases = $container->getAliases(); @@ -89,7 +91,12 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass 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 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass $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 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass $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 90ef09889..0d185ac52 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 996526240..b783a21f3 100644 --- a/lib/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php +++ b/lib/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php @@ -79,7 +79,7 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass 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 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass 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 204401cd2..251f26ef2 100644 --- a/lib/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php +++ b/lib/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php @@ -69,9 +69,9 @@ class DefinitionErrorExceptionPass extends AbstractRecursivePass 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 @@ class DefinitionErrorExceptionPass extends AbstractRecursivePass 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 9b75fea39..0909cf3f9 100644 --- a/lib/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php +++ b/lib/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php @@ -146,7 +146,7 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass $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 677f2f610..369ff47a9 100644 --- a/lib/symfony/dependency-injection/Compiler/PassConfig.php +++ b/lib/symfony/dependency-injection/Compiler/PassConfig.php @@ -97,7 +97,8 @@ class PassConfig 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 72df1efb1..c2cf2903c 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 @@ class RemoveBuildParametersPass implements CompilerPassInterface $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 3a0d07bbe..d6377bb9b 100644 --- a/lib/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php +++ b/lib/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php @@ -41,7 +41,15 @@ class ReplaceAliasByActualDefinitionPass extends AbstractRecursivePass $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 404709585..9fa617822 100644 --- a/lib/symfony/dependency-injection/Compiler/ResolveBindingsPass.php +++ b/lib/symfony/dependency-injection/Compiler/ResolveBindingsPass.php @@ -121,10 +121,10 @@ class ResolveBindingsPass extends AbstractRecursivePass 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 @@ class ResolveBindingsPass extends AbstractRecursivePass { [$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 761f4067b..23d711ca5 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 705bb837b..59d87b394 100644 --- a/lib/symfony/dependency-injection/Compiler/ResolveHotPathPass.php +++ b/lib/symfony/dependency-injection/Compiler/ResolveHotPathPass.php @@ -51,7 +51,7 @@ class ResolveHotPathPass extends AbstractRecursivePass 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 16d0e9fcb..015db9d1c 100644 --- a/lib/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php +++ b/lib/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php @@ -36,7 +36,11 @@ class ResolveReferencesToAliasesPass extends AbstractRecursivePass $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 2544cde95..97f9398e1 100644 --- a/lib/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php +++ b/lib/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php @@ -74,7 +74,7 @@ class ServiceReferenceGraph /** * 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 @@ class ServiceReferenceGraph $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 b607164a6..1fad56666 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 @@ class ServiceReferenceGraphEdge $this->lazy = $lazy; $this->weak = $weak; $this->byConstructor = $byConstructor; + $this->byMultiUseArgument = $byMultiUseArgument; } /** @@ -84,4 +86,9 @@ class ServiceReferenceGraphEdge { 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 fdbd290ba..bca435631 100644 --- a/lib/symfony/dependency-injection/ContainerBuilder.php +++ b/lib/symfony/dependency-injection/ContainerBuilder.php @@ -207,7 +207,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface $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 b897cb2fc..d55a5a100 100644 --- a/lib/symfony/dependency-injection/Dumper/PhpDumper.php +++ b/lib/symfony/dependency-injection/Dumper/PhpDumper.php @@ -458,7 +458,7 @@ EOF; 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 @@ EOF; $asGhostObject = false; $isProxyCandidate = $this->isProxyCandidate($definition, $asGhostObject, $id); - $instantiation = ''; $lastWitherIndex = null; foreach ($definition->getMethodCalls() as $k => $call) { @@ -708,20 +707,26 @@ EOF; } } - 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 ', + }; + + $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 = ''; - if ($isSimpleInstance) { - $return = 'return '; - } else { - $instantiation .= ' = '; - } - - return $this->addNewInstance($definition, ' '.$return.$instantiation, $id, $asGhostObject); + return $code; } private function isTrivialInstance(Definition $definition): bool @@ -1055,7 +1060,7 @@ EOTXT $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 @@ EOTXT || ($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 @@ EOF; 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 @@ EOF; $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 @@ EOF; 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 07fae9871..b5bf0b22c 100644 --- a/lib/symfony/dependency-injection/EnvVarProcessor.php +++ b/lib/symfony/dependency-injection/EnvVarProcessor.php @@ -325,7 +325,7 @@ class EnvVarProcessor implements EnvVarProcessorInterface } 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 5be4a2672..d96eacb6d 100644 --- a/lib/symfony/dependency-injection/Loader/Configurator/AbstractConfigurator.php +++ b/lib/symfony/dependency-injection/Loader/Configurator/AbstractConfigurator.php @@ -46,15 +46,12 @@ abstract class AbstractConfigurator 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 0a54c4344..1b6cd6c2c 100644 --- a/lib/symfony/dependency-injection/Loader/FileLoader.php +++ b/lib/symfony/dependency-injection/Loader/FileLoader.php @@ -166,12 +166,12 @@ abstract class FileLoader extends BaseFileLoader $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 f01cf39d7..fb6cc81f7 100644 --- a/lib/symfony/dependency-injection/Loader/PhpFileLoader.php +++ b/lib/symfony/dependency-injection/Loader/PhpFileLoader.php @@ -57,6 +57,9 @@ class PhpFileLoader extends FileLoader return include $path; }, $this, ProtectedPhpFileLoader::class); + $instanceof = $this->instanceof; + $this->instanceof = []; + try { $callback = $load($path, $this->env); @@ -64,7 +67,7 @@ class PhpFileLoader extends FileLoader $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 49495b706..815c8e422 100644 --- a/lib/symfony/dotenv/Command/DotenvDumpCommand.php +++ b/lib/symfony/dotenv/Command/DotenvDumpCommand.php @@ -23,7 +23,13 @@ use Symfony\Component\Dotenv\Dotenv; /** * 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 3fc741e3e..ddd0863f8 100644 --- a/lib/symfony/error-handler/BufferingLogger.php +++ b/lib/symfony/error-handler/BufferingLogger.php @@ -35,15 +35,12 @@ class BufferingLogger extends AbstractLogger 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 977334551..078f8af56 100644 --- a/lib/symfony/error-handler/DebugClassLoader.php +++ b/lib/symfony/error-handler/DebugClassLoader.php @@ -1216,7 +1216,7 @@ EOTXT; $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 ca793b075..48f3a0a9d 100644 --- a/lib/symfony/error-handler/ErrorRenderer/FileLinkFormatter.php +++ b/lib/symfony/error-handler/ErrorRenderer/FileLinkFormatter.php @@ -67,14 +67,11 @@ class FileLinkFormatter 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 51d2b48e7..83e5d2a8b 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 @@ class Finder implements \IteratorAggregate, \Countable */ 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; - } + 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); + } - $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); + yield $key => $file; + } + }))); + } } if ($this->sort || $this->reverseSorting) { @@ -701,26 +709,13 @@ class Finder implements \IteratorAggregate, \Countable * * 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 7fe8b1a86..d950e48fc 100644 --- a/lib/symfony/finder/Glob.php +++ b/lib/symfony/finder/Glob.php @@ -44,6 +44,9 @@ class Glob $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 @@ class Glob $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 3f1ab79c2..e81155b46 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 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface, Re // 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 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface, Re // 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 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface, Re // 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 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface, Re // 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 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface, Re // 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 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface, Re $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 5a0714791..d83ea3ece 100644 --- a/lib/symfony/form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php +++ b/lib/symfony/form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php @@ -24,6 +24,15 @@ use Symfony\Component\Form\Exception\UnexpectedTypeException; */ 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 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer throw new TransformationFailedException(intl_get_error_message()); } - return $value; + return self::normalizeWhitespace($value); } /** @@ -112,11 +121,7 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer $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 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer // 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 6e9db3e09..2d71f7bce 100644 --- a/lib/symfony/form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/lib/symfony/form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -177,7 +177,7 @@ class NumberToLocalizedStringTransformer implements DataTransformerInterface */ 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 bfede9c04..106cb341d 100644 --- a/lib/symfony/form/Extension/Core/Type/EnumType.php +++ b/lib/symfony/form/Extension/Core/Type/EnumType.php @@ -30,7 +30,17 @@ final class EnumType extends AbstractType ->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 9c9e5b4d7..f4909e23b 100644 --- a/lib/symfony/form/Extension/Core/Type/MoneyType.php +++ b/lib/symfony/form/Extension/Core/Type/MoneyType.php @@ -51,6 +51,12 @@ class MoneyType extends AbstractType 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 40e7580d8..3c485b83a 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 @@ class TextareaType extends AbstractType { 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 beabdd03c..3c0f4e217 100644 --- a/lib/symfony/form/FormBuilder.php +++ b/lib/symfony/form/FormBuilder.php @@ -26,192 +26,192 @@ use Symfony\Component\Form\Extension\Core\Type\TextType; */ 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 = []; + /** + * 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); + public function __construct(?string $name, ?string $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory, array $options = []) + { + parent::__construct($name, $dataClass, $dispatcher, $options); - $this->setFormFactory($factory); - } + $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.'); - } + 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; + if ($child instanceof FormBuilderInterface) { + $this->children[$child->getName()] = $child; - // In case an unresolved child with the same name exists - unset($this->unresolvedChildren[$child->getName()]); + // In case an unresolved child with the same name exists + unset($this->unresolvedChildren[$child->getName()]); - return $this; - } + return $this; + } - if (!\is_string($child) && !\is_int($child)) { - throw new UnexpectedTypeException($child, 'string or Symfony\Component\Form\FormBuilderInterface'); - } + 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); - } + if (null !== $type) { + return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options); + } - return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, 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.'); - } + 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->unresolvedChildren[$name])) { + return $this->resolveChild($name); + } - if (isset($this->children[$name])) { - return $this->children[$name]; - } + if (isset($this->children[$name])) { + return $this->children[$name]; + } - throw new InvalidArgumentException(\sprintf('The child with the name "%s" does not exist.', $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.'); - } + 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]); + unset($this->unresolvedChildren[$name], $this->children[$name]); - return $this; - } + 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.'); - } + 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]); - } + 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.'); - } + 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(); + $this->resolveChildren(); - return $this->children; - } + 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.'); - } + 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); - } + return \count($this->children); + } - public function getFormConfig(): FormConfigInterface - { - /** @var self $config */ - $config = parent::getFormConfig(); + public function getFormConfig(): FormConfigInterface + { + /** @var self $config */ + $config = parent::getFormConfig(); - $config->children = []; - $config->unresolvedChildren = []; + $config->children = []; + $config->unresolvedChildren = []; - return $config; - } + 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.'); - } + 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(); + $this->resolveChildren(); - $form = new Form($this->getFormConfig()); + $form = new Form($this->getFormConfig()); - foreach ($this->children as $child) { - // Automatic initialization is only supported on root forms - $form->add($child->setAutoInitialize(false)->getForm()); - } + 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(); - } + if ($this->getAutoInitialize()) { + // Automatically initialize the form if it is configured so + $form->initialize(); + } - return $form; - } + 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 \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()); - } + 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]; + /** + * Converts an unresolved child into a {@link FormBuilderInterface} instance. + */ + private function resolveChild(string $name): FormBuilderInterface + { + [$type, $options] = $this->unresolvedChildren[$name]; - unset($this->unresolvedChildren[$name]); + unset($this->unresolvedChildren[$name]); - return $this->children[$name] = $this->create($name, $type, $options); - } + 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]); - } + /** + * 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 = []; - } + $this->unresolvedChildren = []; + } } diff --git a/lib/symfony/form/Resources/translations/validators.nb.xlf b/lib/symfony/form/Resources/translations/validators.nb.xlf index 193306b71..0dd82d3f3 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 193306b71..0dd82d3f3 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 f92be10a4..a6409b734 100644 --- a/lib/symfony/form/Util/OrderedHashMap.php +++ b/lib/symfony/form/Util/OrderedHashMap.php @@ -120,16 +120,11 @@ class OrderedHashMap implements \ArrayAccess, \IteratorAggregate, \Countable 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 45a50c1ad..2a12ac83c 100644 --- a/lib/symfony/form/Util/StringUtil.php +++ b/lib/symfony/form/Util/StringUtil.php @@ -36,6 +36,14 @@ class StringUtil 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 949aad31c..639fe721d 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 208e8123c..ff90a9dba 100644 --- a/lib/symfony/framework-bundle/Command/CachePoolPruneCommand.php +++ b/lib/symfony/framework-bundle/Command/CachePoolPruneCommand.php @@ -53,14 +53,21 @@ EOF 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 fb79b39bf..fcef7c1d6 100644 --- a/lib/symfony/framework-bundle/Command/ConfigDebugCommand.php +++ b/lib/symfony/framework-bundle/Command/ConfigDebugCommand.php @@ -161,7 +161,7 @@ EOF $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 46e0baffc..0eba8956c 100644 --- a/lib/symfony/framework-bundle/Command/SecretsEncryptFromLocalCommand.php +++ b/lib/symfony/framework-bundle/Command/SecretsEncryptFromLocalCommand.php @@ -61,14 +61,13 @@ EOF } 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 a5ab48b59..b47449816 100644 --- a/lib/symfony/framework-bundle/Controller/AbstractController.php +++ b/lib/symfony/framework-bundle/Controller/AbstractController.php @@ -157,6 +157,10 @@ abstract class AbstractController implements ServiceSubscriberInterface 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 6e7669a71..428137ff8 100644 --- a/lib/symfony/framework-bundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php +++ b/lib/symfony/framework-bundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php @@ -34,7 +34,10 @@ class TestServiceContainerWeakRefPass implements CompilerPassInterface $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 78ed8b3ac..7fe754e3d 100644 --- a/lib/symfony/framework-bundle/DependencyInjection/Configuration.php +++ b/lib/symfony/framework-bundle/DependencyInjection/Configuration.php @@ -358,7 +358,7 @@ class Configuration implements ConfigurationInterface ->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 @@ class Configuration implements ConfigurationInterface $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 @@ class Configuration implements ConfigurationInterface 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 @@ class Configuration implements ConfigurationInterface ->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 @@ class Configuration implements ConfigurationInterface ->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 @@ class Configuration implements ConfigurationInterface ->end() ->end() ->arrayNode('to') + ->performNoDeepMerging() ->beforeNormalization() ->ifString() ->then(fn ($v) => [$v]) @@ -1866,6 +1857,7 @@ class Configuration implements ConfigurationInterface ->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 @@ class Configuration implements ConfigurationInterface ->end() ->arrayNode('extra') ->info('Extra options for specific HTTP client') + ->useAttributeAsKey('name') ->normalizeKeys(false) ->variablePrototype()->end() ->end() @@ -2097,6 +2090,7 @@ class Configuration implements ConfigurationInterface ->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 2071c13c3..a8ef96b65 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\Encoder\EncoderInterface; 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 @@ class FrameworkExtension extends Extension $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 @@ class FrameworkExtension extends Extension $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 @@ class FrameworkExtension extends Extension } 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 @@ class FrameworkExtension extends Extension 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 @@ class FrameworkExtension extends Extension 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 bcf3a4f9e..4a650af6b 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 c64b0e25f..5c337b730 100644 --- a/lib/symfony/framework-bundle/Test/KernelTestCase.php +++ b/lib/symfony/framework-bundle/Test/KernelTestCase.php @@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase; 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 @@ abstract class KernelTestCase extends TestCase 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 @@ abstract class KernelTestCase extends TestCase 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 @@ abstract class KernelTestCase extends TestCase 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 77135fa06..288fd76e8 100644 --- a/lib/symfony/framework-bundle/Test/TestContainer.php +++ b/lib/symfony/framework-bundle/Test/TestContainer.php @@ -71,15 +71,11 @@ class TestContainer extends Container $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 853c000e0..e735c7564 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 @@ class AcceptHeader */ 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); + $items[] = $item->setIndex($i); + } - $item = new AcceptHeaderItem($part[0], $attributes); - $item->setIndex($index++); - - return $item; - }, $parts)); + return new self($items); } /** @@ -73,7 +70,9 @@ class AcceptHeader */ 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 @@ class AcceptHeader */ 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 @@ class AcceptHeader */ 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 @@ class AcceptHeader */ 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 @@ class AcceptHeader private function sort(): void { if (!$this->sorted) { - uasort($this->items, function (AcceptHeaderItem $a, AcceptHeaderItem $b) { - $qA = $a->getQuality(); - $qB = $b->getQuality(); - - if ($qA === $qB) { - return $a->getIndex() > $b->getIndex() ? 1 : -1; - } - - return $qA > $qB ? -1 : 1; - }); + uasort($this->items, static fn ($a, $b) => $b->getQuality() <=> $a->getQuality() ?: $a->getIndex() <=> $b->getIndex()); $this->sorted = true; } } + + /** + * Generates the canonical key for storing/retrieving an item. + */ + private function getCanonicalKey(AcceptHeaderItem $item): string + { + $parts = []; + + // 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 a66312c8e..8a497a77c 100644 --- a/lib/symfony/http-foundation/Request.php +++ b/lib/symfony/http-foundation/Request.php @@ -857,7 +857,7 @@ class Request * * 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 48c219a7a..8d757f03f 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 @@ class PdoSessionHandler extends AbstractSessionHandler $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 @@ class PdoSessionHandler extends AbstractSessionHandler // - 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 @@ class PdoSessionHandler extends AbstractSessionHandler 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 @@ class PdoSessionHandler extends AbstractSessionHandler 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 @@ class PdoSessionHandler extends AbstractSessionHandler $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 43a9eb84e..e41d03539 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 @@ class SessionHandlerFactory 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 996eacf06..0fb42944f 100644 --- a/lib/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php +++ b/lib/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php @@ -168,6 +168,10 @@ class RequestPayloadValueResolver implements ValueResolverInterface, EventSubscr 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 @@ class RequestPayloadValueResolver implements ValueResolverInterface, EventSubscr 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 2300acf91..8c45b4279 100644 --- a/lib/symfony/http-kernel/DataCollector/DumpDataCollector.php +++ b/lib/symfony/http-kernel/DataCollector/DumpDataCollector.php @@ -143,10 +143,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface $this->clonesIndex = 0; } - /** - * @internal - */ - public function __sleep(): array + public function __serialize(): array { if (!$this->dataCount) { $this->data = []; @@ -161,16 +158,12 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface $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 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface } } - 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 723e758cd..310e7f25a 100644 --- a/lib/symfony/http-kernel/EventListener/CacheAttributeListener.php +++ b/lib/symfony/http-kernel/EventListener/CacheAttributeListener.php @@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel\EventListener; 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 @@ class CacheAttributeListener implements EventSubscriberInterface 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 @@ class CacheAttributeListener implements EventSubscriberInterface $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 @@ class CacheAttributeListener implements EventSubscriberInterface } } + $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 473537d85..4eba39337 100644 --- a/lib/symfony/http-kernel/HttpCache/Store.php +++ b/lib/symfony/http-kernel/HttpCache/Store.php @@ -211,13 +211,9 @@ class Store implements StoreInterface // 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 @@ class Store implements StoreInterface */ 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 a04739505..a2bf0f827 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 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl $this->container = null; $this->requestStackSize = 0; $this->resetServices = false; + $this->handlingHttpCache = false; } /** @@ -108,7 +110,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ 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 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl return; } - if (null === $this->container) { + if (!$this->container) { $this->preBoot(); } @@ -149,7 +151,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ public function terminate(Request $request, Response $response) { - if (false === $this->booted) { + if (!$this->booted) { return; } @@ -163,7 +165,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ public function shutdown() { - if (false === $this->booted) { + if (!$this->booted) { return; } @@ -181,17 +183,26 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl 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 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl { 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 ee37516e1..2570e3fc2 100644 --- a/lib/symfony/mailer/Transport/Smtp/SmtpTransport.php +++ b/lib/symfony/mailer/Transport/Smtp/SmtpTransport.php @@ -154,18 +154,7 @@ class SmtpTransport extends AbstractTransport 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 @@ class SmtpTransport extends AbstractTransport $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 8183c7899..c5a65641b 100644 --- a/lib/symfony/mime/Email.php +++ b/lib/symfony/mime/Email.php @@ -507,7 +507,7 @@ class Email extends Message } 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 777a6a96c..c425b6759 100644 --- a/lib/symfony/mime/Encoder/QpContentEncoder.php +++ b/lib/symfony/mime/Encoder/QpContentEncoder.php @@ -46,9 +46,9 @@ final class QpContentEncoder implements ContentEncoderInterface // 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 160dde329..76ec445a3 100644 --- a/lib/symfony/mime/Encoder/QpEncoder.php +++ b/lib/symfony/mime/Encoder/QpEncoder.php @@ -183,9 +183,9 @@ class QpEncoder implements EncoderInterface { $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 19628b0b1..fd9881b72 100644 --- a/lib/symfony/mime/MimeTypes.php +++ b/lib/symfony/mime/MimeTypes.php @@ -135,7 +135,7 @@ final class MimeTypes implements MimeTypesInterface /** * 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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 @@ final class MimeTypes implements MimeTypesInterface '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 9d30544ae..704211e46 100644 --- a/lib/symfony/mime/Part/MessagePart.php +++ b/lib/symfony/mime/Part/MessagePart.php @@ -60,13 +60,15 @@ class MessagePart extends DataPart 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 b707d458e..6811a7b25 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 @@ $exts = [ '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 da7553cfb..3a232a380 100644 --- a/lib/symfony/options-resolver/OptionsResolver.php +++ b/lib/symfony/options-resolver/OptionsResolver.php @@ -803,7 +803,7 @@ class OptionsResolver implements Options 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 @@ class OptionsResolver implements Options $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 ce7710cfe..4d51197e2 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 e1b42eec5..2907b6b51 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 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property 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 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property 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 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property 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 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property } /** - * @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 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property $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 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property 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 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property } } - 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 d79a6a10a..93a306d33 100644 --- a/lib/symfony/property-info/Extractor/PhpStanExtractor.php +++ b/lib/symfony/property-info/Extractor/PhpStanExtractor.php @@ -154,7 +154,7 @@ final class PhpStanExtractor implements PropertyTypeExtractorInterface, Construc 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 @@ final class PhpStanExtractor implements PropertyTypeExtractorInterface, Construc { $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 @@ final class PhpStanExtractor implements PropertyTypeExtractorInterface, Construc } } - 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 6311c55fd..e59a9ac40 100644 --- a/lib/symfony/property-info/Extractor/ReflectionExtractor.php +++ b/lib/symfony/property-info/Extractor/ReflectionExtractor.php @@ -261,17 +261,13 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp 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 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp } 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 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp $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 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp $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 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp $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 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp */ private function camelize(string $string): string { + if ('' === ltrim($string, '_')) { + return $string; + } + return str_replace(' ', '', ucwords(str_replace('_', ' ', $string))); } @@ -804,7 +834,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp 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 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp 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 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp 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 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp 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 686ea0013..a4d171ef0 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\Compound; 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 @@ final class PhpDocTypeHelper $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 @@ final class PhpDocTypeHelper { $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,14 +166,6 @@ final class PhpDocTypeHelper return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, $collectionKeyTypes, $collectionValueTypes); } - 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); - } - } - $docType = $this->normalizeType($docType); [$phpType, $class] = $this->getPhpTypeAndClass($docType); @@ -167,6 +173,21 @@ final class PhpDocTypeHelper 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; + } + } + return new Type($phpType, $nullable, $class); } diff --git a/lib/symfony/property-info/composer.json b/lib/symfony/property-info/composer.json index 495b51dc5..b2e571ef1 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 fdb659cab..fe4cab4a2 100644 --- a/lib/symfony/routing/Loader/Configurator/CollectionConfigurator.php +++ b/lib/symfony/routing/Loader/Configurator/CollectionConfigurator.php @@ -38,15 +38,12 @@ class CollectionConfigurator $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 9c92a7d72..ad0c6d131 100644 --- a/lib/symfony/routing/Loader/Configurator/ImportConfigurator.php +++ b/lib/symfony/routing/Loader/Configurator/ImportConfigurator.php @@ -30,15 +30,12 @@ class ImportConfigurator $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 9777c6490..9f2284c5c 100644 --- a/lib/symfony/routing/Loader/Configurator/Traits/PrefixTrait.php +++ b/lib/symfony/routing/Loader/Configurator/Traits/PrefixTrait.php @@ -27,10 +27,17 @@ trait PrefixTrait 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 @@ trait PrefixTrait $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 9deb01256..f71264ce9 100644 --- a/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php +++ b/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php @@ -222,7 +222,12 @@ EOF; 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 db754e6de..5177c269a 100644 --- a/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php +++ b/lib/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php @@ -57,7 +57,7 @@ trait CompiledUrlMatcherTrait } 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 @@ trait CompiledUrlMatcherTrait 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 8d1ad4f90..3e7b78b5e 100644 --- a/lib/symfony/routing/Matcher/RedirectableUrlMatcher.php +++ b/lib/symfony/routing/Matcher/RedirectableUrlMatcher.php @@ -41,7 +41,7 @@ abstract class RedirectableUrlMatcher extends UrlMatcher implements Redirectable } 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 20fb06468..8ff018309 100644 --- a/lib/symfony/routing/Matcher/TraceableUrlMatcher.php +++ b/lib/symfony/routing/Matcher/TraceableUrlMatcher.php @@ -63,7 +63,7 @@ class TraceableUrlMatcher extends UrlMatcher $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 ec281fde7..f3ab414f0 100644 --- a/lib/symfony/routing/Matcher/UrlMatcher.php +++ b/lib/symfony/routing/Matcher/UrlMatcher.php @@ -78,8 +78,9 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface 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 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface $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 70798e542..e34dcb75e 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 7032b3e1a..a253bc56d 100644 --- a/lib/symfony/routing/RouteCollection.php +++ b/lib/symfony/routing/RouteCollection.php @@ -239,7 +239,13 @@ class RouteCollection implements \IteratorAggregate, \Countable } 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 564f0eee9..1f338806a 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 7df4a1934..8e74dec18 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 49f48dbed..f868a2e2d 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 181ef2444..6ff4c984b 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 9ace01411..9f960cd1d 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 9ace01411..9f960cd1d 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 dffe36df6..a61036fd1 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 b9d74c004..558366996 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 d0c338682..d4d4e942a 100644 --- a/lib/symfony/string/Slugger/AsciiSlugger.php +++ b/lib/symfony/string/Slugger/AsciiSlugger.php @@ -131,8 +131,8 @@ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface 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 75af2da42..f416ee1b2 100644 --- a/lib/symfony/string/UnicodeString.php +++ b/lib/symfony/string/UnicodeString.php @@ -362,6 +362,44 @@ class UnicodeString extends AbstractUnicodeString 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 56c136882..1a2b41ec6 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 06210b0ed..afedd9928 100644 --- a/lib/symfony/translation-contracts/TranslatorTrait.php +++ b/lib/symfony/translation-contracts/TranslatorTrait.php @@ -41,6 +41,12 @@ trait TranslatorTrait 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 f6cb5239b..3bde82141 100644 --- a/lib/symfony/twig-bridge/Form/TwigRendererEngine.php +++ b/lib/symfony/twig-bridge/Form/TwigRendererEngine.php @@ -71,6 +71,7 @@ class TwigRendererEngine extends AbstractRendererEngine // $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 @@ class TwigRendererEngine extends AbstractRendererEngine // 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 @@ class TwigRendererEngine extends AbstractRendererEngine 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 @@ class TwigRendererEngine extends AbstractRendererEngine // 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 f663de11d..1996595dc 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 bd42f1ac0..75f48558b 100644 --- a/lib/symfony/twig-bundle/TemplateIterator.php +++ b/lib/symfony/twig-bundle/TemplateIterator.php @@ -64,6 +64,12 @@ class TemplateIterator implements \IteratorAggregate 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 13c6d43a2..448a2e9e4 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 dc5f1a961..7ec30d5fa 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 c2bdb7c4e..2685ed174 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 2e7516799..91b5d894a 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 70f2a34c0..8db05f9b9 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 6d2930ff8..53e24f15e 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 827e9a1cd..8feecea15 100644 --- a/lib/symfony/yaml/Inline.php +++ b/lib/symfony/yaml/Inline.php @@ -701,6 +701,10 @@ class Inline 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 40702ed63..744181f73 100644 --- a/lib/symfony/yaml/Parser.php +++ b/lib/symfony/yaml/Parser.php @@ -769,6 +769,14 @@ class Parser 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 cf202b044..cf47a7604 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 131ed97b4..000000000 --- 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 6d94e4109..000000000 --- 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 000000000..f415dd8d4 --- /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 395531d86..09f8f01de 100644 --- a/lib/twig/twig/src/Attribute/AsTwigFilter.php +++ b/lib/twig/twig/src/Attribute/AsTwigFilter.php @@ -31,15 +31,15 @@ use Twig\TwigFilter; 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 9229d128e..d161f06f4 100644 --- a/lib/twig/twig/src/Attribute/AsTwigFunction.php +++ b/lib/twig/twig/src/Attribute/AsTwigFunction.php @@ -31,13 +31,13 @@ use Twig\TwigFunction; 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 40eddf83e..1ce2658b4 100644 --- a/lib/twig/twig/src/Attribute/AsTwigTest.php +++ b/lib/twig/twig/src/Attribute/AsTwigTest.php @@ -31,11 +31,11 @@ use Twig\TwigTest; 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 ff3f0c588..2af647611 100644 --- a/lib/twig/twig/src/Environment.php +++ b/lib/twig/twig/src/Environment.php @@ -43,11 +43,11 @@ use Twig\TokenParser\TokenParserInterface; */ 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 @@ class Environment 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 015085e32..97ed2df99 100644 --- a/lib/twig/twig/src/Error/Error.php +++ b/lib/twig/twig/src/Error/Error.php @@ -148,6 +148,10 @@ class Error extends \Exception } } + 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 @@ class Error extends \Exception 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 727cf7eba..3ba94d076 100644 --- a/lib/twig/twig/src/ExpressionParser.php +++ b/lib/twig/twig/src/ExpressionParser.php @@ -214,7 +214,7 @@ class ExpressionParser { 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 @@ class ExpressionParser $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 1c2ae49dd..96bde555d 100644 --- a/lib/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php +++ b/lib/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php @@ -13,6 +13,7 @@ namespace Twig\ExpressionParser\Infix; 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 @@ trait ArgumentsTrait } $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 000000000..fa8c4f2b0 --- /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 7d1cf5058..31418b585 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 @@ final class DotExpressionParser extends AbstractExpressionParser implements Infi ) { $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 @@ final class DotExpressionParser extends AbstractExpressionParser implements Infi 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 @@ final class DotExpressionParser extends AbstractExpressionParser implements Infi 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 8d0ac674c..4641ef815 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 d98c9adf1..da3805106 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\AbstractExpression; 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 @@ final class LiteralExpressionParser extends AbstractExpressionParser implements 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 @@ final class LiteralExpressionParser extends AbstractExpressionParser implements } $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 35468940a..801390097 100644 --- a/lib/twig/twig/src/ExpressionParser/Prefix/UnaryOperatorExpressionParser.php +++ b/lib/twig/twig/src/ExpressionParser/Prefix/UnaryOperatorExpressionParser.php @@ -33,6 +33,7 @@ final class UnaryOperatorExpressionParser extends AbstractExpressionParser imple private ?PrecedenceChange $precedenceChange = null, private ?string $description = null, private array $aliases = [], + private ?int $operandPrecedence = null, ) { } @@ -41,7 +42,7 @@ final class UnaryOperatorExpressionParser extends AbstractExpressionParser imple */ 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 587997c51..8e39dad37 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 44e4f3f6b..74fcbb857 100644 --- a/lib/twig/twig/src/Extension/AttributeExtension.php +++ b/lib/twig/twig/src/Extension/AttributeExtension.php @@ -104,7 +104,7 @@ final class AttributeExtension extends AbstractExtension ]); 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 @@ final class AttributeExtension extends AbstractExtension ]); 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 @@ final class AttributeExtension extends AbstractExtension ]); 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 f7e4250ae..345f40666 100644 --- a/lib/twig/twig/src/Extension/CoreExtension.php +++ b/lib/twig/twig/src/Extension/CoreExtension.php @@ -17,6 +17,7 @@ use Twig\Error\LoaderError; 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\ModBinary; 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 @@ final class CoreExtension extends AbstractExtension 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 @@ final class CoreExtension extends AbstractExtension 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 @@ final class CoreExtension extends AbstractExtension // ternary operator new ConditionalTernaryExpressionParser(), + // assignment operator + new AssignmentExpressionParser('='), + // Twig callables new IsExpressionParser(), new IsNotExpressionParser(), @@ -417,10 +425,8 @@ final class CoreExtension extends AbstractExtension 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 @@ final class CoreExtension extends AbstractExtension } 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 @@ final class CoreExtension extends AbstractExtension } 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 @@ final class CoreExtension extends AbstractExtension 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 44356f627..60ca35b4e 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 85a98cf3c..7bb62fa78 100644 --- a/lib/twig/twig/src/ExtensionSet.php +++ b/lib/twig/twig/src/ExtensionSet.php @@ -27,6 +27,10 @@ use Twig\Node\Expression\AbstractExpression; 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 @@ final class ExtensionSet } } + 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 027771acc..508a79c02 100644 --- a/lib/twig/twig/src/Lexer.php +++ b/lib/twig/twig/src/Lexer.php @@ -525,7 +525,7 @@ class Lexer 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 fe4365b57..2de39ebb9 100644 --- a/lib/twig/twig/src/Node/EmbedNode.php +++ b/lib/twig/twig/src/Node/EmbedNode.php @@ -41,7 +41,7 @@ class EmbedNode extends IncludeNode ->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 b6f8a6ba4..f9f719dd9 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 @@ class ArrayExpression extends AbstractExpression implements SupportDefinedTestIn 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 @@ class ArrayExpression extends AbstractExpression implements SupportDefinedTestIn 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 32e8d34e4..569dfde05 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 @@ namespace Twig\Node\Expression\Binary; 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 000000000..ed28c19bb --- /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 000000000..2c0853f65 --- /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 000000000..b08a19072 --- /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 000000000..a6a873c51 --- /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 000000000..7b3443298 --- /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 000000000..768d1d64f --- /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 @@ class GetAttrExpression extends AbstractExpression implements SupportDefinedTest 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 @@ class GetAttrExpression extends AbstractExpression implements SupportDefinedTest { $env = $compiler->getEnvironment(); $arrayAccessSandbox = false; + $nullSafe = $this->getAttribute('null_safe'); + $objectVar = null; // optimize array calls if ( @@ -93,14 +95,27 @@ class GetAttrExpression extends AbstractExpression implements SupportDefinedTest ; } - $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 @@ class GetAttrExpression extends AbstractExpression implements SupportDefinedTest 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 f17715bc6..d73502990 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\Attribute\FirstClassTwigCallableReady; 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 b5949848d..a18288083 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 @@ class Parser } } + /** + * @throws SyntaxError + */ public function subparse($test, bool $dropNeedle = false): Node { $lineno = $this->getCurrentToken()->getLine(); @@ -494,11 +500,26 @@ class Parser // 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 104b4f4e0..a0392ff51 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 8f0e6492a..c499e5ec2 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 17ed76cc9..f686e19f0 100644 --- a/lib/twig/twig/src/Runtime/EscaperRuntime.php +++ b/lib/twig/twig/src/Runtime/EscaperRuntime.php @@ -17,7 +17,7 @@ use Twig\Markup; final class EscaperRuntime implements RuntimeExtensionInterface { - /** @var array */ + /** @var array */ private $escapers = []; /** @internal */ @@ -140,6 +140,10 @@ final class EscaperRuntime implements RuntimeExtensionInterface 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 @@ final class EscaperRuntime implements RuntimeExtensionInterface * 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 @@ final class EscaperRuntime implements RuntimeExtensionInterface "\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 @@ final class EscaperRuntime implements RuntimeExtensionInterface * @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 @@ final class EscaperRuntime implements RuntimeExtensionInterface * 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 faf7aee1e..c37209287 100644 --- a/lib/twig/twig/src/Template.php +++ b/lib/twig/twig/src/Template.php @@ -270,7 +270,7 @@ abstract class Template /** * @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 @@ abstract class Template * * @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 656766af5..eb4886579 100644 --- a/lib/twig/twig/src/TokenParser/GuardTokenParser.php +++ b/lib/twig/twig/src/TokenParser/GuardTokenParser.php @@ -32,9 +32,15 @@ final class GuardTokenParser extends AbstractTokenParser $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; }