Skip to content

Commit cc48ead

Browse files
committed
Merge remote-tracking branch 'upstream/7.3' into 7.3
* upstream/7.3: Minor tweaks Add few doc on marshaller in redis adapter Fix PHP block in TypeInfo documentation Fix PHP block in TypeInfo documentation Add the versionadded directive [Console] Add support of millisecondes for formatTime [HttpFoundation] Add StreamedResponse string iterable documentation Minor reword Update controller.rst Minor tweaks [Scheduler] Add some pointers regarding worker processes deployment Add missing argument [Mesenger] Mention that some option doesn't have docs Add more details to TypeInfo documentation
2 parents 33fc669 + 88298ed commit cc48ead

File tree

8 files changed

+223
-14
lines changed

8 files changed

+223
-14
lines changed

components/cache/adapters/redis_adapter.rst

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,13 @@ as the second and third parameters::
3838
// the default lifetime (in seconds) for cache items that do not define their
3939
// own lifetime, with a value 0 causing items to be stored indefinitely (i.e.
4040
// until RedisAdapter::clear() is invoked or the server(s) are purged)
41-
$defaultLifetime = 0
41+
$defaultLifetime = 0,
42+
43+
// $marshaller (optional) An instance of MarshallerInterface to control the serialization
44+
// and deserialization of cache items. By default, native PHP serialization is used.
45+
// This can be useful for compressing data, applying custom serialization logic, or
46+
// optimizing the size and performance of cached items
47+
?MarshallerInterface $marshaller = null
4248
);
4349

4450
Configure the Connection
@@ -266,6 +272,80 @@ performance when using tag-based invalidation::
266272

267273
Read more about this topic in the official `Redis LRU Cache Documentation`_.
268274

275+
Working with Marshaller
276+
-----------------------
277+
278+
TagAwareMarshaller for Tag-Based Caching
279+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
280+
281+
Optimizes caching for tag-based retrieval, allowing efficient management of related items::
282+
283+
$marshaller = new TagAwareMarshaller();
284+
285+
$cache = new RedisAdapter($redis, 'tagged_namespace', 3600, $marshaller);
286+
287+
$item = $cache->getItem('tagged_key');
288+
$item->set(['value' => 'some_data', 'tags' => ['tag1', 'tag2']]);
289+
$cache->save($item);
290+
291+
SodiumMarshaller for Encrypted Caching
292+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
293+
294+
Encrypts cached data using Sodium for enhanced security::
295+
296+
$encryptionKeys = [sodium_crypto_box_keypair()];
297+
$marshaller = new SodiumMarshaller($encryptionKeys);
298+
299+
$cache = new RedisAdapter($redis, 'secure_namespace', 3600, $marshaller);
300+
301+
$item = $cache->getItem('secure_key');
302+
$item->set('confidential_data');
303+
$cache->save($item);
304+
305+
DefaultMarshaller with igbinary Serialization
306+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
307+
308+
Uses ``igbinary` for faster and more efficient serialization when available::
309+
310+
$marshaller = new DefaultMarshaller(true);
311+
312+
$cache = new RedisAdapter($redis, 'optimized_namespace', 3600, $marshaller);
313+
314+
$item = $cache->getItem('optimized_key');
315+
$item->set(['data' => 'optimized_data']);
316+
$cache->save($item);
317+
318+
DefaultMarshaller with Exception on Failure
319+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
320+
321+
Throws an exception if serialization fails, facilitating error handling::
322+
323+
$marshaller = new DefaultMarshaller(false, true);
324+
325+
$cache = new RedisAdapter($redis, 'error_namespace', 3600, $marshaller);
326+
327+
try {
328+
$item = $cache->getItem('error_key');
329+
$item->set('data');
330+
$cache->save($item);
331+
} catch (\ValueError $e) {
332+
echo 'Serialization failed: '.$e->getMessage();
333+
}
334+
335+
SodiumMarshaller with Key Rotation
336+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
337+
338+
Supports key rotation, ensuring secure decryption with both old and new keys::
339+
340+
$keys = [sodium_crypto_box_keypair(), sodium_crypto_box_keypair()];
341+
$marshaller = new SodiumMarshaller($keys);
342+
343+
$cache = new RedisAdapter($redis, 'rotated_namespace', 3600, $marshaller);
344+
345+
$item = $cache->getItem('rotated_key');
346+
$item->set('data_to_encrypt');
347+
$cache->save($item);
348+
269349
.. _`Data Source Name (DSN)`: https://en.wikipedia.org/wiki/Data_source_name
270350
.. _`Redis server`: https://redis.io/
271351
.. _`Redis`: https://github.com/phpredis/phpredis

components/console/helpers/formatterhelper.rst

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,16 @@ Sometimes you want to format seconds to time. This is possible with the
129129
The first argument is the seconds to format and the second argument is the
130130
precision (default ``1``) of the result::
131131

132-
Helper::formatTime(42); // 42 secs
133-
Helper::formatTime(125); // 2 mins
134-
Helper::formatTime(125, 2); // 2 mins, 5 secs
135-
Helper::formatTime(172799, 4); // 1 day, 23 hrs, 59 mins, 59 secs
132+
Helper::formatTime(0.001); // 1 ms
133+
Helper::formatTime(42); // 42 s
134+
Helper::formatTime(125); // 2 min
135+
Helper::formatTime(125, 2); // 2 min, 5 s
136+
Helper::formatTime(172799, 4); // 1 d, 23 h, 59 min, 59 s
137+
Helper::formatTime(172799.056, 5); // 1 d, 23 h, 59 min, 59 s, 56 ms
138+
139+
.. versionadded:: 7.3
140+
141+
Support for formatting up to milliseconds was introduced in Symfony 7.3.
136142

137143
Formatting Memory
138144
-----------------

components/http_foundation.rst

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -681,8 +681,19 @@ Streaming a Response
681681
~~~~~~~~~~~~~~~~~~~~
682682

683683
The :class:`Symfony\\Component\\HttpFoundation\\StreamedResponse` class allows
684-
you to stream the Response back to the client. The response content is
685-
represented by a PHP callable instead of a string::
684+
you to stream the Response back to the client. The response content can be
685+
represented by a string iterable::
686+
687+
use Symfony\Component\HttpFoundation\StreamedResponse;
688+
689+
$chunks = ['Hello', ' World'];
690+
691+
$response = new StreamedResponse();
692+
$response->setChunks($chunks);
693+
$response->send();
694+
695+
For most complex use cases, the response content can be instead represented by
696+
a PHP callable::
686697

687698
use Symfony\Component\HttpFoundation\StreamedResponse;
688699

@@ -710,6 +721,10 @@ represented by a PHP callable instead of a string::
710721
// disables FastCGI buffering in nginx only for this response
711722
$response->headers->set('X-Accel-Buffering', 'no');
712723

724+
.. versionadded:: 7.3
725+
726+
Support for using string iterables was introduced in Symfony 7.3.
727+
713728
Streaming a JSON Response
714729
~~~~~~~~~~~~~~~~~~~~~~~~~
715730

components/type_info.rst

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,24 @@ to the :class:`Symfony\\Component\\TypeInfo\\Type` static methods as following::
4040
// Many others are available and can be
4141
// found in Symfony\Component\TypeInfo\TypeFactoryTrait
4242

43-
The second way of using the component is to use ``TypeInfo`` to resolve a type
44-
based on reflection or a simple string::
43+
Resolvers
44+
~~~~~~~~~
45+
46+
The second way to use the component is by using ``TypeInfo`` to resolve a type
47+
based on reflection or a simple string. This approach is designed for libraries
48+
that need a simple way to describe a class or anything with a type::
4549

4650
use Symfony\Component\TypeInfo\Type;
4751
use Symfony\Component\TypeInfo\TypeResolver\TypeResolver;
4852

53+
class Dummy
54+
{
55+
public function __construct(
56+
public int $id,
57+
) {
58+
}
59+
}
60+
4961
// Instantiate a new resolver
5062
$typeResolver = TypeResolver::create();
5163

@@ -70,6 +82,94 @@ Each of these calls will return you a ``Type`` instance that corresponds to the
7082
static method used. You can also resolve types from a string (as shown in the
7183
``bool`` parameter of the previous example)
7284

73-
.. note::
85+
PHPDoc Parsing
86+
~~~~~~~~~~~~~~
87+
88+
In many cases, you may not have cleanly typed properties or may need more precise
89+
type definitions provided by advanced PHPDoc. To achieve this, you can use a string
90+
resolver based on the PHPDoc annotations.
91+
92+
First, run the command ``composer require phpstan/phpdoc-parser`` to install the
93+
PHP package required for string resolving. Then, follow these steps::
7494

75-
To support raw string resolving, you need to install ``phpstan/phpdoc-parser`` package.
95+
use Symfony\Component\TypeInfo\TypeResolver\TypeResolver;
96+
97+
class Dummy
98+
{
99+
public function __construct(
100+
public int $id,
101+
/** @var string[] $tags */
102+
public array $tags,
103+
) {
104+
}
105+
}
106+
107+
$typeResolver = TypeResolver::create();
108+
$typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns an "int" Type
109+
$typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns a collection with "int" as key and "string" as values Type
110+
111+
Advanced Usages
112+
~~~~~~~~~~~~~~~
113+
114+
The TypeInfo component provides various methods to manipulate and check types,
115+
depending on your needs.
116+
117+
Checking a **simple type**::
118+
119+
// define a simple integer type
120+
$type = Type::int();
121+
// check if the type matches a specific identifier
122+
$type->isIdentifiedBy(TypeIdentifier::INT); // true
123+
$type->isIdentifiedBy(TypeIdentifier::STRING); // false
124+
125+
// define a union type (equivalent to PHP's int|string)
126+
$type = Type::union(Type::string(), Type::int());
127+
// now the second check is true because the union type contains the string type
128+
$type->isIdentifiedBy(TypeIdentifier::INT); // true
129+
$type->isIdentifiedBy(TypeIdentifier::STRING); // true
130+
131+
class DummyParent {}
132+
class Dummy extends DummyParent implements DummyInterface {}
133+
134+
// define an object type
135+
$type = Type::object(Dummy::class);
136+
137+
// check if the type is an object or matches a specific class
138+
$type->isIdentifiedBy(TypeIdentifier::OBJECT); // true
139+
$type->isIdentifiedBy(Dummy::class); // true
140+
// check if it inherits/implements something
141+
$type->isIdentifiedBy(DummyParent::class); // true
142+
$type->isIdentifiedBy(DummyInterface::class); // true
143+
144+
Using callables for **complex checks**::
145+
146+
class Foo
147+
{
148+
private int $integer;
149+
private string $string;
150+
private ?float $float;
151+
}
152+
153+
$reflClass = new \ReflectionClass(Foo::class);
154+
155+
$resolver = TypeResolver::create();
156+
$integerType = $resolver->resolve($reflClass->getProperty('integer'));
157+
$stringType = $resolver->resolve($reflClass->getProperty('string'));
158+
$floatType = $resolver->resolve($reflClass->getProperty('float'));
159+
160+
// define a callable to validate non-nullable number types
161+
$isNonNullableNumber = function (Type $type): bool {
162+
if ($type->isNullable()) {
163+
return false;
164+
}
165+
166+
if ($type->isIdentifiedBy(TypeIdentifier::INT) || $type->isIdentifiedBy(TypeIdentifier::FLOAT)) {
167+
return true;
168+
}
169+
170+
return false;
171+
};
172+
173+
$integerType->isSatisfiedBy($isNonNullableNumber); // true
174+
$stringType->isSatisfiedBy($isNonNullableNumber); // false
175+
$floatType->isSatisfiedBy($isNonNullableNumber); // false

controller.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -898,7 +898,7 @@ method::
898898
{
899899
$response = $this->sendEarlyHints([
900900
new Link(rel: 'preconnect', href: 'https://fonts.google.com'),
901-
(new Link(href: '/style.css'))->withAttribute('as', 'stylesheet'),
901+
(new Link(href: '/style.css'))->withAttribute('as', 'style'),
902902
(new Link(href: '/script.js'))->withAttribute('as', 'script'),
903903
]);
904904

messenger.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1522,7 +1522,7 @@ The transport has a number of options:
15221522
(no description available)
15231523

15241524
``sasl_method``
1525-
1525+
(no description available)
15261526

15271527
``connection_name``
15281528
For custom connection names (requires at least version 1.10 of the PHP AMQP

scheduler.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,13 @@ the Messenger component:
785785
.. image:: /_images/components/scheduler/generate_consume.png
786786
:alt: Symfony Scheduler - generate and consume
787787

788+
.. tip::
789+
790+
Depending on your deployment scenario, you may prefer automating the execution of
791+
the Messenger worker process using tools like cron, Supervisor, or systemd.
792+
This ensures workers are running continuously. For more details, refer to the
793+
`Deploying to Production`_ section of the Messenger component documentation.
794+
788795
Creating a Consumer Programmatically
789796
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
790797

@@ -970,6 +977,7 @@ When using the ``RedispatchMessage``, Symfony will attach a
970977
helping you identify those messages when needed.
971978

972979
.. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html
980+
.. _`Deploying to Production`: https://symfony.com/doc/current/messenger.html#deploying-to-production
973981
.. _`Memoizing`: https://en.wikipedia.org/wiki/Memoization
974982
.. _`cron command-line utility`: https://en.wikipedia.org/wiki/Cron
975983
.. _`crontab.guru website`: https://crontab.guru/

serializer.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1803,7 +1803,7 @@ property. This can be used instead of
18031803
},
18041804
],
18051805
];
1806-
$jsonContent = $serializer->serialize($person, 'json');
1806+
$jsonContent = $serializer->serialize($person, 'json', $context);
18071807
// $jsonContent contains {"name":"cordoval","age":34,"createdAt":"2014-03-22T09:43:12-0500"}
18081808

18091809
Advanced Deserialization

0 commit comments

Comments
 (0)