integration_documentation:plugin:en:integration:shopware_6:extension

integration_documentation:plugin:en:integration:shopware_6:extension

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
integration_documentation:plugin:en:integration:shopware_6:extension [2022/06/21 09:22]
tobi created
integration_documentation:plugin:en:integration:shopware_6:extension [2022/12/13 13:42] (current)
tobi
Line 15: Line 15:
  
 </​markdown>​ </​markdown>​
-<note tip>​Please make sure to use the same major version as the base Findologic plugin. This means that ''​2.x''​ is compatible with ''​2.x''​ and ''​3.x''​ is compatible with ''​3.x'',​ etc.</​note>​+<note tip>​Please make sure to use the same major version as the base Findologic plugin. This means that ''​3.x''​ is compatible with ''​3.x''​ and ''​4.x''​ is compatible with ''​4.x'',​ etc.</​note
 +<​markdown>
  
 ## Basics ## Basics
Line 24: Line 25:
  
 By default the extension plugin decorates the `AttributeAdapter` and `DefaultPropertiesAdapter`,​ which are responsible to generate the attributes and properties of a product. By default the extension plugin decorates the `AttributeAdapter` and `DefaultPropertiesAdapter`,​ which are responsible to generate the attributes and properties of a product.
-Any adapter in `FINDOLOGIC\FinSearch\Export\Adapters` can be decorated.+Any adapter in `FINDOLOGIC\Shopware6Common\Export\Adapters` can be decorated. The original files are located within `vendor/​findologic/​shopware6-common/​src/​Export/​Adapters`.
  
 `src/​Resources/​config/​services.xml` `src/​Resources/​config/​services.xml`
Line 37: Line 38:
         <service         <service
             id="​FINDOLOGIC\ExtendFinSearch\Export\Adapters\AttributeAdapter"​             id="​FINDOLOGIC\ExtendFinSearch\Export\Adapters\AttributeAdapter"​
-            decorates="​FINDOLOGIC\FinSearch\Export\Adapters\AttributeAdapter"​+            decorates="​FINDOLOGIC\Shopware6Common\Export\Adapters\AttributeAdapter"​
             public="​true"​             public="​true"​
             decoration-on-invalid="​ignore"​             decoration-on-invalid="​ignore"​
 +            autowire="​true"​
         >         >
-            <​argument ​type="service" ​id="​service_container"​ /> +            <​argument ​key="$dynamicProductGroupService" type="​service"​ id="​FINDOLOGIC\FinSearch\Export\Services\DynamicProductGroupService" /> 
-            <​argument ​type="​service"​ id="​FINDOLOGIC\FinSearch\Struct\Config" /> +            <​argument ​key="​$catUrlBuilderService" ​type="​service"​ id="FINDOLOGIC\FinSearch\Export\Services\CatUrlBuilderService" /> 
-            <​argument type="​service"​ id="Shopware\Core\Framework\Adapter\Translation\Translator" /> +            <​argument ​key="$translator" type="​service"​ id="Shopware\Core\Framework\Adapter\Translation\Translator" />
-            <​argument ​type="service" ​id="​fin_search.sales_channel_context"​ /> +
-            <​argument ​type="​service"​ id="FINDOLOGIC\FinSearch\Export\UrlBuilderService"​ /> +
-            <​argument type="​service"​ id="​fin_search.export_context" />+
         </​service>​         </​service>​
  
         <service         <service
             id="​FINDOLOGIC\ExtendFinSearch\Export\Adapters\DefaultPropertiesAdapter"​             id="​FINDOLOGIC\ExtendFinSearch\Export\Adapters\DefaultPropertiesAdapter"​
-            decorates="​FINDOLOGIC\FinSearch\Export\Adapters\DefaultPropertiesAdapter"​+            decorates="​FINDOLOGIC\Shopware6Common\Export\Adapters\DefaultPropertiesAdapter"​
             public="​true"​             public="​true"​
             decoration-on-invalid="​ignore"​             decoration-on-invalid="​ignore"​
 +            autowire="​true"​
         >         >
-            <​argument ​type="service" ​id="​FINDOLOGIC\FinSearch\Struct\Config"​ /> +            <​argument ​key="$translator" type="​service"​ id="​Shopware\Core\Framework\Adapter\Translation\Translator"​ />
-            <​argument type="​service"​ id="​fin_search.sales_channel_context"​ /> +
-            <​argument ​type="​service"​ id="​Shopware\Core\Framework\Adapter\Translation\Translator"​ />+
         </​service>​         </​service>​
  
Line 77: Line 75:
  
 use FINDOLOGIC\Export\Data\Attribute;​ use FINDOLOGIC\Export\Data\Attribute;​
-use FINDOLOGIC\FinSearch\Export\Adapters\AttributeAdapter as OriginalAttributeAdapter;​ +use FINDOLOGIC\Shopware6Common\Export\Adapters\AttributeAdapter as OriginalAttributeAdapter;​ 
-use Shopware\Core\Content\Product\ProductEntity;​+use Vin\ShopwareSdk\Data\Entity\Product\ProductEntity;​
  
 class AttributeAdapter extends OriginalAttributeAdapter class AttributeAdapter extends OriginalAttributeAdapter
Line 109: Line 107:
  
 use FINDOLOGIC\Export\Data\Property;​ use FINDOLOGIC\Export\Data\Property;​
-use FINDOLOGIC\FinSearch\Export\Adapters\DefaultPropertiesAdapter as OriginalDefaultPropertiesAdapter;​ +use FINDOLOGIC\Shopware6Common\Export\Adapters\DefaultPropertiesAdapter as OriginalDefaultPropertiesAdapter;​ 
-use Shopware\Core\Content\Product\ProductEntity;​+use Vin\ShopwareSdk\Data\Entity\Product\ProductEntity;​
  
 class DefaultPropertiesAdapter extends OriginalDefaultPropertiesAdapter class DefaultPropertiesAdapter extends OriginalDefaultPropertiesAdapter
Line 129: Line 127:
  
 ### Autoloading ### Autoloading
- 
 </​markdown>​ </​markdown>​
 +
 <note tip>You only need composer autoloading in case you [[https://​getcomposer.org/​doc/​03-cli.md#​require|require additional composer dependencies]].</​note>​ <note tip>You only need composer autoloading in case you [[https://​getcomposer.org/​doc/​03-cli.md#​require|require additional composer dependencies]].</​note>​
 +
 <​markdown>​ <​markdown>​
 +
 ![https://​docs.findologic.com/​lib/​exe/​fetch.php?​t=1603273975&​tok=ddd8c2&​media=integration_documentation:​extension.png](https://​docs.findologic.com/​lib/​exe/​fetch.php?​t=1603273975&​tok=ddd8c2&​media=integration_documentation:​extension.png)  ​ ![https://​docs.findologic.com/​lib/​exe/​fetch.php?​t=1603273975&​tok=ddd8c2&​media=integration_documentation:​extension.png](https://​docs.findologic.com/​lib/​exe/​fetch.php?​t=1603273975&​tok=ddd8c2&​media=integration_documentation:​extension.png)  ​
  
 While composer autoloading is disabled by default, you can always enable it by uncommenting the marked line in `\FINDOLOGIC\ExtendFinSearch\ExtendFinSearch`. While composer autoloading is disabled by default, you can always enable it by uncommenting the marked line in `\FINDOLOGIC\ExtendFinSearch\ExtendFinSearch`.
 +
 +# Examples
 +
 +## Add custom properties to the export
 +
 +The base `DefaultPropertiesAdapter` allows you to add properties by extending the `adapt` function.
 +
 +```php
 +//...
 +public function adapt(ProductEntity $product): array
 +{
 +    $properties = parent::​adapt($product);​
 +
 +    $properties[] = new Property(
 +        'Some property name',
 +        [''​ => 'I am a property value!'​]
 +    );
 +
 +    return $properties;​
 +}
 +```
 +
 +The part `[''​ => 'I am a property value!'​]` has an empty string as array index. An empty string as an array key, simply means that there is no usergroup, as property data can be usergroup-specific.  ​
 +
 +You can read more about usergroups in the [libflexport documentation](https://​github.com/​findologic/​libflexport/​wiki),​ which is the library used to build the export xml.
 +
 +</​markdown>​
 +<note tip>In case you have usergroup-specific data, properties which should be available for all usergroups, must be added individually for each usergroup.</​note>​
 +<​markdown>​
 +
 +## Add variant data to the export
 +
 +By default Findologic maps all variants into a single product during product export. However there is still the possibility to show variant information on listing pages, but this information needs to be exported to Findologic.
 +
 +Please follow the next sections to understand how the core plugin maps variants into a single product.
 +
 +### Basic product mapping
 +
 +Shopware works with display groups, which are used to take one product and all its variants, and map them to one product. See the following table, which represents a simplified product table:
 +
 +| id | parentId | name                                     | displayGroup |
 +|----|----------|------------------------------------------|--------------|
 +| 1  | null     | Findologic T-Shirt ​                      | null         |
 +| 2  | 1        | Findologic T-Shirt (Black - White Logo)  | 1            |
 +| 3  | 1        | Findologic T-Shirt (Gray - Orange Logo)  | 1            |
 +
 +These are three separate products, two of those products are variants of `Findologic T-Shirt`. The `ProductSearcher` is responsible for fetching all variants of one display group, and mapping them together. This results in main product no longer being `Findologic T-Shirt`, but instead `Findologic T-Shirt (Black - White Logo)`. To still have the data of the main product available in the export, the main product, and all other variants, are assigned as children of this variant. ​
 +
 +**Structure:​**
 +```
 +Findologic T-Shirt (Black - White Logo)
 +├── children
 +│   ​├── Findologic T-Shirt (Gray - Orange Logo)
 +│   ​└── Findologic T-Shirt
 +```
 +
 +This data structure is exactly like Shopware determines its results on listing pages. The used main variant in this case is typically the cheapest available variant. In case a product has no variants, or [fan out properties in the product list](https://​docs.shopware.com/​en/​shopware-6-en/​catalogues/​products?​category=shopware-6-en/​catalogues#​variants) is configured, the product has its own display group, so none of this reordering is happening.
 +
 +### Basic code structure
 +
 +This extension will use the defined events from the main plugin.
 +
 +`src/​Subscriber/​ProductSubscriber.php`
 +```php
 +<?php
 +
 +declare(strict_types=1);​
 +
 +namespace FINDOLOGIC\ExtendFinSearch\Subscriber;​
 +
 +use FINDOLOGIC\Export\Data\Property;​
 +use FINDOLOGIC\Shopware6Common\Export\Adapters\AdapterFactory;​
 +use FINDOLOGIC\Shopware6Common\Export\Events\AfterItemBuildEvent;​
 +use FINDOLOGIC\Shopware6Common\Export\Events\AfterVariantAdaptEvent;​
 +use FINDOLOGIC\Shopware6Common\Export\Events\BeforeItemAdaptEvent;​
 +use Symfony\Component\EventDispatcher\EventSubscriberInterface;​
 +use Vin\ShopwareSdk\Data\Entity\Product\ProductEntity;​
 +
 +class ProductSubscriber implements EventSubscriberInterface
 +{
 +    /** @var AdapterFactory */
 +    private $adapterFactory;​
 +
 +    private $variantData = [];
 +
 +    public function __construct(AdapterFactory $adapterFactory)
 +    {
 +        $this->​adapterFactory = $adapterFactory;​
 +    }
 +
 +    public static function getSubscribedEvents()
 +    {
 +        return [
 +            AfterVariantAdaptEvent::​NAME => '​afterVariantAdapted',​
 +            AfterItemBuildEvent::​NAME => '​afterItemCompleted'​
 +        ];
 +    }
 +
 +    public function afterVariantAdapted(AfterVariantAdaptEvent $event)
 +    {
 +        $product = $event->​getProduct();​
 +
 +        $this->​variantData[] = [
 +            // Your variant data
 +        ];
 +    }
 +
 +    public function afterItemCompleted(AfterItemBuildEvent $event)
 +    {
 +        $item = $event->​getItem();​
 +
 +        if (count($this->​variantData)) {
 +            $item->​addProperty(
 +                new Property('​variants',​ [
 +                    ''​ => json_encode($this->​variantData)
 +                ])
 +            );
 +        }
 +        ​
 +        $this->​variantData = [];
 +    }
 +}
 +```
 +
 +`src/​Resources/​config/​services.xml`
 +```xml
 +<?xml version="​1.0"​ ?>
 +<​container xmlns:​xsi="​http://​www.w3.org/​2001/​XMLSchema-instance"​
 +    xmlns="​http://​symfony.com/​schema/​dic/​services"​
 +    xsi:​schemaLocation="​http://​symfony.com/​schema/​dic/​services http://​symfony.com/​schema/​dic/​services/​services-1.0.xsd">​
 +
 +    <​services>​
 +
 +        <service
 +            id="​FINDOLOGIC\ExtendFinSearch\Subscriber\ProductSubscriber"​
 +            class="​FINDOLOGIC\ExtendFinSearch\Subscriber\ProductSubscriber"​
 +            public="​true"​
 +        >
 +            <tag name="​kernel.event_subscriber"​ />
 +            <​argument type="​service"​ id="​FINDOLOGIC\Shopware6Common\Export\Adapters\AdapterFactory"​ />
 +        </​service>​
 +
 +    </​services>​
 +</​container>​
 +```
 +
 +### Add basic variant data
 +
 +`src/​Subscriber/​ProductSubscriber.php`
 +```php
 +//...
 +
 +public function afterVariantAdapted(AfterVariantAdaptEvent $event)
 +{
 +    $product = $event->​getProduct();​
 +
 +    $this->​variantData[] = [
 +        '​name'​ => $this->​getName($product),​
 +        '​url'​ => $this->​getUrl($product),​
 +        '​price'​ => $this->​getPrice($product)
 +    ];
 +}
 +
 +//...
 +
 +private function getName(ProductEntity $productEntity):​ string
 +{
 +    $name = $this->​adapterFactory->​getNameAdapter()->​adapt($productEntity);​
 +
 +    return $name ? $name->​getValues()[''​] : '';​
 +}
 +
 +private function getUrl(ProductEntity $productEntity):​ string
 +{
 +    $url = $this->​adapterFactory->​getUrlAdapter()->​adapt($productEntity);​
 +
 +    return $url ? $url->​getValues()[''​] : '';​
 +}
 +
 +private function getPrice(ProductEntity $productEntity):​ string
 +{
 +    $prices = $this->​adapterFactory->​getPriceAdapter()->​adapt($productEntity);​
 +
 +    $prices = array_filter($prices,​ function (Price $price) {
 +        return array_key_exists('',​ $price->​getValues());​
 +    });
 +
 +    return count($prices) ? current($prices)->​getValues()[''​] : '';​
 +}
 +
 +//...
 +```
 +
 +This will export the `name`, `url` and `price` of each variant, the JSON would be like: 
 +```json
 +[
 +  {
 +    "​name":​ "​Findologic T-Shirt (Gray - Orange Logo)",​
 +    "​url":​ "​https://​store.com/​Findologic-T-Shirt-Gray-Orange-Logo/​411dc735cade4c8789421f9c2aaec51f",​
 +    "​price":​ 59.99
 +  },
 +  {
 +    "​name":​ "​Findologic T-Shirt",​
 +    "​url":​ "​https://​store.com/​Findologic-T-Shirt/​ad99a6257e1546f08dbe9886a48e4230",​
 +    "​price":​ 55.99
 +  },
 +  {
 +    "​name":​ "​Findologic T-Shirt (Black - White Logo)",​
 +    "​url":​ "​https://​store.com/​Findologic-T-Shirt/​7c18c5ff8aa548e1bdba6b738ac42f71",​
 +    "​price":​ 49.99
 +  }
 +]
 +```
 +
 +### Add images
 +
 +For variant images, you will need to add the relevant variant associations as shown [here](#​add_product_or_variant_associations). (`cover` and `media`)
 +
 +Additionally:​
 +`src/​Subscriber/​ProductSubscriber.php`
 +```php
 +// ...
 +
 +public function afterVariantAdapted(AfterVariantAdaptEvent $event)
 +{
 +    $product = $event->​getProduct();​
 +
 +    $this->​variantData[] = [
 +        // ...
 +        '​image'​ => $this->​getImageUrl($product)
 +    ];
 +}
 +
 +// ...
 +
 +private function getImageUrl(ProductEntity $productEntity):​ string
 +{
 +    $images = $this->​adapterFactory->​getImagesAdapter()->​adapt($productEntity);​
 +
 +    return count($images) ? current($images)->​getUrl() : '';​
 +}
 +```
 +
 +### Deal with variant-specific data
 +
 +`src/​Subscriber/​ProductSubscriber.php`
 +```php
 +// ...
 +
 +private const VARIANT_PROPERTY = '​color';​
 +
 +//...
 +
 +public function afterVariantAdapted(AfterVariantAdaptEvent $event)
 +{
 +    $product = $event->​getProduct();​
 +
 +    foreach ($product->​properties as $variantProperty) {
 +        // Ignore all properties except the property we want to export our variants off.
 +        if (
 +            !$variantProperty->​group ||
 +            $variantProperty->​group->​getTranslation('​name'​) !== self::​VARIANT_PROPERTY)
 +        {
 +            continue;
 +        }
 +
 +        $propertyName = $variantProperty->​getTranslation('​name'​);​
 +
 +        $this->​variantData[$propertyName] = [
 +            '​name'​ => $this->​getName($product),​
 +            '​url'​ => $this->​getUrl($product),​
 +            '​price'​ => $this->​getPrice($product),​
 +            '​image'​ => $this->​getImageUrl($product),​
 +            self::​VARIANT_PROPERTY => $propertyName
 +        ];
 +    }
 +}
 +
 +// ...
 +```
 +
 +After this implementation,​ the JSON would be like: 
 +
 +```json
 +{
 +  "​Gray":​ {
 +    "​name":​ "​Findologic T-Shirt (Gray - Orange Logo)",​
 +    "​image":​ "​https://​store.com/​some/​path/​to/​image_800x800.jpg",​
 +    "​url":​ "​https://​store.com/​Findologic-T-Shirt-Gray-Orange-Logo/​411dc735cade4c8789421f9c2aaec51f",​
 +    "​color":​ "​Gray"​
 +  },
 +  "​Black":​ {
 +    "​name":​ "​Findologic T-Shirt (Black - White Logo)",​
 +    "​image":​ "​https://​store.com/​some/​path/​to/​image_800x800.jpg",​
 +    "​url":​ "​https://​store.com/​Findologic-T-Shirt/​7c18c5ff8aa548e1bdba6b738ac42f71",​
 +    "​color":​ "​Black"​
 +  }
 +}
 +```
 +
 +### Usergroup-specific variants
 +
 +`src/​Subscriber/​ProductSubscriber.php`
 +```php
 +//...
 +
 +public function afterVariantAdapted(AfterVariantAdaptEvent $event)
 +{
 +    $product = $event->​getProduct();​
 +
 +    $basicVariantData = [
 +        '​name'​ => $this->​getName($product),​
 +        '​url'​ => $this->​getUrl($product),​
 +        '​image'​ => $this->​getImageUrl($product)
 +    ];
 +
 +    foreach ($this->​adapterFactory->​getPriceAdapter()->​adapt($product) as $price) {
 +        $values = $price->​getValues();​
 +
 +        $variantData = array_merge(
 +            $basicVariantData,​
 +            [
 +                '​price'​ => current($values)
 +            ]
 +        );
 +
 +        $this->​variantData[array_key_first($values)][] = json_encode($variantData);​
 +    }
 +}
 +
 +public function afterItemCompleted(AfterItemBuildEvent $event)
 +{
 +    $variantData = [];
 +    foreach ($this->​variantData as $usergroup => $userGroupVariantData) {
 +        $variantData[$usergroup] = json_encode($userGroupVariantData);​
 +    }
 +
 +    $item = $event->​getItem();​
 +
 +    if (count($this->​variantData)) {
 +        $item->​addProperty(
 +            new Property('​variants',​ $variantData)
 +        );
 +    }
 +}
 +
 +//...
 +```
 +
 +</​markdown>​
 +
 +<note tip>''​variants''​ **must** be exported for **all** usergroups. If a usergroup is not exported, this usergroup will not have any ''​variants''​ data.</​note>​
 +
 +<​markdown>​
 +
 +An XML export with usergroup in properties may look like:
 +
 +```xml
 +<!-- ... -->
 +<​allProperties>​
 +    <​property usergroup="​JyInVwMCBQtTdQ1RAwkmCSRXUVkGBCZ6B1YgDyFXVnc=">​
 +        <key>
 +            <​![CDATA[ variants ]]>
 +        </​key>​
 +        <​value>​
 +            <​![CDATA[
 +                [
 +                    {
 +                        "​name":​ "​Findologic T-Shirt (Gray - Orange Logo)",​
 +                        "​image":​ "​https://​store.com/​some/​path/​to/​image_800x800.jpg",​
 +                        "​url":​ "​https://​store.com/​Findologic-T-Shirt-Gray-Orange-Logo/​411dc735cade4c8789421f9c2aaec51f",​
 +                        "​price":​ 59.99
 +                    },
 +                    {
 +                        "​name":​ "​Findologic T-Shirt",​
 +                        "​image":​ "​https://​store.com/​some/​path/​to/​image_800x800.jpg",​
 +                        "​url":​ "​https://​store.com/​Findologic-T-Shirt/​ad99a6257e1546f08dbe9886a48e4230",​
 +                        "​price":​ 55.99
 +                    },
 +                    {
 +                        "​name":​ "​Findologic T-Shirt (Black - White Logo)",​
 +                        "​image":​ "​https://​store.com/​some/​path/​to/​image_800x800.jpg",​
 +                        "​url":​ "​https://​store.com/​Findologic-T-Shirt/​7c18c5ff8aa548e1bdba6b738ac42f71",​
 +                        "​price":​ 49.99
 +                    }
 +                ]
 +            ]]>
 +        </​value>​
 +    </​property>​
 +    <​property usergroup="​dX1WUgsgCyVUIHcPcXYFUw1xUlBZUwcAB1FUcgNQCwA=">​
 +        <key>
 +            <​![CDATA[ variants ]]>
 +        </​key>​
 +        <​value>​
 +            <​![CDATA[
 +                [
 +                    {
 +                        "​name":​ "​Findologic T-Shirt (Gray - Orange Logo)",​
 +                        "​image":​ "​https://​store.com/​some/​path/​to/​image_800x800.jpg",​
 +                        "​url":​ "​https://​store.com/​Findologic-T-Shirt-Gray-Orange-Logo/​411dc735cade4c8789421f9c2aaec51f",​
 +                        "​price":​ 599.99
 +                    },
 +                    {
 +                        "​name":​ "​Findologic T-Shirt",​
 +                        "​image":​ "​https://​store.com/​some/​path/​to/​image_800x800.jpg",​
 +                        "​url":​ "​https://​store.com/​Findologic-T-Shirt/​ad99a6257e1546f08dbe9886a48e4230",​
 +                        "​price":​ 559.99
 +                    },
 +                    {
 +                        "​name":​ "​Findologic T-Shirt (Black - White Logo)",​
 +                        "​image":​ "​https://​store.com/​some/​path/​to/​image_800x800.jpg",​
 +                        "​url":​ "​https://​store.com/​Findologic-T-Shirt/​7c18c5ff8aa548e1bdba6b738ac42f71",​
 +                        "​price":​ 499.99
 +                    }
 +                ]
 +            ]]>
 +        </​value>​
 +    </​property>​
 +</​allProperties>​
 +<!-- ... -->
 +```
 +
 +## Add product or variant associations
 +
 +Sometimes the plugin doesn'​t add the associations needed in the extension. This may cause the associated field to always return `null. It's also the case if third party plugins extend the product entity with an additional table. Other examples include image URLs or color codes from variant properties.
 +
 +Decorate `FINDOLOGIC\FinSearch\Export\Search\ProductCriteriaBuilder`:​
 +
 +`src/​Export/​Search/​ProductCriteriaBuilder.php`
 +```php
 +<?php
 +
 +declare(strict_types=1);​
 +
 +namespace FINDOLOGIC\ExtendFinSearch\Export\Search;​
 +
 +use FINDOLOGIC\FinSearch\Export\Search\ProductCriteriaBuilder as OriginalProductCriteriaBuilder;​
 +
 +class ProductCriteriaBuilder extends OriginalProductCriteriaBuilder
 +{
 +    public function withProductAssociations():​ OriginalProductCriteriaBuilder
 +    {
 +        parent::​withProductAssociations();​
 +
 +        $this->​criteria->​addAssociations([
 +            // Additional associations
 +        ]);
 +
 +        return $this;
 +    }
 +
 +    public function withVariantAssociations():​ OriginalProductCriteriaBuilder
 +    {
 +        parent::​withVariantAssociations();​
 +
 +        $this->​criteria->​addAssociations([
 +            '​cover',​
 +            '​media'​
 +        ]);
 +
 +        return $this;
 +    }
 +}
 +```
 +
 +`src/​Resources/​config/​services.xml`
 +```xml
 +<?xml version="​1.0"​ ?>
 +<​container xmlns:​xsi="​http://​www.w3.org/​2001/​XMLSchema-instance"​
 +    xmlns="​http://​symfony.com/​schema/​dic/​services"​
 +    xsi:​schemaLocation="​http://​symfony.com/​schema/​dic/​services http://​symfony.com/​schema/​dic/​services/​services-1.0.xsd">​
 +
 +    <​services>​
 +
 +        <!-- ... -->
 +
 +        <service
 +            id="​FINDOLOGIC\ExtendFinSearch\Export\Search\ProductCriteriaBuilder"​
 +            decorates="​FINDOLOGIC\FinSearch\Export\Search\ProductCriteriaBuilder"​
 +            public="​true"​
 +            decoration-on-invalid="​ignore"​
 +            autowire="​true"​
 +        />
 +        ​
 +        <!-- ... -->
 +
 +    </​services>​
 +</​container>​
 +```
 +
 +## Cookie Consent for Direct Integration
 +
 +In case it's required by the integration,​ you are required to add a cookie consent. Please see the Shopware 6 documentation about [Adding a cookie to the cookie manager]( https://​developer.shopware.com/​docs/​guides/​plugins/​plugins/​storefront/​add-cookie-to-manager).
 +
 +There is also an [example](https://​github.com/​findologic/​plugin-shopware-6-extension/​commit/​cf1a0b68a8f590f8eaf818dc038b5903edfbfd80) available in our GitHub repository.
 +
 +## Add custom sorting options for API Integration
 +
 +The Findologic base plugin already provides sorting options for the most common use-cases. The plugin uses `SortingHandler` to send the currently selected sorting option via API parameters to the Findologic Search-API (see [all available SortingHandlers](https://​github.com/​findologic/​plugin-shopware-6/​tree/​develop/​src/​Core/​Content/​Product/​SalesChannel/​Listing/​SortingHandler)).
 +
 +Therefore to handle custom sorting options, create a custom `SortingHandler` in the extension plugin, and override the responsible `SortingHandlerService` to include the created `SortingHandler`.
 +
 +### Prerequisites
 +
 +Before a custom sorting can be used, make sure to export the value for the custom sort in the `<​sort>​` field in the export. See the [XML Format documentation](:​xml_export_documentation:​xml_format#​sorts) for further details.
 +
 +### Implementation
 +
 +**Step 1: Create a `SortingHandler`**
 +
 +Create the folder structure `Core/​Content/​Product/​SalesChannel/​Listing/​SortingHandler` in the extension plugin, and add a custom sorting handler class. In this example it will be `ThirdPartySortingHandler`:​
 +
 +```php
 +use FINDOLOGIC\Api\Requests\SearchNavigation\SearchNavigationRequest;​
 +use FINDOLOGIC\FinSearch\Core\Content\Product\SalesChannel\Listing\SortingHandler\SortingHandlerInterface;​
 +use Shopware\Core\Framework\DataAbstractionLayer\Search\Sorting\FieldSorting;​
 +
 +class ThirdPartySortingHandler implements SortingHandlerInterface
 +{
 +    public function supportsSorting(FieldSorting $fieldSorting):​ bool
 +    {
 +        // Enter your custom sort here.
 +        // To get the name of the sort, select the sort in the storefront and
 +        // add a dd($fieldSorting) here and refresh the page.
 +        return $fieldSorting->​getField() === '​product.third_party_extension.field';​
 +    }
 +
 +    public function generateSorting(FieldSorting $fieldSorting,​ SearchNavigationRequest $searchNavigationRequest):​ void
 +    {
 +        $searchNavigationRequest->​setOrder('​shopsort ' . $fieldSorting->​getDirection());​
 +    }
 +}
 +```
 +
 +**Step 2: Decorate the `SortingHandlerService`**
 +
 +The `SortingHandlerService` holds all available sorting options. Therefore, you want to add your custom sort to this service. The service can be found in `Findologic/​Request/​Handler`. Simply override the `getSortingHandlers` method to include your own custom sorting handler.
 +
 +```php
 +namespace FINDOLOGIC\ExtendFinSearch\Findologic\Request\Handler;​
 +
 +use FINDOLOGIC\ExtendFinSearch\Core\Content\Product\SalesChannel\Listing\SortingHandler\ThirdPartySortingHandler;​
 +use FINDOLOGIC\FinSearch\Core\Content\Product\SalesChannel\Listing\SortingHandler\SortingHandlerInterface;​
 +use FINDOLOGIC\FinSearch\Findologic\Request\Handler\SortingHandlerService as OriginalSortingHandlerService;​
 +
 +class SortingHandlerService extends OriginalSortingHandlerService
 +{
 +    /**
 +     * @return SortingHandlerInterface[]
 +     */
 +    protected function getSortingHandlers():​ array
 +    {
 +        return array_merge(
 +            parent::​getSortingHandlers(),​
 +            [
 +                new ThirdPartySortingHandler()
 +            ]
 +        );
 +    }
 +}
 +```
 +
 +**Step 3: Add the decorated service to the services.xml**
 +
 +As a last step, simply decorate in your `src/​Resources/​config/​services.xml` the service of the main plugin:
 +
 +```xml
 +<?xml version="​1.0"​ ?>
 +<​container xmlns:​xsi="​http://​www.w3.org/​2001/​XMLSchema-instance"​
 +    xmlns="​http://​symfony.com/​schema/​dic/​services"​
 +    xsi:​schemaLocation="​http://​symfony.com/​schema/​dic/​services http://​symfony.com/​schema/​dic/​services/​services-1.0.xsd">​
 +
 +    <​services>​
 +
 +        <service
 +            id="​FINDOLOGIC\ExtendFinSearch\Findologic\Request\Handler\SortingHandlerService"​
 +            decorates="​FINDOLOGIC\FinSearch\Findologic\Request\Handler\SortingHandlerService"​
 +            decoration-on-invalid="​ignore"​
 +        />
 +
 +    </​services>​
 +</​container>​
 +```
 +
 +Once this step is done, selecting your relevant sorting option will send the order parameter to the Findologic API.
 +
 +</​markdown>​