Skip to content

Commit e968429

Browse files
committed
minor #16591 [Serializer] Add context builders documentation (mtarld)
This PR was merged into the 6.1 branch. Discussion ---------- [Serializer] Add context builders documentation Related to symfony/symfony#43973 Closes #16470 Commits ------- 7be3c93 [Serializer] Add context builders documentation
2 parents 4e9a47e + 7be3c93 commit e968429

File tree

3 files changed

+171
-5
lines changed

3 files changed

+171
-5
lines changed

components/serializer.rst

+35
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,41 @@ Option Description Defaul
12021202
to customize the encoding / decoding YAML string
12031203
=============== ======================================================== ==========================
12041204

1205+
.. _component-serializer-context-builders:
1206+
1207+
Context Builders
1208+
----------------
1209+
1210+
Context builders are objects that help creating the :ref:`serialization context <serializer-context>`.
1211+
1212+
You can easily use context builders by instantiating them::
1213+
1214+
use Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder;
1215+
use Symfony\Component\Serializer\Context\Normalizer\ObjectNormalizerContextBuilder;
1216+
1217+
$initialContext = [
1218+
'custom_key' => 'custom_value',
1219+
];
1220+
1221+
$contextBuilder = (new ObjectNormalizerContextBuilder())
1222+
->withContext($initialContext)
1223+
->withGroups(['group1', 'group2']);
1224+
1225+
$contextBuilder = (new CsvEncoderContextBuilder())
1226+
->withContext($contextBuilder->toArray())
1227+
->withDelimiter(';');
1228+
1229+
$serializer->serialize($something, 'csv', $contextBuilder->toArray());
1230+
1231+
.. note::
1232+
1233+
The Serializer component provides a context builder
1234+
for each :ref:`normalizer <component-serializer-normalizers>`
1235+
and :ref:`encoder <component-serializer-encoders>`.
1236+
1237+
You can also create custom context builders to deal with your
1238+
context values. Read more at :doc:`/serializer/custom_context_builders`.
1239+
12051240
Skipping ``null`` Values
12061241
------------------------
12071242

serializer.rst

+50-5
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ possible to set the priority of the tag in order to decide the matching order.
8989
``DateTime`` or ``DateTimeImmutable`` classes to avoid excessive memory
9090
usage and exposing internal details.
9191

92+
.. _serializer-context:
93+
9294
Serializer Context
9395
------------------
9496

@@ -149,6 +151,46 @@ configuration:
149151
;
150152
};
151153
154+
.. _serializer-using-context-builders:
155+
156+
Using Context Builders
157+
----------------------
158+
159+
To define a proper (de)serialization context, you can leverage context builders.
160+
Those are objects that help you to create that context by providing
161+
auto-completion, validation, and documentation::
162+
163+
use Symfony\Component\Serializer\Context\Normalizer\DateTimeNormalizerContextBuilder;
164+
165+
$contextBuilder = (new DateTimeNormalizerContextBuilder())->withFormat('Y-m-d H:i:s');
166+
167+
$serializer->serialize($something, 'json', $contextBuilder->toArray());
168+
169+
Each normalizer/encoder has its related :ref:`context builder <component-serializer-context-builders>`.
170+
To create a full (de)serialization context, you will be able to chain them using the
171+
``withContext`` method. As the ``withContext`` method takes an array as an argument, it is
172+
also possible to pass custom values to that context::
173+
174+
use Symfony\Component\Serializer\Context\Encoder\CsvEncoderContextBuilder;
175+
use Symfony\Component\Serializer\Context\Normalizer\ObjectNormalizerContextBuilder;
176+
177+
$initialContext = [
178+
'custom_key' => 'custom_value',
179+
];
180+
181+
$contextBuilder = (new ObjectNormalizerContextBuilder())
182+
->withContext($initialContext)
183+
->withGroups(['group1', 'group2']);
184+
185+
$contextBuilder = (new CsvEncoderContextBuilder())
186+
->withContext($contextBuilder->toArray())
187+
->withDelimiter(';');
188+
189+
$serializer->serialize($something, 'csv', $contextBuilder->toArray());
190+
191+
If you want auto-completion, validation, and documentation for your custom context values,
192+
you can :doc:`create your context builders </serializer/custom_context_builders>`.
193+
152194
.. _serializer-using-serialization-groups-annotations:
153195

154196
Using Serialization Groups Annotations
@@ -197,11 +239,13 @@ to your class::
197239

198240
You can now choose which groups to use when serializing::
199241

200-
$json = $serializer->serialize(
201-
$product,
202-
'json',
203-
['groups' => 'show_product']
204-
);
242+
use Symfony\Component\Serializer\Context\Normalizer\ObjectNormalizerContextBuilder;
243+
244+
$context = (new ObjectNormalizerContextBuilder())
245+
->withGroups('show_product')
246+
->toArray();
247+
248+
$json = $serializer->serialize($product, 'json', $context);
205249

206250
.. tip::
207251

@@ -293,6 +337,7 @@ take a look at how this bundle works.
293337

294338
serializer/custom_encoders
295339
serializer/custom_normalizer
340+
serializer/custom_context_builders
296341

297342
.. _`API Platform`: https://api-platform.com
298343
.. _`JSON-LD`: https://json-ld.org
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
.. index::
2+
single: Serializer; Custom context builders
3+
4+
How to Create your Custom Context Builder
5+
=========================================
6+
7+
The :doc:`Serializer Component </components/serializer>` uses Normalizers
8+
and Encoders to transform any data to any data-structure (e.g. JSON).
9+
That serialization process could be configured thanks to a
10+
:ref:`serialization context <serializer-context>`, which can be built thanks to
11+
:ref:`context builders <component-serializer-context-builders>`.
12+
13+
Each built-in normalizer/encoder has its related context builder.
14+
But, as an example, you may want to use custom context values
15+
for your :doc:`custom normalizers </serializer/custom_normalizer>`
16+
and create a custom context builder related to them.
17+
18+
Creating a new context builder
19+
------------------------------
20+
21+
Let's imagine that you want to handle date denormalization differently if they
22+
are coming from a legacy system, by converting them to ``null`` if the serialized
23+
value is ``0000-00-00``. To do that you'll first have to create your normalizer::
24+
25+
// src/Serializer/ZeroDateTimeDenormalizer.php
26+
namespace App\Serializer;
27+
28+
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
29+
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
30+
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
31+
32+
final class ZeroDateTimeDenormalizer implements DenormalizerInterface, DenormalizerAwareInterface
33+
{
34+
use DenormalizerAwareTrait;
35+
36+
public function denormalize($data, string $type, string $format = null, array $context = [])
37+
{
38+
if ('0000-00-00' === $data) {
39+
return null;
40+
}
41+
42+
unset($context['zero_datetime_to_null']);
43+
44+
return $this->denormalizer->denormalize($data, $type, $format, $context);
45+
}
46+
47+
public function supportsDenormalization($data, string $type, string $format = null, array $context = [])
48+
{
49+
return true === ($context['zero_datetime_to_null'] ?? false)
50+
&& is_a($type, \DateTimeInterface::class, true);
51+
}
52+
}
53+
54+
You'll therefore be able to cast zero-ish dates to ``null`` during denormalization::
55+
56+
$legacyData = '{"updatedAt": "0000-00-00"}';
57+
58+
$serializer->deserialize($legacyData, MyModel::class, 'json', ['zero_datetime_to_null' => true]);
59+
60+
Then, if you don't want other developers to have to remind the precise ``zero_date_to_null`` context key,
61+
you can create a dedicated context builder::
62+
63+
// src/Serializer/LegacyContextBuilder
64+
namespace App\Serializer;
65+
66+
use Symfony\Component\Serializer\Context\ContextBuilderTrait;
67+
68+
final class LegacyContextBuilder
69+
{
70+
use ContextBuilderTrait;
71+
72+
public function withLegacyDates(bool $legacy): static
73+
{
74+
return $this->with('zero_datetime_to_null', $legacy);
75+
}
76+
}
77+
78+
And finally use it to build the serialization context::
79+
80+
$legacyData = '{"updatedAt": "0000-00-00"}';
81+
82+
$context = (new LegacyContextBuilder())
83+
->withLegacyDates(true)
84+
->toArray();
85+
86+
$serializer->deserialize($legacyData, MyModel::class, 'json', $context);

0 commit comments

Comments
 (0)