Page 1 of 2

Get product category

Posted: 02 Jun 2018, 14:16
by Alex K
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.

Re: Get product category

Posted: 02 Jun 2018, 20:46
by aimeos
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 ... 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 );

Re: Get product category

Posted: 03 Jun 2018, 11:34
by Alex K
I need both) Thank you for help! I will try!

Re: Get product category

Posted: 04 Jun 2018, 14:06
by Alex K
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 );
	}

}

Re: Get product category

Posted: 04 Jun 2018, 14:12
by Alex K
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;
	}
}

Re: Get product category

Posted: 04 Jun 2018, 16:28
by aimeos
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.

Re: Get product category

Posted: 19 Aug 2018, 15:54
by sixbynine
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

Re: Get product category

Posted: 25 Mar 2021, 07:36
by mr.zherart
Hi, Aimeos. I have the same question about getting the product category.
I am using shop "aimeos/aimeos-laravel": "~2020.10".

In our case:
1. product URL should have /{f_name}/{d_name} structure (so we need add f_name param everywhere in $view->url helper of product),
2. we restrict a product to have only one category,
3. sometimes, we need to fetch products by attribute and have a mix of products with different categories /{f_name}/{d_name} in the list.

I see answers on the forum about using catalog.lists.refid and, right now, I use trait with fetch all catalogs by product ids and set each related category to a product. However, it is tedious to set up decorators for all client/html wich work with products and set up product->category relation.

I want to ask. Maybe I can somehow use a decorator to extend mshop manager sql join and manager item for getting category with each product (I just need category URL segment), or add the catalog to mshop_product_list item for getting like product relation domain?

Thank you for your answer and the great framework!

Re: Get product category

Posted: 28 Mar 2021, 06:44
by aimeos
In 2020.x and later, things are much simpler now. The product manager can retrieve the categories attached to the products itself if you use:

Code: Select all

$productManager->search( $productManager->filter(), ['catalog' => ['text']] );
This will add the categories including their texts to the product items. For the HTML frontend, you can also add them by configuration using:

Code: Select all

client/html/catalog/domains => ['media', 'price', 'text', 'catalog' => ['text']]

Re: Get product category

Posted: 31 Mar 2021, 13:35
by mr.zherart
Yes, it is working. Thank you.

But it is not obvious in documentation, moreover, for those who will read this, I will add that catalog (also as supplier, stock *) retrives via dot notation like $item->get('.catalog') and not by $item->getRefItem('catalog').

* I found this in vendor/aimeos/aimeos-core/lib/mshoplib/src/MShop/Product/Manager/Standard.php, but not tested, and maybe it wrong conclusion (about supplier and stock).