From aa84c7d4673f5523f135ebbf4b34f04172edae3f Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Tue, 13 May 2025 18:49:03 +0200 Subject: [PATCH 01/49] [Form] Adding `DataPart` to manually set the `Content-Type` Page: https://symfony.com/doc/6.4/http_client.html#uploading-data --- http_client.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/http_client.rst b/http_client.rst index 32ef552c64f..ba3c3d5a9dc 100644 --- a/http_client.rst +++ b/http_client.rst @@ -665,6 +665,15 @@ of the opened file, but you can configure both with the PHP streaming configurat $formData->getParts(); // Returns two instances of TextPart both // with the name "array_field" +Usually, the ``Content-Type`` of each form's part is detected automatically. However, +you can override it by passing a ``DataPart``:: + + use Symfony\Component\Mime\Part\DataPart; + + $formData = new FormDataPart([ + ['json_data' => new DataPart(json_encode($json), null, 'application/json')] + ]; + By default, HttpClient streams the body contents when uploading them. This might not work with all servers, resulting in HTTP status code 411 ("Length Required") because there is no ``Content-Length`` header. The solution is to turn the body From f8ae9b9190831f8423a0498092791ab47ff7bef1 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Tue, 13 May 2025 18:55:47 +0200 Subject: [PATCH 02/49] Update http_client.rst --- http_client.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http_client.rst b/http_client.rst index ba3c3d5a9dc..3d4f7d98c44 100644 --- a/http_client.rst +++ b/http_client.rst @@ -672,7 +672,7 @@ you can override it by passing a ``DataPart``:: $formData = new FormDataPart([ ['json_data' => new DataPart(json_encode($json), null, 'application/json')] - ]; + ]); By default, HttpClient streams the body contents when uploading them. This might not work with all servers, resulting in HTTP status code 411 ("Length Required") From 297146e5087feaf8b153b0bb7f15d2e559d6d801 Mon Sep 17 00:00:00 2001 From: Mathias Arlaud Date: Thu, 19 Dec 2024 15:33:00 +0100 Subject: [PATCH 03/49] [Serializer] [JsonStreamer] Add streaming JSON documentation --- serializer.rst | 32 ++ serializer/streaming_json.rst | 675 ++++++++++++++++++++++++++++++++++ 2 files changed, 707 insertions(+) create mode 100644 serializer/streaming_json.rst diff --git a/serializer.rst b/serializer.rst index 4dd689a5ab5..93f370995ea 100644 --- a/serializer.rst +++ b/serializer.rst @@ -629,6 +629,38 @@ all the properties of the class:: // ... } +Serializing JSON using streams +------------------------------ + +Symfony is able of encoding PHP data structures to JSON streams and decoding +JSON streams back into PHP data structures. + +To do so, it relies on the JsonStreamer component, which is designed for high +efficiency and can process large JSON data incrementally without needing to +load the entire content into memory. + +When deciding between the :doc:`Serializer component ` and the +JsonStreamer component, consider the following: + +- **Serializer Component**: Ideal for scenarios requiring flexibility, such as + dynamically manipulating object shapes using normalizers and denormalizers, + or handling complex objects which multiple serialization representation. + Plus, it allows working with formats beyond JSON (and even with a custom + format of yours). + +- **JsonStreamer Component**: Ideal for simple objects and tasks that + demand high performance and minimal memory usage. It's particularly + effective when processing very large JSON datasets or in scenarios that + require streaming JSON in real-time without loading the entire dataset + into memory. + +Choosing between the two depends on your specific use case requirements. +The JsonStreamer component is tailored to optimize for performance and memory +efficiency, while the Serializer component offers flexibility and broader +format support. + +Read more about streaming JSON in :doc:`/serializer/streaming_json`. + Serializing to or from PHP Arrays --------------------------------- diff --git a/serializer/streaming_json.rst b/serializer/streaming_json.rst new file mode 100644 index 00000000000..3cf4de3ef0b --- /dev/null +++ b/serializer/streaming_json.rst @@ -0,0 +1,675 @@ +Streaming JSON +============== + +Symfony is able of encoding PHP data structures to JSON streams and decoding +JSON streams back into PHP data structures. + +To do so, it relies on the JsonStreamer component, which is designed for high +efficiency and can process large JSON data incrementally without needing to +load the entire content into memory. + +.. tip:: + + This component is ideal for handling APIs or interacting with third-party + APIs. It transforms incoming JSON request payloads into PHP objects that + your application can work with. Similarly, it converts processed PHP + objects into a JSON stream for outgoing responses. + +Installation +------------ + +To install the JsonStreamer component in applications that use +:ref:`Symfony Flex `, run this command: + +.. code-block:: terminal + + $ composer require symfony/json-streamer + +.. include:: /components/require_autoload.rst.inc + +.. warning:: + + The JsonStreamer component is :doc:`experimental ` + and could be changed at any time without prior notice. + +Encoding objects +---------------- + +Let's say that we have the following ``Cat`` class:: + + // src/Dto/Cat.php + namespace App\Dto; + + use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; + + #[JsonStreamable] + class Cat + { + public string $name; + public string $age; + } + +.. warning:: + + The JsonStreamer only works with PHP classes without constructor and + composed by public properties only. + +If you want to encode ``Cat`` objects to a JSON stream (e.g. to send them +via an API response), you can get the ``json_streamer.stream_writer`` service by using +the :class:`Symfony\\Component\\JsonStreamer\\StreamWriterInterface` parameter type +with the ``$jsonStreamWriter`` name, and use the :method:`Symfony\\Component\\JsonStreamer\\StreamWriterInterface::write` +method: + +.. configuration-block:: + + .. code-block:: php-symfony + + // src/Controller/CatController.php + namespace App\Controller; + + use App\Dto\Cat; + use App\Repository\CatRepository; + use Symfony\Component\HttpFoundation\StreamedResponse; + use Symfony\Component\JsonStreamer\StreamWriterInterface; + use Symfony\Component\TypeInfo\Type; + + class CatController + { + public function retrieveCats(StreamWriterInterface $jsonStreamWriter, CatRepository $catRepository): StreamedResponse + { + $cats = $catRepository->findAll(); + $type = Type::list(Type::object(Cat::class)); + + $json = $jsonStreamWriter->write($cats, $type); + + return new StreamedResponse($json); + } + } + + .. code-block:: php-standalone + + use App\Dto\Cat; + use App\Repository\CatRepository; + use Symfony\Component\HttpFoundation\StreamedResponse; + use Symfony\Component\JsonStreamer\JsonStreamWriter; + use Symfony\Component\TypeInfo\Type; + + // ... + + $jsonWriter = JsonStreamWriter::create(); + + $cats = $catRepository->findAll(); + $type = Type::list(Type::object(Cat::class)); + + $json = $jsonWriter->write($cats, $type); + + $response = new StreamedResponse($json); + + // ... + +.. note:: + + You can explicitly inject the ``json_streamer.stream_writer`` service by + using the ``#[Target('json_streamer.stream_writer')]`` autowire attribute. + +Decoding objects +---------------- + +Besides encoding objects to JSON, you can decode JSON to objects. + +To do so, you can get the ``json_streamer.stream_reader`` service by using the +:class:`Symfony\\Component\\JsonStreamer\\StreamReaderInterface` parameter type +with the ``$jsonStreamReader`` name, and use the :method:`Symfony\\Component\\JsonStreamer\\StreamReaderInterface::read` +method: + +.. configuration-block:: + + .. code-block:: php-symfony + + // src/Service/TombolaService.php + namespace App\Service; + + use App\Dto\Cat; + use Symfony\Component\DependencyInjection\Attribute\Autowire; + use Symfony\Component\JsonStreamer\StreamReaderInterface; + use Symfony\Component\TypeInfo\Type; + + class TombolaService + { + private string $catsJsonFile; + + public function __construct( + private StreamReaderInterface $jsonStreamReader, + #[Autowire(param: 'kernel.root_dir')] + string $rootDir, + ) { + $this->catsJsonFile = sprintf('%s/var/cats.json', $rootDir); + } + + public function pickTheTenthCat(): ?Cat + { + $jsonResource = fopen($this->catsJsonFile, 'r'); + $type = Type::iterable(Type::object(Cat::class)); + + /** @var iterable $cats */ + $cats = $this->jsonStreamReader->read($jsonResource, $type); + + $i = 0; + foreach ($cats as $cat) { + if ($i === 9) { + return $cat; + } + + ++$i; + } + + return null; + } + + /** + * @return list + */ + public function listEligibleCatNames(): array + { + $json = file_get_contents($this->catsJsonFile); + $type = Type::iterable(Type::object(Cat::class)); + + /** @var iterable $cats */ + $cats = $this->jsonStreamReader->read($json, $type); + + return array_map(fn(Cat $cat) => $cat->name, iterator_to_array($cats)); + } + } + + .. code-block:: php-standalone + + // src/Service/TombolaService.php + namespace App\Service; + + use App\Dto\Cat; + use Symfony\Component\JsonStreamer\JsonStreamReader; + use Symfony\Component\JsonStreamer\StreamReaderInterface; + use Symfony\Component\TypeInfo\Type; + + class TombolaService + { + private StreamReaderInterface $jsonStreamReader; + private string $catsJsonFile; + + public function __construct( + private string $catsJsonFile, + ) { + $this->jsonStreamReader = JsonStreamReader::create(); + } + + public function pickTheTenthCat(): ?Cat + { + $jsonResource = fopen($this->catsJsonFile, 'r'); + $type = Type::iterable(Type::object(Cat::class)); + + /** @var iterable $cats */ + $cats = $this->jsonStreamReader->read($jsonResource, $type); + + $i = 0; + foreach ($cats as $cat) { + if ($i === 9) { + return $cat; + } + + ++$i; + } + + return null; + } + + /** + * @return list + */ + public function listEligibleCatNames(): array + { + $json = file_get_contents($this->catsJsonFile); + $type = Type::iterable(Type::object(Cat::class)); + + /** @var iterable $cats */ + $cats = $this->jsonStreamReader->read($json, $type); + + return array_map(fn(Cat $cat) => $cat->name, iterator_to_array($cats)); + } + } + +.. note:: + + You can explicitly inject the ``json_streamer.stream_reader`` service by + using the ``#[Target('json_streamer.stream_reader')]`` autowire attribute. + +The upper code demonstrates two different approaches to decoding JSON data +using the JsonStreamer: + +* decoding from a stream (``pickTheTenthCat``) +* decoding from a string (``listEligibleCatNames``). + +Both methods work with the same JSON data but differ in memory usage and +speed optimization. + + +Decoding from a stream +~~~~~~~~~~~~~~~~~~~~~~ + +In the ``pickTheTenthCat`` method, the JSON data is read as a stream using +:phpfunction:`fopen`. Streams are useful when working with large files +because the data is processed incrementally rather than loading the entire +file into memory. + +To improve memory efficiency, the JsonStreamer creates `ghost objects`_ +instead of fully instantiating objects. Ghosts objects are lightweight +placeholders that represent the objects but don't fully load their data +into memory until it's needed. This approach reduces memory usage, especially +for large datasets. + +* Advantage: Efficient memory usage, suitable for very large JSON files. +* Disadvantage: Slightly slower than decoding a full string because data is + loaded on-demand. + +Decoding from a string +~~~~~~~~~~~~~~~~~~~~~~ + +In the ``listEligibleCatNames`` method, the entire JSON file is read into +a string using :phpfunction:`file_get_contents`. This string is then passed +to the decoder, which fully instantiates all the objects in the JSON data +upfront. + +This approach is faster because all the objects are created immediately, +making subsequent operations on the data quicker. However, it uses more +memory since the entire file content and all objects are loaded at once. + +* Advantage: Faster processing, suitable for small to medium-sized JSON files. +* Disadvantage: Higher memory usage, not ideal for large JSON files. + +.. tip:: + + Prefer stream decoding when working with large JSON files to conserve + memory. + + Prefer string decoding instead when performance is more critical and the + JSON file size is manageable. + +Enabling PHPDoc reading +----------------------- + +The JsonStreamer component can be able to process advanced PHPDoc type +definitions, such as generics, and read/generate JSON for complex PHP +objects. + +For example, let's consider this ``Shelter`` class that defines a generic +``TAnimal`` type, which can be a ``Cat`` or a ``Dog``:: + + // src/Dto/Shelter.php + namespace App\Dto; + + use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; + + /** + * @template TAnimal of Cat|Dog + */ + #[JsonStreamable] + class Shelter + { + /** + * @var list + */ + public array $animals; + } + + +To enable PHPDoc interpretation, run the following command: + +.. code-block:: terminal + + $ composer require phpstan/phpdoc-parser + +Then, when encoding/decoding an instance of the ``Shelter`` class, you can +specify the concrete type information, and the JsonStreamer will deal with the +correct JSON structure:: + + use App\Dto\Cat; + use App\Dto\Shelter; + use Symfony\Component\TypeInfo\Type; + + $json = <<read($json, $type); // will be populated with Cat instances + +Configuring encoding/decoding +----------------------------- + +While it's not recommended to change to object shape and values during +encoding and decoding, it is sometimes unavoidable. + +Configuring the encoded name +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is possible to configure the JSON key associated to a property thanks to +the :class:`Symfony\\Component\\JsonStreamer\\Attribute\\StreamedName` +attribute:: + + // src/Dto/Duck.php + namespace App\Dto; + + use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; + use Symfony\Component\JsonStreamer\Attribute\StreamedName; + + #[JsonStreamable] + class Duck + { + #[StreamedName('@id')] + public string $id; + } + +By doing so, the ``Duck::$id`` property will be mapped to the ``@id`` JSON key:: + + use App\Dto\Duck; + use Symfony\Component\TypeInfo\Type; + + // ... + + $duck = new Duck(); + $duck->id = '/ducks/daffy'; + + echo (string) $jsonStreamWriter->write($duck, Type::object(Duck::class)); + + // This will output: + // { + // "@id": "/ducks/daffy" + // } + +Configuring the encoded value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to manipulate the value related to a property during the encoding +process, you can use the :class:`Symfony\\Component\\JsonStreamer\\Attribute\\ValueTransformer` +attribute. Its ``nativeToStream`` property takes a callable, or a :ref:`value transformer service id `. + +When a callable is specified, it must either be a public static method or +non-anonymous function with the following signature:: + + $transformer = function (mixed $data, array $options = []): mixed { /* ... */ }; + +Then, you just have to specify the function identifier in the attribute:: + + // src/Dto/Duck.php + namespace App\Dto; + + use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; + use Symfony\Component\JsonStreamer\Attribute\ValueTransformer; + + #[JsonStreamable] + class Duck + { + #[ValueTransformer(nativeToStream: 'strtoupper')] + public string $name; + + #[ValueTransformer(nativeToStream: [self::class, 'formatHeight'])] + public int $height; + + public static function formatHeight(int $value, array $options = []): string + { + return sprintf('%.2fcm', $value / 100); + } + } + +For example, by configuring the ``Duck`` class like above, the ``name`` and +``height`` values will be transformed during encoding:: + + use App\Dto\Duck; + use Symfony\Component\TypeInfo\Type; + + // ... + + $duck = new Duck(); + $duck->name = 'daffy'; + $duck->height = 5083; + + echo (string) $jsonStreamWriter->write($duck, Type::object(Duck::class)); + + // This will output: + // { + // "name": "DAFFY", + // "height": "50.83cm" + // } + +Configuring the decoded value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can as well manipulate the value related to a property during decoding +using the :class:`Symfony\\Component\\JsonStreamer\\Attribute\\ValueTransformer` +attribute. Its ``streamToNative`` property can take either a callable or a :ref:`value transformer service id `. + +When a callable is specified, it must either be a public static method or +a non-anonymous function with the following signature:: + + $valueTransformer = function (mixed $data, array $options = []): mixed { /* ... */ }; + +You can specify a function identifier in the attribute as follows:: + + // src/Dto/Duck.php + namespace App\Dto; + + use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; + use Symfony\Component\JsonStreamer\Attribute\ValueTransformer; + + #[JsonStreamable] + class Duck + { + #[ValueTransformer(streamToNative: [self::class, 'retrieveFirstName'])] + public string $firstName; + + #[ValueTransformer(streamToNative: [self::class, 'retrieveLastName'])] + public string $lastName; + + public static function retrieveFirstName(string $normalized, array $options = []): string + { + return explode(' ', $normalized)[0]; + } + + public static function retrieveLastName(string $normalized, array $options = []): string + { + return explode(' ', $normalized)[1]; + } + } + +For instance, the above configuration for the ``Duck`` class will transform +the `name` property from the input JSON during decoding:: + + use App\Dto\Duck; + use Symfony\Component\TypeInfo\Type; + + // ... + + $duck = $jsonStreamReader->read( + '{"name": "Daffy Duck"}', + Type::object(Duck::class), + ); + + // The $duck variable will contain: + // object(Duck)#1 (1) { + // ["firstName"] => string(5) "Daffy" + // ["lastName"] => string(4) "Duck" + // } + +.. _json-streamer-transform-with-services: + +Transform value using services +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When static methods or functions are not enough, you can transform the value +thanks to a value transformer service. + +To do so, create a service implementing the :class:`Symfony\\Component\\JsonStreamer\\ValueTransformer\\ValueTransformerInterface`:: + + // src/Transformer/DogUrlTransformer.php + namespace App\Transformer; + + use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; + use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + use Symfony\Component\TypeInfo\Type; + + class DogUrlTransformer implements ValueTransformerInterface + { + public function __construct( + private UrlGeneratorInterface $urlGenerator, + ) { + } + + public function transform(mixed $value, array $options = []): string + { + if (!is_int($value)) { + throw new \InvalidArgumentException(sprintf('The value must be "int", "%s" given.', get_debug_type($value))); + } + + return $this->urlGenerator->generate('show_dog', ['id' => $value]); + } + + public static function getStreamValueType(): Type + { + return Type::string(); + } + } + +.. note:: + + The ``getStreamValueType`` method should return the type of what the value + will be in the JSON stream. + +And then, configure the :class:`Symfony\\Component\\JsonStreamer\\Attribute\\ValueTransformer` +attribute to use that service:: + + // src/Dto/Dog.php + namespace App\Dto; + + use App\Transformer\DogUrlTransformer; + use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; + use Symfony\Component\JsonStreamer\Attribute\StreamedName; + use Symfony\Component\JsonStreamer\Attribute\ValueTransformer; + + #[JsonStreamable] + class Dog + { + #[StreamedName('url')] + #[ValueTransformer(nativeToStream: DogUrlTransformer::class)] + public int $id; + } + +.. tip:: + + The value transformers will be intensively called during the + decoding and encoding. So be sure to keep them as fast as possible + (avoid calling external APIs or the database for example). + +Configure keys and values dynamically +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The JsonStreamer leverages services implementing the :class:`Symfony\\Component\\JsonStreamer\\Mapping\\PropertyMetadataLoaderInterface` +to determine the shape and values of objects during encoding/decoding. + +These services are highly flexible and can be decorated to handle dynamic +configurations, offering much greater power compared to using attributes:: + + namespace App\Streamer\SensitivePropertyMetadataLoader; + + use App\Dto\SensitiveInterface; + use App\Streamer\ValueTransformer\EncryptorValueTransformer; + use Symfony\Component\DependencyInjection\Attribute\AsDecorator; + use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated; + use Symfony\Component\JsonStreamer\Mapping\PropertyMetadata; + use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; + use Symfony\Component\TypeInfo\Type; + + #[AsDecorator('json_streamer.write.property_metadata_loader')] + class SensitivePropertyMetadataLoader implements PropertyMetadataLoaderInterface + { + public function __construct( + #[AutowireDecorated] + private PropertyMetadataLoaderInterface $decorated, + ) { + } + + public function load(string $className, array $options = [], array $context = []): array + { + $propertyMetadataMap = $this->decorated->load($className, $options, $context); + + if (!is_a($className, SensitiveInterface::class, true)) { + return $propertyMetadataMap; + } + + // you can configure value transformers + foreach ($propertyMetadataMap as $jsonKey => $metadata) { + if (in_array($metadata->getName(), $className::getPropertiesToEncrypt(), true)) { + $propertyMetadataMap[$jsonKey] = $metadata + ->withType(Type::string()) + ->withAdditionalNativeToStreamValueTransformer(EncryptorValueTransformer::class); + } + } + + // you can remove existing properties + foreach ($propertyMetadataMap as $jsonKey => $metadata) { + if (in_array($metadata->getName(), $className::getPropertiesToRemove(), true)) { + unset($propertyMetadataMap[$jsonKey]); + } + } + + // you can rename JSON keys + foreach ($propertyMetadataMap as $jsonKey => $metadata) { + $propertyMetadataMap[md5($jsonKey)] = $propertyMetadataMap[$jsonKey]; + unset($propertyMetadataMap[$jsonKey]); + } + + // you can add virtual properties + $propertyMetadataMap['is_sensitive'] = new PropertyMetadata( + name: 'theNameWontBeUsed', + type: Type::bool(), + nativeToStreamValueTransformers: [fn() => true], + ); + + return $propertyMetadataMap; + } + } + +However, this flexibility comes with complexity. Decorating property metadata +loaders requires a deep understanding of the system. + +For most use cases, the attributes approach is sufficient, and the dynamic +capabilities of property metadata loaders should be reserved for scenarios +where their additional power is genuinely necessary. + +Marking objects as streamable +----------------------------- + +The ``JsonStreamable`` attribute is used to mark a class as streamable. +While this attribute is not mandatory, it is highly recommended because it +plays a crucial role during the cache warm-up process by generating the +files necessary for encoding and decoding operations, and thereby improving +performance. + +It includes two properties: ``asObject`` and ``asList``. These properties +define the structure in which the marked class should be prepared during the +cache warm-up process:: + + use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; + + #[JsonStreamable(asObject: true, asList: true)] + class StreamableData + { + // ... + } + +.. _ghost objects: https://en.wikipedia.org/wiki/Lazy_loading#Ghost From 077e59646d2cff54dd24d777dfbe02308f3f4a50 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 10 Jul 2025 07:58:17 +0200 Subject: [PATCH 04/49] list shortcuts of global CLI options as well --- console/input.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/console/input.rst b/console/input.rst index 813ab683428..09cba08a41a 100644 --- a/console/input.rst +++ b/console/input.rst @@ -416,15 +416,16 @@ The Console component adds some predefined options to all commands: * ``--verbose``: sets the verbosity level (e.g. ``1`` the default, ``2`` and ``3``, or you can use respective shortcuts ``-v``, ``-vv`` and ``-vvv``) -* ``--quiet``: disables output and interaction -* ``--no-interaction``: disables interaction -* ``--version``: outputs the version number of the console application -* ``--help``: displays the command help +* ``--quiet|-q``: disables output and interaction +* ``--no-interaction|-n``: disables interaction +* ``--version|-V``: outputs the version number of the console application +* ``--help|-h``: displays the command help * ``--ansi|--no-ansi``: whether to force of disable coloring the output +* ``--profile``: enables the Symfony profiler When using the ``FrameworkBundle``, two more options are predefined: -* ``--env``: sets the Kernel configuration environment (defaults to ``APP_ENV``) +* ``--env|-e``: sets the Kernel configuration environment (defaults to ``APP_ENV``) * ``--no-debug``: disables Kernel debug (defaults to ``APP_DEBUG``) So your custom commands can use them too out-of-the-box. From 1e3c81382b16162fbb5bb07396c35ca770ddb57e Mon Sep 17 00:00:00 2001 From: Franck Matsos Date: Mon, 14 Jul 2025 11:03:29 +0200 Subject: [PATCH 05/49] Update context7.json --- context7.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/context7.json b/context7.json index 8cbc5bd67d3..dc9d2c43c13 100644 --- a/context7.json +++ b/context7.json @@ -7,19 +7,19 @@ "branch": "7.3", "previousVersions": [ { - "branch": "7.3", + "tag": "7.3", "title": "v7.3" }, { - "branch": "7.2", + "tag": "7.2", "title": "v7.2" }, { - "branch": "7.0", + "tag": "7.0", "title": "v7.0" }, { - "branch": "6.4", + "tag": "6.4", "title": "v6.4" } ] From dd4cac424158e92b617b04c726450a8f38a49014 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 15 Jul 2025 08:32:34 +0200 Subject: [PATCH 06/49] [AssetMapper] Missing 'importmap:remove' command --- frontend/asset_mapper.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/frontend/asset_mapper.rst b/frontend/asset_mapper.rst index ca500a9686d..e16dac9230b 100644 --- a/frontend/asset_mapper.rst +++ b/frontend/asset_mapper.rst @@ -279,6 +279,35 @@ You can update your third-party packages to their current versions by running: The ``importmap:install`` and ``importmap:outdated`` commands were introduced in Symfony 6.4. +Removing Packages from importmap +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to remove a JavaScript package that was previously added to your ``importmap.php`` file, you can use the ``importmap:remove`` command. + +.. code-block:: terminal + + $ php bin/console importmap:remove + +For example, to remove the ``lodash`` package from your importmap: + +.. code-block:: terminal + + $ php bin/console importmap:remove lodash + +This will update your ``importmap.php`` file and remove the specified package (and any dependencies added along with it). +After running this command, it is recommended to also run: + +.. code-block:: terminal + + $ php bin/console importmap:install + +This ensures your ``assets/vendor/`` directory is in sync with the updated importmap configuration. + +.. tip:: + + Removing a package from the importmap does not automatically remove any references to it in your JavaScript files. + Make sure to update your code to remove any ``import`` statements that reference the removed package. + How does the importmap Work? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From a4619deee18409f3c7d8780e21352919856070ec Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 15 Jul 2025 08:34:23 +0200 Subject: [PATCH 07/49] Tweaks --- frontend/asset_mapper.rst | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/frontend/asset_mapper.rst b/frontend/asset_mapper.rst index e16dac9230b..6f045938339 100644 --- a/frontend/asset_mapper.rst +++ b/frontend/asset_mapper.rst @@ -279,34 +279,32 @@ You can update your third-party packages to their current versions by running: The ``importmap:install`` and ``importmap:outdated`` commands were introduced in Symfony 6.4. -Removing Packages from importmap -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you need to remove a JavaScript package that was previously added to your ``importmap.php`` file, you can use the ``importmap:remove`` command. - -.. code-block:: terminal - - $ php bin/console importmap:remove +Removing JavaScript Packages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For example, to remove the ``lodash`` package from your importmap: +If you need to remove a JavaScript package that was previously added to your +``importmap.php`` file, use the ``importmap:remove`` command. For example, to +remove the ``lodash`` package: .. code-block:: terminal $ php bin/console importmap:remove lodash -This will update your ``importmap.php`` file and remove the specified package (and any dependencies added along with it). -After running this command, it is recommended to also run: +This updates your ``importmap.php`` file and removes the specified package +(along with any dependencies that were added with it). + +After running this command, it's recommended to also run the following to ensure +that your ``assets/vendor/`` directory is in sync with the updated import map: .. code-block:: terminal $ php bin/console importmap:install -This ensures your ``assets/vendor/`` directory is in sync with the updated importmap configuration. - .. tip:: - Removing a package from the importmap does not automatically remove any references to it in your JavaScript files. - Make sure to update your code to remove any ``import`` statements that reference the removed package. + Removing a package from the import map does not automatically remove any + references to it in your JavaScript files. Make sure to update your code and + remove any ``import`` statements that reference the removed package. How does the importmap Work? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 0cb7c166611913c6b4246baf8fde0c4d910cd0db Mon Sep 17 00:00:00 2001 From: Mimi <160484490+hmeknassi@users.noreply.github.com> Date: Mon, 14 Jul 2025 09:32:47 +0200 Subject: [PATCH 08/49] Update lock.rst Adds a clarification in the Lock component documentation about the the values to use for the env variable LOCK_DSN in order to activate the NullStore and the InMemoryStore. --- components/lock.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/lock.rst b/components/lock.rst index b8ba38c8fc7..1bcdc51f80e 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -405,7 +405,8 @@ Store Scope Blocking Ex Symfony includes two other special stores that are mostly useful for testing: ``InMemoryStore``, which saves locks in memory during a process, and ``NullStore``, - which doesn't persist anything. + which doesn't persist anything. To activate either one, simply set the ``LOCK_DSN`` to + ``null`` or ``in-memory``. .. versionadded:: 7.2 From df56c8e54dc921cc400af62c1fb9eedab09a7687 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 15 Jul 2025 09:04:44 +0200 Subject: [PATCH 09/49] Tweaks --- components/lock.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 1bcdc51f80e..8d50a0c297e 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -404,9 +404,9 @@ Store Scope Blocking Ex .. tip:: Symfony includes two other special stores that are mostly useful for testing: - ``InMemoryStore``, which saves locks in memory during a process, and ``NullStore``, - which doesn't persist anything. To activate either one, simply set the ``LOCK_DSN`` to - ``null`` or ``in-memory``. + + * ``InMemoryStore`` (``LOCK_DSN=in-memory``), which saves locks in memory during a process; + * ``NullStore`` (``LOCK_DSN=null``) which doesn't persist anything. .. versionadded:: 7.2 From 5fd4e234ad29b54b252dee8f0f779b5b85875aeb Mon Sep 17 00:00:00 2001 From: tcoch Date: Tue, 15 Jul 2025 11:20:08 +0200 Subject: [PATCH 10/49] Add tip about default value --- routing.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/routing.rst b/routing.rst index 58f3fa28c80..102aef454f0 100644 --- a/routing.rst +++ b/routing.rst @@ -936,6 +936,10 @@ other configuration formats they are defined with the ``defaults`` option: Now, when the user visits ``/blog``, the ``blog_list`` route will match and ``$page`` will default to a value of ``1``. +.. tip:: + + The default value is allowed to not match the requirement. + .. warning:: You can have more than one optional parameter (e.g. ``/blog/{slug}/{page}``), From 6a007d438610fc2712bca9d6b05e232ec995e403 Mon Sep 17 00:00:00 2001 From: Wolfgang Klinger Date: Thu, 17 Jul 2025 09:19:18 +0200 Subject: [PATCH 11/49] bug #60745 [Scheduler] Add warning about comma-separated weekdays in PeriodicalTrigger --- scheduler.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scheduler.rst b/scheduler.rst index 5028c00e2ec..6701c1446e7 100644 --- a/scheduler.rst +++ b/scheduler.rst @@ -286,6 +286,16 @@ defined by PHP datetime functions:: RecurringMessage::every('3 weeks', new Message()); RecurringMessage::every('first Monday of next month', new Message()); +.. note:: + + Comma-separated weekdays (e.g., ``'Monday, Thursday, Saturday'``) are not supported + by the ``every()`` method. For multiple weekdays, use cron expressions instead: + + .. code-block:: diff + + - RecurringMessage::every('Monday, Thursday, Saturday', new Message()); + + RecurringMessage::cron('5 12 * * 1,4,6', new Message()); + .. tip:: You can also define periodic tasks using :ref:`the AsPeriodicTask attribute `. From d1b52cb60de3fb00a7511d7cbda0e8f82af08c15 Mon Sep 17 00:00:00 2001 From: Samuel NELA Date: Thu, 17 Jul 2025 22:25:24 +0200 Subject: [PATCH 12/49] [Setup] Use the stable version to create a new application --- setup.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.rst b/setup.rst index 20d71d112eb..dfc26901d74 100644 --- a/setup.rst +++ b/setup.rst @@ -48,10 +48,10 @@ application: .. code-block:: terminal # run this if you are building a traditional web application - $ symfony new my_project_directory --version="7.3.x-dev" --webapp + $ symfony new my_project_directory --version="7.3.x" --webapp # run this if you are building a microservice, console application or API - $ symfony new my_project_directory --version="7.3.x-dev" + $ symfony new my_project_directory --version="7.3.x" The only difference between these two commands is the number of packages installed by default. The ``--webapp`` option installs extra packages to give @@ -63,12 +63,12 @@ Symfony application using Composer: .. code-block:: terminal # run this if you are building a traditional web application - $ composer create-project symfony/skeleton:"7.3.x-dev" my_project_directory + $ composer create-project symfony/skeleton:"7.3.x" my_project_directory $ cd my_project_directory $ composer require webapp # run this if you are building a microservice, console application or API - $ composer create-project symfony/skeleton:"7.3.x-dev" my_project_directory + $ composer create-project symfony/skeleton:"7.3.x" my_project_directory No matter which command you run to create the Symfony application. All of them will create a new ``my_project_directory/`` directory, download some dependencies From 8579d1c217c14a9e6432da16cbbcfeb45f3ea977 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 18 Jul 2025 14:58:26 +0200 Subject: [PATCH 13/49] Tweak --- http_client.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http_client.rst b/http_client.rst index d8627e8282f..bdc843a32e8 100644 --- a/http_client.rst +++ b/http_client.rst @@ -672,7 +672,7 @@ of the opened file, but you can configure both with the PHP streaming configurat $formData->getParts(); // Returns two instances of TextPart both // with the name "array_field" -Usually, the ``Content-Type`` of each form's part is detected automatically. However, +The ``Content-Type`` of each form's part is detected automatically. However, you can override it by passing a ``DataPart``:: use Symfony\Component\Mime\Part\DataPart; From 89718f0c106b95c1b5a3ed7cb386ba96dd8ac30e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 2 Jun 2025 09:46:08 +0200 Subject: [PATCH 14/49] [DomCrawler] Add more details about some methods --- testing/dom_crawler.rst | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/testing/dom_crawler.rst b/testing/dom_crawler.rst index 9d527304f96..9f419bf9b63 100644 --- a/testing/dom_crawler.rst +++ b/testing/dom_crawler.rst @@ -21,27 +21,29 @@ selects the last one on the page, and then selects its immediate ancestor elemen Many other methods are also available: ``filter('h1.title')`` - Nodes that match the CSS selector. + Finds nodes that match the given CSS selector (which must be supported by + Symfony's :doc:`CSS Selector component `). ``filterXpath('h1')`` - Nodes that match the XPath expression. + Finds nodes matching the given `XPath expression`_. ``eq(1)`` - Node for the specified index. + Returns the node at the given index (``0`` is the first node). ``first()`` - First node. + Returns the first node (equivalent to ``eq(0)``). ``last()`` - Last node. + Returns the last node. ``siblings()`` - Siblings. + Returns all sibling nodes (nodes with the same parent, excluding the current node). ``nextAll()`` - All following siblings. + Returns all following siblings (same parent, after the current node). ``previousAll()`` - All preceding siblings. + Returns all preceding siblings (same parent, before the current node). ``ancestors()`` - Returns the ancestor nodes. + Returns all ancestor nodes (parents, grandparents, etc., up to the ```` + element). ``children()`` - Returns children nodes. + Returns all direct child nodes of the current node. ``reduce($lambda)`` - Nodes for which the callable does not return false. + Filters the nodes using a callback; keeps only those for which it returns ``true``. Since each of these methods returns a new ``Crawler`` instance, you can narrow down your node selection by chaining the method calls:: @@ -91,3 +93,5 @@ The Crawler can extract information from the nodes:: $data = $crawler->each(function ($node, int $i): string { return $node->attr('href'); }); + +.. _`XPath expression`: https://developer.mozilla.org/en-US/docs/Web/XML/XPath From 642c4f2a051330e486e1a8c4b9a184733e7a6422 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 4 Jun 2025 16:54:16 +0200 Subject: [PATCH 15/49] [DependencyInjection] Document the different types of service arguments --- service_container.rst | 121 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/service_container.rst b/service_container.rst index c1f5dc7b5f4..f94b15233c3 100644 --- a/service_container.rst +++ b/service_container.rst @@ -323,6 +323,127 @@ type-hints by running: [...] +In addition to injecting services, you can also pass scalar values and collections +as arguments of other services: + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + App\Service\SomeService: + arguments: + # string, numeric and boolean arguments can be passed "as is" + - 'Foo' + - true + - 7 + - 3.14 + + # constants can be built-in, user-defined, or Enums + - !php/const E_ALL + - !php/const PDO::FETCH_NUM + - !php/const Symfony\Component\HttpKernel\Kernel::VERSION + - !php/const App\Config\SomeEnum::SomeCase + + # when not using autowiring, you can pass service arguments explicitly + - '@some-service-id' # the leading '@' tells this is a service ID, not a string + - '@?some-service-id' # using '?' means to pass null if service doesn't exist + + # binary contents are passed encoded as base64 strings + - !!binary VGhpcyBpcyBhIEJlbGwgY2hhciAH + + # collections (arrays) can include any type of argument + - + first: !php/const true + second: 'Foo' + + .. code-block:: xml + + + + + + + + + Foo + 7 + 3.14 + + Foo + + true + + + E_ALL + PDO::FETCH_NUM + Symfony\Component\HttpKernel\Kernel::VERSION + App\Config\SomeEnum::SomeCase + + + + + + VGhpcyBpcyBhIEJlbGwgY2hhciAH + + + + true + Foo + + + + + + + + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use Symfony\Component\DependencyInjection\ContainerInterface; + use Symfony\Component\DependencyInjection\Reference; + + return static function (ContainerConfigurator $container) { + $services = $container->services(); + + $services->set(App\Service\SomeService::class) + // string, numeric and boolean arguments can be passed "as is" + ->arg(0, 'Foo') + ->arg(1, true) + ->arg(2, 7) + ->arg(3, 3.14) + + // constants: built-in, user-defined, or Enums + ->arg(4, E_ALL) + ->arg(5, \PDO::FETCH_NUM) + ->arg(6, Symfony\Component\HttpKernel\Kernel::VERSION) + ->arg(7, App\Config\SomeEnum::SomeCase) + + // when not using autowiring, you can pass service arguments explicitly + ->arg(8, service('some-service-id')) # fails if service doesn't exist + # passes null if service doesn't exist + ->arg(9, new Reference('some-service-id', Reference::IGNORE_ON_INVALID_REFERENCE)) + + // collection with mixed argument types + ->arg(10, [ + 'first' => true, + 'second' => 'Foo', + ]); + + // ... + }; + Handling Multiple Services ~~~~~~~~~~~~~~~~~~~~~~~~~~ From 547dac6ee151d7ab4966cf0f0668865e4be29057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Fri, 18 Jul 2025 15:57:35 +0200 Subject: [PATCH 16/49] Fixed typo in setup.rst --- setup.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.rst b/setup.rst index 4136c42d693..2b1c3b86f85 100644 --- a/setup.rst +++ b/setup.rst @@ -103,7 +103,7 @@ Git, setup your project with the following commands: You'll probably also need to customize your :ref:`.env file ` and do a few other project-specific tasks (e.g. creating a database). When -working on a existing Symfony application for the first time, it may be useful +working on an existing Symfony application for the first time, it may be useful to run this command which displays information about the project: .. code-block:: terminal From cf5532d122eb6c88e5caf388fb60990b28a0f585 Mon Sep 17 00:00:00 2001 From: Andrii Sukhoi Date: Tue, 9 Jul 2024 15:57:25 +0200 Subject: [PATCH 17/49] Add mentions where to find configCache --- components/dependency_injection/compilation.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/dependency_injection/compilation.rst b/components/dependency_injection/compilation.rst index f3a48b0ee8a..ed06050f7cb 100644 --- a/components/dependency_injection/compilation.rst +++ b/components/dependency_injection/compilation.rst @@ -504,7 +504,8 @@ serves at dumping the compiled container:: The ``file_put_contents()`` function is not atomic. That could cause issues in a production environment with multiple concurrent requests. Instead, use the :ref:`dumpFile() method ` from Symfony Filesystem - component or other methods provided by Symfony (e.g. ``$containerConfigCache->write()``) + component or other methods provided by Symfony (e.g. ``$containerConfigCache->write()`` + which is part of the :doc:`Config component `) which are atomic. ``ProjectServiceContainer`` is the default name given to the dumped container From 164b8fe612a8e4b8ff2e416c3c49dad200d655d3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 18 Jul 2025 16:08:02 +0200 Subject: [PATCH 18/49] Tweaks --- components/dependency_injection/compilation.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/dependency_injection/compilation.rst b/components/dependency_injection/compilation.rst index ed06050f7cb..06233a6baed 100644 --- a/components/dependency_injection/compilation.rst +++ b/components/dependency_injection/compilation.rst @@ -501,12 +501,12 @@ serves at dumping the compiled container:: .. tip:: - The ``file_put_contents()`` function is not atomic. That could cause issues - in a production environment with multiple concurrent requests. Instead, use - the :ref:`dumpFile() method ` from Symfony Filesystem - component or other methods provided by Symfony (e.g. ``$containerConfigCache->write()`` - which is part of the :doc:`Config component `) - which are atomic. + The ``file_put_contents()`` function is not atomic. This can cause issues in + production environments with multiple concurrent requests. Instead, use the + :ref:`dumpFile() method ` from the + :doc:`Filesystem component ` or other atomic methods + provided by Symfony (e.g. the ``$containerConfigCache->write()`` method from + the :doc:`Config component `). ``ProjectServiceContainer`` is the default name given to the dumped container class. However, you can change this with the ``class`` option when you From 4aaca90daf15d09361711a7cf053e35de9524960 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Sun, 20 Jul 2025 17:37:11 +0200 Subject: [PATCH 19/49] Document how to resolve env var at compile time --- .../dependency_injection/compilation.rst | 18 ++++++++++++++++++ configuration/env_var_processors.rst | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/components/dependency_injection/compilation.rst b/components/dependency_injection/compilation.rst index 06233a6baed..9a48003de38 100644 --- a/components/dependency_injection/compilation.rst +++ b/components/dependency_injection/compilation.rst @@ -612,3 +612,21 @@ have the cache will be considered stale. In the full-stack framework the compilation and caching of the container is taken care of for you. + +.. _resolving-env-vars-at-compile-time: + +Resolving Environment Variable At Compile Time +---------------------------------------------- + +Environment variables value can be resolved at compile time by using the following code:: + + $parameterValue = $container->resolveEnvPlaceholders( + $container->getParameter('%env(ENV_VAR_NAME)%'), + true // Resolve to actual values + ); + +.. warning:: + + Environment variables are usually a runtime concern. One of the major drawbacks of resolving them + at compile time is that you'll need to manually clear the cache when changing their value (which is exactly + what you don't have to do for env vars under normal circumstances). diff --git a/configuration/env_var_processors.rst b/configuration/env_var_processors.rst index 1e57fd65387..fbd7d38754b 100644 --- a/configuration/env_var_processors.rst +++ b/configuration/env_var_processors.rst @@ -912,3 +912,9 @@ To enable the new processor in the app, register it as a service and tag. If you're using the :ref:`default services.yaml configuration `, this is already done for you, thanks to :ref:`autoconfiguration `. + +Resolving Environment Variable At Compile Time +---------------------------------------------- + +Although environment variables are usually a runtime concept, you can also resolve them +:ref:`at compile time `. From 696827ca3749a55d8b88225e5fba9a20d14797db Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 22 Jul 2025 16:46:26 +0200 Subject: [PATCH 20/49] Minor reword --- .../dependency_injection/compilation.rst | 18 +++++++++++------- configuration/env_var_processors.rst | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/components/dependency_injection/compilation.rst b/components/dependency_injection/compilation.rst index 9a48003de38..11ef8b23c2f 100644 --- a/components/dependency_injection/compilation.rst +++ b/components/dependency_injection/compilation.rst @@ -618,15 +618,19 @@ have the cache will be considered stale. Resolving Environment Variable At Compile Time ---------------------------------------------- -Environment variables value can be resolved at compile time by using the following code:: +.. caution:: + + **This practice is discouraged**. Use it only if you fully understand the implications. + +By default, environment variables are resolved at runtime. However, you can +force their resolution at compile time using the following code:: $parameterValue = $container->resolveEnvPlaceholders( $container->getParameter('%env(ENV_VAR_NAME)%'), - true // Resolve to actual values + true // resolve to actual values ); -.. warning:: - - Environment variables are usually a runtime concern. One of the major drawbacks of resolving them - at compile time is that you'll need to manually clear the cache when changing their value (which is exactly - what you don't have to do for env vars under normal circumstances). +However, a **major drawback** of this approach is that you must manually clear +the cache when changing the value of an environment variable. This goes +against the typical behavior of environment variables, which are designed +to be dynamic and not require cache invalidation. diff --git a/configuration/env_var_processors.rst b/configuration/env_var_processors.rst index fbd7d38754b..ecf5d37cc05 100644 --- a/configuration/env_var_processors.rst +++ b/configuration/env_var_processors.rst @@ -916,5 +916,5 @@ this is already done for you, thanks to :ref:`autoconfiguration `. From d50c1d481bfb0d469fae36e41b29b97b28bf7840 Mon Sep 17 00:00:00 2001 From: "Phil E. Taylor" Date: Wed, 23 Jul 2025 09:44:53 +0100 Subject: [PATCH 21/49] s/sytsem/system --- reference/configuration/doctrine.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst index 2aa716ae9fc..db6336e1ee6 100644 --- a/reference/configuration/doctrine.rst +++ b/reference/configuration/doctrine.rst @@ -353,7 +353,7 @@ to cache each of Doctrine ORM elements (queries, results, etc.): ->pool('doctrine.result_cache_pool') ->adapters('cache.app') ->pool('doctrine.system_cache_pool') - ->adapters('cache.sytsem'); + ->adapters('cache.system'); $doctrine->orm() // ... From 6e16fec488ba6c1972c77efc134f749d6ce7687c Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 23 Jul 2025 10:51:27 +0200 Subject: [PATCH 22/49] minor --- components/dependency_injection/compilation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/dependency_injection/compilation.rst b/components/dependency_injection/compilation.rst index 11ef8b23c2f..7db22a68d5f 100644 --- a/components/dependency_injection/compilation.rst +++ b/components/dependency_injection/compilation.rst @@ -618,7 +618,7 @@ have the cache will be considered stale. Resolving Environment Variable At Compile Time ---------------------------------------------- -.. caution:: +.. warning:: **This practice is discouraged**. Use it only if you fully understand the implications. From 05760815da8b9ec8ca23fd5000ae3821537ccdc0 Mon Sep 17 00:00:00 2001 From: Mathieu Santostefano Date: Wed, 23 Jul 2025 10:27:06 +0200 Subject: [PATCH 23/49] Add Christopher Hertel as a core team member --- contributing/core_team.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contributing/core_team.rst b/contributing/core_team.rst index d776cd4ed93..932cc390d60 100644 --- a/contributing/core_team.rst +++ b/contributing/core_team.rst @@ -101,7 +101,8 @@ Active Core Members * **Berislav Balogović** (`hypemc`_); * **Mathias Arlaud** (`mtarld`_); * **Florent Morselli** (`spomky`_); - * **Alexandre Daubois** (`alexandre-daubois`_). + * **Alexandre Daubois** (`alexandre-daubois`_); + * **Christopher Hertel** (`chr-hertel`_). * **Security Team** (``@symfony/security`` on GitHub): @@ -378,4 +379,5 @@ discretion of the **Project Leader**. .. _`spomky`: https://github.com/spomky/ .. _`alexandre-daubois`: https://github.com/alexandre-daubois/ .. _`tucksaun`: https://github.com/tucksaun/ +.. _`chr-hertel`: https://github.com/chr-hertel/ .. _`the releases page`: https://symfony.com/releases From 0918b691d9af0cd7e6540e09e520d88a8c104cee Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 18 Jul 2025 09:34:53 +0200 Subject: [PATCH 24/49] [HtmlSanitizer] Fix method names --- html_sanitizer.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/html_sanitizer.rst b/html_sanitizer.rst index 17096db913f..920d37a81c3 100644 --- a/html_sanitizer.rst +++ b/html_sanitizer.rst @@ -819,16 +819,16 @@ URLs of ```` elements: (new HtmlSanitizerConfig()) // if `true`, all URLs using the `http://` scheme will be converted to // use the `https://` scheme instead. `http` still needs to be - // allowed in `allowedLinkSchemes` + // allowed in `allowLinkSchemes` ->forceHttpsUrls() // specifies the allowed URL schemes. If the URL has a different scheme, the // attribute will be dropped - ->allowedLinkSchemes(['http', 'https', 'mailto']) + ->allowLinkSchemes(['http', 'https', 'mailto']) // specifies the allowed hosts, the attribute will be dropped if the // URL contains a different host which is not a subdomain of the allowed host - ->allowedLinkHosts(['symfony.com']) // Also allows any subdomain (i.e. www.symfony.com) + ->allowLinkHosts(['symfony.com']) // Also allows any subdomain (i.e. www.symfony.com) // whether to allow relative links (i.e. URLs without scheme and host) ->allowRelativeLinks() @@ -938,16 +938,16 @@ the HTML sanitizer: ``src``, ``href``, ``lowsrc``, ``background`` and ``ping``. (new HtmlSanitizerConfig()) // if `true`, all URLs using the `http://` scheme will be converted to // use the `https://` scheme instead. `http` still needs to be - // allowed in `allowedMediaSchemes` + // allowed in `allowMediaSchemes` ->forceHttpsUrls() // specifies the allowed URL schemes. If the URL has a different scheme, the // attribute will be dropped - ->allowedMediaSchemes(['http', 'https', 'mailto']) + ->allowMediaSchemes(['http', 'https', 'mailto']) // specifies the allowed hosts, the attribute will be dropped if the URL // contains a different host which is not a subdomain of the allowed host - ->allowedMediaHosts(['symfony.com']) // Also allows any subdomain (i.e. www.symfony.com) + ->allowMediaHosts(['symfony.com']) // Also allows any subdomain (i.e. www.symfony.com) // whether to allow relative URLs (i.e. URLs without scheme and host) ->allowRelativeMedias() From 609d93af6f76714534efdbaeff85b4c1c47f08bd Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 23 Jul 2025 12:06:50 +0200 Subject: [PATCH 25/49] [Testing] Update a section heading to improve search results --- testing.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/testing.rst b/testing.rst index b88a55832a5..189440f5195 100644 --- a/testing.rst +++ b/testing.rst @@ -745,8 +745,10 @@ a shortcut to make AJAX requests:: // the required HTTP_X_REQUESTED_WITH header is added automatically $client->xmlHttpRequest('POST', '/submit', ['name' => 'Fabien']); -Sending Custom Headers -...................... +.. _sending-custom-headers: + +Sending Custom HTTP Headers +........................... If your application behaves according to some HTTP headers, pass them as the second argument of ``createClient()``:: From 2f40c4097fa373e4e5c5bec4cf8e15967b4bc80c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 23 Jul 2025 22:03:43 +0200 Subject: [PATCH 26/49] remove invalid redirection entry --- _build/redirection_map | 1 - 1 file changed, 1 deletion(-) diff --git a/_build/redirection_map b/_build/redirection_map index 8d121257713..995ea20f4cc 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -570,7 +570,6 @@ /frontend/encore/server-data /frontend/server-data /components/serializer /serializer /serializer/custom_encoder /serializer/encoders#serializer-custom-encoder -/components/string /string /form/button_based_validation /form/validation_groups /form/data_based_validation /form/validation_groups /form/validation_group_service_resolver /form/validation_groups From 6a79b526bc97fad7c4bfeada27578f1814fe0dde Mon Sep 17 00:00:00 2001 From: Arend Hummeling Date: Thu, 24 Jul 2025 10:21:58 +0200 Subject: [PATCH 27/49] fix: resolve confusing typo in php config example --- logging/monolog_email.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logging/monolog_email.rst b/logging/monolog_email.rst index 99a416913c8..d52629e0797 100644 --- a/logging/monolog_email.rst +++ b/logging/monolog_email.rst @@ -180,7 +180,7 @@ You can adjust the time period using the ``time`` option: // ... $monolog->handler('deduplicated') - ->type('deduplicated') + ->type('deduplication') // the time in seconds during which duplicate entries are discarded (default: 60) ->time(10) ->handler('symfony_mailer') @@ -304,7 +304,7 @@ get logged on the server as well as the emails being sent: ; $monolog->handler('deduplicated') - ->type('deduplicated') + ->type('deduplication') ->handler('symfony_mailer') ; From 23b89f68270c706c5d9c7597c08be697a5a9b832 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 23 Jul 2025 10:50:21 +0200 Subject: [PATCH 28/49] minor #21234 Typo s/sytsem/system (PhilETaylor) This PR was merged into the 7.3 branch. Discussion ---------- Typo s/sytsem/system Simple typo fix Commits ------- d50c1d481 s/sytsem/system --- reference/configuration/doctrine.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst index 9fc9a0b16a8..9b1569622e7 100644 --- a/reference/configuration/doctrine.rst +++ b/reference/configuration/doctrine.rst @@ -353,7 +353,7 @@ to cache each of Doctrine ORM elements (queries, results, etc.): ->pool('doctrine.result_cache_pool') ->adapters('cache.app') ->pool('doctrine.system_cache_pool') - ->adapters('cache.sytsem'); + ->adapters('cache.system'); $doctrine->orm() // ... From 2bc78c16afa3e87c5e4cc90ce4808837ee5ecced Mon Sep 17 00:00:00 2001 From: ahmetkun Date: Thu, 24 Jul 2025 23:11:49 +0300 Subject: [PATCH 29/49] Update rate_limiter.rst --- rate_limiter.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rate_limiter.rst b/rate_limiter.rst index 3a517c37bd4..5fd453f0534 100644 --- a/rate_limiter.rst +++ b/rate_limiter.rst @@ -646,7 +646,7 @@ Then, inject and use as normal:: use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\RateLimiter\RateLimiterFactory; + use Symfony\Component\RateLimiter\RateLimiterFactoryInterface; class ContactController extends AbstractController { From e946b313b5ce28a030874c88ba9486ef5724de6f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 25 Jul 2025 13:20:13 +0200 Subject: [PATCH 30/49] Rewords --- serializer.rst | 45 +++--- serializer/streaming_json.rst | 277 ++++++++++++++++------------------ 2 files changed, 154 insertions(+), 168 deletions(-) diff --git a/serializer.rst b/serializer.rst index be31fc66a9e..eb06f1b34a1 100644 --- a/serializer.rst +++ b/serializer.rst @@ -629,37 +629,34 @@ all the properties of the class:: // ... } -Serializing JSON using streams +Serializing JSON Using Streams ------------------------------ -Symfony is able of encoding PHP data structures to JSON streams and decoding -JSON streams back into PHP data structures. +Symfony can encode PHP data structures to JSON streams and decode JSON streams +back into PHP data structures. -To do so, it relies on the JsonStreamer component, which is designed for high -efficiency and can process large JSON data incrementally without needing to -load the entire content into memory. +To do this, it relies on the :doc:`JsonStreamer component `, +which is designed for high efficiency and can process large JSON data incrementally, +without needing to load the entire content into memory. -When deciding between the :doc:`Serializer component ` and the -JsonStreamer component, consider the following: +When deciding between the Serializer component and the JsonStreamer component, +consider the following: -- **Serializer Component**: Ideal for scenarios requiring flexibility, such as - dynamically manipulating object shapes using normalizers and denormalizers, - or handling complex objects which multiple serialization representation. - Plus, it allows working with formats beyond JSON (and even with a custom - format of yours). +* **Serializer Component**: Best suited for use cases that require flexibility, + such as dynamically manipulating object structures using normalizers and + denormalizers, or handling complex objects with multiple serialization + formats. It also supports output formats beyond JSON (including your own + custom ones). +* **JsonStreamer Component**: Best suited for simple objects and scenarios that + demand high performance and low memory usage. It's particularly effective + for processing very large JSON datasets or when streaming JSON in real-time + without loading the entire dataset into memory. -- **JsonStreamer Component**: Ideal for simple objects and tasks that - demand high performance and minimal memory usage. It's particularly - effective when processing very large JSON datasets or in scenarios that - require streaming JSON in real-time without loading the entire dataset - into memory. +The choice depends on your specific use case. The JsonStreamer component is +tailored for performance and memory efficiency, whereas the Serializer +component provides greater flexibility and broader format support. -Choosing between the two depends on your specific use case requirements. -The JsonStreamer component is tailored to optimize for performance and memory -efficiency, while the Serializer component offers flexibility and broader -format support. - -Read more about streaming JSON in :doc:`/serializer/streaming_json`. +Read more about :doc:`streaming JSON `. Serializing to or from PHP Arrays --------------------------------- diff --git a/serializer/streaming_json.rst b/serializer/streaming_json.rst index 3cf4de3ef0b..3fd44824bc6 100644 --- a/serializer/streaming_json.rst +++ b/serializer/streaming_json.rst @@ -1,25 +1,28 @@ Streaming JSON ============== -Symfony is able of encoding PHP data structures to JSON streams and decoding -JSON streams back into PHP data structures. +.. versionadded:: 7.3 -To do so, it relies on the JsonStreamer component, which is designed for high -efficiency and can process large JSON data incrementally without needing to -load the entire content into memory. + The JsonStreamer component was introduced in Symfony 7.3 as an + :doc:`experimental feature `. -.. tip:: +Symfony can encode PHP data structures to JSON streams and decode JSON streams +back into PHP data structures. + +To do so, it relies on the **JsonStreamer** component, which is designed for +high efficiency and can process large JSON data incrementally without needing +to load the entire content into memory. - This component is ideal for handling APIs or interacting with third-party - APIs. It transforms incoming JSON request payloads into PHP objects that - your application can work with. Similarly, it converts processed PHP - objects into a JSON stream for outgoing responses. +This component is ideal for handling APIs or interacting with third-party APIs. +It transforms incoming JSON request payloads into PHP objects that your +application can work with. Similarly, it converts processed PHP objects into a +JSON stream for outgoing responses. Installation ------------ -To install the JsonStreamer component in applications that use -:ref:`Symfony Flex `, run this command: +In applications using :ref:`Symfony Flex `, run this command to +install the JsonStreamer component: .. code-block:: terminal @@ -27,38 +30,43 @@ To install the JsonStreamer component in applications that use .. include:: /components/require_autoload.rst.inc -.. warning:: - - The JsonStreamer component is :doc:`experimental ` - and could be changed at any time without prior notice. - -Encoding objects +Encoding Objects ---------------- -Let's say that we have the following ``Cat`` class:: +JsonStreamer only works with PHP classes that have **no constructor** and are +composed solely of **public properties**, like `DTO classes`_. Consider the +following ``Cat`` class:: // src/Dto/Cat.php namespace App\Dto; - use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; - - #[JsonStreamable] class Cat { public string $name; public string $age; } -.. warning:: +To encode ``Cat`` objects into a JSON stream (e.g., to send them in an API +response), first apply the ``#[JsonStreamable]`` attribute to the class. This +attribute is optional, but it :ref:`improves performance ` +by pre-generating encoding and decoding files during cache warm-up:: - The JsonStreamer only works with PHP classes without constructor and - composed by public properties only. + namespace App\Dto; -If you want to encode ``Cat`` objects to a JSON stream (e.g. to send them -via an API response), you can get the ``json_streamer.stream_writer`` service by using -the :class:`Symfony\\Component\\JsonStreamer\\StreamWriterInterface` parameter type -with the ``$jsonStreamWriter`` name, and use the :method:`Symfony\\Component\\JsonStreamer\\StreamWriterInterface::write` -method: + use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; + + #[JsonStreamable] + class Cat + { + // ... + } + +Next, inject the JSON stream writer into your service. The service ``id`` is +``json_streamer.stream_writer``, but you can also get it by type-hinting a +``$jsonStreamWriter`` argument with :class:`Symfony\\Component\\JsonStreamer\\StreamWriterInterface`. + +Use the :method:`Symfony\\Component\\JsonStreamer\\StreamWriterInterface::write` +method of the service to perform the actual JSON conversion: .. configuration-block:: @@ -107,20 +115,21 @@ method: // ... -.. note:: +.. tip:: You can explicitly inject the ``json_streamer.stream_writer`` service by using the ``#[Target('json_streamer.stream_writer')]`` autowire attribute. -Decoding objects +Decoding Objects ---------------- -Besides encoding objects to JSON, you can decode JSON to objects. +In addition to encoding, you can decode JSON into PHP objects. -To do so, you can get the ``json_streamer.stream_reader`` service by using the -:class:`Symfony\\Component\\JsonStreamer\\StreamReaderInterface` parameter type -with the ``$jsonStreamReader`` name, and use the :method:`Symfony\\Component\\JsonStreamer\\StreamReaderInterface::read` -method: +To do this, inject the JSON stream reader into your service. The service ``id`` is +``json_streamer.stream_reader``, but you can also get it by type-hinting a +``$jsonStreamReader`` argument with :class:`Symfony\\Component\\JsonStreamer\\StreamReaderInterface`. +Next, use the :method:`Symfony\\Component\\JsonStreamer\\StreamReaderInterface::read` +method to perform the actual JSON parsing: .. configuration-block:: @@ -237,71 +246,56 @@ method: } } -.. note:: +.. tip:: You can explicitly inject the ``json_streamer.stream_reader`` service by using the ``#[Target('json_streamer.stream_reader')]`` autowire attribute. -The upper code demonstrates two different approaches to decoding JSON data -using the JsonStreamer: +The examples above demonstrate two different approaches to decoding JSON data +using JsonStreamer: * decoding from a stream (``pickTheTenthCat``) -* decoding from a string (``listEligibleCatNames``). - -Both methods work with the same JSON data but differ in memory usage and -speed optimization. +* decoding from a string (``listEligibleCatNames``) +Both methods handle the same JSON data but differ in memory usage and performance. +Use streams if optimizing memory usage is more important. Use strings if +performance is more important. -Decoding from a stream +Decoding from a Stream ~~~~~~~~~~~~~~~~~~~~~~ In the ``pickTheTenthCat`` method, the JSON data is read as a stream using -:phpfunction:`fopen`. Streams are useful when working with large files -because the data is processed incrementally rather than loading the entire -file into memory. +:phpfunction:`fopen`. This is useful for large files, as the data is processed +incrementally rather than being fully loaded into memory. -To improve memory efficiency, the JsonStreamer creates `ghost objects`_ -instead of fully instantiating objects. Ghosts objects are lightweight -placeholders that represent the objects but don't fully load their data -into memory until it's needed. This approach reduces memory usage, especially -for large datasets. +To optimize memory usage, JsonStreamer creates `ghost objects`_ instead of +fully instantiating them. These lightweight placeholders delay object creation +until the data is actually needed. -* Advantage: Efficient memory usage, suitable for very large JSON files. -* Disadvantage: Slightly slower than decoding a full string because data is - loaded on-demand. +* Advantage: Efficient memory usage, ideal for very large JSON files. +* Disadvantage: Slightly slower due to lazy loading. -Decoding from a string +Decoding from a String ~~~~~~~~~~~~~~~~~~~~~~ -In the ``listEligibleCatNames`` method, the entire JSON file is read into -a string using :phpfunction:`file_get_contents`. This string is then passed -to the decoder, which fully instantiates all the objects in the JSON data -upfront. +In the ``listEligibleCatNames`` method, the entire JSON file is read into a +string using :phpfunction:`file_get_contents`. The decoder then instantiates +all the objects immediately. -This approach is faster because all the objects are created immediately, -making subsequent operations on the data quicker. However, it uses more -memory since the entire file content and all objects are loaded at once. +This approach is faster because all objects are created immediately, but it +requires more memory. -* Advantage: Faster processing, suitable for small to medium-sized JSON files. -* Disadvantage: Higher memory usage, not ideal for large JSON files. +* Advantage: Faster, ideal for small to medium JSON files. +* Disadvantage: Higher memory usage, unsuitable for large files. -.. tip:: - - Prefer stream decoding when working with large JSON files to conserve - memory. - - Prefer string decoding instead when performance is more critical and the - JSON file size is manageable. - -Enabling PHPDoc reading +Enabling PHPDoc Reading ----------------------- -The JsonStreamer component can be able to process advanced PHPDoc type -definitions, such as generics, and read/generate JSON for complex PHP -objects. +The JsonStreamer component can read advanced PHPDoc type definitions (e.g., +generics) and process complex PHP objects accordingly. -For example, let's consider this ``Shelter`` class that defines a generic -``TAnimal`` type, which can be a ``Cat`` or a ``Dog``:: +Consider the ``Shelter`` class that defines a generic ``TAnimal`` type, which +can be a ``Cat`` or a ``Dog``:: // src/Dto/Shelter.php namespace App\Dto; @@ -320,16 +314,15 @@ For example, let's consider this ``Shelter`` class that defines a generic public array $animals; } - -To enable PHPDoc interpretation, run the following command: +To enable PHPDoc parsing, run: .. code-block:: terminal $ composer require phpstan/phpdoc-parser -Then, when encoding/decoding an instance of the ``Shelter`` class, you can -specify the concrete type information, and the JsonStreamer will deal with the -correct JSON structure:: +Then, when encoding/decoding a ``Shelter`` instance, you can specify the +concrete type information, and JsonStreamer will correctly interpret the JSON +structure:: use App\Dto\Cat; use App\Dto\Shelter; @@ -349,18 +342,17 @@ correct JSON structure:: $catShelter = $jsonStreamReader->read($json, $type); // will be populated with Cat instances -Configuring encoding/decoding +Configuring Encoding/Decoding ----------------------------- -While it's not recommended to change to object shape and values during -encoding and decoding, it is sometimes unavoidable. +While it's usually best not to alter the shape or values of objects during +serialization, sometimes it's necessary. -Configuring the encoded name +Configuring the Encoded Name ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -It is possible to configure the JSON key associated to a property thanks to -the :class:`Symfony\\Component\\JsonStreamer\\Attribute\\StreamedName` -attribute:: +You can configure the JSON key for a property using the +:class:`Symfony\\Component\\JsonStreamer\\Attribute\\StreamedName` attribute:: // src/Dto/Duck.php namespace App\Dto; @@ -375,7 +367,7 @@ attribute:: public string $id; } -By doing so, the ``Duck::$id`` property will be mapped to the ``@id`` JSON key:: +This maps the ``Duck::$id`` property to the ``@id`` JSON key:: use App\Dto\Duck; use Symfony\Component\TypeInfo\Type; @@ -392,19 +384,20 @@ By doing so, the ``Duck::$id`` property will be mapped to the ``@id`` JSON key:: // "@id": "/ducks/daffy" // } -Configuring the encoded value +Configuring the Encoded Value ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you need to manipulate the value related to a property during the encoding -process, you can use the :class:`Symfony\\Component\\JsonStreamer\\Attribute\\ValueTransformer` -attribute. Its ``nativeToStream`` property takes a callable, or a :ref:`value transformer service id `. +To transform a property's value during encoding, use the +:class:`Symfony\\Component\\JsonStreamer\\Attribute\\ValueTransformer` +attribute. Its ``nativeToStream`` option accepts a callable or a +:ref:`value transformer service id `. -When a callable is specified, it must either be a public static method or -non-anonymous function with the following signature:: +The callable must be a public static method or non-anonymous function with this +signature:: $transformer = function (mixed $data, array $options = []): mixed { /* ... */ }; -Then, you just have to specify the function identifier in the attribute:: +Then specify it in the attribute:: // src/Dto/Duck.php namespace App\Dto; @@ -427,8 +420,8 @@ Then, you just have to specify the function identifier in the attribute:: } } -For example, by configuring the ``Duck`` class like above, the ``name`` and -``height`` values will be transformed during encoding:: +The following example transforms the ``name`` and ``height`` properties during +encoding:: use App\Dto\Duck; use Symfony\Component\TypeInfo\Type; @@ -447,19 +440,20 @@ For example, by configuring the ``Duck`` class like above, the ``name`` and // "height": "50.83cm" // } -Configuring the decoded value +Configuring the Decoded Value ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can as well manipulate the value related to a property during decoding -using the :class:`Symfony\\Component\\JsonStreamer\\Attribute\\ValueTransformer` -attribute. Its ``streamToNative`` property can take either a callable or a :ref:`value transformer service id `. +To transform a property's value during decoding, use the +:class:`Symfony\\Component\\JsonStreamer\\Attribute\\ValueTransformer` +attribute. Its ``streamToNative`` option accepts a callable or a +:ref:`value transformer service id `. -When a callable is specified, it must either be a public static method or -a non-anonymous function with the following signature:: +The callable must be a public static method or non-anonymous function with this +signature:: $valueTransformer = function (mixed $data, array $options = []): mixed { /* ... */ }; -You can specify a function identifier in the attribute as follows:: +Then specify it in the attribute:: // src/Dto/Duck.php namespace App\Dto; @@ -487,8 +481,7 @@ You can specify a function identifier in the attribute as follows:: } } -For instance, the above configuration for the ``Duck`` class will transform -the `name` property from the input JSON during decoding:: +This will extract first and last names from a full name in the input JSON:: use App\Dto\Duck; use Symfony\Component\TypeInfo\Type; @@ -508,13 +501,11 @@ the `name` property from the input JSON during decoding:: .. _json-streamer-transform-with-services: -Transform value using services -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When static methods or functions are not enough, you can transform the value -thanks to a value transformer service. +Transforming Value Using Services +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To do so, create a service implementing the :class:`Symfony\\Component\\JsonStreamer\\ValueTransformer\\ValueTransformerInterface`:: +When callables are not enough, you can use a service implementing the +:class:`Symfony\\Component\\JsonStreamer\\ValueTransformer\\ValueTransformerInterface`:: // src/Transformer/DogUrlTransformer.php namespace App\Transformer; @@ -547,11 +538,10 @@ To do so, create a service implementing the :class:`Symfony\\Component\\JsonStre .. note:: - The ``getStreamValueType`` method should return the type of what the value - will be in the JSON stream. + The ``getStreamValueType()`` method must return the value's type as it will + appear in the JSON stream. -And then, configure the :class:`Symfony\\Component\\JsonStreamer\\Attribute\\ValueTransformer` -attribute to use that service:: +To use this transformer in a class, configure the ``#[ValueTransformer]`` attribute:: // src/Dto/Dog.php namespace App\Dto; @@ -571,18 +561,18 @@ attribute to use that service:: .. tip:: - The value transformers will be intensively called during the - decoding and encoding. So be sure to keep them as fast as possible - (avoid calling external APIs or the database for example). + Value transformers are called frequently during encoding and decoding. Keep + them lightweight and avoid calls to external APIs or the database. -Configure keys and values dynamically -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Configuring Keys and Values Dynamically +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The JsonStreamer leverages services implementing the :class:`Symfony\\Component\\JsonStreamer\\Mapping\\PropertyMetadataLoaderInterface` -to determine the shape and values of objects during encoding/decoding. +JsonStreamer uses services that implement the +:class:`Symfony\\Component\\JsonStreamer\\Mapping\\PropertyMetadataLoaderInterface` +to control the shape and values of objects during encoding/decoding. -These services are highly flexible and can be decorated to handle dynamic -configurations, offering much greater power compared to using attributes:: +These services are highly flexible and can be decorated to support dynamic +configurations, providing more flexibility than attributes:: namespace App\Streamer\SensitivePropertyMetadataLoader; @@ -644,25 +634,23 @@ configurations, offering much greater power compared to using attributes:: } } -However, this flexibility comes with complexity. Decorating property metadata -loaders requires a deep understanding of the system. +Although powerful, this approach introduces complexity. Decorating property +metadata loaders requires a deep understanding of the internals. + +For most use cases, attribute-based configuration is sufficient. Reserve +dynamic loaders for advanced scenarios. -For most use cases, the attributes approach is sufficient, and the dynamic -capabilities of property metadata loaders should be reserved for scenarios -where their additional power is genuinely necessary. +.. _json-streamer-streamable-attribute: -Marking objects as streamable +Marking Objects as Streamable ----------------------------- -The ``JsonStreamable`` attribute is used to mark a class as streamable. -While this attribute is not mandatory, it is highly recommended because it -plays a crucial role during the cache warm-up process by generating the -files necessary for encoding and decoding operations, and thereby improving -performance. +The ``JsonStreamable`` attribute marks a class as streamable. While not strictly +required, it's highly recommended because it enables cache warm-up to pre-generate +encoding/decoding files, improving performance. -It includes two properties: ``asObject`` and ``asList``. These properties -define the structure in which the marked class should be prepared during the -cache warm-up process:: +It includes two optional properties: ``asObject`` and ``asList``, which define +how the class should be prepared during cache warm-up:: use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; @@ -672,4 +660,5 @@ cache warm-up process:: // ... } +.. _`DTO classes`: https://en.wikipedia.org/wiki/Data_transfer_object .. _ghost objects: https://en.wikipedia.org/wiki/Lazy_loading#Ghost From c8b2959e7a8ae08db86ce964378b0ce122dbdbf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFck=20Piera?= Date: Fri, 25 Jul 2025 16:38:09 +0200 Subject: [PATCH 31/49] Fix extra space in inherit_data_option.rst --- form/inherit_data_option.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/form/inherit_data_option.rst b/form/inherit_data_option.rst index 2caa0afcdbe..8067e932c5a 100644 --- a/form/inherit_data_option.rst +++ b/form/inherit_data_option.rst @@ -29,7 +29,7 @@ entities, a ``Company`` and a ``Customer``:: private string $firstName; private string $lastName; - private string $address; + private string $address; private string $zipcode; private string $city; private string $country; From 8bf25c84a2a9f58c99d02c5938266dbfec7ba012 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 28 Jul 2025 08:43:50 +0200 Subject: [PATCH 32/49] Readd String component URL redirection --- _build/redirection_map | 1 + 1 file changed, 1 insertion(+) diff --git a/_build/redirection_map b/_build/redirection_map index 560f241b93c..c30723eac58 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -575,6 +575,7 @@ /doctrine/reverse_engineering /doctrine#doctrine-adding-mapping /components/serializer /serializer /serializer/custom_encoder /serializer/encoders#serializer-custom-encoder +/components/string /string /form/button_based_validation /form/validation_groups /form/data_based_validation /form/validation_groups /form/validation_group_service_resolver /form/validation_groups From 5c9b8735424af532b1242e5ed3525afb8f4a3bc7 Mon Sep 17 00:00:00 2001 From: Jan Rosier Date: Tue, 29 Jul 2025 17:57:44 +0200 Subject: [PATCH 33/49] Update sreencast title --- page_creation.rst | 4 ++-- setup.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/page_creation.rst b/page_creation.rst index 3315dff279d..0e2fd78e180 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -18,7 +18,7 @@ two-step process: .. admonition:: Screencast :class: screencast - Do you prefer video tutorials? Check out the `Harmonious Development with Symfony`_ + Do you prefer video tutorials? Check out the `Cosmic Coding with Symfony`_ screencast series. .. seealso:: @@ -302,5 +302,5 @@ Go Deeper with HTTP & Framework Fundamentals .. _`Twig`: https://twig.symfony.com .. _`Composer`: https://getcomposer.org -.. _`Harmonious Development with Symfony`: https://symfonycasts.com/screencast/symfony/setup +.. _`Cosmic Coding with Symfony`: https://symfonycasts.com/screencast/symfony/setup .. _`attributes`: https://www.php.net/manual/en/language.attributes.overview.php diff --git a/setup.rst b/setup.rst index f78d8047dfd..0f103ce476d 100644 --- a/setup.rst +++ b/setup.rst @@ -4,7 +4,7 @@ Installing & Setting up the Symfony Framework .. admonition:: Screencast :class: screencast - Do you prefer video tutorials? Check out the `Harmonious Development with Symfony`_ + Do you prefer video tutorials? Check out the `Cosmic Coding with Symfony`_ screencast series. .. _symfony-tech-requirements: @@ -311,7 +311,7 @@ Learn More setup/web_server_configuration setup/* -.. _`Harmonious Development with Symfony`: https://symfonycasts.com/screencast/symfony +.. _`Cosmic Coding with Symfony`: https://symfonycasts.com/screencast/symfony .. _`Install Composer`: https://getcomposer.org/download/ .. _`install the Symfony CLI`: https://symfony.com/download .. _`symfony-cli/symfony-cli GitHub repository`: https://github.com/symfony-cli/symfony-cli From 75cc14558e0ee5984dc673156fbf8273bcfba1c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Marinetti?= Date: Wed, 30 Jul 2025 11:35:26 +0200 Subject: [PATCH 34/49] minor #21259 add missing use in code example --- routing.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/routing.rst b/routing.rst index 4f34e084d61..69e6cebb01c 100644 --- a/routing.rst +++ b/routing.rst @@ -1559,6 +1559,7 @@ This way, the ``product_show`` alias could be deprecated. namespace App\Controller; use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\Routing\Attribute\DeprecatedAlias; use Symfony\Component\Routing\Attribute\Route; class ProductController From 96c1e2d94d1139a9e5a2e106542a30fd48e9387e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 30 Jul 2025 15:10:03 +0200 Subject: [PATCH 35/49] Add a missing versionadded directive --- routing.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/routing.rst b/routing.rst index 69e6cebb01c..9925b323304 100644 --- a/routing.rst +++ b/routing.rst @@ -1661,6 +1661,10 @@ This way, the ``product_show`` alias could be deprecated. ) ; +.. versionadded:: 7.3 + + The ``DeprecatedAlias`` class for PHP attributes was introduced in Symfony 7.3. + In this example, every time the ``product_show`` alias is used, a deprecation warning is triggered, advising you to stop using this route and prefer using ``product_details``. From 86a10b474c67889202acbf6e7616cbb191a1086a Mon Sep 17 00:00:00 2001 From: Mathieu Date: Fri, 1 Aug 2025 19:09:08 +0200 Subject: [PATCH 36/49] [ExpressionLanguage] Fix backslashes count --- reference/formats/expression_language.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/formats/expression_language.rst b/reference/formats/expression_language.rst index d064eedb02a..9052b2f9520 100644 --- a/reference/formats/expression_language.rst +++ b/reference/formats/expression_language.rst @@ -178,7 +178,7 @@ This also works with class constants:: } var_dump($expressionLanguage->evaluate( - 'constant("App\\\SomeNamespace\\\Foo::API_ENDPOINT")' + 'constant("App\\\\SomeNamespace\\\\Foo::API_ENDPOINT")' )); This will print out ``/api``. @@ -196,7 +196,7 @@ This function will return the case of an enumeration:: } var_dump(App\Enum\Foo::Bar === $expressionLanguage->evaluate( - 'enum("App\\\SomeNamespace\\\Foo::Bar")' + 'enum("App\\\\SomeNamespace\\\\Foo::Bar")' )); This will print out ``true``. From 622c018c9fba1a76797652a69a0f44b9f4eeb7a9 Mon Sep 17 00:00:00 2001 From: Sajad Torkamani Date: Sun, 3 Aug 2025 17:06:28 +0100 Subject: [PATCH 37/49] fix typo --- testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing.rst b/testing.rst index 189440f5195..49680ce26c9 100644 --- a/testing.rst +++ b/testing.rst @@ -113,7 +113,7 @@ to use the Symfony Kernel to fetch a service from the dependency injection container. Symfony provides a :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\KernelTestCase` -class to help you creating and booting the kernel in your tests using +class to help you create and boot the kernel in your tests using ``bootKernel()``:: // tests/Service/NewsletterGeneratorTest.php From c0a518da73dd6463770520da535daa96fe4c54f0 Mon Sep 17 00:00:00 2001 From: Raistlfiren Date: Mon, 4 Aug 2025 16:08:47 -0500 Subject: [PATCH 38/49] PHPUnit Version update PHPUnit V10 uses `bootstrap` instead of `extension`. - Element 'extension': This element is not expected. Expected is ( bootstrap ). --- testing.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testing.rst b/testing.rst index 49680ce26c9..21a788d8a17 100644 --- a/testing.rst +++ b/testing.rst @@ -397,6 +397,8 @@ Now, enable it as a PHPUnit extension: + + From df8ab070a0fc813f6aa6146427ff61442686aa72 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 6 Aug 2025 12:54:07 +0200 Subject: [PATCH 39/49] Tweaks --- testing.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/testing.rst b/testing.rst index 21a788d8a17..042f381caa6 100644 --- a/testing.rst +++ b/testing.rst @@ -396,9 +396,10 @@ Now, enable it as a PHPUnit extension: - - + + + From fa5a1aa845a08a251992aa60b3e94b8a673f02c5 Mon Sep 17 00:00:00 2001 From: Chad Meyers Date: Tue, 5 Aug 2025 09:15:36 -0500 Subject: [PATCH 40/49] [Testing] fix phpunit.dist.xml code example --- testing/end_to_end.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/end_to_end.rst b/testing/end_to_end.rst index 80e970bd2cd..000f6c623cc 100644 --- a/testing/end_to_end.rst +++ b/testing/end_to_end.rst @@ -80,9 +80,9 @@ To register the Panther extension, add the following lines to ``phpunit.xml.dist .. code-block:: xml - + - + Without the extension, the web server used by Panther to serve the application From 3e180f7cb546dad7e80d60a9b09ee87449b54e03 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 6 Aug 2025 13:04:36 +0200 Subject: [PATCH 41/49] Tweaks --- testing/end_to_end.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/testing/end_to_end.rst b/testing/end_to_end.rst index 000f6c623cc..9b3829cd1bc 100644 --- a/testing/end_to_end.rst +++ b/testing/end_to_end.rst @@ -76,13 +76,17 @@ When using the extension in conjunction with the ``PANTHER_ERROR_SCREENSHOT_DIR` environment variable, tests using the Panther client that fail or error (after the client is created) will automatically get a screenshot taken to help debugging. -To register the Panther extension, add the following lines to ``phpunit.xml.dist``: +To register the Panther extension, add the following lines to ``phpunit.dist.xml`` +(in legacy PHPUnit versions older than 10, the file is named ``phpunit.xml.dist``): .. code-block:: xml + + + Without the extension, the web server used by Panther to serve the application From 2b6d28bc506e4e63249c0985a1e849c1e62a78de Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 6 Aug 2025 13:11:06 +0200 Subject: [PATCH 42/49] Updates related to the main PHPUnit configuration file --- bundles/best_practices.rst | 2 +- create_framework/unit_testing.rst | 2 +- setup/upgrade_major.rst | 2 +- testing.rst | 16 ++++++++-------- testing/bootstrap.rst | 4 ++-- testing/end_to_end.rst | 4 ++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst index 99d254b7929..5f0259e074e 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -188,7 +188,7 @@ the ``tests/`` directory. Tests should follow the following principles: .. note:: A test suite must not contain ``AllTests.php`` scripts, but must rely on the - existence of a ``phpunit.xml.dist`` file. + existence of a ``phpunit.dist.xml`` file. Continuous Integration ---------------------- diff --git a/create_framework/unit_testing.rst b/create_framework/unit_testing.rst index f935a024b20..8d35b3a310c 100644 --- a/create_framework/unit_testing.rst +++ b/create_framework/unit_testing.rst @@ -14,7 +14,7 @@ using `PHPUnit`_. At first, install PHPUnit as a development dependency: $ composer require --dev phpunit/phpunit:^10.0 -Then, create a PHPUnit configuration file in ``example.com/phpunit.xml.dist``: +Then, create a PHPUnit configuration file in ``example.com/phpunit.dist.xml``: .. code-block:: xml diff --git a/setup/upgrade_major.rst b/setup/upgrade_major.rst index ab05f2b202b..bfd2714532e 100644 --- a/setup/upgrade_major.rst +++ b/setup/upgrade_major.rst @@ -114,7 +114,7 @@ done! .. code-block:: xml - + diff --git a/testing.rst b/testing.rst index 042f381caa6..31237e6344d 100644 --- a/testing.rst +++ b/testing.rst @@ -55,16 +55,16 @@ This command automatically runs your application tests. Each test is a PHP class ending with "Test" (e.g. ``BlogControllerTest``) that lives in the ``tests/`` directory of your application. -PHPUnit is configured by the ``phpunit.xml.dist`` file in the root of your -application. The default configuration provided by Symfony Flex will be -enough in most cases. Read the `PHPUnit documentation`_ to discover all -possible configuration options (e.g. to enable code coverage or to split -your test into multiple "test suites"). +PHPUnit is configured by the ``phpunit.dist.xml`` file in the root of your +application (in PHPUnit versions older than 10, the file is named ``phpunit.xml.dist``). +The default configuration provided by Symfony Flex will be enough in most cases. +Read the `PHPUnit documentation`_ to discover all possible configuration options +(e.g. to enable code coverage or to split your test into multiple "test suites"). .. note:: :ref:`Symfony Flex ` automatically creates - ``phpunit.xml.dist`` and ``tests/bootstrap.php``. If these files are + ``phpunit.dist.xml`` and ``tests/bootstrap.php``. If these files are missing, you can try running the recipe again using ``composer recipes:install phpunit/phpunit --force -v``. @@ -81,7 +81,7 @@ By convention, the ``tests/`` directory should replicate the directory of your application for unit tests. So, if you're testing a class in the ``src/Form/`` directory, put the test in the ``tests/Form/`` directory. Autoloading is automatically enabled via the ``vendor/autoload.php`` file -(as configured by default in the ``phpunit.xml.dist`` file). +(as configured by default in the ``phpunit.dist.xml`` file). You can run tests using the ``bin/phpunit`` command: @@ -391,7 +391,7 @@ Now, enable it as a PHPUnit extension: .. code-block:: xml - + diff --git a/testing/bootstrap.rst b/testing/bootstrap.rst index 59fc289f0be..83e8e55149b 100644 --- a/testing/bootstrap.rst +++ b/testing/bootstrap.rst @@ -35,11 +35,11 @@ You can modify this file to add custom logic: .. note:: If you don't use Symfony Flex, make sure this file is configured as - bootstrap file in your ``phpunit.xml.dist`` file: + bootstrap file in your ``phpunit.dist.xml`` file: .. code-block:: xml - + + From 9b45a862fb1c49326eee946ad8ff815cbf14b78a Mon Sep 17 00:00:00 2001 From: EL Mehdi EL MAIS Date: Sat, 2 Aug 2025 14:23:12 +0100 Subject: [PATCH 43/49] Add note about PHP-FPM detection in Symfony local server --- setup/symfony_cli.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/symfony_cli.rst b/setup/symfony_cli.rst index e0e05d951d3..7b20c871558 100644 --- a/setup/symfony_cli.rst +++ b/setup/symfony_cli.rst @@ -155,7 +155,7 @@ Enabling PHP-FPM PHP-FPM must be installed locally for the Symfony server to utilize. When the server starts, it checks for ``web/index_dev.php``, ``web/index.php``, -``public/app_dev.php``, ``public/app.php`` in that order. If one is found, the +``public/app_dev.php``, ``public/app.php``, ``public/index.php`` in that order. If one is found, the server will automatically start with PHP-FPM enabled. Otherwise the server will start without PHP-FPM and will show a ``Page not found`` page when trying to access a ``.php`` file in the browser. From 5cac5edd2cdad1a1494ffc2cea13dee6b188727e Mon Sep 17 00:00:00 2001 From: Santiago San Martin Date: Thu, 7 Aug 2025 19:20:05 -0300 Subject: [PATCH 44/49] [Routing] correct environment-specific routing configuration examples --- routing.rst | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/routing.rst b/routing.rst index 102aef454f0..541ba971f67 100644 --- a/routing.rst +++ b/routing.rst @@ -282,10 +282,10 @@ given value: .. code-block:: yaml # config/routes.yaml - tools: - path: /tools - controller: App\Controller\DefaultController::developerTools - env: dev + when@dev: + tools: + path: /tools + controller: App\Controller\DefaultController::developerTools .. code-block:: xml @@ -296,9 +296,9 @@ given value: xsi:schemaLocation="http://symfony.com/schema/routing https://symfony.com/schema/routing/routing-1.0.xsd"> - - dev - + + + .. code-block:: php @@ -308,10 +308,11 @@ given value: use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; return function (RoutingConfigurator $routes): void { - $routes->add('tools', '/tools') - ->controller([DefaultController::class, 'developerTools']) - ->env('dev') - ; + if('dev' === $routes->env()) { + $routes->add('tools', '/tools') + ->controller([DefaultController::class, 'developerTools']) + ; + } }; .. _routing-matching-expressions: From 1322666f11809d6c4d2e0c98e48df8952b88fe03 Mon Sep 17 00:00:00 2001 From: Antoine M Date: Thu, 7 Aug 2025 11:13:28 +0200 Subject: [PATCH 45/49] chore(readme): upgrade logo for light/dark mode --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c063058c02..84f91fbbbbc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- + Symfony Logo

From 0859c9b1af74ce874faf4eb612b2630f8098e4fb Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 13 Aug 2025 15:41:30 +0200 Subject: [PATCH 46/49] [Mailer] Add missing formats & fix format order in Bridge table --- mailer.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mailer.rst b/mailer.rst index bdc50757cdd..6979c91bc31 100644 --- a/mailer.rst +++ b/mailer.rst @@ -180,9 +180,9 @@ party provider: +------------------------+---------------------------------------------------------+ | Provider | Formats | +========================+=========================================================+ -| `AhaSend`_ | - API ``ahasend+api://KEY@default`` | +| `AhaSend`_ | - SMTP ``ahasend+smtp://USERNAME:PASSWORD@default`` | | | - HTTP n/a | -| | - SMTP ``ahasend+smtp://USERNAME:PASSWORD@default`` | +| | - API ``ahasend+api://KEY@default`` | +------------------------+---------------------------------------------------------+ | `Amazon SES`_ | - SMTP ``ses+smtp://USERNAME:PASSWORD@default`` | | | - HTTP ``ses+https://ACCESS_KEY:SECRET_KEY@default`` | From 3f69ad07222eead3b7c810ca2f2b496a22e49a6a Mon Sep 17 00:00:00 2001 From: Mark Schmale Date: Wed, 13 Aug 2025 16:31:41 +0200 Subject: [PATCH 47/49] fix small typo in RedisAdapter docs --- components/cache/adapters/redis_adapter.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/cache/adapters/redis_adapter.rst b/components/cache/adapters/redis_adapter.rst index c0295b487a0..ac32e1bbd39 100644 --- a/components/cache/adapters/redis_adapter.rst +++ b/components/cache/adapters/redis_adapter.rst @@ -9,7 +9,7 @@ Redis Cache Adapter article if you are using it in a Symfony application. This adapter stores the values in-memory using one (or more) `Redis server`_ -of `Valkey`_ server instances. +or `Valkey`_ server instances. Unlike the :doc:`APCu adapter `, and similarly to the :doc:`Memcached adapter `, it is not limited to the current server's From 0683d2560f5423b33cf980137715f150e50531b2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 13 Aug 2025 12:58:17 +0200 Subject: [PATCH 48/49] [Translation] Mention that you need to install the PHP extension --- translation.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/translation.rst b/translation.rst index 2f0206563ee..0ac252ddfbc 100644 --- a/translation.rst +++ b/translation.rst @@ -52,6 +52,12 @@ First, run this command to install the translator before using it: $ composer require symfony/translation +Symfony includes several internationalization polyfills (``symfony/polyfill-intl-icu``, +``symfony/polyfill-intl-messageformatter``, etc.) that allow you to use translation +features even without the `PHP intl extension`_. However, these polyfills only +support English translations, so you must install the PHP ``intl`` extension +when translating into other languages. + .. _translation-configuration: Configuration @@ -1595,6 +1601,7 @@ Learn more .. _`ICU MessageFormat`: https://unicode-org.github.io/icu/userguide/format_parse/messages/ .. _`ISO 3166-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes .. _`ISO 639-1`: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes +.. _`PHP intl extension`: https://php.net/book.intl .. _`Translatable Extension`: https://github.com/doctrine-extensions/DoctrineExtensions/blob/main/doc/translatable.md .. _`Translatable Behavior`: https://github.com/KnpLabs/DoctrineBehaviors .. _`Custom Language Name setting`: https://docs.lokalise.com/en/articles/1400492-uploading-files#custom-language-codes From 1fe21d4239250b5fcacf313e1202285ec80ed709 Mon Sep 17 00:00:00 2001 From: Jan Klan <5463371+janklan@users.noreply.github.com> Date: Thu, 14 Aug 2025 06:55:50 +0930 Subject: [PATCH 49/49] Clarify renaning arguments isn't generally covered by the BC promise --- contributing/code/bc.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contributing/code/bc.rst b/contributing/code/bc.rst index ad394d2720c..ee3f72a0333 100644 --- a/contributing/code/bc.rst +++ b/contributing/code/bc.rst @@ -285,6 +285,7 @@ Make final No Move to parent class Yes :ref:`Add argument without a default value ` No :ref:`Add argument with a default value ` No :ref:`[7] ` :ref:`[8] ` +Rename argument Yes :ref:`[10] ` Remove argument No :ref:`[3] ` Add default value to an argument No :ref:`[7] ` :ref:`[8] ` Remove default value of an argument No @@ -304,6 +305,7 @@ Make public No Move to parent class Yes :ref:`Add argument without a default value ` No :ref:`Add argument with a default value ` No :ref:`[7] ` :ref:`[8] ` +Rename argument Yes :ref:`[10] ` Remove argument No :ref:`[3] ` Add default value to an argument No :ref:`[7] ` :ref:`[8] ` Remove default value of an argument No :ref:`[7] ` @@ -320,6 +322,7 @@ Change name Yes Make public or protected Yes Add argument without a default value Yes Add argument with a default value Yes +Rename argument Yes Remove argument Yes Add default value to an argument Yes Remove default value of an argument Yes