diff --git a/UPGRADE-API-1.13.md b/UPGRADE-API-1.13.md
index 1b441c0a168..ba0e6b3c140 100644
--- a/UPGRADE-API-1.13.md
+++ b/UPGRADE-API-1.13.md
@@ -1,5 +1,18 @@
# UPGRADE FROM `v1.12.x` TO `v1.13.0`
+1. All the `:read` serialization groups are now split to `index` and `show`.
+ By this change, the `:read` serialization group is now deprecated and will no more used in the future.
+ There is a BC layer that will allow you to use the `:read` serialization group `Sylius\Bundle\ApiBundle\SerializerContextBuilder\ReadOperationContextBuilder` by adding the `read` serialization group to your context.
+ Inside of this service there are 2 configurable parameters `$skipAddingReadGroup` and `$skipAddingIndexAndShowGroups` that will allow you to skip adding the chosen serialization group to your context.
+ To configure skipping adding the index and show or read serialization groups to the context, add the following configuration to your `config/packages/_sylius.yaml` file:
+
+ ```yaml
+ sylius_api:
+ serialization_groups:
+ skip_adding_index_and_show_groups: true
+ skip_adding_read_group: true
+ ```
+
1. The constructor of `Sylius\Bundle\ApiBundle\Serializer\ChannelDenormalizer` has been changed:
```diff
diff --git a/src/Sylius/Bundle/ApiBundle/DependencyInjection/Configuration.php b/src/Sylius/Bundle/ApiBundle/DependencyInjection/Configuration.php
index 07e6c289d71..ed0839b3a49 100644
--- a/src/Sylius/Bundle/ApiBundle/DependencyInjection/Configuration.php
+++ b/src/Sylius/Bundle/ApiBundle/DependencyInjection/Configuration.php
@@ -41,6 +41,19 @@ public function getConfigTreeBuilder(): TreeBuilder
->scalarPrototype()->end()
->end()
->end()
+ ->children()
+ ->arrayNode('serialization_groups')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->booleanNode('skip_adding_read_group')
+ ->defaultFalse()
+ ->end()
+ ->booleanNode('skip_adding_index_and_show_groups')
+ ->defaultFalse()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
->children()
->variableNode('product_image_prefix')
->defaultValue('media/image')
diff --git a/src/Sylius/Bundle/ApiBundle/DependencyInjection/SyliusApiExtension.php b/src/Sylius/Bundle/ApiBundle/DependencyInjection/SyliusApiExtension.php
index 2bc40dab2e9..c8bc585d366 100644
--- a/src/Sylius/Bundle/ApiBundle/DependencyInjection/SyliusApiExtension.php
+++ b/src/Sylius/Bundle/ApiBundle/DependencyInjection/SyliusApiExtension.php
@@ -39,6 +39,8 @@ public function load(array $configs, ContainerBuilder $container): void
$config['filter_eager_loading_extension']['restricted_resources'],
);
$container->setParameter('sylius_api.order_states_to_filter_out', $config['order_states_to_filter_out']);
+ $container->setParameter('sylius_api.serialization_groups.skip_adding_read_group', $config['serialization_groups']['skip_adding_read_group']);
+ $container->setParameter('sylius_api.serialization_groups.skip_adding_index_and_show_groups', $config['serialization_groups']['skip_adding_index_and_show_groups']);
$loader->load('services.xml');
diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/context_builders.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/context_builders.xml
index 97b341e9ee8..a5292631a74 100644
--- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/context_builders.xml
+++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/context_builders.xml
@@ -27,6 +27,16 @@
+
+
+ %sylius_api.serialization_groups.skip_adding_read_group%
+ %sylius_api.serialization_groups.skip_adding_index_and_show_groups%
+
+
$extractedAttributes
+ *
+ * @return array
+ */
+ public function createFromRequest(Request $request, bool $normalization, array $extractedAttributes = null): array
+ {
+ $context = $this->decorated->createFromRequest($request, $normalization, $extractedAttributes);
+
+ $groups = $context['groups'] ?? [];
+ $groups = is_string($groups) ? [$groups] : $groups;
+
+ if ($groups === []) {
+ return $context;
+ }
+
+ foreach ($groups as $group) {
+ if ($this->shouldReadGroupBeAdded($group) && !$this->skipAddingReadGroup) {
+ $readGroup = str_replace([':show', ':index'], ':read', $group);
+
+ if (in_array($readGroup, $groups, true)) {
+ continue;
+ }
+
+ $groups[] = $readGroup;
+ }
+
+ if ($this->shouldIndexAndShowGroupsBeAdded($group) && !$this->skipAddingIndexAndShowGroups) {
+ $indexGroup = str_replace(':read', ':index', $group);
+ $showGroup = str_replace(':read', ':show', $group);
+
+ if (!in_array($indexGroup, $groups, true)) {
+ $groups[] = $indexGroup;
+ }
+
+ if (!in_array($showGroup, $groups, true)) {
+ $groups[] = $showGroup;
+ }
+ }
+ }
+
+ $context['groups'] = $groups;
+
+ return $context;
+ }
+
+ private function shouldReadGroupBeAdded(string $group): bool
+ {
+ return str_ends_with($group, ':show') || str_ends_with($group, ':index');
+ }
+
+ private function shouldIndexAndShowGroupsBeAdded(string $group): bool
+ {
+ return str_ends_with($group, ':read');
+ }
+}
diff --git a/src/Sylius/Bundle/ApiBundle/Tests/DependencyInjection/SyliusApiExtensionTest.php b/src/Sylius/Bundle/ApiBundle/Tests/DependencyInjection/SyliusApiExtensionTest.php
index f9de62d6bf0..da649561b40 100644
--- a/src/Sylius/Bundle/ApiBundle/Tests/DependencyInjection/SyliusApiExtensionTest.php
+++ b/src/Sylius/Bundle/ApiBundle/Tests/DependencyInjection/SyliusApiExtensionTest.php
@@ -106,6 +106,28 @@ public function it_loads_order_states_to_filter_out_parameter_properly(): void
);
}
+ /** @test */
+ public function it_loads_skip_read_and_skip_index_and_show_serialization_groups_parameters_properly(): void
+ {
+ $this->container->setParameter('kernel.bundles_metadata', ['SyliusApiBundle' => ['path' => __DIR__ . '../..']]);
+
+ $this->load([
+ 'serialization_groups' => [
+ 'skip_adding_read_group' => true,
+ 'skip_adding_index_and_show_groups' => false,
+ ],
+ ]);
+
+ $this->assertContainerBuilderHasParameter(
+ 'sylius_api.serialization_groups.skip_adding_read_group',
+ true,
+ );
+ $this->assertContainerBuilderHasParameter(
+ 'sylius_api.serialization_groups.skip_adding_index_and_show_groups',
+ false,
+ );
+ }
+
/** @test */
public function it_loads_default_filter_eager_loading_extension_restricted_operations_configuration_properly(): void
{
diff --git a/src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/ReadOperationContextBuilderSpec.php b/src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/ReadOperationContextBuilderSpec.php
new file mode 100644
index 00000000000..5617133a554
--- /dev/null
+++ b/src/Sylius/Bundle/ApiBundle/spec/SerializerContextBuilder/ReadOperationContextBuilderSpec.php
@@ -0,0 +1,83 @@
+beConstructedWith($decoratedSerializerContextBuilder, false, false);
+ }
+
+ function it_updates_an_context_with_index_and_show_serialization_groups_if_only_read_provided(
+ Request $request,
+ SerializerContextBuilderInterface $decoratedSerializerContextBuilder,
+ ): void {
+ $decoratedSerializerContextBuilder->createFromRequest($request, true, [])->willReturn([
+ 'groups' => ['foo:read'],
+ ]);
+
+ $this->createFromRequest($request, true, [])->shouldReturn([
+ 'groups' => ['foo:read', 'foo:index', 'foo:show'],
+ ]);
+ }
+
+ function it_updates_an_context_with_read_serialization_groups_if_only_index_and_show_provided(
+ Request $request,
+ SerializerContextBuilderInterface $decoratedSerializerContextBuilder,
+ ): void {
+ $decoratedSerializerContextBuilder->createFromRequest($request, true, [])->willReturn([
+ 'groups' => ['foo:read'],
+ ]);
+
+ $this->createFromRequest($request, true, [])->shouldReturn([
+ 'groups' => ['foo:read', 'foo:index', 'foo:show'],
+ ]);
+ }
+
+ function it_does_not_update_context_with_read_group_if_skip_adding_read_parameter_is_set_to_true(
+ Request $request,
+ SerializerContextBuilderInterface $decoratedSerializerContextBuilder,
+ ): void {
+ $this->beConstructedWith($decoratedSerializerContextBuilder, true, false);
+
+ $decoratedSerializerContextBuilder->createFromRequest($request, true, [])->willReturn([
+ 'groups' => ['foo:show'],
+ ]);
+
+ $this->createFromRequest($request, true, [])->shouldReturn([
+ 'groups' => ['foo:show'],
+ ]);
+ }
+
+ function it_does_not_update_context_with_show_and_index_group_if_skip_adding_show_and_index_is_set_to_true(
+ Request $request,
+ SerializerContextBuilderInterface $decoratedSerializerContextBuilder,
+ ): void {
+ $this->beConstructedWith($decoratedSerializerContextBuilder, false, true);
+
+ $decoratedSerializerContextBuilder->createFromRequest($request, true, [])->willReturn([
+ 'groups' => ['foo:read'],
+ ]);
+
+ $this->createFromRequest($request, true, [])->shouldReturn([
+ 'groups' => ['foo:read'],
+ ]);
+ }
+}