Skip to content

Commit

Permalink
product filters on search page are now provided via Luigi's Box
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasLudvik committed Mar 28, 2024
1 parent b05634e commit d42f640
Show file tree
Hide file tree
Showing 12 changed files with 330 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ protected function mapPrice(ProductFilterData $productFilterData, array $luigisB
$priceFrom = $productFilterData->minimalPrice === null ? '' : $productFilterData->minimalPrice->getAmount();
$priceTo = $productFilterData->maximalPrice === null ? '' : $productFilterData->maximalPrice->getAmount();

$luigisBoxFilter[self::FILTER_AND][] = 'price:' . $priceFrom . '|' . $priceTo;
$luigisBoxFilter[self::FILTER_OR][] = 'price_amount:' . $priceFrom . '|' . $priceTo;
}

return $luigisBoxFilter;
Expand All @@ -101,7 +101,7 @@ protected function mapAvailability(
array $luigisBoxFilter,
): array {
if ($productFilterData->inStock === true) {
$luigisBoxFilter[self::FILTER_AND][] = 'availability:1';
$luigisBoxFilter[self::FILTER_OR][] = 'availability:1';
}

return $luigisBoxFilter;
Expand Down
28 changes: 19 additions & 9 deletions src/Component/LuigisBox/LuigisBoxClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ protected function getTrackerId(): string
* @param array $filter
* @param string $userIdentifier
* @param string|null $orderingMode
* @param string[] $facetNames
* @return \Shopsys\LuigisBoxBundle\Component\LuigisBox\LuigisBoxResult[]
*/
public function getData(
Expand All @@ -74,6 +75,7 @@ public function getData(
array $filter,
string $userIdentifier,
?string $orderingMode,
array $facetNames = [],
): array {
$this->checkNecessaryConfigurationIsSet();
$this->validateActionIsValid($action);
Expand All @@ -89,6 +91,7 @@ public function getData(
$filter,
$userIdentifier,
$orderingMode,
$facetNames,
),
),
true,
Expand All @@ -107,13 +110,14 @@ public function getData(
'filter' => $filter,
'userIdentifier' => $userIdentifier,
'orderingMode' => $orderingMode,
'facets' => $facetNames,
],
);

return $this->getEmptyResults(array_keys($limitsByType));
}

if ($action === self::ACTION_SEARCH) {
if ($action === static::ACTION_SEARCH) {
$data = $data['results'];
}

Expand All @@ -129,7 +133,7 @@ protected function getEmptyResults(array $types): array
$resultsByType = [];

foreach ($types as $type) {
$resultsByType[$type] = new LuigisBoxResult([], [], 0);
$resultsByType[$type] = new LuigisBoxResult([], [], 0, []);
}

return $resultsByType;
Expand All @@ -142,7 +146,7 @@ protected function getEmptyResults(array $types): array
*/
protected function getTotalHitsFromData(array $data, string $action): int
{
if ($action === self::ACTION_AUTOCOMPLETE) {
if ($action === static::ACTION_AUTOCOMPLETE) {
return (int)$data['exact_match_hits_count'] + (int)$data['partial_match_hits_count'];
}

Expand All @@ -157,6 +161,7 @@ protected function getTotalHitsFromData(array $data, string $action): int
* @param array $filter
* @param string $userIdentifier
* @param string|null $orderingMode
* @param string[] $facetNames
* @return string
*/
protected function getLuigisBoxApiUrl(
Expand All @@ -167,6 +172,7 @@ protected function getLuigisBoxApiUrl(
array $filter,
string $userIdentifier,
?string $orderingMode,
array $facetNames = [],
): string {
$url = $this->luigisBoxApiUrl .
$action . '/' .
Expand All @@ -175,15 +181,18 @@ protected function getLuigisBoxApiUrl(
'&hit_fields=url' .
'&user_id=' . $userIdentifier;

if ($action === self::ACTION_SEARCH) {
if ($action === static::ACTION_SEARCH) {
$quicksearchTypesWithLimits = $this->getQuicksearchTypesWithLimits($limitsByType);

$url .=
'&remove_fields=nested' .
'&size=' . $this->getMainTypeLimit($limitsByType) .
'&from=' . $page;
$url .=
$quicksearchTypesWithLimits !== '' ? '&quicksearch_types=' . $quicksearchTypesWithLimits : '';
$url .= $quicksearchTypesWithLimits !== '' ? '&quicksearch_types=' . $quicksearchTypesWithLimits : '';

if (count($facetNames) > 0) {
$url .= '&facets=' . implode(',', $facetNames);
}

foreach ($filter as $key => $filterValues) {
foreach ($filterValues as $filterValue) {
Expand All @@ -198,7 +207,7 @@ protected function getLuigisBoxApiUrl(
}
}

if ($action === self::ACTION_AUTOCOMPLETE && count($limitsByType) > 0) {
if ($action === static::ACTION_AUTOCOMPLETE && count($limitsByType) > 0) {
$url .= '&type=' . $this->mapLimitsByTypeToLuigisBoxLimit($limitsByType);
}

Expand Down Expand Up @@ -247,7 +256,7 @@ protected function getIdFromIdentity(string $identity): int
protected function getMainType(array $types): string
{
if (in_array(static::TYPE_IN_LUIGIS_BOX_PRODUCT, $types, true)) {
return self::TYPE_IN_LUIGIS_BOX_PRODUCT;
return static::TYPE_IN_LUIGIS_BOX_PRODUCT;
}

return reset($types);
Expand Down Expand Up @@ -302,6 +311,7 @@ protected function getResultsIndexedByItemType(array $data, string $action, arra
$idsByType[$type] ?? [],
$idsWithPrefixByType[$type] ?? [],
$this->getTotalHitsFromData($data, $action),
$data['facets'] ?? [],
);
}

Expand Down Expand Up @@ -347,7 +357,7 @@ protected function mapLimitsByTypeToLuigisBoxLimit(array $limitsByType): string
*/
protected function validateActionIsValid(string $action): void
{
if (!in_array($action, [self::ACTION_SEARCH, self::ACTION_AUTOCOMPLETE], true)) {
if (!in_array($action, [static::ACTION_SEARCH, static::ACTION_AUTOCOMPLETE], true)) {
throw new LuigisBoxActionNotRecognizedException($action);
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/Component/LuigisBox/LuigisBoxResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ class LuigisBoxResult
* @param int[] $ids
* @param string[] $idsWithPrefix
* @param int $itemsCount
* @param array $facets
*/
public function __construct(
protected readonly array $ids,
protected readonly array $idsWithPrefix,
protected readonly int $itemsCount,
protected readonly array $facets,
) {
}

Expand All @@ -41,4 +43,12 @@ public function getItemsCount(): int
{
return $this->itemsCount;
}

/**
* @return array
*/
public function getFacets(): array
{
return $this->facets;
}
}
10 changes: 10 additions & 0 deletions src/Model/Batch/LuigisBoxBatchLoadData.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class LuigisBoxBatchLoadData
* @param array $filter
* @param string $userIdentifier
* @param string|null $orderingMode
* @param string[] $facetNames
*/
public function __construct(
protected readonly string $type,
Expand All @@ -25,6 +26,7 @@ public function __construct(
protected readonly array $filter,
protected readonly string $userIdentifier,
protected readonly ?string $orderingMode = null,
protected readonly array $facetNames = [],
) {
}

Expand Down Expand Up @@ -91,4 +93,12 @@ public function getUserIdentifier(): string
{
return $this->userIdentifier;
}

/**
* @return string[]
*/
public function getFacetNames(): array
{
return $this->facetNames;
}
}
14 changes: 14 additions & 0 deletions src/Model/Batch/LuigisBoxBatchLoadDataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Overblog\GraphQLBundle\Definition\Argument;
use Shopsys\LuigisBoxBundle\Component\LuigisBox\Filter\ProductFilterToLuigisBoxFilterMapper;
use Shopsys\LuigisBoxBundle\Component\LuigisBox\LuigisBoxClient;
use Shopsys\LuigisBoxBundle\Model\Product\Filter\LuigisBoxFacetsToProductFilterOptionsMapper;

class LuigisBoxBatchLoadDataFactory
{
Expand Down Expand Up @@ -51,6 +52,19 @@ public function create(
$luigisBoxFilter,
$userIdentifier,
$orderingMode,
$this->getFacetNamesByType($type),
);
}

/**
* @param string $type
* @return string[]
*/
protected function getFacetNamesByType(string $type): array
{
return match ($type) {
LuigisBoxClient::TYPE_IN_LUIGIS_BOX_PRODUCT => LuigisBoxFacetsToProductFilterOptionsMapper::PRODUCT_FACET_NAMES,
default => [],
};
}
}
71 changes: 56 additions & 15 deletions src/Model/Batch/LuigisBoxBatchLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ class LuigisBoxBatchLoader
*/
protected static array $totalsByType = [];

/**
* @var array<int, array<string, mixed>>
*/
protected static array $facets = [];

protected ?LuigisBoxBatchLoadData $mainBatchLoadData = null;

/**
* @param \Shopsys\LuigisBoxBundle\Component\LuigisBox\LuigisBoxClient $luigisBoxClient
* @param \GraphQL\Executor\Promise\PromiseAdapter $promiseAdapter
Expand Down Expand Up @@ -50,7 +57,15 @@ public function __construct(
*/
public static function getTotalByType(string $type): int
{
return self::$totalsByType[$type] ?? 0;
return static::$totalsByType[$type] ?? 0;
}

/**
* @return array<int, array<string, mixed>>
*/
public static function getFacets(): array
{
return static::$facets;
}

/**
Expand All @@ -60,22 +75,27 @@ public static function getTotalByType(string $type): int
public function loadByBatchData(array $luigisBoxBatchLoadData): Promise
{
$mainBatchLoadData = $this->getMainBatchLoadData($luigisBoxBatchLoadData);
$query = $mainBatchLoadData->getQuery();
$endpoint = $mainBatchLoadData->getEndpoint();
$page = $mainBatchLoadData->getPage();
$productFilter = $mainBatchLoadData->getFilter();
$productOrderingMode = $mainBatchLoadData->getOrderingMode();
$userIdentifier = $mainBatchLoadData->getUserIdentifier();
$limitsByType = [];

foreach ($luigisBoxBatchLoadData as $luigisBoxBatchLoadDataItem) {
$limitsByType[$luigisBoxBatchLoadDataItem->getType()] = $luigisBoxBatchLoadDataItem->getLimit();
}

return $this->promiseAdapter->all($this->mapDataByTypes(
$this->luigisBoxClient->getData($query, $endpoint, $page, $limitsByType, $productFilter, $userIdentifier, $productOrderingMode),
$limitsByType,
));
return $this->promiseAdapter->all(
$this->mapDataByTypes(
$this->luigisBoxClient->getData(
$mainBatchLoadData->getQuery(),
$mainBatchLoadData->getEndpoint(),
$mainBatchLoadData->getPage(),
$limitsByType,
$mainBatchLoadData->getFilter(),
$mainBatchLoadData->getUserIdentifier(),
$mainBatchLoadData->getOrderingMode(),
$mainBatchLoadData->getFacetNames(),
),
$limitsByType,
),
);
}

/**
Expand Down Expand Up @@ -106,7 +126,14 @@ protected function mapDataByTypes(array $luigisBoxResults, array $limitsByType):
$mappedDataOfCurrentType = $this->mapBrandData($luigisBoxResults[$type]);
}

self::$totalsByType[$type] = count($mappedDataOfCurrentType);
if ($type === $this->getMainType()) {
static::$facets = $luigisBoxResults[$type]->getFacets();
static::$totalsByType[$type] = $luigisBoxResults[$type]->getItemsCount();
} else {
static::$totalsByType[$type] = -1;
}

static::$totalsByType[$type] = count($mappedDataOfCurrentType);
$mappedData[] = $mappedDataOfCurrentType;
}

Expand Down Expand Up @@ -175,16 +202,30 @@ protected function mapBrandData(LuigisBoxResult $luigisBoxResult): array
*/
protected function getMainBatchLoadData(array $luigisBoxBatchLoadData): LuigisBoxBatchLoadData
{
$mainBatchLoadData = null;
if ($this->mainBatchLoadData !== null) {
return $this->mainBatchLoadData;
}

foreach ($luigisBoxBatchLoadData as $luigisBoxBatchLoadDataItem) {
if ($luigisBoxBatchLoadDataItem->getType() === LuigisBoxClient::TYPE_IN_LUIGIS_BOX_PRODUCT) {
$mainBatchLoadData = $luigisBoxBatchLoadDataItem;
$this->mainBatchLoadData = $luigisBoxBatchLoadDataItem;

break;
}
}

return $mainBatchLoadData ?? reset($luigisBoxBatchLoadData);
if ($this->mainBatchLoadData === null) {
$this->mainBatchLoadData = reset($luigisBoxBatchLoadData);
}

return $this->mainBatchLoadData;
}

/**
* @return string
*/
protected function getMainType(): string
{
return $this->mainBatchLoadData->getType();
}
}
47 changes: 47 additions & 0 deletions src/Model/Brand/BrandRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace Shopsys\LuigisBoxBundle\Model\Brand;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Shopsys\FrameworkBundle\Component\Doctrine\OrderByCollationHelper;
use Shopsys\FrameworkBundle\Component\Domain\Domain;
use Shopsys\FrameworkBundle\Model\Product\Brand\Brand;

class BrandRepository
{
/**
* @param \Doctrine\ORM\EntityManagerInterface $em
* @param \Shopsys\FrameworkBundle\Component\Domain\Domain $domain
*/
public function __construct(
protected readonly EntityManagerInterface $em,
protected readonly Domain $domain,
) {
}

/**
* @return \Doctrine\ORM\EntityRepository
*/
protected function getBrandRepository(): EntityRepository
{
return $this->em->getRepository(Brand::class);
}

/**
* @param string[] $brandNames
* @return \Shopsys\FrameworkBundle\Model\Product\Brand\Brand[]
*/
public function getBrandsByNames(array $brandNames): array
{
$queryBuilder = $this->getBrandRepository()
->createQueryBuilder('b')
->andWhere('b.name IN(:brandNames)');
$queryBuilder->setParameter('brandNames', $brandNames);
$queryBuilder->orderBy(OrderByCollationHelper::createOrderByForLocale('b.name', $this->domain->getLocale()));

return $queryBuilder->getQuery()->getResult();
}
}
Loading

0 comments on commit d42f640

Please sign in to comment.