Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat view more #14

Merged
merged 1 commit into from
Mar 11, 2024
Merged
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
82 changes: 82 additions & 0 deletions src/Controller/Filter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php
/**
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Gally to newer versions in the future.
*
* @package Gally
* @author Stephan Hochdörfer <[email protected]>, Gally Team <[email protected]>
* @copyright 2022-present Smile
* @license Open Software License v. 3.0 (OSL-3.0)
*/

declare(strict_types=1);

namespace Gally\SyliusPlugin\Controller;

use Gally\SyliusPlugin\Form\Type\Filter\GallyDynamicFilterType;
use Gally\SyliusPlugin\Grid\Filter\Type\SelectFilterType;
use Gally\SyliusPlugin\Search\Adapter;
use Gally\SyliusPlugin\Service\FilterConverter;
use Sylius\Bundle\TaxonomyBundle\Doctrine\ORM\TaxonRepository;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Locale\Context\LocaleContextInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

final class Filter extends AbstractController
{
public function __construct(
private Adapter $adapter,
private ChannelContextInterface $channelContext,
private LocaleContextInterface $localeContext,
private TaxonRepository $taxonRepository,
private FormFactoryInterface $formFactory,
private FilterConverter $filterConverter,
) {
}

public function viewMore(Request $request, string $filterField): Response
{
$search = $request->get('search');
$filters = $request->get('filters')['gally'] ?? [];
$gallyFilters = [];
foreach ($filters as $field => $value) {
$gallyFilter = $this->filterConverter->convert($field, $value);
if ($gallyFilter) {
$gallyFilters[] = $gallyFilter;
}
}

$choices = [];
$currentTaxonId = $request->get('taxon');
$aggregationOptions = $this->adapter->viewMoreOption(
$this->channelContext->getChannel(),
$currentTaxonId ? $this->taxonRepository->find($currentTaxonId) : null,
$this->localeContext->getLocaleCode(),
$filterField,
$gallyFilters,
$search,
);

foreach ($aggregationOptions as $option) {
$choices[$option['label']] = $option['value'];
}

$options = [
'block_prefix' => 'sylius_gally_filter_checkbox',
'choices' => $choices,
'expanded' => true,
'multiple' => true,
];

$form = $this->formFactory->createNamed('criteria')->add('gally', GallyDynamicFilterType::class);
$form->get('gally')->add($filterField, SelectFilterType::class, $options);
$form->get('gally')->get($filterField)->setData($filters[$filterField] ?? null);
$html = $this->renderView('@GallySyliusPlugin/Grid/Filter/gally_dynamic_filter.html.twig', ['form' => $form]);

return $this->json(['html' => $html]);
}
}
53 changes: 45 additions & 8 deletions src/Form/Type/Filter/GallyDynamicFilterType.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,29 @@
namespace Gally\SyliusPlugin\Form\Type\Filter;

use Gally\SyliusPlugin\Event\GridFilterUpdateEvent;
use Gally\SyliusPlugin\Grid\Filter\Type\SelectFilterType;
use Gally\SyliusPlugin\Search\Aggregation\Aggregation;
use Gally\SyliusPlugin\Search\Aggregation\AggregationOption;
use Sylius\Bundle\GridBundle\Form\Type\Filter\BooleanFilterType;
use Sylius\Bundle\GridBundle\Form\Type\Filter\SelectFilterType;
use Sylius\Bundle\TaxonomyBundle\Doctrine\ORM\TaxonRepository;
use Sylius\Component\Grid\Parameters;
use Sylius\Component\Locale\Context\LocaleContextInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\RangeType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class GallyDynamicFilterType extends AbstractType
{
public function __construct(
private UrlGeneratorInterface $router,
private RequestStack $requestStack,
private TaxonRepository $taxonRepository,
private LocaleContextInterface $localeContext,
) {
}

/**
* @var Aggregation[]
*/
Expand Down Expand Up @@ -78,16 +91,20 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
/** @var AggregationOption $option */
$choices[$option->getLabel()] = $option->getId();
}
$options = [
'block_prefix' => 'sylius_gally_filter_checkbox',
'label' => $aggregation->getLabel(),
'choices' => $choices,
'expanded' => true,
'multiple' => true,
];
if ($aggregation->hasMore()) {
$options['has_more_url'] = $this->buildHasMoreUrl($aggregation->getField());
}
$builder->add(
$aggregation->getField(),
SelectFilterType::class,
[
'block_prefix' => 'sylius_gally_filter_checkbox',
'label' => $aggregation->getLabel(),
'choices' => $choices,
'expanded' => true,
'multiple' => true,
]
$options
);
break;
default:
Expand All @@ -100,4 +117,24 @@ public function onFilterUpdate(GridFilterUpdateEvent $event): void
{
$this->aggregations = $event->getAggregations();
}

private function buildHasMoreUrl(string $field): string
{
$request = $this->requestStack->getCurrentRequest();
$parameters = new Parameters($request->query->all());
$criteria = $parameters->get('criteria', []);
$search = (isset($criteria['search'], $criteria['search']['value'])) ? $criteria['search']['value'] : '';
unset($criteria['search']);
$taxon = $this->taxonRepository->findOneBySlug($request->attributes->get('slug'), $this->localeContext->getLocaleCode());

return $this->router->generate(
'gally_filter_view_more_ajax',
[
'filterField' => $field,
'search' => $search,
'filters' => $criteria,
'taxon' => $taxon->getId(),
]
);
}
}
29 changes: 8 additions & 21 deletions src/Grid/Filter/GallyDynamicFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,22 @@

namespace Gally\SyliusPlugin\Grid\Filter;

use Gally\SyliusPlugin\Service\FilterConverter;
use Sylius\Component\Grid\Data\DataSourceInterface;
use Sylius\Component\Grid\Filtering\FilterInterface;

class GallyDynamicFilter implements FilterInterface
{
public function __construct(private FilterConverter $filterConverter)
{
}

public function apply(DataSourceInterface $dataSource, string $name, $data, array $options): void
{
foreach ($data as $field => $value) {
if ('' === $value) {
continue;
}

if (str_contains($field, '_slider')) {
$field = str_replace('_slider', '', $field);
$values = explode(';', $value, 2);
$dataSource->restrict($dataSource->getExpressionBuilder()->andX(
$dataSource->getExpressionBuilder()->greaterThanOrEqual($field, (int) $values[0]),
$dataSource->getExpressionBuilder()->lessThanOrEqual($field, (int) $values[1]),
));
} elseif (str_contains($field, '_boolean')) {
$field = str_replace('_boolean', '', $field);
$value = ('true' === $value);
$dataSource->restrict($dataSource->getExpressionBuilder()->equals($field, $value));
} else {
if (\is_array($value)) {
$dataSource->restrict($dataSource->getExpressionBuilder()->in($field, $value));
} else {
$dataSource->restrict($dataSource->getExpressionBuilder()->equals($field, $value));
}
$gallyFilter = $this->filterConverter->convert($field, $value);
if ($gallyFilter) {
$dataSource->restrict($gallyFilter);
}
}
}
Expand Down
40 changes: 40 additions & 0 deletions src/Grid/Filter/Type/SelectFilterType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php
/**
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Gally to newer versions in the future.
*
* @package Gally
* @author Stephan Hochdörfer <[email protected]>, Gally Team <[email protected]>
* @copyright 2022-present Smile
* @license Open Software License v. 3.0 (OSL-3.0)
*/

declare(strict_types=1);

namespace Gally\SyliusPlugin\Grid\Filter\Type;

use Sylius\Bundle\GridBundle\Form\Type\Filter\SelectFilterType as BaseSelectFilterType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;

final class SelectFilterType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefined(['has_more_url'])
->addAllowedTypes('has_more_url', 'string');
}

public function getParent(): string
{
return BaseSelectFilterType::class;
}

public function buildView(FormView $view, FormInterface $form, array $options): void
{
$view->vars['has_more_url'] = $options['has_more_url'] ?? null;
}
}
25 changes: 25 additions & 0 deletions src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
<argument type="service" id="Gally\SyliusPlugin\Synchronizer\LocalizedCatalogSynchronizer" />
</service>


<service id="Gally\SyliusPlugin\Service\FilterConverter" />

<service id="Gally\SyliusPlugin\Controller\AdminGallyController">
<argument type="service" id="Gally\SyliusPlugin\Repository\GallyConfigurationRepository" />
<argument type="service" id="Gally\SyliusPlugin\Api\AuthenticationTokenProvider" />
Expand All @@ -42,6 +45,19 @@
<tag name="controller.service_arguments" />
</service>

<service id="Gally\SyliusPlugin\Controller\Filter">
<argument type="service" id="Gally\SyliusPlugin\Search\Adapter" />
<argument type="service" id="sylius.context.channel" />
<argument type="service" id="sylius.context.locale" />
<argument type="service" id="sylius.repository.taxon" />
<argument type="service" id="form.factory" />
<argument type="service" id="Gally\SyliusPlugin\Service\FilterConverter" />
<call method="setContainer">
<argument type="service" id="service_container" />
</call>
<tag name="controller.service_arguments" />
</service>

<service id="Gally\SyliusPlugin\Form\Extension\ChannelTypeExtension">
<tag name="form.type_extension"/>
</service>
Expand All @@ -64,11 +80,20 @@
</service>

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

<service id="Gally\SyliusPlugin\Form\Type\Filter\GallyDynamicFilterType" autoconfigure="true">
<argument type="service" id="router" />
<argument type="service" id="request_stack" />
<argument type="service" id="sylius.repository.taxon" />
<argument type="service" id="sylius.context.locale" />
<tag name="kernel.event_listener" event="gally.grid.configure_filter" method="onFilterUpdate" />
</service>

<service id="sylius.form.type.grid_filter.select" class="Sylius\Bundle\GridBundle\Form\Type\Filter\SelectFilterType">
<tag name="form.type" />
</service>
</services>
</container>
8 changes: 7 additions & 1 deletion src/Resources/config/shop_routing.yml
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
# Define your own shop routes here
#sylius_shop_partial_cart_add_item_ajax:
gally_filter_view_more_ajax:
path: /viewMore/{filterField}
methods: [ GET ]
defaults:
_controller: Gally\SyliusPlugin\Controller\Filter::viewMore
_format: json
4 changes: 4 additions & 0 deletions src/Resources/public/view-more.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#searchbar .field .view-more {
color: rgba(0, 0, 0, 0.87);
cursor: pointer;
}
25 changes: 25 additions & 0 deletions src/Resources/public/view-more.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
$(document).ready(function() {
$(document).on(
'click',
'#searchbarTextField .view-more',
function (event) {
event. preventDefault();

let linkEl = $(event.target),
form = linkEl.closest('form'),
choicesEl = $('#' + linkEl.data('for') + ' > .fields');

form.addClass('loading');

$.get(
linkEl.data('href'),
function( data ) {
choicesEl.replaceWith($(data.html).find('.fields'));
linkEl.hide();
}
).always(function() {
form.removeClass('loading');
});
}
);
});
1 change: 1 addition & 0 deletions src/Resources/translations/messages.en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ gally_sylius:
header: Gally configuration
filters:
headline: Filters
view_more: View more
form:
active: Enable Gally
product_index_batch_size: Product Indexing Batch Size
Expand Down
3 changes: 3 additions & 0 deletions src/Resources/views/Form/_checkbox.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
{{- form_label(form) -}}
{% set attr = attr|merge({'class': attr.class|default ~ ' ui'}) %}
{{- form_widget(form, {'attr': attr}) -}}
{% if has_more_url %}
<a class="view-more" data-for="{{ form.vars.id }}" data-href="{{ has_more_url }}">{{ 'gally_sylius.ui.filters.view_more'|trans }}</a>
{% endif %}
</div>
{%- endblock sylius_gally_filter_checkbox_row %}
4 changes: 4 additions & 0 deletions src/Resources/views/Product/Index/_filters.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
<div class="four wide column">
<div class="ui segment">
<form method="get" action="{{ path('sylius_shop_product_index', {'slug': app.request.attributes.get('slug')}) }}" class="ui loadable form">
{# Keep the current search in the query on filtering #}
{% if products.parameters.get('criteria').search is defined %}
<input type="hidden" name="criteria[search][value]" value="{{ products.parameters.get('criteria').search.value }}" />
{% endif %}
<div class="ui stackable grid" id="searchbar">
<div class="column" id="searchbarTextField">
{% for filter in products.definition.enabledFilters %}
Expand Down
1 change: 1 addition & 0 deletions src/Resources/views/events_javascript.html.twig
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
{% include '@SyliusUi/_javascripts.html.twig' with {'path': 'bundles/gallysyliusplugin/nouislider.min.js'} %}
{% include '@SyliusUi/_javascripts.html.twig' with {'path': 'bundles/gallysyliusplugin/range-slider.js'} %}
{% include '@SyliusUi/_javascripts.html.twig' with {'path': 'bundles/gallysyliusplugin/view-more.js'} %}
1 change: 1 addition & 0 deletions src/Resources/views/events_stylesheets.html.twig
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
{% include '@SyliusUi/_stylesheets.html.twig' with {'path': 'bundles/gallysyliusplugin/nouislider.min.css'} %}
{% include '@SyliusUi/_stylesheets.html.twig' with {'path': 'bundles/gallysyliusplugin/slider.css'} %}
{% include '@SyliusUi/_stylesheets.html.twig' with {'path': 'bundles/gallysyliusplugin/view-more.css'} %}
Loading
Loading