Get product category

Questions around the TYPO3 integration and plugins
Forum rules
Always add your TYPO3, Aimeos and PHP version as well as your environment (Linux/Mac/Win)
Spam and unrelated posts will be removed immediately!
Alex K
Posts: 9
Joined: 14 May 2018, 06:22

Get product category

Post 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.

User avatar
aimeos
Administrator
Posts: 7836
Joined: 01 Jan 1970, 00:00

Re: Get product category

Post 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 ... 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 );
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

Alex K
Posts: 9
Joined: 14 May 2018, 06:22

Re: Get product category

Post by Alex K » 03 Jun 2018, 11:34

I need both) Thank you for help! I will try!

Alex K
Posts: 9
Joined: 14 May 2018, 06:22

Re: Get product category

Post 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 );
	}

}

Alex K
Posts: 9
Joined: 14 May 2018, 06:22

Re: Get product category

Post 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;
	}
}

User avatar
aimeos
Administrator
Posts: 7836
Joined: 01 Jan 1970, 00:00

Re: Get product category

Post 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.
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

sixbynine
Posts: 93
Joined: 10 Jan 2018, 11:22

Re: Get product category

Post 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

mr.zherart
Posts: 27
Joined: 04 Jun 2020, 14:00

Re: Get product category

Post by mr.zherart » 25 Mar 2021, 07:36

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!

User avatar
aimeos
Administrator
Posts: 7836
Joined: 01 Jan 1970, 00:00

Re: Get product category

Post by aimeos » 28 Mar 2021, 06:44

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']]
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

mr.zherart
Posts: 27
Joined: 04 Jun 2020, 14:00

Re: Get product category

Post by mr.zherart » 31 Mar 2021, 13:35

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).

Post Reply