Question

I've been experimenting with SearchCriteriaBuilder but I can't seem to get the syntax right to apply multiple sort.

I've tried this

$this->searchCriteriaBuilder->addFilter(EntryInterface::STATUS, 1, 'eq');
$sort = [];
$sort[] = $this->sortOrder->setField(EntryInterface::COUNTRY)
    ->setDirection(SortOrder::SORT_ASC);
$sort[] = $this->sortOrder->setField(EntryInterface::SORT)
    ->setDirection(SortOrder::SORT_ASC);

$this->searchCriteriaBuilder->setSortOrders($sort);
$searchCriteria = $this->searchCriteriaBuilder->create();
return $this->entryRepositoryInterface->getList($searchCriteria)->getItems();

And this...

$this->searchCriteriaBuilder->addFilter(EntryInterface::STATUS, 1, 'eq');
$sortOne = $this->sortOrder->setField(EntryInterface::COUNTRY)
    ->setDirection(SortOrder::SORT_ASC);
$sortTwo = $this->sortOrder->setField(EntryInterface::SORT)
    ->setDirection(SortOrder::SORT_ASC);

$this->searchCriteriaBuilder->setSortOrders([$sortOne, $sortTwo]);
$searchCriteria = $this->searchCriteriaBuilder->create();
return $this->entryRepositoryInterface->getList($searchCriteria)->getItems();

One more I tried

[...]
$this->searchCriteriaBuilder->setSortOrders([$sortOne]);
$this->searchCriteriaBuilder->setSortOrders([$sortTwo]);
[...]

But only one sort applies.

I've checked the docs and I'm still unsure.

Is it possible to apply multiple sorts?

Was it helpful?

Solution

The reason it doesn't work for you is that $this->sortOrder is a singleton object. So $sortOne and $sortTwo are referred to the same object.

$sortOne = $this->sortOrder->setField(EntryInterface::COUNTRY)
    ->setDirection(SortOrder::SORT_ASC);
$sortTwo = $this->sortOrder->setField(EntryInterface::SORT)
    ->setDirection(SortOrder::SORT_ASC);

The solution here is to use SortOrderFactory to create $sortOne and $sortTwo object. E.g.

$this->searchCriteriaBuilder->addFilter(EntryInterface::STATUS, 1, 'eq');
$sortOne = $this->sortOrderFactory->create()->setField(EntryInterface::COUNTRY)
    ->setDirection(SortOrder::SORT_ASC);
$sortTwo = $this->sortOrderFactory->create()->setField(EntryInterface::SORT)
    ->setDirection(SortOrder::SORT_ASC);

$this->searchCriteriaBuilder->setSortOrders([$sortOne, $sortTwo]);
$searchCriteria = $this->searchCriteriaBuilder->create();
return $this->entryRepositoryInterface->getList($searchCriteria)->getItems();

FYI, I've also created 2 dummy examples at the webroot folder on a default Magento sample data to prove it. See them here

I hope that it helps.

OTHER TIPS

Full working example based on other answer

use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Api\SortOrder;
use Magento\Framework\Api\SortOrderFactory;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
use Xigen\Estimator\Api\Data\EntryInterface;
use Xigen\Estimator\Api\EntryRepositoryInterface;

    /**
     * @param \Magento\Framework\App\Helper\Context $context
     * @param \Xigen\Estimator\Api\EntryRepositoryInterface $entryRepositoryInterface
     * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
     * @param \Magento\Framework\Api\SortOrderFactory $sortOrderFactory
     */
    public function __construct(
        Context $context,
        EntryRepositoryInterface $entryRepositoryInterface,
        SearchCriteriaBuilder $searchCriteriaBuilder,
        SortOrderFactory $sortOrderFactory
    ) {
        $this->entryRepositoryInterface = $entryRepositoryInterface;
        $this->sortOrderFactory = $sortOrderFactory;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        parent::__construct($context);
    }

    /**
     * Get estimates
     * @param country
     * @return array
     */
    public function getEstimates($country = null)
    {
        $this->searchCriteriaBuilder->addFilter(EntryInterface::STATUS, 1, 'eq');

        if ($country) {
            $this->searchCriteriaBuilder->addFilter(EntryInterface::COUNTRY, $country, 'eq');
        }

        $sortOne = $this->sortOrderFactory->create()
            ->setField(EntryInterface::COUNTRY)
            ->setDirection(SortOrder::SORT_ASC);
        $sortTwo = $this->sortOrderFactory->create()
            ->setField(EntryInterface::SORT)
            ->setDirection(SortOrder::SORT_ASC);

        $this->searchCriteriaBuilder->setSortOrders([$sortOne, $sortTwo]);
        $searchCriteria = $this->searchCriteriaBuilder->create();
        return $this->entryRepositoryInterface->getList($searchCriteria)->getItems();
    }

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top