Skip to content

Commit fe49925

Browse files
Feat view more
1 parent 77cfd63 commit fe49925

18 files changed

+379
-41
lines changed

src/Controller/Filter.php

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
/**
3+
* DISCLAIMER
4+
*
5+
* Do not edit or add to this file if you wish to upgrade Gally to newer versions in the future.
6+
*
7+
* @package Gally
8+
* @author Stephan Hochdörfer <[email protected]>, Gally Team <[email protected]>
9+
* @copyright 2022-present Smile
10+
* @license Open Software License v. 3.0 (OSL-3.0)
11+
*/
12+
13+
declare(strict_types=1);
14+
15+
namespace Gally\SyliusPlugin\Controller;
16+
17+
use Gally\SyliusPlugin\Form\Type\Filter\GallyDynamicFilterType;
18+
use Gally\SyliusPlugin\Grid\Filter\Type\SelectFilterType;
19+
use Gally\SyliusPlugin\Search\Adapter;
20+
use Gally\SyliusPlugin\Service\FilterConverter;
21+
use Sylius\Bundle\TaxonomyBundle\Doctrine\ORM\TaxonRepository;
22+
use Sylius\Component\Channel\Context\ChannelContextInterface;
23+
use Sylius\Component\Locale\Context\LocaleContextInterface;
24+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
25+
use Symfony\Component\Form\FormFactoryInterface;
26+
use Symfony\Component\HttpFoundation\Request;
27+
use Symfony\Component\HttpFoundation\Response;
28+
29+
final class Filter extends AbstractController
30+
{
31+
public function __construct(
32+
private Adapter $adapter,
33+
private ChannelContextInterface $channelContext,
34+
private LocaleContextInterface $localeContext,
35+
private TaxonRepository $taxonRepository,
36+
private FormFactoryInterface $formFactory,
37+
private FilterConverter $filterConverter,
38+
) {
39+
}
40+
41+
public function viewMore(Request $request, string $filterField): Response
42+
{
43+
$search = $request->get('search');
44+
$filters = $request->get('filters')['gally'] ?? [];
45+
$gallyFilters = [];
46+
foreach ($filters as $field => $value) {
47+
$gallyFilter = $this->filterConverter->convert($field, $value);
48+
if ($gallyFilter) {
49+
$gallyFilters[] = $gallyFilter;
50+
}
51+
}
52+
53+
$choices = [];
54+
$currentTaxonId = $request->get('taxon');
55+
$aggregationOptions = $this->adapter->viewMoreOption(
56+
$this->channelContext->getChannel(),
57+
$currentTaxonId ? $this->taxonRepository->find($currentTaxonId) : null,
58+
$this->localeContext->getLocaleCode(),
59+
$filterField,
60+
$gallyFilters,
61+
$search,
62+
);
63+
64+
foreach ($aggregationOptions as $option) {
65+
$choices[$option['label']] = $option['value'];
66+
}
67+
68+
$options = [
69+
'block_prefix' => 'sylius_gally_filter_checkbox',
70+
'choices' => $choices,
71+
'expanded' => true,
72+
'multiple' => true,
73+
];
74+
75+
$form = $this->formFactory->createNamed('criteria')->add('gally', GallyDynamicFilterType::class);
76+
$form->get('gally')->add($filterField, SelectFilterType::class, $options);
77+
$form->get('gally')->get($filterField)->setData($filters[$filterField] ?? null);
78+
$html = $this->renderView('@GallySyliusPlugin/Grid/Filter/gally_dynamic_filter.html.twig', ['form' => $form]);
79+
80+
return $this->json(['html' => $html]);
81+
}
82+
}

src/Form/Type/Filter/GallyDynamicFilterType.php

+45-8
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,29 @@
1515
namespace Gally\SyliusPlugin\Form\Type\Filter;
1616

1717
use Gally\SyliusPlugin\Event\GridFilterUpdateEvent;
18+
use Gally\SyliusPlugin\Grid\Filter\Type\SelectFilterType;
1819
use Gally\SyliusPlugin\Search\Aggregation\Aggregation;
1920
use Gally\SyliusPlugin\Search\Aggregation\AggregationOption;
2021
use Sylius\Bundle\GridBundle\Form\Type\Filter\BooleanFilterType;
21-
use Sylius\Bundle\GridBundle\Form\Type\Filter\SelectFilterType;
22+
use Sylius\Bundle\TaxonomyBundle\Doctrine\ORM\TaxonRepository;
23+
use Sylius\Component\Grid\Parameters;
24+
use Sylius\Component\Locale\Context\LocaleContextInterface;
2225
use Symfony\Component\Form\AbstractType;
2326
use Symfony\Component\Form\Extension\Core\Type\RangeType;
2427
use Symfony\Component\Form\FormBuilderInterface;
28+
use Symfony\Component\HttpFoundation\RequestStack;
29+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
2530

2631
class GallyDynamicFilterType extends AbstractType
2732
{
33+
public function __construct(
34+
private UrlGeneratorInterface $router,
35+
private RequestStack $requestStack,
36+
private TaxonRepository $taxonRepository,
37+
private LocaleContextInterface $localeContext,
38+
) {
39+
}
40+
2841
/**
2942
* @var Aggregation[]
3043
*/
@@ -78,16 +91,20 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
7891
/** @var AggregationOption $option */
7992
$choices[$option->getLabel()] = $option->getId();
8093
}
94+
$options = [
95+
'block_prefix' => 'sylius_gally_filter_checkbox',
96+
'label' => $aggregation->getLabel(),
97+
'choices' => $choices,
98+
'expanded' => true,
99+
'multiple' => true,
100+
];
101+
if ($aggregation->hasMore()) {
102+
$options['has_more_url'] = $this->buildHasMoreUrl($aggregation->getField());
103+
}
81104
$builder->add(
82105
$aggregation->getField(),
83106
SelectFilterType::class,
84-
[
85-
'block_prefix' => 'sylius_gally_filter_checkbox',
86-
'label' => $aggregation->getLabel(),
87-
'choices' => $choices,
88-
'expanded' => true,
89-
'multiple' => true,
90-
]
107+
$options
91108
);
92109
break;
93110
default:
@@ -100,4 +117,24 @@ public function onFilterUpdate(GridFilterUpdateEvent $event): void
100117
{
101118
$this->aggregations = $event->getAggregations();
102119
}
120+
121+
private function buildHasMoreUrl(string $field): string
122+
{
123+
$request = $this->requestStack->getCurrentRequest();
124+
$parameters = new Parameters($request->query->all());
125+
$criteria = $parameters->get('criteria', []);
126+
$search = (isset($criteria['search'], $criteria['search']['value'])) ? $criteria['search']['value'] : '';
127+
unset($criteria['search']);
128+
$taxon = $this->taxonRepository->findOneBySlug($request->attributes->get('slug'), $this->localeContext->getLocaleCode());
129+
130+
return $this->router->generate(
131+
'gally_filter_view_more_ajax',
132+
[
133+
'filterField' => $field,
134+
'search' => $search,
135+
'filters' => $criteria,
136+
'taxon' => $taxon->getId(),
137+
]
138+
);
139+
}
103140
}

src/Grid/Filter/GallyDynamicFilter.php

+8-21
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,22 @@
1414

1515
namespace Gally\SyliusPlugin\Grid\Filter;
1616

17+
use Gally\SyliusPlugin\Service\FilterConverter;
1718
use Sylius\Component\Grid\Data\DataSourceInterface;
1819
use Sylius\Component\Grid\Filtering\FilterInterface;
1920

2021
class GallyDynamicFilter implements FilterInterface
2122
{
23+
public function __construct(private FilterConverter $filterConverter)
24+
{
25+
}
26+
2227
public function apply(DataSourceInterface $dataSource, string $name, $data, array $options): void
2328
{
2429
foreach ($data as $field => $value) {
25-
if ('' === $value) {
26-
continue;
27-
}
28-
29-
if (str_contains($field, '_slider')) {
30-
$field = str_replace('_slider', '', $field);
31-
$values = explode(';', $value, 2);
32-
$dataSource->restrict($dataSource->getExpressionBuilder()->andX(
33-
$dataSource->getExpressionBuilder()->greaterThanOrEqual($field, (int) $values[0]),
34-
$dataSource->getExpressionBuilder()->lessThanOrEqual($field, (int) $values[1]),
35-
));
36-
} elseif (str_contains($field, '_boolean')) {
37-
$field = str_replace('_boolean', '', $field);
38-
$value = ('true' === $value);
39-
$dataSource->restrict($dataSource->getExpressionBuilder()->equals($field, $value));
40-
} else {
41-
if (\is_array($value)) {
42-
$dataSource->restrict($dataSource->getExpressionBuilder()->in($field, $value));
43-
} else {
44-
$dataSource->restrict($dataSource->getExpressionBuilder()->equals($field, $value));
45-
}
30+
$gallyFilter = $this->filterConverter->convert($field, $value);
31+
if ($gallyFilter) {
32+
$dataSource->restrict($gallyFilter);
4633
}
4734
}
4835
}
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
/**
3+
* DISCLAIMER
4+
*
5+
* Do not edit or add to this file if you wish to upgrade Gally to newer versions in the future.
6+
*
7+
* @package Gally
8+
* @author Stephan Hochdörfer <[email protected]>, Gally Team <[email protected]>
9+
* @copyright 2022-present Smile
10+
* @license Open Software License v. 3.0 (OSL-3.0)
11+
*/
12+
13+
declare(strict_types=1);
14+
15+
namespace Gally\SyliusPlugin\Grid\Filter\Type;
16+
17+
use Sylius\Bundle\GridBundle\Form\Type\Filter\SelectFilterType as BaseSelectFilterType;
18+
use Symfony\Component\Form\AbstractType;
19+
use Symfony\Component\Form\FormInterface;
20+
use Symfony\Component\Form\FormView;
21+
use Symfony\Component\OptionsResolver\OptionsResolver;
22+
23+
final class SelectFilterType extends AbstractType
24+
{
25+
public function configureOptions(OptionsResolver $resolver): void
26+
{
27+
$resolver->setDefined(['has_more_url'])
28+
->addAllowedTypes('has_more_url', 'string');
29+
}
30+
31+
public function getParent(): string
32+
{
33+
return BaseSelectFilterType::class;
34+
}
35+
36+
public function buildView(FormView $view, FormInterface $form, array $options): void
37+
{
38+
$view->vars['has_more_url'] = $options['has_more_url'] ?? null;
39+
}
40+
}

src/Resources/config/services.xml

+25
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
<argument type="service" id="Gally\SyliusPlugin\Synchronizer\LocalizedCatalogSynchronizer" />
3232
</service>
3333

34+
35+
<service id="Gally\SyliusPlugin\Service\FilterConverter" />
36+
3437
<service id="Gally\SyliusPlugin\Controller\AdminGallyController">
3538
<argument type="service" id="Gally\SyliusPlugin\Repository\GallyConfigurationRepository" />
3639
<argument type="service" id="Gally\SyliusPlugin\Api\AuthenticationTokenProvider" />
@@ -42,6 +45,19 @@
4245
<tag name="controller.service_arguments" />
4346
</service>
4447

48+
<service id="Gally\SyliusPlugin\Controller\Filter">
49+
<argument type="service" id="Gally\SyliusPlugin\Search\Adapter" />
50+
<argument type="service" id="sylius.context.channel" />
51+
<argument type="service" id="sylius.context.locale" />
52+
<argument type="service" id="sylius.repository.taxon" />
53+
<argument type="service" id="form.factory" />
54+
<argument type="service" id="Gally\SyliusPlugin\Service\FilterConverter" />
55+
<call method="setContainer">
56+
<argument type="service" id="service_container" />
57+
</call>
58+
<tag name="controller.service_arguments" />
59+
</service>
60+
4561
<service id="Gally\SyliusPlugin\Form\Extension\ChannelTypeExtension">
4662
<tag name="form.type_extension"/>
4763
</service>
@@ -64,11 +80,20 @@
6480
</service>
6581

6682
<service id="Gally\SyliusPlugin\Grid\Filter\GallyDynamicFilter">
83+
<argument type="service" id="Gally\SyliusPlugin\Service\FilterConverter" />
6784
<tag name="sylius.grid_filter" type="gally_dynamic_filter" form_type="Gally\SyliusPlugin\Form\Type\Filter\GallyDynamicFilterType" />
6885
</service>
6986

7087
<service id="Gally\SyliusPlugin\Form\Type\Filter\GallyDynamicFilterType" autoconfigure="true">
88+
<argument type="service" id="router" />
89+
<argument type="service" id="request_stack" />
90+
<argument type="service" id="sylius.repository.taxon" />
91+
<argument type="service" id="sylius.context.locale" />
7192
<tag name="kernel.event_listener" event="gally.grid.configure_filter" method="onFilterUpdate" />
7293
</service>
94+
95+
<service id="sylius.form.type.grid_filter.select" class="Sylius\Bundle\GridBundle\Form\Type\Filter\SelectFilterType">
96+
<tag name="form.type" />
97+
</service>
7398
</services>
7499
</container>

src/Resources/config/shop_routing.yml

+7-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1-
# Define your own shop routes here
1+
#sylius_shop_partial_cart_add_item_ajax:
2+
gally_filter_view_more_ajax:
3+
path: /viewMore/{filterField}
4+
methods: [ GET ]
5+
defaults:
6+
_controller: Gally\SyliusPlugin\Controller\Filter::viewMore
7+
_format: json

src/Resources/public/view-more.css

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#searchbar .field .view-more {
2+
color: rgba(0, 0, 0, 0.87);
3+
cursor: pointer;
4+
}

src/Resources/public/view-more.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
$(document).ready(function() {
2+
$(document).on(
3+
'click',
4+
'#searchbarTextField .view-more',
5+
function (event) {
6+
event. preventDefault();
7+
8+
let linkEl = $(event.target),
9+
form = linkEl.closest('form'),
10+
choicesEl = $('#' + linkEl.data('for') + ' > .fields');
11+
12+
form.addClass('loading');
13+
14+
$.get(
15+
linkEl.data('href'),
16+
function( data ) {
17+
choicesEl.replaceWith($(data.html).find('.fields'));
18+
linkEl.hide();
19+
}
20+
).always(function() {
21+
form.removeClass('loading');
22+
});
23+
}
24+
);
25+
});

src/Resources/translations/messages.en.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ gally_sylius:
1313
header: Gally configuration
1414
filters:
1515
headline: Filters
16+
view_more: View more
1617
form:
1718
active: Enable Gally
1819
product_index_batch_size: Product Indexing Batch Size

src/Resources/views/Form/_checkbox.html.twig

+3
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@
33
{{- form_label(form) -}}
44
{% set attr = attr|merge({'class': attr.class|default ~ ' ui'}) %}
55
{{- form_widget(form, {'attr': attr}) -}}
6+
{% if has_more_url %}
7+
<a class="view-more" data-for="{{ form.vars.id }}" data-href="{{ has_more_url }}">{{ 'gally_sylius.ui.filters.view_more'|trans }}</a>
8+
{% endif %}
69
</div>
710
{%- endblock sylius_gally_filter_checkbox_row %}

src/Resources/views/Product/Index/_filters.html.twig

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
<div class="four wide column">
44
<div class="ui segment">
55
<form method="get" action="{{ path('sylius_shop_product_index', {'slug': app.request.attributes.get('slug')}) }}" class="ui loadable form">
6+
{# Keep the current search in the query on filtering #}
7+
{% if products.parameters.get('criteria').search is defined %}
8+
<input type="hidden" name="criteria[search][value]" value="{{ products.parameters.get('criteria').search.value }}" />
9+
{% endif %}
610
<div class="ui stackable grid" id="searchbar">
711
<div class="column" id="searchbarTextField">
812
{% for filter in products.definition.enabledFilters %}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
{% include '@SyliusUi/_javascripts.html.twig' with {'path': 'bundles/gallysyliusplugin/nouislider.min.js'} %}
22
{% include '@SyliusUi/_javascripts.html.twig' with {'path': 'bundles/gallysyliusplugin/range-slider.js'} %}
3+
{% include '@SyliusUi/_javascripts.html.twig' with {'path': 'bundles/gallysyliusplugin/view-more.js'} %}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
{% include '@SyliusUi/_stylesheets.html.twig' with {'path': 'bundles/gallysyliusplugin/nouislider.min.css'} %}
22
{% include '@SyliusUi/_stylesheets.html.twig' with {'path': 'bundles/gallysyliusplugin/slider.css'} %}
3+
{% include '@SyliusUi/_stylesheets.html.twig' with {'path': 'bundles/gallysyliusplugin/view-more.css'} %}

0 commit comments

Comments
 (0)