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

Improve synonym functionality #15

Merged
merged 1 commit into from
Aug 22, 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
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"require": {
"php": ">=8.1",
"ext-json": "*",
"doctrine/collections": "^1.8 || ^2.0",
"doctrine/event-manager": "^1.2 || ^2.0",
"doctrine/orm": "^2.14 || ^3.0",
"doctrine/persistence": "^2.5 || ^3.0",
Expand All @@ -30,6 +31,7 @@
"sylius/core": "^1.0",
"sylius/core-bundle": "^1.0",
"sylius/currency": "^1.0",
"sylius/grid-bundle": "^1.11",
"sylius/locale": "^1.0",
"sylius/locale-bundle": "^1.0",
"sylius/product": "^1.0",
Expand All @@ -42,6 +44,7 @@
"symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0",
"symfony/form": "^5.4 || ^6.4 || ^7.0",
"symfony/http-foundation": "^5.4 || ^6.4 || ^7.0",
"symfony/http-kernel": "^5.4 || ^6.4 || ^7.0",
"symfony/messenger": "^5.4 || ^6.4 || ^7.0",
"symfony/options-resolver": "^5.4 || ^6.4 || ^7.0",
"symfony/routing": "^5.4 || ^6.4 || ^7.0",
Expand Down
65 changes: 61 additions & 4 deletions src/DependencyInjection/SetonoSyliusMeilisearchExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ public function prepend(ContainerBuilder $container): void
]);

$container->prependExtensionConfig('sylius_grid', [
'templates' => [
'filter' => [
'indexes' => '@SetonoSyliusMeilisearchPlugin/admin/grid/filter/indexes.html.twig',
],
],
'grids' => [
'setono_sylius_meilisearch_admin_synonym' => [
'driver' => [
Expand All @@ -108,23 +113,69 @@ public function prepend(ContainerBuilder $container): void
'type' => 'string',
'label' => 'setono_sylius_meilisearch.ui.synonym',
],
'enabled' => [
'type' => 'twig',
'label' => 'sylius.ui.enabled',
'options' => [
'template' => '@SyliusUi/Grid/Field/enabled.html.twig',
],
],
'indexes' => [
'type' => 'twig',
'label' => 'setono_sylius_meilisearch.ui.indexes',
'path' => '.',
'options' => [
'template' => '@SetonoSyliusMeilisearchPlugin/admin/grid/field/_indexes.html.twig',
],
],
'locale' => [
'type' => 'string',
'label' => 'sylius.ui.locale',
],
'channel' => [
'type' => 'string',
'label' => 'sylius.ui.channel',
'channels' => [
'type' => 'twig',
'label' => 'sylius.ui.channels',
'options' => [
'template' => '@SyliusAdmin/Grid/Field/_channels.html.twig',
],
],
],
'filters' => [
'search' => [
'type' => 'string',
'label' => 'sylius.ui.search',
'label' => 'setono_sylius_meilisearch.ui.search_term_and_synonym',
'options' => [
'fields' => ['term', 'synonym'],
],
],
'enabled' => [
'type' => 'boolean',
'label' => 'sylius.ui.enabled',
],
'indexes' => [
'type' => 'indexes',
'label' => 'setono_sylius_meilisearch.ui.indexes',
'form_options' => [
'placeholder' => 'sylius.ui.all',
],
],
'locale' => [
'type' => 'entity',
'label' => 'sylius.ui.locale',
'form_options' => [
'class' => '%sylius.model.locale.class%',
],
],
'channel' => [
'type' => 'entities',
'label' => 'sylius.ui.channel',
'form_options' => [
'class' => '%sylius.model.channel.class%',
],
'options' => [
'field' => 'channels.id',
],
],
],
'actions' => [
'main' => [
Expand All @@ -140,6 +191,12 @@ public function prepend(ContainerBuilder $container): void
'type' => 'delete',
],
],
// todo in the future it might be a good user experience if we had bulk actions for adding indexes and channels to synonyms
'bulk' => [
'delete' => [
'type' => 'delete',
],
],
],
],
],
Expand Down
25 changes: 24 additions & 1 deletion src/EventListener/Doctrine/SynonymListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
use Doctrine\Persistence\Event\LifecycleEventArgs;
use Setono\SyliusMeilisearchPlugin\Message\Command\UpdateSynonyms;
use Setono\SyliusMeilisearchPlugin\Model\SynonymInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Messenger\MessageBusInterface;

final class SynonymListener
final class SynonymListener implements EventSubscriberInterface
{
private bool $update = false;

public function __construct(private readonly MessageBusInterface $commandBus)
{
}
Expand All @@ -30,12 +34,31 @@ public function postRemove(LifecycleEventArgs $eventArgs): void
$this->handle($eventArgs);
}

/**
* This method can be called multiple times in the same request, therefore we set a flag to only dispatch the command once
*/
public function handle(LifecycleEventArgs $eventArgs): void
{
if (!$eventArgs->getObject() instanceof SynonymInterface) {
return;
}

$this->update = true;
}

public function dispatch(): void
{
if (!$this->update) {
return;
}

$this->commandBus->dispatch(new UpdateSynonyms());
}

public static function getSubscribedEvents(): array
{
return [
KernelEvents::RESPONSE => ['dispatch', 10],
loevgaard marked this conversation as resolved.
Show resolved Hide resolved
];
}
}
5 changes: 4 additions & 1 deletion src/Factory/SynonymFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ public function createInverseFromExisting(SynonymInterface $synonym): SynonymInt
$obj->setTerm($synonym->getSynonym());
$obj->setSynonym($synonym->getTerm());
$obj->setLocale($synonym->getLocale());
$obj->setChannel($synonym->getChannel());

foreach ($synonym->getChannels() as $channel) {
$obj->addChannel($channel);
}

return $obj;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Setono\SyliusMeilisearchPlugin\EventSubscriber;
namespace Setono\SyliusMeilisearchPlugin\Form\EventSubscriber;

use Doctrine\Persistence\ManagerRegistry;
use Setono\Doctrine\ORMTrait;
Expand Down
37 changes: 37 additions & 0 deletions src/Form/Type/IndexChoiceType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusMeilisearchPlugin\Form\Type;

use Setono\SyliusMeilisearchPlugin\Config\IndexRegistryInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;

final class IndexChoiceType extends AbstractType
{
public function __construct(private readonly IndexRegistryInterface $indexRegistry)
{
}

public function configureOptions(OptionsResolver $resolver): void
{
$names = $this->indexRegistry->getNames();

$resolver->setDefaults([
'choices' => array_combine($names, $names),
'choice_label' => static fn (string $name): string => ucfirst($name),
]);
}

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

public function getBlockPrefix(): string
{
return 'setono_sylius_meilisearch_index_choice';
}
}
17 changes: 15 additions & 2 deletions src/Form/Type/SynonymType.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Sylius\Bundle\LocaleBundle\Form\Type\LocaleChoiceType;
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
Expand Down Expand Up @@ -42,8 +43,20 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
->add('locale', LocaleChoiceType::class, [
'label' => 'sylius.ui.locale',
])
->add('channel', ChannelChoiceType::class, [
'label' => 'sylius.ui.channel',
->add('channels', ChannelChoiceType::class, [
'multiple' => true,
'expanded' => true,
'label' => 'sylius.ui.channels',
'required' => false,
])
->add('indexes', IndexChoiceType::class, [
'multiple' => true,
'expanded' => true,
'label' => 'setono_sylius_meilisearch.form.synonym.indexes',
'required' => false,
])
->add('enabled', CheckboxType::class, [
'label' => 'sylius.ui.enabled',
'required' => false,
])
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void {
Expand Down
20 changes: 20 additions & 0 deletions src/Grid/Filter/IndexFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusMeilisearchPlugin\Grid\Filter;

use Sylius\Component\Grid\Data\DataSourceInterface;
use Sylius\Component\Grid\Filtering\FilterInterface;

class IndexFilter implements FilterInterface
{
public function apply(DataSourceInterface $dataSource, string $name, $data, array $options): void
{
if (!is_string($data) || '' === $data) {
return;
}

$dataSource->restrict($dataSource->getExpressionBuilder()->like($name, '%"' . $data . '"%'));
}
}
7 changes: 1 addition & 6 deletions src/Meilisearch/SynonymResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,11 @@ public function __construct(private readonly SynonymRepositoryInterface $synonym

public function resolve(IndexScope $indexScope): array
{
// it doesn't make sense to resolve synonyms if the locale is not set
if (null === $indexScope->localeCode) {
return [];
}

/** @var list<array{term: non-empty-string, synonym: non-empty-string}> $synonyms */
$synonyms = array_map(static fn (SynonymInterface $synonym): array => [
'term' => (string) $synonym->getTerm(),
'synonym' => (string) $synonym->getSynonym(),
], $this->synonymRepository->findByLocaleAndChannel($indexScope->localeCode, $indexScope->channelCode));
], $this->synonymRepository->findEnabledByIndexScope($indexScope));

$resolvedSynonyms = [];
foreach ($synonyms as $synonym) {
Expand Down
66 changes: 61 additions & 5 deletions src/Model/Synonym.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@

namespace Setono\SyliusMeilisearchPlugin\Model;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Sylius\Component\Channel\Model\ChannelInterface;
use Sylius\Component\Locale\Model\LocaleInterface;
use Sylius\Component\Resource\Model\TimestampableTrait;
use Sylius\Component\Resource\Model\ToggleableTrait;
use function Symfony\Component\String\u;

class Synonym implements SynonymInterface
{
use TimestampableTrait;
use ToggleableTrait;

protected ?int $id = null;

protected ?string $term = null;
Expand All @@ -18,7 +25,16 @@ class Synonym implements SynonymInterface

protected ?LocaleInterface $locale = null;

protected ?ChannelInterface $channel = null;
/** @var Collection<array-key, ChannelInterface> */
protected Collection $channels;

/** @var list<string>|null */
protected ?array $indexes = null;

public function __construct()
{
$this->channels = new ArrayCollection();
}

public function getId(): ?int
{
Expand Down Expand Up @@ -55,13 +71,53 @@ public function setLocale(?LocaleInterface $locale): void
$this->locale = $locale;
}

public function getChannel(): ?ChannelInterface
public function getChannels(): Collection
{
return $this->channels;
}

public function addChannel(ChannelInterface $channel): void
{
if (!$this->hasChannel($channel)) {
$this->channels->add($channel);
}
}

public function removeChannel(ChannelInterface $channel): void
{
if ($this->hasChannel($channel)) {
$this->channels->removeElement($channel);
}
}

public function hasChannel(ChannelInterface $channel): bool
{
return $this->channels->contains($channel);
}

public function getIndexes(): array
{
return $this->indexes ?? [];
}

public function addIndex(string $index): void
{
$this->indexes[] = $index;
}

public function removeIndex(string $index): void
{
return $this->channel;
$indexes = $this->getIndexes();
$key = array_search($index, $indexes, true);
if ($key !== false) {
unset($indexes[$key]);
}

$this->indexes = [] === $indexes ? null : array_values($indexes);
}

public function setChannel(?ChannelInterface $channel): void
public function hasIndex(string $index): bool
{
$this->channel = $channel;
return in_array($index, $this->getIndexes(), true);
}
}
Loading
Loading