From 54911e25470003db4224df7ed0823dbfe341e58c Mon Sep 17 00:00:00 2001 From: arti0090 Date: Mon, 17 May 2021 10:58:34 +0200 Subject: [PATCH 1/6] [DOCS] Modify serialization fields in api --- docs/customization/api.rst | 197 ++++++++++++++++++++++++++++++++++++- 1 file changed, 196 insertions(+), 1 deletion(-) diff --git a/docs/customization/api.rst b/docs/customization/api.rst index a4cb09a41b4..05696bf84eb 100644 --- a/docs/customization/api.rst +++ b/docs/customization/api.rst @@ -95,4 +95,199 @@ The next step is to modify the security configuration in ``config/packages/secur Changing prefix without security configuration update can expose confidential data (like customers addresses). -After these two steps you can start to use endpoints with new prefixes. +After these two steps you can start to use endpoints with new prefixes + +How to customize serialization? +=============================== + +Let's assume that you want to modify responses with your custom fields serialized in response. +For an example we will use ``Product`` resource and customize its fields. + +Adding a field to response +========================== + +Let's say that you want to add a new field named ``additionalText`` to ``Product``. +First let's create a new serializer that will supports our ``Product`` resource. + +.. code-block:: php + + objectNormalizer = $objectNormalizer; + } + + public function normalize($object, $format = null, array $context = []) + { + Assert::isInstanceOf($object, ProductInterface::class); + + $data = $this->objectNormalizer->normalize($object, $format, $context); + + return $data; + } + + public function supportsNormalization($data, $format = null, $context = []): bool + { + return $data instanceof ProductInterface; + } + } + +And now let's declare it's service in config files. + +.. code-block:: xml + + + + + + +Then we can add the new field. + +.. code-block:: php + + //... + $data = $this->objectNormalizer->normalize($object, $format, $context); + + $data['additionalText'] = 'your custom text or logic that will be added to this field.'; + + return $data; + //... + +Now your response should be extended with new field + +.. code-block:: javascript + + { + //... + "id": 123, + "code": "product_code", + "variants": [ + "/api/v2/shop/product-variants/product-variant-0", + ], + "additionalText": "my additional field with text", + //... + } + +Removing a field from response +============================== + +Let's say that for some reason you want to remove some field from serialization. +Your possible solution could be that you use serialization groups. +Those will limit the fields from your resource, according to serialization groups that you will choose. + +.. tip:: + + Read more about API Platform `serialization groups `_ + +But if you want to remove the field by utilising serializer, first step is to create a class as in ``Adding a field from response`` and register it's service. + +Let's assume that ``Product`` resource returns + +.. code-block:: javascript + + { + //... + "id": 123, + "code": "product_code", + "variants": [ + "/api/v2/shop/product-variants/product-variant-0", + ], + "translations": { + "en_US": { + "@id": "/api/v2/shop/product-translations/123", + "@type": "ProductTranslation", + "id": 123, + "name": "product name", + "slug": "product-name" + } + } + +Then let's say you want to remove ``translations``. We can do it by adding + +.. code-block:: php + + //... + $data = $this->objectNormalizer->normalize($object, $format, $context); + + unset($data['translations']); // removes `translations` from response + + return $data; + //... + +Now your response fields should look like this + +.. code-block:: javascript + + { + //... + "id": 123, + "code": "product_code", + "variants": [ + "/api/v2/shop/product-variants/product-variant-0", + ] + } + +Renaming a field from response +============================== + +As simple as any other steps, renaming name of response fields is also very simple. +Let's modify the ``optionValues`` name to ``options`` that's how response looks like now + +.. code-block:: javascript + + { + //... + "id": 123, + "code": "product_code", + "product": "/api/v2/shop/products/product_code", + "optionValues": [ + "/api/v2/shop/product-option-values/product_size_s" + ], + //... + } + +Now let's modify the serialization class that we used before with some simple logic + +.. code-block:: php + + //... + $data = $this->objectNormalizer->normalize($object, $format, $context); + + $data['options'] = $data['optionValues']; // this will change the name of your field + unset($data['optionValues']); // optionally you can also remove old `optionValues` field + + return $data; + //... + +And here we go, now your response should look like this + +.. code-block:: javascript + + { + //... + "id": 123, + "code": "product_code", + "product": "/api/v2/shop/products/product_code", + "options": [ + "/api/v2/shop/product-option-values/product_size_s" + ], + //... + } + +.. tip:: + + Read more about API Platform `serialization `_ From 1e7099a2511c51a0392ea8ca0c99bd7127b7f52b Mon Sep 17 00:00:00 2001 From: arti0090 Date: Wed, 19 May 2021 12:36:58 +0200 Subject: [PATCH 2/6] Add customization by changing config files --- docs/customization/api.rst | 202 +++++++++++++++++++++++++++++++++---- 1 file changed, 180 insertions(+), 22 deletions(-) diff --git a/docs/customization/api.rst b/docs/customization/api.rst index 05696bf84eb..1fe90e10c06 100644 --- a/docs/customization/api.rst +++ b/docs/customization/api.rst @@ -24,6 +24,16 @@ If your project was created before v1.10, make sure your API Platform config fol swagger: versions: [3] +And if you want to modify serialization add this code to framework config: + +.. code-block:: yaml + + # config/packages/framework.yaml + //... + serializer: + mapping: + paths: [ '%kernel.project_dir%/config/serialization' ] + How to add an additional endpoint? ---------------------------------- @@ -98,16 +108,77 @@ The next step is to modify the security configuration in ``config/packages/secur After these two steps you can start to use endpoints with new prefixes How to customize serialization? -=============================== +------------------------------- -Let's assume that you want to modify responses with your custom fields serialized in response. +Let's say that you want to change the serialized fields in your responses. For an example we will use ``Product`` resource and customize its fields. Adding a field to response -========================== +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Let's say that you want to serialize existing field named ``averageRating`` to ``Product`` in admin response so the administrator would be able to check what is products average rating. + +First let's copy serialization configuration file named ``Product.xml`` from ``%kernel.project_dir%/vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/`` +to ``config/serialization/Product.xml`` + +Then let's find the attribute ``averageRating``: + +.. code-block:: xml + + + + shop:product:read + + + + +and add serialization group that is used by endpoint we want to modify + +.. tip:: + + You can create your own serialization group for every endpoint or use the one out of the box. If you don't know the name of group for endpoint you want to modify, + you can find it by searching for your class configuration file in `%kernel.project_dir%/vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources`` + and look for path that you want to modify. + +In this case the new ``group`` is called ``admin:product:read``: + +.. code-block:: xml + + + + admin:product:read + shop:product:read + + + +After this change your response should be extended with new field: + +.. code-block:: javascript + + { + //... + "id": 123, + "code": "product_code", + "variants": [ + "/api/v2/shop/product-variants/product-variant-0", + ], + "averageRating": 3, + //... + } + +.. tip:: + + Read more about API Platform `serialization groups `_ + + +We were able to add a field that exists in ``Product`` class, but what if you want to extend it with custom fields? +Let's customize response now with your custom fields serialized in response. + +Adding a custom field to response +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Let's say that you want to add a new field named ``additionalText`` to ``Product``. -First let's create a new serializer that will supports our ``Product`` resource. +First let's create a new serializer that will support our ``Product`` resource: .. code-block:: php @@ -146,7 +217,7 @@ First let's create a new serializer that will supports our ``Product`` resource. } } -And now let's declare it's service in config files. +And now let's declare its service in config files: .. code-block:: xml @@ -155,7 +226,7 @@ And now let's declare it's service in config files. -Then we can add the new field. +Then we can add the new field: .. code-block:: php @@ -167,7 +238,7 @@ Then we can add the new field. return $data; //... -Now your response should be extended with new field +Now your response should be extended with the new field: .. code-block:: javascript @@ -182,20 +253,18 @@ Now your response should be extended with new field //... } -Removing a field from response -============================== +Removing a field from a response +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Let's say that for some reason you want to remove some field from serialization. -Your possible solution could be that you use serialization groups. +One of possible solution could be that you use serialization groups. Those will limit the fields from your resource, according to serialization groups that you will choose. .. tip:: Read more about API Platform `serialization groups `_ -But if you want to remove the field by utilising serializer, first step is to create a class as in ``Adding a field from response`` and register it's service. - -Let's assume that ``Product`` resource returns +Let's assume that ``Product`` resource returns such a response: .. code-block:: javascript @@ -216,7 +285,71 @@ Let's assume that ``Product`` resource returns } } -Then let's say you want to remove ``translations``. We can do it by adding +Then let's say you want to remove ``translations``. + +Utilising serialization groups to remove fields might be quite tricky as symfony combines all of the serialization files into one. +The easiest solution to remove the field is to create a new serialization group and use it for fields you want to have and declare this group in the endpoint. + +First let's add the ``config/api_platform/Product.xml`` configuration file. See ``How to add an additional endpoint?`` for more information. +Then let's modify the endpoint. For this example i will use GET item in shop, but you can also create some custom endpoint: + +.. code-block:: xml + + + + GET + /shop/products/{code} + + Use code to retrieve a product resource. + + + shop:product:read + + + + +then let's change the serialization group in ``normalization_context`` attribute to `shop:product:custom_read`: + +.. code-block:: xml + + + + shop:product:custom_read + + + +Now we need to modify the file ``config/serialization/Product.xml`` and add this custom serialization group to fields we want to show: + +.. code-block:: xml + + + + admin:product:read + + + admin:product:create + admin:product:read + admin:product:update + shop:product:read + + + admin:product:create + admin:product:read + admin:product:update + shop:product:read + shop:product:custom_read + + + +.. note:: + + In example the ``translations`` doesn't have the new group ``shop:product:custom_read`` so it won't be shown by that endpoint. + The rest of fields that we wan't to show has the new serialization group declared. + +In cases, where you would like to remove small amount of fields, the serializer would be a way to go. +First step is to create a class as in ``Adding a field from response`` and register it's service. + +Then modify it's logic with this code: .. code-block:: php @@ -228,7 +361,7 @@ Then let's say you want to remove ``translations``. We can do it by adding return $data; //... -Now your response fields should look like this +Now your response fields should look like this: .. code-block:: javascript @@ -238,14 +371,15 @@ Now your response fields should look like this "code": "product_code", "variants": [ "/api/v2/shop/product-variants/product-variant-0", - ] + ], + // the translations which were here are now removed } -Renaming a field from response -============================== +Renaming a field of a response +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -As simple as any other steps, renaming name of response fields is also very simple. -Let's modify the ``optionValues`` name to ``options`` that's how response looks like now +Renaming name of response fields is very simple. In this example +let's modify the ``optionValues`` name to ``options``, that's how response looks like now: .. code-block:: javascript @@ -260,7 +394,31 @@ Let's modify the ``optionValues`` name to ``options`` that's how response looks //... } -Now let's modify the serialization class that we used before with some simple logic +The simplest method to achieve this is to modify serialization configuration file. +We can use the file ``config/serialization/Product.xml`` from example above and find the attribute named ``optionValues`` + +.. code-block:: xml + + + + admin:product:read + shop:product:read + + + +And just add a ``serialized-name`` into attribute description with new name: + +.. code-block:: xml + + + + admin:product:read + shop:product:read + + + +You can also achieve this by utilising serializer class. +In this example we will modify it, so the name of field would be changed. Just add some custom logic: .. code-block:: php @@ -273,7 +431,7 @@ Now let's modify the serialization class that we used before with some simple lo return $data; //... -And here we go, now your response should look like this +And here we go, now your response should look like this: .. code-block:: javascript From 7be7c25e1da23981d633fcefa77b555eb1bba761 Mon Sep 17 00:00:00 2001 From: arti0090 Date: Fri, 21 May 2021 08:45:48 +0200 Subject: [PATCH 3/6] lexical fixes and changes for Normalizer example --- docs/customization/api.rst | 45 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/docs/customization/api.rst b/docs/customization/api.rst index 1fe90e10c06..67991b6f8f1 100644 --- a/docs/customization/api.rst +++ b/docs/customization/api.rst @@ -116,7 +116,7 @@ For an example we will use ``Product`` resource and customize its fields. Adding a field to response ~~~~~~~~~~~~~~~~~~~~~~~~~~ -Let's say that you want to serialize existing field named ``averageRating`` to ``Product`` in admin response so the administrator would be able to check what is products average rating. +Let's say that you want to serialize existing field named ``averageRating`` to ``Product`` in admin response so the administrator would be able to check what is the average rating of product. First let's copy serialization configuration file named ``Product.xml`` from ``%kernel.project_dir%/vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/`` to ``config/serialization/Product.xml`` @@ -190,48 +190,53 @@ First let's create a new serializer that will support our ``Product`` resource: use Sylius\Component\Core\Model\ProductInterface; use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface; - use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; + use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; use Webmozart\Assert\Assert; - final class ProductSerializer implements ContextAwareNormalizerInterface + final class ProductNormalizer implements ContextAwareNormalizerInterface, NormalizerAwareInterface { - /** @var NormalizerInterface */ - private $objectNormalizer; + use NormalizerAwareTrait; - public function __construct(NormalizerInterface $objectNormalizer) { - $this->objectNormalizer = $objectNormalizer; - } + private const ALREADY_CALLED = 'product_normalizer_already_called'; public function normalize($object, $format = null, array $context = []) { Assert::isInstanceOf($object, ProductInterface::class); + Assert::keyNotExists($context, self::ALREADY_CALLED); + + $context[self::ALREADY_CALLED] = true; - $data = $this->objectNormalizer->normalize($object, $format, $context); + $data = $this->normalizer->normalize($object, $format, $context); return $data; } public function supportsNormalization($data, $format = null, $context = []): bool { + if (isset($context[self::ALREADY_CALLED])) { + return false; + } + return $data instanceof ProductInterface; } } And now let's declare its service in config files: -.. code-block:: xml +.. code-block:: yaml - - - - + # config/services.yaml + App\Serializer\ProductNormalizer: + tags: + - { name: 'serializer.normalizer', priority: 100 } Then we can add the new field: .. code-block:: php //... - $data = $this->objectNormalizer->normalize($object, $format, $context); + $data = $this->normalizer->normalize($object, $format, $context); $data['additionalText'] = 'your custom text or logic that will be added to this field.'; @@ -287,7 +292,7 @@ Let's assume that ``Product`` resource returns such a response: Then let's say you want to remove ``translations``. -Utilising serialization groups to remove fields might be quite tricky as symfony combines all of the serialization files into one. +Utilising serialization groups to remove fields might be quite tricky as Symfony combines all of the serialization files into one. The easiest solution to remove the field is to create a new serialization group and use it for fields you want to have and declare this group in the endpoint. First let's add the ``config/api_platform/Product.xml`` configuration file. See ``How to add an additional endpoint?`` for more information. @@ -344,17 +349,17 @@ Now we need to modify the file ``config/serialization/Product.xml`` and add this .. note:: In example the ``translations`` doesn't have the new group ``shop:product:custom_read`` so it won't be shown by that endpoint. - The rest of fields that we wan't to show has the new serialization group declared. + The rest of the fields that we want to show have the new serialization group declared. In cases, where you would like to remove small amount of fields, the serializer would be a way to go. -First step is to create a class as in ``Adding a field from response`` and register it's service. +First step is to create a class as in ``Adding a custom field to response`` and register its service. Then modify it's logic with this code: .. code-block:: php //... - $data = $this->objectNormalizer->normalize($object, $format, $context); + $data = $this->normalizer->normalize($object, $format, $context); unset($data['translations']); // removes `translations` from response @@ -423,7 +428,7 @@ In this example we will modify it, so the name of field would be changed. Just a .. code-block:: php //... - $data = $this->objectNormalizer->normalize($object, $format, $context); + $data = $this->normalizer->normalize($object, $format, $context); $data['options'] = $data['optionValues']; // this will change the name of your field unset($data['optionValues']); // optionally you can also remove old `optionValues` field From 6c076c138c1810c9e9a37bda80f89f337de51c17 Mon Sep 17 00:00:00 2001 From: arti0090 Date: Fri, 21 May 2021 08:58:05 +0200 Subject: [PATCH 4/6] add notes regarding adding/extending existing normalizers --- docs/customization/api.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/customization/api.rst b/docs/customization/api.rst index 67991b6f8f1..ab12c8d1312 100644 --- a/docs/customization/api.rst +++ b/docs/customization/api.rst @@ -178,7 +178,10 @@ Adding a custom field to response ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Let's say that you want to add a new field named ``additionalText`` to ``Product``. -First let's create a new serializer that will support our ``Product`` resource: +First we need to create a new serializer that will support our ``Product`` resource, but in this case we have a ``ProductNormalizer`` provided from Sylius. +Unfortunately we cannot use more than one normalizer per resource, hence we will override existing one. + +Let's than copy code of ProductNormalizer from ``vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Serializer/ProductNormalizer.php`` : .. code-block:: php @@ -208,6 +211,8 @@ First let's create a new serializer that will support our ``Product`` resource: $context[self::ALREADY_CALLED] = true; $data = $this->normalizer->normalize($object, $format, $context); + $variant = $this->defaultProductVariantResolver->getVariant($object); + $data['defaultVariant'] = $variant === null ? null : $this->iriConverter->getIriFromItem($variant); return $data; } @@ -231,6 +236,11 @@ And now let's declare its service in config files: tags: - { name: 'serializer.normalizer', priority: 100 } +.. warning:: + + As we can use only one Normalizer per resource we need to set priority higher then one from Sylius. + Default value for Sylius Normalizers is typically 64, but if you want to be sure, check the values in ``src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml`` + Then we can add the new field: .. code-block:: php From 2c93fe9312266e1b91ecd3a8de8758c4051eb6d2 Mon Sep 17 00:00:00 2001 From: arti0090 Date: Mon, 24 May 2021 12:23:50 +0200 Subject: [PATCH 5/6] new example and fixes --- docs/customization/api.rst | 175 ++++++++++++++++++++++++++----------- 1 file changed, 123 insertions(+), 52 deletions(-) diff --git a/docs/customization/api.rst b/docs/customization/api.rst index ab12c8d1312..1354cd9014c 100644 --- a/docs/customization/api.rst +++ b/docs/customization/api.rst @@ -105,7 +105,7 @@ The next step is to modify the security configuration in ``config/packages/secur Changing prefix without security configuration update can expose confidential data (like customers addresses). -After these two steps you can start to use endpoints with new prefixes +After these two steps you can start to use endpoints with new prefixes. How to customize serialization? ------------------------------- @@ -118,21 +118,24 @@ Adding a field to response Let's say that you want to serialize existing field named ``averageRating`` to ``Product`` in admin response so the administrator would be able to check what is the average rating of product. -First let's copy serialization configuration file named ``Product.xml`` from ``%kernel.project_dir%/vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/`` -to ``config/serialization/Product.xml`` - -Then let's find the attribute ``averageRating``: +First let's create serialization configuration file named ``Product.xml`` in ``config/serialization/Product.xml`` +and and add serialization group that is used by endpoint we want to modify, in this case the new ``group`` is called ``admin:product:read``: .. code-block:: xml - - - shop:product:read - - + - -and add serialization group that is used by endpoint we want to modify + + + + admin:product:read + shop:product:read + + + .. tip:: @@ -140,16 +143,9 @@ and add serialization group that is used by endpoint we want to modify you can find it by searching for your class configuration file in `%kernel.project_dir%/vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources`` and look for path that you want to modify. -In this case the new ``group`` is called ``admin:product:read``: - -.. code-block:: xml +.. tip:: - - - admin:product:read - shop:product:read - - + The serialization groups from Sylius look this way to reflect: ``user context``, ``resource name`` and ``type of operation``. After this change your response should be extended with new field: @@ -174,11 +170,95 @@ After this change your response should be extended with new field: We were able to add a field that exists in ``Product`` class, but what if you want to extend it with custom fields? Let's customize response now with your custom fields serialized in response. +.. tip:: + + The same way you may expose additional fields added to any Sylius resource + Adding a custom field to response ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Let's say that you want to add a new field named ``additionalText`` to ``Product``. -First we need to create a new serializer that will support our ``Product`` resource, but in this case we have a ``ProductNormalizer`` provided from Sylius. +Let's say that you want to add a new field named ``additionalText`` to ``Customer``. +First we need to create a new serializer that will support this resource. Let's name it ``CustomerNormalizer``: + +.. code-block:: php + + normalizer->normalize($object, $format, $context); + + return $data; + } + + public function supportsNormalization($data, $format = null, $context = []): bool + { + if (isset($context[self::ALREADY_CALLED])) { + return false; + } + + return $data instanceof CustomerInterface; + } + } + +And now let's declare its service in config files: + +.. code-block:: yaml + + # config/services.yaml + App\Serializer\CustomerNormalizer: + tags: + - { name: 'serializer.normalizer', priority: 100 } + +Then we can add the new field: + +.. code-block:: php + + //... + $data = $this->normalizer->normalize($object, $format, $context); + + $data['additionalText'] = 'your custom text or logic that will be added to this field.'; + + return $data; + //... + +Now your response should be extended with the new field: + +.. code-block:: javascript + + { + //... + "id": 123, + "email": "sylius@example.com", + "firstName": "sylius", + "additionalText": "my additional field with text", + //... + } + +But let's consider another case where the Normalizer exists for given Resource. +Here we will also add a new field named ``additionalText`` but this time to ``Product``. +First we need to create a serializer that will support our ``Product`` resource, but in this case we have a ``ProductNormalizer`` provided from Sylius. Unfortunately we cannot use more than one normalizer per resource, hence we will override existing one. Let's than copy code of ProductNormalizer from ``vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Serializer/ProductNormalizer.php`` : @@ -239,7 +319,7 @@ And now let's declare its service in config files: .. warning:: As we can use only one Normalizer per resource we need to set priority higher then one from Sylius. - Default value for Sylius Normalizers is typically 64, but if you want to be sure, check the values in ``src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml`` + You can find priority value of Normalizer in ``src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml`` Then we can add the new field: @@ -253,7 +333,7 @@ Then we can add the new field: return $data; //... -Now your response should be extended with the new field: +And your response should be extended with the new field: .. code-block:: javascript @@ -306,7 +386,7 @@ Utilising serialization groups to remove fields might be quite tricky as Symfony The easiest solution to remove the field is to create a new serialization group and use it for fields you want to have and declare this group in the endpoint. First let's add the ``config/api_platform/Product.xml`` configuration file. See ``How to add an additional endpoint?`` for more information. -Then let's modify the endpoint. For this example i will use GET item in shop, but you can also create some custom endpoint: +Then let's modify the endpoint. For this example I will use GET item in the shop, but you can also create some custom endpoint: .. code-block:: xml @@ -333,32 +413,23 @@ then let's change the serialization group in ``normalization_context`` attribute -Now we need to modify the file ``config/serialization/Product.xml`` and add this custom serialization group to fields we want to show: +Now we can define all the fields we want to expose in the ``config/serialization/Product.xml``: .. code-block:: xml - admin:product:read - - - admin:product:create - admin:product:read - admin:product:update - shop:product:read + shop:product:custom_read + - admin:product:create - admin:product:read - admin:product:update - shop:product:read shop:product:custom_read .. note:: - In example the ``translations`` doesn't have the new group ``shop:product:custom_read`` so it won't be shown by that endpoint. + In xml example the ``translations`` is not declared with ``shop:product:custom_read`` group, so endpoint won't return this value. The rest of the fields that we want to show have the new serialization group declared. In cases, where you would like to remove small amount of fields, the serializer would be a way to go. @@ -394,7 +465,7 @@ Renaming a field of a response ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Renaming name of response fields is very simple. In this example -let's modify the ``optionValues`` name to ``options``, that's how response looks like now: +let's modify the ``options`` name to ``optionValues``, that's how response looks like now: .. code-block:: javascript @@ -403,21 +474,21 @@ let's modify the ``optionValues`` name to ``options``, that's how response looks "id": 123, "code": "product_code", "product": "/api/v2/shop/products/product_code", - "optionValues": [ + "options": [ "/api/v2/shop/product-option-values/product_size_s" ], //... } -The simplest method to achieve this is to modify serialization configuration file. -We can use the file ``config/serialization/Product.xml`` from example above and find the attribute named ``optionValues`` +The simplest method to achieve this is to modify the serialization configuration file that we've already created. +Let's add to the ``config/serialization/Product.xml`` file config for ``options`` with a ``serialized-name`` attribute description: .. code-block:: xml - - admin:product:read - shop:product:read + + admin:product:read + shop:product:read @@ -426,9 +497,9 @@ And just add a ``serialized-name`` into attribute description with new name: .. code-block:: xml - - admin:product:read - shop:product:read + + admin:product:read + shop:product:read @@ -440,8 +511,8 @@ In this example we will modify it, so the name of field would be changed. Just a //... $data = $this->normalizer->normalize($object, $format, $context); - $data['options'] = $data['optionValues']; // this will change the name of your field - unset($data['optionValues']); // optionally you can also remove old `optionValues` field + $data['optionValues'] = $data['options']; // this will change the name of your field + unset($data['options']); // optionally you can also remove old `options` field return $data; //... @@ -455,7 +526,7 @@ And here we go, now your response should look like this: "id": 123, "code": "product_code", "product": "/api/v2/shop/products/product_code", - "options": [ + "optionValues": [ "/api/v2/shop/product-option-values/product_size_s" ], //... From 6c125ea44afe43cd2f6c4a672e37493492b60ba3 Mon Sep 17 00:00:00 2001 From: arti0090 Date: Tue, 25 May 2021 07:36:10 +0200 Subject: [PATCH 6/6] Language related fixes --- docs/customization/api.rst | 49 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/docs/customization/api.rst b/docs/customization/api.rst index 1354cd9014c..e35e87f5006 100644 --- a/docs/customization/api.rst +++ b/docs/customization/api.rst @@ -24,7 +24,7 @@ If your project was created before v1.10, make sure your API Platform config fol swagger: versions: [3] -And if you want to modify serialization add this code to framework config: +Also, if you're planning to modify serialization add this code to framework config: .. code-block:: yaml @@ -34,6 +34,8 @@ And if you want to modify serialization add this code to framework config: mapping: paths: [ '%kernel.project_dir%/config/serialization' ] +.. _how-to-add-additional-endpoint: + How to add an additional endpoint? ---------------------------------- @@ -116,10 +118,11 @@ For an example we will use ``Product`` resource and customize its fields. Adding a field to response ~~~~~~~~~~~~~~~~~~~~~~~~~~ -Let's say that you want to serialize existing field named ``averageRating`` to ``Product`` in admin response so the administrator would be able to check what is the average rating of product. +Let's say that you want to serialize the existing field named ``averageRating`` to ``Product`` in the admin response +so the administrator would be able to check what is the average rating of product. First let's create serialization configuration file named ``Product.xml`` in ``config/serialization/Product.xml`` -and and add serialization group that is used by endpoint we want to modify, in this case the new ``group`` is called ``admin:product:read``: +and add serialization group that is used by endpoint we want to modify, in this case the new ``group`` is called ``admin:product:read``: .. code-block:: xml @@ -139,8 +142,9 @@ and and add serialization group that is used by endpoint we want to modify, in t .. tip:: - You can create your own serialization group for every endpoint or use the one out of the box. If you don't know the name of group for endpoint you want to modify, - you can find it by searching for your class configuration file in `%kernel.project_dir%/vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources`` + You can create your own serialization group for every endpoint or use the one out of the box. + If you don't know the name of group for endpoint you want to modify, you can find it by searching + for your class configuration file in `%kernel.project_dir%/vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources`` and look for path that you want to modify. .. tip:: @@ -170,10 +174,6 @@ After this change your response should be extended with new field: We were able to add a field that exists in ``Product`` class, but what if you want to extend it with custom fields? Let's customize response now with your custom fields serialized in response. -.. tip:: - - The same way you may expose additional fields added to any Sylius resource - Adding a custom field to response ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -256,12 +256,12 @@ Now your response should be extended with the new field: //... } -But let's consider another case where the Normalizer exists for given Resource. +But let's consider another case where the Normalizer exists for a given Resource. Here we will also add a new field named ``additionalText`` but this time to ``Product``. -First we need to create a serializer that will support our ``Product`` resource, but in this case we have a ``ProductNormalizer`` provided from Sylius. -Unfortunately we cannot use more than one normalizer per resource, hence we will override existing one. +First, we need to create a serializer that will support our ``Product`` resource but in this case, we have a ``ProductNormalizer`` provided by Sylius. +Unfortunately, we cannot use more than one normalizer per resource, hence we will override the existing one. -Let's than copy code of ProductNormalizer from ``vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Serializer/ProductNormalizer.php`` : +Let's then copy the code of ProductNormalizer from ``vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Serializer/ProductNormalizer.php`` : .. code-block:: php @@ -318,8 +318,8 @@ And now let's declare its service in config files: .. warning:: - As we can use only one Normalizer per resource we need to set priority higher then one from Sylius. - You can find priority value of Normalizer in ``src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml`` + As we can use only one Normalizer per resource we need to set priority for it, higher then the priority of the Sylius one. + You can find the priority value of the Sylius Normalizer in ``src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml`` Then we can add the new field: @@ -351,8 +351,8 @@ And your response should be extended with the new field: Removing a field from a response ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Let's say that for some reason you want to remove some field from serialization. -One of possible solution could be that you use serialization groups. +Let's say that for some reason you want to remove a field from serialization. +One possible solution could be that you use serialization groups. Those will limit the fields from your resource, according to serialization groups that you will choose. .. tip:: @@ -383,10 +383,10 @@ Let's assume that ``Product`` resource returns such a response: Then let's say you want to remove ``translations``. Utilising serialization groups to remove fields might be quite tricky as Symfony combines all of the serialization files into one. -The easiest solution to remove the field is to create a new serialization group and use it for fields you want to have and declare this group in the endpoint. +The easiest solution to remove the field is to create a new serialization group, use it for the fields you want to have, and declare this group in the endpoint. -First let's add the ``config/api_platform/Product.xml`` configuration file. See ``How to add an additional endpoint?`` for more information. -Then let's modify the endpoint. For this example I will use GET item in the shop, but you can also create some custom endpoint: +First, let's add the ``config/api_platform/Product.xml`` configuration file. See :ref:`how-to-add-additional-endpoint` for more information. +Then let's modify the endpoint. For this example, we will use GET item in the shop, but you can also create some custom endpoint: .. code-block:: xml @@ -464,7 +464,7 @@ Now your response fields should look like this: Renaming a field of a response ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Renaming name of response fields is very simple. In this example +Changing the name of response fields is very simple. In this example let's modify the ``options`` name to ``optionValues``, that's how response looks like now: .. code-block:: javascript @@ -492,7 +492,7 @@ Let's add to the ``config/serialization/Product.xml`` file config for ``options` -And just add a ``serialized-name`` into attribute description with new name: +And just add a ``serialized-name`` into the attribute description with a new name: .. code-block:: xml @@ -532,6 +532,7 @@ And here we go, now your response should look like this: //... } -.. tip:: +Learn more +----------- - Read more about API Platform `serialization `_ +* `API Platform serialization `_