3
0

Update search service

This commit is contained in:
brabli
2026-05-07 17:30:00 +01:00
parent df9b7f9bf1
commit 90e23eb13e
+65 -77
View File
@@ -5,107 +5,95 @@ declare(strict_types=1);
namespace Pcm\SearchBundle\Service; namespace Pcm\SearchBundle\Service;
use Pcm\SearchBundle\Entity\SearchIndex; use Pcm\SearchBundle\Entity\SearchIndex;
use Pcm\SearchBundle\Entity\Interface\SearchableInterface; use Pcm\SearchBundle\Interface\SearchableInterface;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
class SearchService final class SearchService
{ {
public function __construct(private EntityManagerInterface $em) {} public function __construct(private EntityManagerInterface $em)
/**
* Given an $entity that implements SearchableInterface, this method
* creates or updates a SearchIndex $entity
*
* @param SearchableInterface $entity
* @return void
*/
public function index(SearchableInterface $entity)
{ {
$searchIndex = $this->createSearchResult($entity); }
$this->em->persist($searchIndex); public function index(SearchableInterface $entity): void
{
$index = $this->createSearchResult($entity);
$this->em->persist($index);
$this->em->flush();
}
public function unIndex(SearchableInterface $entity): void
{
$entityId = $this->requireEntityId($entity);
$index = $this->findIndex($this->resolveClass($entity), $entityId);
if ($index === null) {
return;
}
$this->em->remove($index);
$this->em->flush(); $this->em->flush();
} }
/** /**
* Given an $entity that implements SearchableInterface, this method removes * Finds or creates the SearchIndex row for the given entity and populates
* the item from the search index * its title and search text from the entity. The returned row is unflushed.
*
* @param SearchableInterface $entity
* @return void
*/
public function unIndex(SearchableInterface $entity)
{
$class = $this->em->getClassMetadata($entity::class)->getName();
$search_result = $this
->em
->getRepository(SearchIndex::class)
->findOneBy(['entityClass' => $class, 'entityId' => $entity->getId()]);
if ($search_result) {
$this->em->remove($search_result);
$this->em->flush();
}
}
/**
* Given an entity that implements SearchableInterface, this method first checks
* if the relevant SearchIndex entity exists. If it doesn't, it's created. The
* title and index data are set based on the methods in the $entity
*
* @param SearchableInterface $entity
* @return SearchIndex
*/ */
public function createSearchResult(SearchableInterface $entity): SearchIndex public function createSearchResult(SearchableInterface $entity): SearchIndex
{ {
$values = []; $entityId = $this->requireEntityId($entity);
$class = $this->resolveClass($entity);
$index = $this->findIndex($class, $entityId) ?? new SearchIndex($class, $entityId);
foreach ($entity->getSearchValues() as $value) { $index->setTitle($entity->getSearchTitle());
$values[] = $value; $index->setSearchText(implode(' ', $entity->getSearchValues()));
}
$data = implode(' ', $values); return $index;
$class = $this->em->getClassMetadata($entity::class)->getName();
$searchResult = $this
->em
->getRepository(SearchIndex::class)
->findOneBy(
[
'entityClass' => $class,
'entityId' => $entity->getId()
]
);
if (!$searchResult) {
$searchResult = new SearchIndex();
$searchResult->setEntityClass($class);
$searchResult->setEntityId($entity->getId());
}
$searchResult->setTitle($entity->getSearchTitle());
$searchResult->setData($data);
return $searchResult;
} }
/** /**
* Finds all searchable Doctrine entities the implement SearchableInterface * @return class-string[]
* @return array
*/ */
public function getSearchableClasses(): array public function getSearchableClasses(): array
{ {
$metadata = $this->em->getMetadataFactory()->getAllMetadata(); $classes = [];
$searchables = [];
foreach ($metadata as $meta) { foreach ($this->em->getMetadataFactory()->getAllMetadata() as $meta) {
if ($meta->reflClass->implementsInterface(SearchableInterface::class)) { if ($meta->reflClass->implementsInterface(SearchableInterface::class)) {
$searchables[] = $meta->name; $classes[] = $meta->name;
} }
} }
return $searchables; return $classes;
}
private function findIndex(string $class, int $entityId): ?SearchIndex
{
return $this->em
->getRepository(SearchIndex::class)
->findOneBy(['entityClass' => $class, 'entityId' => $entityId]);
}
private function requireEntityId(SearchableInterface $entity): int
{
$entityId = $entity->getId();
if ($entityId === null) {
throw new \LogicException('Entity must be persisted before indexing.');
}
return $entityId;
}
/**
* @template T of object
*
* @param T $entity
*
* @return class-string<T>
*/
private function resolveClass(object $entity): string
{
return $this->em->getClassMetadata($entity::class)->getName();
} }
} }