Questions around the TYPO3 integration and plugins as well as Flow and NeosCMS
Forum rules: Always add your TYPO3/Flow, Aimeos and PHP version as well as your environment (Linux/Mac/Win)
#6189 by Alex K
02 Jun 2018, 14:16
Hi) I cant find any information how to get Categories list of Product. I checked default templates and documentation for class Item.. but failed. Please, can you show me right way?) I want to show product category to some products.
#6191 by aimeos
02 Jun 2018, 20:46
Do you want to show the current category of the product or all product categories if the product is in several categories?

The categories are not retrieved by default for each product, so you have to create a decorator for the catalog lists HTML client that fetches the categories for the products shown: https://aimeos.org/docs/Developers/Html_frontend/Extend_existing_components

To get the categories use something like this:
Code: Select all$listManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'catalog/lists' );
$search = $listManager->createSearch( true );
$expr = [
    $search->compare( '==', 'catalog.lists.refid', array_keys( $view->listProductItems ) ),
    $search->compare(  '==, 'catalog.lists.domain', 'product' ),
    $search->getConditions()
];
$search->setConditions( $search->combine( '&&', $expr ) );

$map = [];
foreach( $listManager->searchItems( $search ) as $listItem ) {
    $map[$listItem->getRefId()] = $listItem->getParentId();
}

$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'catalog' );
$search = $manager->createSearch( true );
$expr = [
    $search->compare( '==', 'catalog.id', $map ),
    $search->getConditions(),
];
$search->setConditions( $search->combine( '&&', $expr ) );

$view->listListMap = $map;
$view->listCategories = $manager->searchItems( $search );
#6199 by Alex K
04 Jun 2018, 14:06
Thanks again for help! I finnaly got my categories for each product with help of decorator. I hope it's not forbiden, i'll give my result as example, if someone need it.

Thi is my Decorator for List, it's fast solution.
Code: Select all<?php
namespace Aimeos\Client\Html\Common\Decorator;

class CategoryListsDecorator
    extends \Aimeos\Client\Html\Common\Decorator\Base
    implements \Aimeos\Client\Html\Common\Decorator\Iface
{
   /**
    * Adds the data to the view object required by the templates
    *
    * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
    * @param array &$tags Result array for the list of tags that are associated to the output
    * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
    * @return \Aimeos\MW\View\Iface The view object with the data required by the templates
    * @since 2018.01
    */
   public function addData( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
   {
      $view = parent::addData( $view, $tags, $expire );
      if(count($view->get( 'listProductItems' )) > 0){
         $productsList = $view->get( 'listProductItems' );
         $productsList = $this->reachProducts($productsList);
         $view->listProductItems = $productsList;
      } else {
         $productsList = $view->get( 'promoItems' );
         $productsList = $this->reachProducts($productsList);
         $view->promoItems = $productsList;
      }
      return $view;
   }

   protected function reachProducts($productsList){
      foreach ($productsList as $id => $item) {
            $res = $this->getCategories($item);
            $productsList[$id]->listCategories = $res;
      }
      return $productsList;
   }


   protected function getCategories($product){
      $listManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'catalog/lists' );
      $search = $listManager->createSearch( true );
      $expr = [
          $search->compare( '==', 'catalog.lists.refid', $product->getId() ),
          $search->compare(  '==', 'catalog.lists.domain', 'product' ),
          $search->getConditions()
      ];
      $search->setConditions( $search->combine( '&&', $expr ) );
      $map = [];
      foreach( $listManager->searchItems( $search ) as $listItem ) {
          $map[] = $listItem->getParentId();
      }
      $manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'catalog' );
      $search = $manager->createSearch( true );
      $expr = [
          $search->compare( '==', 'catalog.id', $map ),
          $search->getConditions(),
      ];
      $search->setConditions( $search->combine( '&&', $expr ) );
      return $manager->searchItems( $search );
   }

}
#6200 by Alex K
04 Jun 2018, 14:12
And also simple decorator for detail product

Code: Select all<?php
namespace Aimeos\Client\Html\Common\Decorator;

class CategoryDetailDecorator
    extends \Aimeos\Client\Html\Common\Decorator\Base
    implements \Aimeos\Client\Html\Common\Decorator\Iface
{

   /**
    * Adds the data to the view object required by the templates
    *
    * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
    * @param array &$tags Result array for the list of tags that are associated to the output
    * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
    * @return \Aimeos\MW\View\Iface The view object with the data required by the templates
    * @since 2018.01
    */
   public function addData( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
   {
      $view = parent::addData( $view, $tags, $expire );
      $listManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'catalog/lists' );
      $search = $listManager->createSearch( true );

      $expr = [
          $search->compare( '==', 'catalog.lists.refid', $view->get( 'detailProductItem' )->getId() ),
          $search->compare(  '==', 'catalog.lists.domain', 'product' ),
          $search->getConditions()
      ];

      $search->setConditions( $search->combine( '&&', $expr ) );
      $map = [];
      foreach( $listManager->searchItems( $search ) as $listItem ) {
          $map[] = $listItem->getParentId();
      }

      $manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'catalog' );
      $search = $manager->createSearch( true );
      $expr = [
          $search->compare( '==', 'catalog.id', $map ),
          $search->getConditions(),
      ];
      $search->setConditions( $search->combine( '&&', $expr ) );
      $view->listCategories = $manager->searchItems( $search );      
      return $view;
   }
}
#6202 by aimeos
04 Jun 2018, 16:28
Your decorator for the list slows down your application because you fetch the categories for each product separately. Instead, you should retrieve all catalog<->product references and catalog items once and map them afterwards. This will be much faster.
#6730 by sixbynine
19 Aug 2018, 15:54
Hello,

I'm trying to create a new decorator. I had a few beginner questions and I find the answers by testing in the meantime :)
So it is solved !

I keep the post just in case it could help someone else !

Basically, my decorator was not working because I needed to clear the cache so aimeos can use the updated shop.php config file.

I read :
- https://aimeos.org/docs/Developers/Html ... components
- this post

I decided to make a few tests... I first tried to make one with the code available here (thank you Alex K!)

Code: Select all<?php
namespace Aimeos\Client\Html\Common\Decorator;

class CategoryListsDecorator
    extends \Aimeos\Client\Html\Common\Decorator\Base
    implements \Aimeos\Client\Html\Common\Decorator\Iface
{
   /**
    * Adds the data to the view object required by the templates
    *
    * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
    * @param array &$tags Result array for the list of tags that are associated to the output
    * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
    * @return \Aimeos\MW\View\Iface The view object with the data required by the templates
    * @since 2018.01
    */
   public function addData( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
   {
      $view = parent::addData( $view, $tags, $expire );
      if(count($view->get( 'listProductItems' )) > 0){
         $productsList = $view->get( 'listProductItems' );
         $productsList = $this->reachProducts($productsList);
         $view->listProductItems = $productsList;
      } else {
         $productsList = $view->get( 'promoItems' );
         $productsList = $this->reachProducts($productsList);
         $view->promoItems = $productsList;
      }
      return $view;
   }

   protected function reachProducts($productsList){
      foreach ($productsList as $id => $item) {
            $res = $this->getCategories($item);
            $productsList[$id]->listCategories = $res;
      }
      return $productsList;
   }


   protected function getCategories($product){
      $listManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'catalog/lists' );
      $search = $listManager->createSearch( true );
      $expr = [
          $search->compare( '==', 'catalog.lists.refid', $product->getId() ),
          $search->compare(  '==', 'catalog.lists.domain', 'product' ),
          $search->getConditions()
      ];
      $search->setConditions( $search->combine( '&&', $expr ) );
      $map = [];
      foreach( $listManager->searchItems( $search ) as $listItem ) {
          $map[] = $listItem->getParentId();
      }
      $manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'catalog' );
      $search = $manager->createSearch( true );
      $expr = [
          $search->compare( '==', 'catalog.id', $map ),
          $search->getConditions(),
      ];
      $search->setConditions( $search->combine( '&&', $expr ) );
      return $manager->searchItems( $search );
   }

}



and I've a few simple questions :

Let's guess my decorator is called like this one CategoryListsDecorator

1. I added my decorator in my shop.php file :

Code: Select all'client' => [
      'html' => [
         'catalog' => [
          'lists' => [
            'decorators' => [
              'global' =>array('CategoryListsDecorator'),
              ],
            ],
        ],

      ],
],


Is this the correct way? YES

2. About the path of my decorator, I guess it is like the basket plugins : MyDecoratorName.php

So I add it in my ext folder :
/ext/myext/client/html/src/Client/Html/Common/Decorator/CategoryListsDecorator.php

Is this correct? YES

3. Mmmh... stupid question :roll: how do i finally get the new data in the list body view?

Could it be this way:

Code: Select all$listCategories = $this->get( 'myParam', [] );


?
YES but $this->myParam works too :)

As always, thank you very much for your patience !

sbn