ai-controller-frontend
ai-controller-frontend copied to clipboard
Default sorting of products
According to the documentation, the default sorting for products jsonapi is according to their positioning in the catalog.
This does not work properly without specifying a category with f_catid.
Either the documentation should warn about this, or the default behaviour should be changed to reflect the documentation, ie. by default sorting by the root catalogs positions.
Another issue is that the relevance sorting option cannot be combined with other sorting options.
For example sort=text,-ctime can create a primary and secondary sort criteria, but relevance cannot be used in this way.
For example the combination sort=relevance,-ctime&filter[f_catid]=1 does not work the same way as the previous example since the "relevance sorting" is applied after the ctime sorting.
If PRs are wanted I can probably fix this so that "relevance" is an actual sorting option that can be combined with other options, and is actually applied as deafult.
Relevant code:
// controller/frontend/src/Controller/Frontend/Product/Standard.php
public function sort( string $key = null ) : Iface
{
$list = $this->splitKeys( $key );
foreach( $list as $sortkey )
{
$direction = ( $sortkey[0] === '-' ? '-' : '+' );
$sortkey = ltrim( $sortkey, '+-' );
switch( $sortkey )
{
case 'relevance': // <---------------- Not actually a sort option, default sort implemented in category function only if cateogry filter is used
break;
case 'code':
$this->addExpression( $this->filter->sort( $direction, 'product.code' ) );
break;
case 'ctime':
$this->addExpression( $this->filter->sort( $direction, 'product.ctime' ) );
break;
...
}
}
}
// controller/frontend/src/Controller/Frontend/Product/Standard.php
public function category( $catIds, string $listtype = 'default', int $level = \Aimeos\MW\Tree\Manager\Base::LEVEL_ONE ) : Iface
{
if( !empty( $catIds ) && ( $ids = $this->validateIds( (array) $catIds ) ) !== [] ) // <------------------- Is only applied if f_catid is specified, but should according to docs be the default
{
if( $level != \Aimeos\MW\Tree\Manager\Base::LEVEL_ONE )
{
$list = map();
$cntl = \Aimeos\Controller\Frontend::create( $this->getContext(), 'catalog' );
foreach( $ids as $catId ) {
$list->union( $cntl->root( $catId )->getTree( $level )->toList() );
}
$ids = $this->validateIds( $list->keys()->toArray() );
}
$func = $this->filter->make( 'index.catalog:position', [$listtype, $ids] );
$this->addExpression( $this->filter->compare( '==', 'index.catalog.id', $ids ) );
$this->addExpression( $this->filter->compare( '>=', $func, 0 ) );
$func = $this->filter->make( 'sort:index.catalog:position', [$listtype, $ids] );
$this->addExpression( $this->filter->sort( '+', $func ) );
$this->addExpression( $this->filter->sort( '+', 'product.id' ) ); // prevent flaky order if products have same position
}
return $this;
}
Either the documentation should warn about this, or the default behaviour should be changed to reflect the documentation, ie. by default sorting by the root catalogs positions.
The documentation needs to be updated to communicate that better because the positions for relevance sorting are bound to the categories and without a category there are not positions to sort by. Can you propose a PR for the docs repo (https://github.com/aimeos/aimeos-docs)?
Another issue is that the relevance sorting option cannot be combined with other sorting options.
For example
sort=text,-ctimecan create a primary and secondary sort criteria, but relevance cannot be used in this way. For example the combinationsort=relevance,-ctime&filter[f_catid]=1does not work the same way as the previous example since the "relevancesorting" is applied after thectimesorting.
This is also related to the first point: Without category, not sorting by position is possible and you need the list type and category IDs (which are not available in sort() method) to apply the sort criteria.