Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion config/services/controller.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,25 @@
<argument>%bitbag_es_shop_product_price_property_prefix%</argument>
</service>

<service id="bitbag_sylius_elasticsearch_plugin.controller.request_data_handler.taxon_products_sort" class="BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler\TaxonProductsSortDataHandler">
<argument type="service" id="bitbag_sylius_elasticsearch_plugin.property_name_resolver.channel_pricing" />
<argument type="service" id="sylius.context.channel" />
<argument type="service" id="bitbag.sylius_elasticsearch_plugin.context.taxon" />
<argument type="service" id="bitbag_sylius_elasticsearch_plugin.property_name_resolver.taxon_position" />
<argument>%bitbag_es_shop_product_sold_units%</argument>
<argument>%bitbag_es_shop_product_created_at%</argument>
<argument>%bitbag_es_shop_product_price_property_prefix%</argument>
<argument>%bitbag_es_shop_taxon_position_property_prefix%</argument>
</service>

<service id="bitbag_sylius_elasticsearch_plugin.controller.request_data_handler.site_wide" class="BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler\SiteWideDataHandler">
<argument type="service" id="bitbag_sylius_elasticsearch_plugin.controller.request_data_handler.shop_products_sort" />
<argument type="service" id="bitbag_sylius_elasticsearch_plugin.controller.request_data_handler.pagination" />
</service>

<service id="bitbag_sylius_elasticsearch_plugin.controller.request_data_handler.taxon" class="BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler\TaxonDataHandler">
<argument type="service" id="bitbag_sylius_elasticsearch_plugin.controller.request_data_handler.shop_product_list" />
<argument type="service" id="bitbag_sylius_elasticsearch_plugin.controller.request_data_handler.shop_products_sort" />
<argument type="service" id="bitbag_sylius_elasticsearch_plugin.controller.request_data_handler.taxon_products_sort" />
<argument type="service" id="bitbag_sylius_elasticsearch_plugin.controller.request_data_handler.pagination" />
</service>
</services>
Expand Down
7 changes: 7 additions & 0 deletions config/twig/bitbag_twig_hooks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ sylius_twig_hooks:
template: '@SyliusShop/product/index/content/body/main/filters/controls/sorting/menu.html.twig'
priority: 0
'bitbag.sylius_elasticsearch_plugin.taxon_products_search.index.content.body.main.filters.controls.sorting.menu':
position:
template: '@BitBagSyliusElasticsearchPlugin/Shop/TaxonProductsSearch/content/body/main/sorting/item.html.twig'
configuration:
title: 'bitbag_sylius_elasticsearch_plugin.ui.position'
order_by: 'taxon_position'
sort: 'asc'
priority: 700
bestsellers:
template: '@BitBagSyliusElasticsearchPlugin/Shop/TaxonProductsSearch/content/body/main/sorting/item.html.twig'
configuration:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<?php

/*
* This file was created by developers working at BitBag
* Do you need more information about us and what we do? Visit our https://bitbag.io website!
* We are hiring developers from all over the world. Join us and start your new, exciting adventure and become part of us: https://bitbag.io/career
*/

declare(strict_types=1);

namespace spec\BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler;

use BitBag\SyliusElasticsearchPlugin\Context\TaxonContextInterface;
use BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler\ShopProductsSortDataHandler;
use BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler\SortDataHandlerInterface;
use BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler\TaxonProductsSortDataHandler;
use BitBag\SyliusElasticsearchPlugin\PropertyNameResolver\ConcatedNameResolverInterface;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Channel\Model\ChannelInterface;
use Sylius\Component\Core\Model\TaxonInterface;

final class TaxonProductsSortDataHandlerSpec extends ObjectBehavior
{
public function let(
ConcatedNameResolverInterface $channelPricingNameResolver,
ChannelContextInterface $channelContext,
TaxonContextInterface $taxonContext,
ConcatedNameResolverInterface $taxonPositionNameResolver,
): void {
$this->beConstructedWith(
$channelPricingNameResolver,
$channelContext,
$taxonContext,
$taxonPositionNameResolver,
'sold_units',
'created_at',
'price',
'taxon_position'
);
}

function it_is_initializable(): void
{
$this->shouldHaveType(TaxonProductsSortDataHandler::class);
}

function it_is_a_shop_products_sort_data_handler(): void
{
$this->shouldHaveType(ShopProductsSortDataHandler::class);
}

function it_implements_sort_data_handler_interface(): void
{
$this->shouldHaveType(SortDataHandlerInterface::class);
}

function it_sorts_by_taxon_position_ascending_by_default(
TaxonContextInterface $taxonContext,
TaxonInterface $taxon,
ConcatedNameResolverInterface $taxonPositionNameResolver,
): void {
$taxonContext->getTaxon()->willReturn($taxon);
$taxon->getCode()->willReturn('t_shirts');
$taxonPositionNameResolver->resolvePropertyName('t_shirts')->willReturn('taxon_position_t_shirts');

$this->retrieveData([])->shouldBeEqualTo([
'sort' => [
'taxon_position_t_shirts' => [
'order' => SortDataHandlerInterface::SORT_ASC_INDEX,
'unmapped_type' => 'keyword',
],
],
]);
}

function it_resolves_the_taxon_position_field_for_the_current_taxon(
TaxonContextInterface $taxonContext,
TaxonInterface $taxon,
ConcatedNameResolverInterface $taxonPositionNameResolver,
): void {
$taxonContext->getTaxon()->willReturn($taxon);
$taxon->getCode()->willReturn('mugs');
$taxonPositionNameResolver->resolvePropertyName('mugs')->willReturn('taxon_position_mugs');

$this->retrieveData([
'order_by' => 'taxon_position',
'sort' => 'desc',
])->shouldBeEqualTo([
'sort' => [
'taxon_position_mugs' => [
'order' => SortDataHandlerInterface::SORT_DESC_INDEX,
'unmapped_type' => 'keyword',
],
],
]);
}

function it_still_resolves_the_price_field_per_channel(
ChannelContextInterface $channelContext,
ChannelInterface $channel,
ConcatedNameResolverInterface $channelPricingNameResolver,
): void {
$channelContext->getChannel()->willReturn($channel);
$channel->getCode()->willReturn('WEB');
$channelPricingNameResolver->resolvePropertyName('WEB')->willReturn('price_WEB');

$this->retrieveData([
'order_by' => 'price',
'sort' => 'asc',
])->shouldBeEqualTo([
'sort' => [
'price_WEB' => [
'order' => SortDataHandlerInterface::SORT_ASC_INDEX,
'unmapped_type' => 'keyword',
],
],
]);
}

function it_throws_an_exception_for_an_unsupported_sorter(): void
{
$this->shouldThrow(\UnexpectedValueException::class)->during('retrieveData', [
['order_by' => 'unsupported'],
]);
}
}
43 changes: 31 additions & 12 deletions src/Controller/RequestDataHandler/ShopProductsSortDataHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,58 @@
use Sylius\Component\Channel\Context\ChannelContextInterface;
use UnexpectedValueException;

final class ShopProductsSortDataHandler implements SortDataHandlerInterface
class ShopProductsSortDataHandler implements SortDataHandlerInterface
{
public function __construct(
private ConcatedNameResolverInterface $channelPricingNameResolver,
private ChannelContextInterface $channelContext,
private string $soldUnitsProperty,
private string $createdAtProperty,
private string $pricePropertyPrefix
protected ConcatedNameResolverInterface $channelPricingNameResolver,
protected ChannelContextInterface $channelContext,
protected string $soldUnitsProperty,
protected string $createdAtProperty,
protected string $pricePropertyPrefix
) {
}

public function retrieveData(array $requestData): array
{
$data = [];

$orderBy = $requestData[self::ORDER_BY_INDEX] ?? $this->createdAtProperty;
$orderBy = $requestData[self::ORDER_BY_INDEX] ?? $this->getDefaultOrderBy();
$sort = $requestData[self::SORT_INDEX] ?? self::SORT_ASC_INDEX;

$availableSorters = [$this->soldUnitsProperty, $this->createdAtProperty, $this->pricePropertyPrefix];
$availableSorting = [self::SORT_ASC_INDEX, self::SORT_DESC_INDEX];

if (!in_array($orderBy, $availableSorters, true) || !in_array($sort, $availableSorting, true)) {
if (!in_array($orderBy, $this->getAvailableSorters(), true) || !in_array($sort, $availableSorting, true)) {
throw new UnexpectedValueException();
}

$orderBy = $this->resolveOrderByProperty($orderBy);

$data['sort'] = [$orderBy => ['order' => strtolower($sort), 'unmapped_type' => 'keyword']];

return $data;
}

protected function getDefaultOrderBy(): string
{
return $this->createdAtProperty;
}

/**
* @return string[]
*/
protected function getAvailableSorters(): array
{
return [$this->soldUnitsProperty, $this->createdAtProperty, $this->pricePropertyPrefix];
}

protected function resolveOrderByProperty(string $orderBy): string
{
if ($this->pricePropertyPrefix === $orderBy) {
/** @var string $channelCode */
$channelCode = $this->channelContext->getChannel()->getCode();
$orderBy = $this->channelPricingNameResolver->resolvePropertyName($channelCode);
}

$data['sort'] = [$orderBy => ['order' => strtolower($sort), 'unmapped_type' => 'keyword']];

return $data;
return $orderBy;
}
}
61 changes: 61 additions & 0 deletions src/Controller/RequestDataHandler/TaxonProductsSortDataHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

/*
* This file has been created by developers from BitBag.
* Feel free to contact us once you face any issues or want to start
* another great project.
* You can find more information about us on https://bitbag.io and write us
* an email on hello@bitbag.io.
*/

declare(strict_types=1);

namespace BitBag\SyliusElasticsearchPlugin\Controller\RequestDataHandler;

use BitBag\SyliusElasticsearchPlugin\Context\TaxonContextInterface;
use BitBag\SyliusElasticsearchPlugin\PropertyNameResolver\ConcatedNameResolverInterface;
use Sylius\Component\Channel\Context\ChannelContextInterface;

final class TaxonProductsSortDataHandler extends ShopProductsSortDataHandler
{
public function __construct(
ConcatedNameResolverInterface $channelPricingNameResolver,
ChannelContextInterface $channelContext,
private TaxonContextInterface $taxonContext,
private ConcatedNameResolverInterface $taxonPositionNameResolver,
string $soldUnitsProperty,
string $createdAtProperty,
string $pricePropertyPrefix,
private string $taxonPositionPropertyPrefix
) {
parent::__construct(
$channelPricingNameResolver,
$channelContext,
$soldUnitsProperty,
$createdAtProperty,
$pricePropertyPrefix
);
}

protected function getDefaultOrderBy(): string
{
return $this->taxonPositionPropertyPrefix;
}

protected function getAvailableSorters(): array
{
return array_merge(parent::getAvailableSorters(), [$this->taxonPositionPropertyPrefix]);
}

protected function resolveOrderByProperty(string $orderBy): string
{
if ($this->taxonPositionPropertyPrefix === $orderBy) {
/** @var string $taxonCode */
$taxonCode = $this->taxonContext->getTaxon()->getCode();

return $this->taxonPositionNameResolver->resolvePropertyName($taxonCode);
}

return parent::resolveOrderByProperty($orderBy);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
{% set route_parameters = app.request.query.all|unset_elements(['order_by', 'sort', 'page']) %}

{% if app.request.query.all()['order_by'] is not defined or app.request.query.all()['order_by'] is empty %}
{% set current_sorting_label = 'bitbag_sylius_elasticsearch_plugin.ui.newest'|trans|lower %}
{% set current_sorting_label = 'bitbag_sylius_elasticsearch_plugin.ui.position'|trans|lower %}
{% elseif app.request.query.all()['order_by'] == 'taxon_position' %}
{% set current_sorting_label = 'bitbag_sylius_elasticsearch_plugin.ui.position'|trans|lower %}
{% elseif app.request.query.all()['order_by'] == 'sold_units'%}
{% set current_sorting_label = 'bitbag_sylius_elasticsearch_plugin.ui.bestsellers'|trans|lower %}
{% elseif app.request.query.all()['order_by'] == 'product_created_at' and app.request.query.all()['sort'] == 'desc'%}
Expand Down
1 change: 1 addition & 0 deletions translations/messages.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ bitbag_sylius_elasticsearch_plugin:
filter_results: Filter results
filter: Filter
sort: Sort by
position: Position
bestsellers: Bestsellers
newest: Newest
oldest: Oldest
Expand Down
Loading