vendor/store.shopware.com/loyxxsw6categorytreeteaser/src/LoyxxSW6CategoryTreeTeaser.php line 22

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace LoyxxSW6CategoryTreeTeaser;
  3. use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotCollection;
  4. use Shopware\Core\Framework\Context;
  5. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  8. use Shopware\Core\Framework\Plugin;
  9. use Shopware\Core\Framework\Plugin\Context\InstallContext;
  10. use Shopware\Core\Framework\Plugin\Context\UninstallContext;
  11. use Shopware\Core\Framework\Plugin\Context\UpdateContext;
  12. use Shopware\Core\System\CustomField\Aggregate\CustomFieldSet\CustomFieldSetEntity;
  13. use Shopware\Core\System\CustomField\CustomFieldEntity;
  14. use Shopware\Core\System\CustomField\CustomFieldTypes;
  15. use Symfony\Component\Filesystem\Filesystem;
  16. use Symfony\Component\Finder\Finder;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\Serializer\Encoder\JsonEncoder;
  19. class LoyxxSW6CategoryTreeTeaser extends Plugin
  20. {
  21.     public const CUSTOM_FIELD_PREFIX 'loyxx_category_tree_teaser';
  22.     public $iconFile __DIR__ '/Resources/config/storefront.icons.json';
  23.     public $shoppingWorldIconFile __DIR__ '/Resources/config/storefront.shopping.world.icons.json';
  24.     public $icons = [];
  25.     public $shoppingWorldIcons = [];
  26.     public function install(InstallContext $installContext): void
  27.     {
  28.         parent::install($installContext);
  29.         $this->_updateCMSSlotName($installContext->getContext());
  30.         $this->_prepareStorefrontIcons();
  31.         $this->createCustomFieldSystem($installContext);
  32.     }
  33.     public function uninstall(UninstallContext $uninstallContext): void
  34.     {
  35.         parent::uninstall($uninstallContext);
  36.         $this->removeCustomFieldSystem($uninstallContext);
  37.     }
  38.     public function update(UpdateContext $updateContext): void
  39.     {
  40.         parent::update($updateContext);
  41.         $this->_updateCMSSlotName($updateContext->getContext());
  42.         $this->_prepareStorefrontIcons();
  43.         $this->updateCustomFieldSystem($updateContext);
  44.     }
  45.     private function createCustomFieldSystem(InstallContext $installContext)
  46.     {
  47.         $customFieldSetRepository $this->container->get('custom_field_set.repository');
  48.         $context $installContext->getContext();
  49.         //check if the custom field set is defined
  50.         $criteria = new Criteria();
  51.         $criteria->addFilter(new EqualsFilter('name', static::CUSTOM_FIELD_PREFIX));
  52.         $customFieldSetEntity $customFieldSetRepository->searchIds($criteria$context);
  53.         if (!$customFieldSetEntity->getTotal()) {
  54.             $customFieldSetRepository->create(
  55.                 [
  56.                     [
  57.                         'name' => static::CUSTOM_FIELD_PREFIX,
  58.                         'customFields' => $this->_getCustomFieldItems(),
  59.                         'relations' => [
  60.                             ['entityName' => 'category']
  61.                         ],
  62.                         'config' => [
  63.                             'description' => [
  64.                                 'en-GB' => 'Category tree teaser manager.',
  65.                                 'de-DE' => 'Kategorie-Teaser-Manager'
  66.                             ],
  67.                             'label' => [
  68.                                 'en-GB' => 'Category Tree Teaser',
  69.                                 'de-DE' => 'Kategorie-Teaser'
  70.                             ],
  71.                             'translated' => true
  72.                         ]
  73.                     ]
  74.                 ],
  75.                 $context
  76.             );
  77.         }
  78.     }
  79.     private function removeCustomFieldSystem(UninstallContext $uninstallContext)
  80.     {
  81.         $customFieldSetRepository $this->container->get('custom_field_set.repository');
  82.         $context $uninstallContext->getContext();
  83.         //check if the custom field set is defined
  84.         $criteria = new Criteria();
  85.         $criteria->addFilter(new EqualsFilter('name', static::CUSTOM_FIELD_PREFIX));
  86.         $customFieldSetEntity $customFieldSetRepository->searchIds($criteria$context);
  87.         if ($customFieldSetEntity->getTotal()) {
  88.             $customFieldSetRepository->delete(array_values($customFieldSetEntity->getData()), $context);
  89.         }
  90.         // Remove icon file
  91.        $this->deleteIconFiles();
  92.     }
  93.     private function _updateCMSSlotName(Context $context)
  94.     {
  95.         $cmsSlotRepository $this->container->get('cms_slot.repository');
  96.         // take old cms repositories
  97.         $criteria = new Criteria();
  98.         $criteria->addFilter(new EqualsFilter('type''category-tree-teaser'));
  99.         $criteria->addFilter(new EqualsFilter('slot''content'));
  100.         /** @var CmsSlotCollection $slots */
  101.         $slots $cmsSlotRepository->search($criteria$context);
  102.         if ($slots->count() !== 0) {
  103.             foreach ($slots->getElements() as $slot) {
  104.                 // update name
  105.                 $currentConfig $slot->getConfig();
  106.                 if (!isset($currentConfig['categories'])) {
  107.                     $currentConfig['categories'] = [
  108.                         "value" => [],
  109.                         "source" => "static"
  110.                     ];
  111.                     $currentConfig['enableCustomCategories'] = [
  112.                         "value" => false,
  113.                         "source" => "static"
  114.                     ];
  115.                 }
  116.                 $cmsSlotRepository->update([
  117.                     ['id' => $slot->getId(), 'slot' => 'categoryTreeTeaser''config' => $currentConfig]
  118.                 ], $context);
  119.             }
  120.         }
  121.     }
  122.     private function _prepareStorefrontIcons()
  123.     {
  124.         // refresh icons
  125.         $this->deleteIconFiles();
  126.         // get all icons from
  127.         $storefrontIconPath rtrim($this->container->getParameter('storefrontRoot'), '/') . '/Resources/app/storefront/dist/assets/icon/default';
  128.         $storefrontIconBundlePath $this->getThemeDirectory();
  129.         $finder = new Finder();
  130.         $finder->files()
  131.             ->in($storefrontIconPath)
  132.             ->name('*.svg')
  133.             ->ignoreDotFiles(true)
  134.             ->ignoreVCS(true)
  135.             ->sortByName();
  136.         if ($finder->hasResults()) {
  137.             foreach ($finder as $file) {
  138.                 $filename $file->getBasename();
  139.                 $name $file->getBasename('.' $file->getExtension());
  140.                 $icon $storefrontIconBundlePath $filename;
  141.                 $this->icons[] = compact('name''filename''icon');
  142.                 if (strtolower(strtolower(substr($name05))) === 'arrow') {
  143.                     $this->shoppingWorldIcons[] = compact('name''filename''icon');
  144.                 }
  145.             }
  146.         }
  147.         if (empty($this->icons)) {
  148.             foreach (['arrow-left.svg''arrow-right.svg''arrow-down.svg''arrow-up.svg''bag.svg''bag-product.svg'] as $file) {
  149.                 $icon = [
  150.                     'name' => basename($file'.svg'),
  151.                     'filename' => $file,
  152.                     'icon' => $storefrontIconBundlePath $file
  153.                 ];
  154.                 $this->icons[] = $icon;
  155.                 $this->shoppingWorldIcons[] = $icon;
  156.             }
  157.         }
  158.         $fs = new Filesystem();
  159.         $fs->dumpFile($this->iconFile, (new JsonEncoder())->encode($this->iconsJsonEncoder::FORMAT));
  160.         $fs->dumpFile($this->shoppingWorldIconFile, (new JsonEncoder())->encode($this->shoppingWorldIconsJsonEncoder::FORMAT));
  161.     }
  162.     private function getThemeDirectory($default true,$absolutePath false)
  163.     {
  164.         if ($default){
  165.             return '/bundles/storefront/assets/icon/default/';
  166.         }
  167.         $finder = new Finder();
  168.         $finder->files()
  169.             ->in($this->container->getParameter('shopware.filesystem.public.config.root') . '/theme')
  170.             ->name("*.svg")
  171.             ->ignoreDotFiles(true)
  172.             ->ignoreVCS(true)
  173.             ->sortByName();
  174.         foreach ($finder as $file) {
  175.           if (!is_null($file)){
  176.               break;
  177.           }
  178.         }
  179.         return $absolutePath $file->getPath() : '/theme/'.$file->getRelativePath() .'/';
  180.     }
  181.     private function updateCustomFieldSystem(UpdateContext $updateContext)
  182.     {
  183.         $customFieldSetRepository $this->container->get('custom_field_set.repository');
  184.         $context $updateContext->getContext();
  185.         //check if the custom field set is defined
  186.         $criteria = new Criteria();
  187.         $criteria->addFilter(new EqualsFilter('name', static::CUSTOM_FIELD_PREFIX));
  188.         $criteria->addAssociation('customFields');
  189.         /** @var CustomFieldSetEntity $customFieldSetEntity */
  190.         $customFieldSetEntity $customFieldSetRepository->search($criteria$context)->first();
  191.         if ($customFieldSetEntity) {
  192.             $customFields $this->_getCustomFieldItems();
  193.             /** @var CustomFieldEntity $item */
  194.             foreach ($customFieldSetEntity->getCustomFields() as $item) {
  195.                 $key array_search($item->getName(), array_column($customFields'name')) ;
  196.                if ($key !== FALSE){
  197.                    $customFields[$key]['id'] = $item->getId();
  198.                }
  199.             }
  200.             $customFieldSetRepository->upsert(
  201.                 [
  202.                     [
  203.                         'id' => $customFieldSetEntity->getId(),
  204.                         'name' => static::CUSTOM_FIELD_PREFIX,
  205.                         'customFields' => $customFields
  206.                     ]
  207.                 ],
  208.                 $context
  209.             );
  210.         }
  211.     }
  212.     private function deleteIconFiles()
  213.     {
  214.         $fs = new Filesystem();
  215.         $fs->remove([
  216.             $this->iconFile,
  217.             $this->shoppingWorldIconFile
  218.         ]);
  219.     }
  220.     private function _getCustomFieldItems() : array
  221.     {
  222.         $options = [];
  223.         $options[] = [
  224.             "label" => [
  225.                 "de-DE" => 'Keine',
  226.                 "en-GB" => 'None'
  227.             ],
  228.             "value" => 'none'
  229.         ];
  230.         if ($this->icons) {
  231.             foreach ($this->icons as $icon) {
  232.                 $name ucwords(str_replace('-'' '$icon['name']));
  233.                 $options[] = [
  234.                     "label" => [
  235.                         "de-DE" => $name,
  236.                         "en-GB" => $name
  237.                     ],
  238.                     "value" => $icon['name']
  239.                 ];
  240.             }
  241.         }
  242.         return [
  243.             [
  244.                 'name' => static::CUSTOM_FIELD_PREFIX '_disabled',
  245.                 'type' => CustomFieldTypes::BOOL,
  246.                 'config' => [
  247.                     'type' => 'switch',
  248.                     'label' => [
  249.                         'en-GB' => 'Hide category teaser element for this category entirely',
  250.                         'de-DE' => 'Kategorie-Teaser-Element für diese Kategorie vollständig ausblenden'
  251.                     ],
  252.                     'componentName' => 'sw-field',
  253.                     'customFieldType' => 'switch',
  254.                     'customFieldPosition' => 1,
  255.                     'helpText' => [
  256.                         'en-GB' => 'After enabling this option, the whole category teaser is no longer visible in this category',
  257.                         'de-DE' => 'Nachdem Sie diese Option aktiviert haben, ist der gesamte Kategorie Teaser in dieser Kategorie nicht mehr sichtbar'
  258.                     ],
  259.                     'translated' => true
  260.                 ]
  261.             ],
  262.             [
  263.                 'name' => static::CUSTOM_FIELD_PREFIX '_hidden_from_teaser',
  264.                 'type' => CustomFieldTypes::BOOL,
  265.                 'config' => [
  266.                     'type' => 'switch',
  267.                     'label' => [
  268.                         'en-GB' => 'Exclude this category from category teaser element',
  269.                         'de-DE' => 'Diese Kategorie aus dem Kategorie Teaser Element ausschließen'
  270.                     ],
  271.                     'componentName' => 'sw-field',
  272.                     'customFieldType' => 'switch',
  273.                     'customFieldPosition' => 2,
  274.                     'helpText' => [
  275.                         'en-GB' => 'After enabling this option this category will not be visible inside the category teaser',
  276.                         'de-DE' => 'Nachdem Sie diese Option aktiviert haben, ist diese Kategorie im Kategorie Teaser nicht mehr sichtbar'
  277.                     ],
  278.                     'translated' => true
  279.                 ]
  280.             ],
  281.             [
  282.                 'name' => static::CUSTOM_FIELD_PREFIX '_teaser',
  283.                 'type' => CustomFieldTypes::HTML,
  284.                 'config' => [
  285.                     'type' => 'textEditor',
  286.                     'label' => [
  287.                         'en-GB' => 'Teaser Text',
  288.                         'de-DE' => 'Teaser-Text'
  289.                     ],
  290.                     'componentName' => 'sw-text-editor',
  291.                     'customFieldType' => 'textEditor',
  292.                     'customFieldPosition' => 3,
  293.                     'helpText' => [
  294.                         'en-GB' => ' If you enable this option, an additional teaser text is displayed below the categories name. To add this text, go to the custom field section under Catalog > Categories > Select your category. Keep the teaser text as short as possible',
  295.                         'de-DE' => 'Wenn Sie diese Option aktivieren, wird unterhalb des Kategorie Names ein zusätzlicher Teaser Text angezeigt. Um diesen Text hinzuzufügen, gehen Sie unter Kataloge > Kategorien > jeweilige Kategorie auswählen in den Bereich der Zusatzfelder. Halten Sie den Teaser Text möglichst kurz'
  296.                     ],
  297.                     'translated' => true
  298.                 ]
  299.             ],
  300.             [
  301.                 'name' => static::CUSTOM_FIELD_PREFIX '_icons',
  302.                 'type' => CustomFieldTypes::SELECT,
  303.                 'config' => [
  304.                     'type' => 'select',
  305.                     'label' => [
  306.                         'en-GB' => 'Custom Icon',
  307.                         'de-DE' => ' Zusätzliches Icon'
  308.                     ],
  309.                     "options" => $options,
  310.                     "placeholder" => [
  311.                         "en-GB" => null,
  312.                         "de-DE" => null
  313.                     ],
  314.                     'componentName' => 'sw-single-select',
  315.                     'customFieldType' => 'select',
  316.                     'customFieldPosition' => 4,
  317.                     'helpText' => [
  318.                         'en-GB' => 'If you select a custom icon, it will be displayed before the category name within the teaser block ',
  319.                         'de-DE' => 'Wenn Sie ein benutzerdefiniertes  Zusätzliches Icon auswählen, wird es vor dem Kategorienamen innerhalb des Teaser-Blocks angezeigt '
  320.                     ],
  321.                     'translated' => true
  322.                 ]
  323.             ],
  324.             [
  325.                 'name' => static::CUSTOM_FIELD_PREFIX '_hide_shopping_world_icon',
  326.                 'type' => CustomFieldTypes::BOOL,
  327.                 'config' => [
  328.                     'type' => 'switch',
  329.                     'label' => [
  330.                         'en-GB' => 'Hide icon assigned through shopping world configuration',
  331.                         'de-DE' => 'Durch die Konfiguration der Einkaufswelt zugewiesenes Symbol ausblenden'
  332.                     ],
  333.                     'componentName' => 'sw-field',
  334.                     'customFieldType' => 'switch',
  335.                     'customFieldPosition' => 5,
  336.                     'helpText' => [
  337.                         'en-GB' => 'When you enable this option, the icon assigned to the teaser block through shopping world configuration will be hidden',
  338.                         'de-DE' => 'Wenn Sie diese Option aktivieren, wird das  Zusätzliches Icon, das dem Teaser-Block durch die Konfiguration der Einkaufswelt zugewiesen wurde, ausgeblendet'
  339.                     ],
  340.                     'translated' => true
  341.                 ]
  342.             ],
  343.             [
  344.                 'name' => static::CUSTOM_FIELD_PREFIX '_hide_label',
  345.                 'type' => CustomFieldTypes::BOOL,
  346.                 'config' => [
  347.                     'type' => 'switch',
  348.                     'label' => [
  349.                         'en-GB' => 'Hide category label',
  350.                         'de-DE' => 'Kategoriebeschriftung ausblenden'
  351.                     ],
  352.                     'componentName' => 'sw-field',
  353.                     'customFieldType' => 'switch',
  354.                     'customFieldPosition' => 6,
  355.                     'helpText' => [
  356.                         'en-GB' => 'If you activate this option, the category name is not displayed at the bottom of the category image.',
  357.                         'de-DE' => 'Wenn Sie diese Option aktivieren, wird der Kategoriename nicht am unteren Rand des Kategoriebildes angezeigt.'
  358.                     ],
  359.                     'translated' => true
  360.                 ]
  361.             ],
  362.             [
  363.                 'name' => static::CUSTOM_FIELD_PREFIX '_label_image',
  364.                 'type' => 'media',
  365.                 'config' => [
  366.                     'type' => 'media',
  367.                     'label' => [
  368.                         'en-GB' => 'Select an optional caption image',
  369.                         'de-DE' => 'Wählen Sie ein optionales Untertitel-Bild aus.'
  370.                     ],
  371.                     'componentName' => 'sw-media-field',
  372.                     'customFieldType' => 'media',
  373.                     'customFieldPosition' => 7,
  374.                     'helpText' => [
  375.                         'en-GB' => 'The caption image is optional and appears between the main category image and the category name. (Ideal for displaying brand logos below the main image of the category teaser).',
  376.                         'de-DE' => 'Das Bild ist optional und wird zwischen dem Hauptkategoriebild und dem Kategorienamen angezeigt. (Ideal für die Anzeige von Markenlogos unterhalb des Hauptbildes des Kategorie-Teasers).'
  377.                     ],
  378.                     'translated' => true
  379.                 ]
  380.             ]
  381.         ];
  382.     }
  383. }