integration_documentation:plugin:en:integration:shopware_5:extension

integration_documentation:plugin:en:integration:shopware_5:extension

Differences

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

Link to this comparison view

Next revision
Previous revision
integration_documentation:plugin:en:integration:shopware_5:extension [2021/11/30 16:55]
tobi created
integration_documentation:plugin:en:integration:shopware_5:extension [2022/04/21 18:17] (current)
daniel
Line 11: Line 11:
  
 1. Download the latest zip file from our [GitHub release](https://​github.com/​findologic/​plugin-shopware-5-extension/​releases) page.  1. Download the latest zip file from our [GitHub release](https://​github.com/​findologic/​plugin-shopware-5-extension/​releases) page. 
-2. Open the Plugin Manager + 
-3. Click "Upload plugin" -> select downloaded zip file -> Click "​Upload plugin"​ again+2. Open the Plugin Manager ​in the Shopware backend. 
 + 
 +3. Click **Upload plugin** and select downloaded zip file.
  
     ![](https://​docs.findologic.com/​lib/​exe/​fetch.php?​cache=&​media=integration_documentation:​plugin:​en:​integration:​shopware_5:​plugin_installation.png)     ![](https://​docs.findologic.com/​lib/​exe/​fetch.php?​cache=&​media=integration_documentation:​plugin:​en:​integration:​shopware_5:​plugin_installation.png)
Line 117: Line 119:
     }     }
  
-    /+    //...
-     * Example on how to add custom properties to the item +
-     */ +
-    public function setProperties() +
-    { +
-        parent::​setProperties();​ +
-    } +
- +
-    /* +
-     * Direct Integration only: +
-     * Example on how to add a property with all variants as a JSON. +
-     * Each variant includes the corresponding URL and assigned images. +
-     * +
-     * Example: +
-     * { +
-     ​* ​  "​red":​ { +
-     ​* ​    "​productUrl":​ "​https://​www.example.com/​de/​jacket?​number=SW10000-01",​ +
-     ​* ​    "​images":​ [ +
-     ​* ​      "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-red-01.jpg",​ +
-     ​* ​      "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-red-02.jpg",​ +
-     ​* ​    ], +
-     ​* ​    "​thumbnails":​ [ +
-     ​* ​      "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-red-01_200x200.jpg",​ +
-     ​* ​      "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-red-02_200x200.jpg",​ +
-     ​* ​    ], +
-     ​* ​  }, +
-     ​* ​  "​black":​ { +
-     ​* ​    "​productUrl":​ "​https://​www.example.com/​de/​jacket?​number=SW10000-02",​ +
-     ​* ​    "​images":​ [ +
-     ​* ​      "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-black-01.jpg",​ +
-     ​* ​      "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-black-02.jpg",​ +
-     ​* ​    ], +
-     ​* ​    "​thumbnails":​ [ +
-     ​* ​      "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-black-01_200x200.jpg",​ +
-     ​* ​      "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-black-02_200x200.jpg",​ +
-     ​* ​    ], +
-     ​* ​  } +
-     * } +
-     */ +
-    protected function addVariantsJson() +
-    { +
-        $variants = []; +
- +
-        /** @var Detail $variant */ +
-        foreach ($this->​variantArticles as $variant) { +
-            if (!$variant->​getActive() || +
-                count($variant->​getConfiguratorOptions()) === 0 || +
-                (Shopware()->​Config()->​get('​hideNoInStock'​) && $variant->​getInStock() < 1) +
-            ) { +
-                continue; +
-            } +
- +
-            foreach ($variant->​getConfiguratorOptions() as $option) { +
-                if (StaticHelper::​isEmpty($option->​getName()) || +
-                    StaticHelper::​isEmpty($option->​getGroup()->​getName()) +
-                ) { +
-                    continue; +
-                } +
- +
-                $variantType = StaticHelper::​removeControlCharacters($option->​getGroup()->​getName());​ +
-                $variantValue = StaticHelper::​removeControlCharacters($option->​getName());​ +
- +
-                if ($variantType === self::​VARIANT_TYPE && !isset($variants[$variantValue])) { +
-                    $variants[$variantValue] = $this->​getNewVariant($variant);​ +
-                } +
-            } +
-        } +
- +
-        if (!StaticHelper::​isEmpty($variants)) { +
-            $this->​xmlArticle->​addProperty( +
-                new Property('​variants',​ [''​ => json_encode($variants)]) +
-            ); +
-        } +
-    } +
- +
-    /** +
-     * @param Detail $variant +
-     * @return array +
-     */ +
-    protected function getNewVariant($variant) +
-    { +
-        return [ +
-            '​productUrl'​ => $this->​getUrlByVariant($variant),​ +
-            '​images'​ => $this->​getVariantImages($variant),​ +
-            '​thumbnails'​ => $this->​getVariantImages($variant,​ true), +
-        ]; +
-    } +
- +
-    /** +
-     * @param Detail $variant +
-     * @param boolean $getThumbnail +
-     * @return string[] +
-     */ +
-    protected function getVariantImages($variant,​ $getThumbnail = false) +
-    { +
-        $images = []; +
- +
-        /** @var Image $image */ +
-        foreach ($variant->​getImages() as $image) { +
-            if (!$image->​getParent() || $image->​getParent()->​getMedia() === null) { +
-                continue; +
-            } +
- +
-            $imageUrl = $this->​getImageUrlByImage($image->​getParent(),​ $getThumbnail);​ +
-            if ($imageUrl) { +
-                $images[$image->​getPosition()] = $imageUrl;​ +
-            } +
-        } +
- +
-        return array_values($images);​ +
-    } +
- +
-    /** +
-     * @param Image $image +
-     * @param boolean $getThumbnail +
-     * @return string|null +
-     */ +
-    protected function getImageUrlByImage($image,​ $getThumbnail = false) +
-    { +
-        /** @var Image $imageRaw */ +
-        $imageRaw = $image->​getMedia();​ +
-        if (!($imageRaw instanceof Media) || $imageRaw === null) { +
-            return null; +
-        } +
- +
-        try { +
-            $imageDetails = $imageRaw->​getThumbnailFilePaths();​ +
-            $imageDefault = $imageRaw->​getPath();​ +
-        } catch (Exception $ex) { +
-            // Entity removed +
-            return null; +
-        } +
- +
-        if (count($imageDetails) > 0) { +
-            return $getThumbnail +
-                ? strtr($this->​mediaService->​getUrl(array_values($imageDetails)[0]),​ self::​URL_REPLACEMENTS) +
-                : strtr($this->​mediaService->​getUrl($imageDefault),​ self::​URL_REPLACEMENTS);​ +
-        } +
- +
-        return null; +
-    } +
- +
-    /** +
-     * @param Detail $variant +
-     * @return string +
-     */ +
-    protected function getUrlByVariant($variant) +
-    { +
-        $baseLink = $this->​getBaseLinkByVariant($variant);​ +
- +
-        return Shopware()->​Modules()->​Core()->​sRewriteLink($baseLink,​ $variant->​getArticle()->​getName());​ +
-    } +
- +
-    /** +
-     * @param Detail $variant +
-     * @return string +
-     */ +
-    protected function getBaseLinkByVariant($variant) +
-    { +
-        return sprintf( +
-            '​%s?​sViewport=detail&​sArticle=%s&​number=%s',​ +
-            Shopware()->​Config()->​get('​baseFile'​),​ +
-            $variant->​getArticle()->​getId(),​ +
-            $variant->​getNumber() +
-        ); +
-    }+
 } }
  
Line 328: Line 165:
 <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>​ <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>​ <​markdown>​
 +
 +## Add a custom free text field
 +
 +The default [attributes export](https://​docs.findologic.com/​doku.php?​id=integration_documentation:​plugin:​en:​integration:​shopware_5:​export_information#​attributes) contains the free text field from `attr1` to `attr20`. Additional and custom free text fields can be exported using the example below.
 +
 +```php
 +use FINDOLOGIC\Export\Data\Attribute;​
 +use FINDOLOGIC\Export\Data\Property;​
 +
 +public function __construct(
 +    Article $shopwareArticle,​
 +    $shopKey,
 +    array $allUserGroups,​
 +    array $salesFrequency,​
 +    Category $baseCategory
 +) {
 +    parent::​__construct($shopwareArticle,​ $shopKey, $allUserGroups,​ $salesFrequency,​ $baseCategory);​
 +
 +    if ($this->​legacyStruct) {
 +        $this->​addAdditionalFreeTextFields();​
 +    }
 +}
 +    ​
 +// ...
 +public function addAdditionalFreeTextFields():​ void
 +{
 +    $freeTextFields = $this->​baseVariant->​getAttribute();​
 +    ​
 +    // Add free text field as property (without usergroup)
 +    if(is_callable([$freeTextFields,​ '​getCustomRatingCount'​])) {
 +        $customRatingCount = $freeTextFields->​getCustomRatingCount();​
 +        if (!StaticHelper::​isEmpty($customRatingCount)) {
 +            $this->​xmlArticle->​addProperty(
 +                new Property('​rating_count',​ [''​ => StaticHelper::​cleanString($customRatingCount)])
 +            );
 +        }
 +    }
 +    ​
 +    // Add free text field as attribute
 +    if(is_callable([$freeTextFields,​ '​getCustomRatingAvg'​])) {
 +        $customRatingAvg = $freeTextFields->​getCustomRatingAvg();​
 +        if (!StaticHelper::​isEmpty($customRatingAvg)) {
 +            $this->​xmlArticle->​addAttribute(
 +                new Attribute('​rating_avg',​ [StaticHelper::​cleanString($customRatingAvg)])
 +            );
 +        }
 +    }
 +}
 +// ...
 +```
 +
 +The function names are dynamically generated by Shopware. They are accessible as PascalCase, prefixed with "​get"​. So the getter for the free text field `custom_rating_count`,​ is generated as `getCustomRatingCount`.
  
 ## Add variant data to the export ## Add variant data to the export
  
-The default extension plugin already includes the code to export variants as a JSON string, ​this code just needs a small adaption:+The default extension plugin already includes the code to export variants as a JSON string, ​the provided ​code just needs a small adaption:
  
 1. Check out the variant configuration and get the property name, which defines your variants. 1. Check out the variant configuration and get the property name, which defines your variants.
-    ![]()+    ![](https://​docs.findologic.com/​lib/​exe/​fetch.php?​cache=&​media=integration_documentation:​plugin:​en:​integration:​shopware_5:​get_variant_name.png) 
 +     
 +2. Configure the variant name in the constant `VARIANT_TYPE` (line 19) 
 + 
 +3. Comment out the line 40-44 
 +    ```php 
 +    //        $this->​mediaService = Shopware()->​Container()->​get('​shopware_media.media_service'​);​ 
 +    // 
 +    //        if ($this->​legacyStruct) { 
 +    //            $this->​addVariantsJson();​ 
 +    //        } 
 +    ``` 
 + 
 +The exported variant JSON could look like: 
 + 
 +```json 
 +
 +    "​red":​ { 
 +        "​productUrl":​ "​https://​www.example.com/​de/​jacket?​number=SW10000-01",​ 
 +        "​images":​ [ 
 +            "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-red-01.jpg",​ 
 +            "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-red-02.jpg",​ 
 +        ], 
 +        "​thumbnails":​ [ 
 +            "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-red-01_200x200.jpg",​ 
 +            "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-red-02_200x200.jpg",​ 
 +        ], 
 +    }, 
 +    "​black":​ { 
 +        "​productUrl":​ "​https://​www.example.com/​de/​jacket?​number=SW10000-02",​ 
 +        "​images":​ [ 
 +            "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-black-01.jpg",​ 
 +            "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-black-02.jpg",​ 
 +        ], 
 +        "​thumbnails":​ [ 
 +            "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-black-01_200x200.jpg",​ 
 +            "​https://​www.example.com/​media/​image/​73/​bc/​ef/​jacket-black-02_200x200.jpg",​ 
 +        ], 
 +    } 
 +
 +``` 
 + 
 +## Add custom sorting options for API Integration 
 + 
 +</​markdown>​ 
 +<note important>​Requires Findologic Plugin v11.5.2 or above</​note>​ 
 +<​markdown>​ 
 + 
 +The Findologic 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-5/​tree/​main/​FinSearchUnified/​Bundle/​SearchBundleFindologic/​SortingHandler)). 
 + 
 +To handle custom sorting options, create a custom `SortingHandler` in the extension plugin, and override the responsible `QueryBuilderFactory` to include the created `SortingHandler`. 
 + 
 +Supported Shopware 5 sortings by default: 
 +- Release date 
 +- Popularity 
 +- Product name 
 +- Price 
 +- Relevance 
 + 
 +### 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 
 + 
 +Example implementation for sorting according to the stock value. This can be done for any non-supported sorting option, or with some sorting from a third-party plugin. 
 + 
 +**Step 1: Export the sort value** 
 + 
 +The export of the stock value needs to be added to `ExtendFinSearchUnified/​BusinessLogic/​Models/​FindologicArticleModel.php` 
 + 
 +```php 
 +<?php 
 + 
 +namespace ExtendFinSearchUnified\BusinessLogic\Models;​ 
 + 
 +use FINDOLOGIC\Export\Data\Sort;​ 
 +use FinSearchUnified\BusinessLogic\Models\FindologicArticleModel as OriginalFindologicArticleModel;​ 
 +use Shopware\Models\Article\Article;​ 
 +use Shopware\Models\Category\Category;​ 
 + 
 +class FindologicArticleModel extends OriginalFindologicArticleModel 
 +
 +    public function __construct( 
 +        Article $shopwareArticle,​ 
 +        $shopKey, 
 +        array $allUserGroups,​ 
 +        array $salesFrequency,​ 
 +        Category $baseCategory 
 +    ) { 
 +        parent::​__construct($shopwareArticle,​ $shopKey, $allUserGroups,​ $salesFrequency,​ $baseCategory);​ 
 + 
 +        $this->​setSort();​ 
 +    } 
 + 
 +    public function setSort() 
 +    { 
 +        $sort = new Sort(); 
 +        $sort->​setValue($this->​baseVariant->​getInStock());​ 
 + 
 +        $this->​xmlArticle->​setSort($sort);​ 
 +    } 
 +
 +``` 
 + 
 +**Step 2: Find the correct Shopware/​Third-party sorting class** 
 + 
 +The available Shopware sorting classes can be found [here](https://​github.com/​shopware/​shopware/​tree/​5.7/​engine/​Shopware/​Bundle/​SearchBundle/​Sorting). This is needed for the compatibility check inside the `SortingHandler`. 
 + 
 +Using `ProductStockSorting` for this example. 
 + 
 +**Step 2: Create a `SortingHandler`** 
 + 
 +Create the folder structure `Bundle/​SearchBundleFindologic/​SortingHandler` in the extension plugin, and add a custom sorting handler class. In this example it will be `ProductStockSortingHandler`:​ 
 + 
 +```php 
 +<?php 
 + 
 +namespace ExtendFinSearchUnified\Bundle\SearchBundleFindologic\SortingHandler;​ 
 + 
 +use FinSearchUnified\Bundle\SearchBundleFindologic\QueryBuilder\QueryBuilder;​ 
 +use FinSearchUnified\Bundle\SearchBundleFindologic\SortingHandlerInterface;​ 
 +use Shopware\Bundle\SearchBundle\Sorting\ProductStockSorting;​ 
 +use Shopware\Bundle\SearchBundle\SortingInterface;​ 
 +use Shopware\Bundle\StoreFrontBundle\Struct\ShopContextInterface;​ 
 + 
 +class ProductStockSortingHandler implements SortingHandlerInterface 
 +
 +    /** 
 +     * Checks if the passed sorting can be handled by this class 
 +     * 
 +     * @param SortingInterface $sorting 
 +     * 
 +     * @return bool 
 +     */ 
 +    public function supportsSorting(SortingInterface $sorting) 
 +    { 
 +        return $sorting instanceof ProductStockSorting;​ 
 +    } 
 + 
 +    /** 
 +     * Handles the passed sorting object. 
 +     * 
 +     * @param SortingInterface $sorting 
 +     * @param QueryBuilder $query 
 +     * @param ShopContextInterface $context 
 +     */ 
 +    public function generateSorting(SortingInterface $sorting, QueryBuilder $query, ShopContextInterface $context) 
 +    { 
 +        /** @var ProductStockSorting $sorting */ 
 +        $query->​addOrder('​shopsort ' . $sorting->​getDirection());​ 
 +    } 
 +
 +``` 
 + 
 +**Step 3: Decorate the `QueryBuilderFactory`** 
 + 
 +The `QueryBuilderFactory` registers all the available sorting options. Add your custom sort to this factory. 
 +Create the folder structure `Bundle/​SearchBundleFindologic/​QueryBuilder` in the extension plugin, and add the file `QueryBuilderFactory`. Override the `registerSortingHandlers` method and add your handler to the array. 
 + 
 +```php 
 +<?php 
 + 
 +namespace ExtendFinSearchUnified\Bundle\SearchBundleFindologic\QueryBuilder;​ 
 + 
 +use ExtendFinSearchUnified\Bundle\SearchBundleFindologic\SortingHandler\ProductStockSortingHandler;​ 
 +use FinSearchUnified\Bundle\SearchBundleFindologic\QueryBuilder\QueryBuilderFactory as OriginalQueryBuilderFactory;​ 
 +use FinSearchUnified\Bundle\SearchBundleFindologic\SortingHandlerInterface;​ 
 + 
 +class QueryBuilderFactory extends OriginalQueryBuilderFactory 
 +
 +    /** 
 +     * @return SortingHandlerInterface[] 
 +     */ 
 +    protected function registerSortingHandlers() 
 +    { 
 +        $sortingHandlers = parent::​registerSortingHandlers();​ 
 + 
 +        $sortingHandlers[] = new ProductStockSortingHandler();​ 
 + 
 +        return $sortingHandlers;​ 
 +    } 
 +
 +``` 
 + 
 + 
 +**Step 4: Add the decorated factory to the services.xml** 
 + 
 +Finally decorate it in your `Resources/​services.xml`:​ 
 + 
 +```xml 
 +<?xml version="​1.0"​ encoding="​utf-8"?>​ 
 +<​container xmlns="​http://​symfony.com/​schema/​dic/​services"​ 
 +           ​xmlns:​xsi="​http://​www.w3.org/​2001/​XMLSchema-instance"​ 
 +           ​xsi:​schemaLocation="​http://​symfony.com/​schema/​dic/​services http://​symfony.com/​schema/​dic/​services/​services-1.0.xsd">​ 
 +    <​services>​ 
 +        <​service 
 +            id="​extend_fin_search_unified.article_model_factory"​ 
 +            class="​ExtendFinSearchUnified\BusinessLogic\FindologicArticleFactory"​ 
 +            decorates="​fin_search_unified.article_model_factory"​ 
 +        > 
 +        </​service>​ 
 + 
 +        <​service 
 +            id="​extend_fin_search_unified.query_builder_factory"​ 
 +            class="​ExtendFinSearchUnified\Bundle\SearchBundleFindologic\QueryBuilder\QueryBuilderFactory"​ 
 +            decorates="​fin_search_unified.query_builder_factory"​ 
 +        > 
 +            <​argument type="​service"​ id="​shopware_plugininstaller.plugin_manager"​ /> 
 +            <​argument type="​service"​ id="​config"​ /> 
 +        </​service>​ 
 +    </​services>​ 
 +</​container>​ 
 +``` 
 + 
 +Once this step is done, selecting your relevant sorting option will send the order parameter to the Findologic API.
  
 </​markdown>​ </​markdown>​