Loading config/services.yaml +2 −1 Original line number Diff line number Diff line Loading @@ -25,3 +25,4 @@ services: App\Service\FilterService: $finder: '@fos_elastica.finder.product' $categoryFinder: '@fos_elastica.finder.category' No newline at end of file src/Request/GetFilteredProductsRequest.php +42 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,12 @@ class GetFilteredProductsRequest { private array $filters; private ?string $category = null; private ?float $minPrice = null; private ?float $maxPrice = null; public function getFilters(): array { return $this->filters; Loading @@ -19,4 +25,40 @@ class GetFilteredProductsRequest return $this; } public function getCategory(): ?string { return $this->category; } public function setCategory(?string $category): self { $this->category = $category; return $this; } public function getMinPrice(): ?float { return $this->minPrice; } public function setMinPrice(?float $minPrice): self { $this->minPrice = $minPrice; return $this; } public function getMaxPrice(): ?float { return $this->maxPrice; } public function setMaxPrice(?float $maxPrice): self { $this->maxPrice = $maxPrice; return $this; } } src/Resolver/RequestQueryArgumentResolver.php +12 −10 Original line number Diff line number Diff line Loading @@ -30,27 +30,29 @@ readonly class RequestQueryArgumentResolver implements ValueResolverInterface try { $strQuery = []; $arrQuery = []; $props = []; foreach ($request->query->all() as $key => $value) { if (property_exists($argument->getType(), $key)) { $props[$key] = ctype_digit($value) ? (int) $value : $value; continue; } if (!is_array($value)) { $strQuery[$key] = $value; $strQuery[$key] = ctype_digit($value) ? (int) $value : $value; continue; } $arrQuery[$key] = $value; } $query = array_map( static function (string $value) { $int_value = ctype_digit($value) ? (int) $value : null; return $int_value ?? $value; }, $strQuery); $query = array_merge($query, $arrQuery); $query = array_merge($strQuery, $arrQuery); $model = $this->serializer->deserialize( json_encode(['filters' => $query], JSON_THROW_ON_ERROR), json_encode( array_merge(['filters' => $query], $props), JSON_THROW_ON_ERROR ), $argument->getType(), JsonEncoder::FORMAT ); Loading src/Service/FilterService.php +45 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ class FilterService private AttributeItemRepository $attributeItemRepository, private ProductAttributeRepository $productAttributeRepository, private FinderInterface $finder, private FinderInterface $categoryFinder, ) { } Loading Loading @@ -50,9 +51,30 @@ class FilterService public function getProducts(GetFilteredProductsRequest $request): array { $filters = $request->getFilters(); $andOuter = new Query\BoolQuery(); if ($request->getCategory() !== null) { $category = $this->categoryFinder->find( new Query\MatchQuery('name', $request->getCategory()) ); $categories = $this->findChildrenCategories($category); foreach ($categories as $category) { $andOuter->addShould(new Query\MatchQuery('category.name', $category->getName())); } } $range = []; if ($request->getMinPrice() !== null) { $range['gte'] = $request->getMinPrice(); } if ($request->getMaxPrice() !== null) { $range['lte'] = $request->getMaxPrice(); } if (!empty($range)) { $andOuter->addMust(new Query\Range('price', $range)); } foreach ($filters as $filterName => $filterValues) { $filterName = str_replace('_', ' ', $filterName); $orOuter = new Query\BoolQuery(); Loading @@ -65,7 +87,7 @@ class FilterService $isDate = \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $filterValue); $andInner = new Query\BoolQuery(); $optionTerm = new Query\MatchQuery('product_attributes.attribute.name', $filterName); $keyTerm = new Query\MatchQuery('product_attributes.attribute.name', $filterName); if (ctype_digit($filterValue)) { $valueTerm = (new Query\Term())->setTerm('product_attributes.value_int', $filterValue); Loading @@ -77,7 +99,7 @@ class FilterService $valueTerm = new Query\MatchQuery('product_attributes.value_item.name', $filterValue); } $andInner->addMust($optionTerm); $andInner->addMust($keyTerm); $andInner->addMust($valueTerm); $orOuter->addShould($andInner); Loading @@ -88,4 +110,24 @@ class FilterService return $this->finder->find(new Query($andOuter)); } private function findChildrenCategories(array $categories): array { $newCategories = $categories; foreach ($categories as $category) { $children = $this->categoryFinder->find( (new Query\Term())->setTerm('parentId', $category->getId()) ); if (empty($children) || in_array($children[0], $categories, true)) { continue; } $newCategories = array_merge($categories, $children); $newCategories = $this->findChildrenCategories($newCategories); } return $newCategories; } } Loading
config/services.yaml +2 −1 Original line number Diff line number Diff line Loading @@ -25,3 +25,4 @@ services: App\Service\FilterService: $finder: '@fos_elastica.finder.product' $categoryFinder: '@fos_elastica.finder.category' No newline at end of file
src/Request/GetFilteredProductsRequest.php +42 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,12 @@ class GetFilteredProductsRequest { private array $filters; private ?string $category = null; private ?float $minPrice = null; private ?float $maxPrice = null; public function getFilters(): array { return $this->filters; Loading @@ -19,4 +25,40 @@ class GetFilteredProductsRequest return $this; } public function getCategory(): ?string { return $this->category; } public function setCategory(?string $category): self { $this->category = $category; return $this; } public function getMinPrice(): ?float { return $this->minPrice; } public function setMinPrice(?float $minPrice): self { $this->minPrice = $minPrice; return $this; } public function getMaxPrice(): ?float { return $this->maxPrice; } public function setMaxPrice(?float $maxPrice): self { $this->maxPrice = $maxPrice; return $this; } }
src/Resolver/RequestQueryArgumentResolver.php +12 −10 Original line number Diff line number Diff line Loading @@ -30,27 +30,29 @@ readonly class RequestQueryArgumentResolver implements ValueResolverInterface try { $strQuery = []; $arrQuery = []; $props = []; foreach ($request->query->all() as $key => $value) { if (property_exists($argument->getType(), $key)) { $props[$key] = ctype_digit($value) ? (int) $value : $value; continue; } if (!is_array($value)) { $strQuery[$key] = $value; $strQuery[$key] = ctype_digit($value) ? (int) $value : $value; continue; } $arrQuery[$key] = $value; } $query = array_map( static function (string $value) { $int_value = ctype_digit($value) ? (int) $value : null; return $int_value ?? $value; }, $strQuery); $query = array_merge($query, $arrQuery); $query = array_merge($strQuery, $arrQuery); $model = $this->serializer->deserialize( json_encode(['filters' => $query], JSON_THROW_ON_ERROR), json_encode( array_merge(['filters' => $query], $props), JSON_THROW_ON_ERROR ), $argument->getType(), JsonEncoder::FORMAT ); Loading
src/Service/FilterService.php +45 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ class FilterService private AttributeItemRepository $attributeItemRepository, private ProductAttributeRepository $productAttributeRepository, private FinderInterface $finder, private FinderInterface $categoryFinder, ) { } Loading Loading @@ -50,9 +51,30 @@ class FilterService public function getProducts(GetFilteredProductsRequest $request): array { $filters = $request->getFilters(); $andOuter = new Query\BoolQuery(); if ($request->getCategory() !== null) { $category = $this->categoryFinder->find( new Query\MatchQuery('name', $request->getCategory()) ); $categories = $this->findChildrenCategories($category); foreach ($categories as $category) { $andOuter->addShould(new Query\MatchQuery('category.name', $category->getName())); } } $range = []; if ($request->getMinPrice() !== null) { $range['gte'] = $request->getMinPrice(); } if ($request->getMaxPrice() !== null) { $range['lte'] = $request->getMaxPrice(); } if (!empty($range)) { $andOuter->addMust(new Query\Range('price', $range)); } foreach ($filters as $filterName => $filterValues) { $filterName = str_replace('_', ' ', $filterName); $orOuter = new Query\BoolQuery(); Loading @@ -65,7 +87,7 @@ class FilterService $isDate = \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $filterValue); $andInner = new Query\BoolQuery(); $optionTerm = new Query\MatchQuery('product_attributes.attribute.name', $filterName); $keyTerm = new Query\MatchQuery('product_attributes.attribute.name', $filterName); if (ctype_digit($filterValue)) { $valueTerm = (new Query\Term())->setTerm('product_attributes.value_int', $filterValue); Loading @@ -77,7 +99,7 @@ class FilterService $valueTerm = new Query\MatchQuery('product_attributes.value_item.name', $filterValue); } $andInner->addMust($optionTerm); $andInner->addMust($keyTerm); $andInner->addMust($valueTerm); $orOuter->addShould($andInner); Loading @@ -88,4 +110,24 @@ class FilterService return $this->finder->find(new Query($andOuter)); } private function findChildrenCategories(array $categories): array { $newCategories = $categories; foreach ($categories as $category) { $children = $this->categoryFinder->find( (new Query\Term())->setTerm('parentId', $category->getId()) ); if (empty($children) || in_array($children[0], $categories, true)) { continue; } $newCategories = array_merge($categories, $children); $newCategories = $this->findChildrenCategories($newCategories); } return $newCategories; } }