diff --git a/composer.json b/composer.json index d63e2c6..af3e446 100644 --- a/composer.json +++ b/composer.json @@ -68,11 +68,11 @@ "lexik/jwt-authentication-bundle": "^2.17", "matthiasnoback/symfony-dependency-injection-test": "^4.3 || ^5.1", "nyholm/psr7": "^1.8", - "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.6.17", + "phpspec/prophecy-phpunit": "^2.3", + "phpunit/phpunit": "^9.6.21", "psalm/plugin-phpunit": "^0.18.4", "setono/code-quality-pack": "^2.8.3", - "sylius/sylius": "~1.12.18", + "sylius/sylius": "~1.12.19", "symfony/browser-kit": "^5.4 || ^6.4 || ^7.0", "symfony/debug-bundle": "^5.4 || ^6.4 || ^7.0", "symfony/dotenv": "^5.4 || ^6.4 || ^7.0", diff --git a/src/Document/Attribute/Sortable.php b/src/Document/Attribute/Sortable.php index 32693f9..e00221b 100644 --- a/src/Document/Attribute/Sortable.php +++ b/src/Document/Attribute/Sortable.php @@ -14,9 +14,7 @@ final class Sortable final public const DESC = 'desc'; public function __construct( - /** - * The direction of the sorting. If null, both directions are allowed - */ + /** The direction of the sorting. If null, both directions are allowed */ public readonly ?string $direction = null, ) { } diff --git a/src/Document/Product.php b/src/Document/Product.php index cf0111f..7388010 100644 --- a/src/Document/Product.php +++ b/src/Document/Product.php @@ -43,6 +43,7 @@ class Product extends Document implements UrlAwareInterface public ?float $originalPrice = null; + #[Sortable(direction: Sortable::DESC)] public float $popularity = 0.0; /** diff --git a/src/Form/Builder/SearchFormBuilder.php b/src/Form/Builder/SearchFormBuilder.php index b874dea..bd9dbb1 100644 --- a/src/Form/Builder/SearchFormBuilder.php +++ b/src/Form/Builder/SearchFormBuilder.php @@ -19,6 +19,7 @@ final class SearchFormBuilder implements SearchFormBuilderInterface public function __construct( private readonly FormFactoryInterface $formFactory, private readonly FacetFormBuilderInterface $facetFormBuilder, + private readonly SortingFormBuilderInterface $sortingFormBuilder, private readonly MetadataFactoryInterface $metadataFactory, private readonly Index $index, ) { @@ -119,16 +120,7 @@ public function build(SearchResult $searchResult): FormInterface $searchFormBuilder->add($facetsFormBuilder); - $searchFormBuilder->add(SearchRequest::QUERY_PARAMETER_SORT, ChoiceType::class, [ - 'choices' => [ - 'Cheapest first' => 'price:asc', - 'Biggest discount' => 'discount:desc', - 'Newest first' => 'createdAt:desc', - 'Relevance' => '', - ], - 'required' => false, - 'placeholder' => 'Sort by', - ]); + $this->sortingFormBuilder->build($searchFormBuilder, $metadata); $this->buildPagination($searchResult, $searchFormBuilder); diff --git a/src/Form/Builder/SortingFormBuilder.php b/src/Form/Builder/SortingFormBuilder.php new file mode 100644 index 0000000..c756ef4 --- /dev/null +++ b/src/Form/Builder/SortingFormBuilder.php @@ -0,0 +1,42 @@ +getSortableAttributes() as $sortable) { + foreach (self::resolveDirections($sortable) as $direction) { + $choices[sprintf('setono_sylius_meilisearch.form.search.sorting.%s.%s', $sortable->name, $direction)] = sprintf('%s:%s', $sortable->name, $direction); + } + } + $searchFormBuilder->add(SearchRequest::QUERY_PARAMETER_SORT, ChoiceType::class, [ + 'choices' => $choices, + 'required' => false, + 'placeholder' => 'setono_sylius_meilisearch.form.search.sorting.placeholder', + ]); + } + + /** + * @return list + */ + private static function resolveDirections(Sortable $sortable): array + { + if (null === $sortable->direction) { + return [SortableAttribute::ASC, SortableAttribute::DESC]; + } + + return [$sortable->direction]; + } +} diff --git a/src/Form/Builder/SortingFormBuilderInterface.php b/src/Form/Builder/SortingFormBuilderInterface.php new file mode 100644 index 0000000..9dce308 --- /dev/null +++ b/src/Form/Builder/SortingFormBuilderInterface.php @@ -0,0 +1,13 @@ + + + + + + @@ -32,6 +38,7 @@ + diff --git a/src/Resources/public/js/search.js b/src/Resources/public/js/search.js index 1ed5136..ed2011b 100644 --- a/src/Resources/public/js/search.js +++ b/src/Resources/public/js/search.js @@ -71,7 +71,7 @@ class SearchManager { field.dispatchEvent(new CustomEvent('search:filter-changed', { bubbles: true })); } else if(field.name === 'p') { field.dispatchEvent(new CustomEvent('search:page-changed', { bubbles: true })); - } else if(field.classList.contains('sort')) { + } else if(field.classList.contains('ssm-sort')) { field.dispatchEvent(new CustomEvent('search:sort-changed', { bubbles: true })); } }); diff --git a/src/Resources/translations/messages.en.yaml b/src/Resources/translations/messages.en.yaml index ef46a86..fcbe249 100644 --- a/src/Resources/translations/messages.en.yaml +++ b/src/Resources/translations/messages.en.yaml @@ -10,6 +10,20 @@ setono_sylius_meilisearch: previous: Previous next: Next q_placeholder: Search... + sorting: + placeholder: Sort by... + price: + asc: "Price: low to high" + desc: "Price: high to low" + createdAt: + asc: "Oldest" + desc: "Newest" + discount: + asc: "Discount: low to high" + desc: "Discount: high to low" + popularity: + asc: "Least popular" + desc: "Most popular" synonym: term: Term synonym: Synonym diff --git a/tests/Application/templates/bundles/SetonoSyliusMeilisearchPlugin/search/index.html.twig b/tests/Application/templates/bundles/SetonoSyliusMeilisearchPlugin/search/index.html.twig index 2feb461..5394a75 100644 --- a/tests/Application/templates/bundles/SetonoSyliusMeilisearchPlugin/search/index.html.twig +++ b/tests/Application/templates/bundles/SetonoSyliusMeilisearchPlugin/search/index.html.twig @@ -89,9 +89,5 @@ margin: 0 !important; text-align-last: right; } - - .ssm-sort option { - direction: rtl; - } {% endblock %} diff --git a/tests/Unit/Form/Builder/SortingFormBuilderTest.php b/tests/Unit/Form/Builder/SortingFormBuilderTest.php new file mode 100644 index 0000000..84e531b --- /dev/null +++ b/tests/Unit/Form/Builder/SortingFormBuilderTest.php @@ -0,0 +1,46 @@ +prophesize(FormBuilderInterface::class); + $searchFormBuilder->add(SearchRequest::QUERY_PARAMETER_SORT, ChoiceType::class, [ + 'choices' => [ + 'setono_sylius_meilisearch.form.search.sorting.name.asc' => 'name:asc', + 'setono_sylius_meilisearch.form.search.sorting.name.desc' => 'name:desc', + 'setono_sylius_meilisearch.form.search.sorting.price.desc' => 'price:desc', + ], + 'required' => false, + 'placeholder' => 'setono_sylius_meilisearch.form.search.sorting.placeholder', + ])->willReturn($searchFormBuilder)->shouldBeCalledOnce(); + + $metadata = $this->prophesize(MetadataInterface::class); + $metadata->getSortableAttributes()->willReturn([ + new Sortable('name'), + new Sortable('price', SortableAttribute::DESC), + ]); + + $builder = new SortingFormBuilder(); + $builder->build($searchFormBuilder->reveal(), $metadata->reveal()); + } +}