Skip to content

Commit

Permalink
feat: Always use SolrSearchResultItem to wrap a single object from se…
Browse files Browse the repository at this point in the history
…arch engine results.

BREAKING CHANGE: `getResultItems` method will always return `array<SolrSearchResultItem>` no matter item type or highlighting.
  • Loading branch information
ambroisemaupate committed Feb 13, 2024
1 parent 21fdc5c commit 00ebe1d
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public function getItemCount(): int
/**
* @inheritDoc
*/
public function getEntities()
public function getEntities(): array
{
if (null !== $this->searchResults) {
return $this->searchResults->getResultItems();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use RZ\Roadiz\CoreBundle\Preview\PreviewResolverInterface;
use RZ\Roadiz\CoreBundle\SearchEngine\NodeSourceSearchHandlerInterface;
use RZ\Roadiz\CoreBundle\SearchEngine\SearchResultsInterface;
use RZ\Roadiz\CoreBundle\SearchEngine\SolrSearchResultItem;
use RZ\Roadiz\CoreBundle\SearchEngine\SolrSearchResults;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Contracts\EventDispatcher\Event;
Expand Down Expand Up @@ -434,7 +435,7 @@ public function findOneBy(
*
* @param string $query Solr query string (for example: `text:Lorem Ipsum`)
* @param int $limit Result number to fetch (default: all)
* @return array
* @return array<SolrSearchResultItem<NodesSources>>
*/
public function findBySearchQuery(string $query, int $limit = 25): array
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,50 +54,55 @@ public function getNodeSourcesBySearchTerm(
): array {
$safeSearchTerms = strip_tags($searchTerm);

/*
* First try with Solr
/**
* First try with Solr.
*
* @var array<SolrSearchResultItem<NodesSources>> $nodesSources
*/
/** @var array $nodesSources */
$nodesSources = $this->getRepository()->findBySearchQuery(
$safeSearchTerms,
$resultCount
);

if (count($nodesSources) > 0) {
return array_map(function (SolrSearchResultItem $item) {
return $item->getItem();
}, $nodesSources);
}

/*
* Second try with sources fields
*/
if (count($nodesSources) === 0) {
$nodesSources = $this->getRepository()->searchBy(
$safeSearchTerms,
[],
[],
$resultCount
);
$nodesSources = $this->getRepository()->searchBy(
$safeSearchTerms,
[],
[],
$resultCount
);

if (count($nodesSources) === 0) {
/*
* Then try with node name.
*/
$qb = $this->getRepository()->createQueryBuilder('ns');
if (count($nodesSources) === 0) {
/*
* Then try with node name.
*/
$qb = $this->getRepository()->createQueryBuilder('ns');

$qb->select('ns, n')
->innerJoin('ns.node', 'n')
->andWhere($qb->expr()->orX(
$qb->expr()->like('n.nodeName', ':nodeName'),
$qb->expr()->like('ns.title', ':nodeName')
))
->setMaxResults($resultCount)
->setParameter('nodeName', '%' . $safeSearchTerms . '%');
$qb->select('ns, n')
->innerJoin('ns.node', 'n')
->andWhere($qb->expr()->orX(
$qb->expr()->like('n.nodeName', ':nodeName'),
$qb->expr()->like('ns.title', ':nodeName')
))
->setMaxResults($resultCount)
->setParameter('nodeName', '%' . $safeSearchTerms . '%');

if (null !== $translation) {
$qb->andWhere($qb->expr()->eq('ns.translation', ':translation'))
->setParameter('translation', $translation);
}
try {
return $qb->getQuery()->getResult();
} catch (NoResultException $e) {
return [];
}
if (null !== $translation) {
$qb->andWhere($qb->expr()->eq('ns.translation', ':translation'))
->setParameter('translation', $translation);
}
try {
return $qb->getQuery()->getResult();
} catch (NoResultException $e) {
return [];
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
interface SearchResultsInterface extends \Iterator
{
public function getResultCount(): int;
/**
* @return array<SolrSearchResultItem>
*/
public function getResultItems(): array;
public function map(callable $callable): array;
}
48 changes: 48 additions & 0 deletions lib/RoadizCoreBundle/src/SearchEngine/SolrSearchResultItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\CoreBundle\SearchEngine;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use Symfony\Component\Serializer\Attribute\Groups;

/**
* @template T of object
*/
#[ApiResource(
stateless: true,
)]
final class SolrSearchResultItem
{
/**
* @param T $item
* @param array<string, array<string>> $highlighting
*/
public function __construct(
protected readonly object $item,
protected readonly array $highlighting = []
) {
}

/**
* @return T
*/
#[ApiProperty]
#[Groups(['get'])]
public function getItem(): object
{
return $this->item;
}

/**
* @return array<string, array<string>>
*/
#[ApiProperty]
#[Groups(['get'])]
public function getHighlighting(): array
{
return $this->highlighting;
}
}
82 changes: 34 additions & 48 deletions lib/RoadizCoreBundle/src/SearchEngine/SolrSearchResults.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,49 +8,41 @@
use JMS\Serializer\Annotation as JMS;
use RZ\Roadiz\CoreBundle\Entity\DocumentTranslation;
use RZ\Roadiz\CoreBundle\Entity\NodesSources;
use RZ\Roadiz\Documents\Models\DocumentInterface;
use Symfony\Component\Serializer\Attribute\Ignore;

/**
* Wrapper over Solr search results and metas.
*
* @package RZ\Roadiz\CoreBundle\SearchEngine
*/
class SolrSearchResults implements SearchResultsInterface
{
/**
* @JMS\Exclude()
*/
protected array $response;
/**
* @JMS\Exclude()
*/
protected ObjectManager $entityManager;
/**
* @JMS\Exclude()
*/
#[JMS\Exclude]
#[Ignore]
protected int $position;

/**
* @JMS\Exclude()
* @var array<SolrSearchResultItem>|null
*/
#[JMS\Exclude]
#[Ignore]
protected ?array $resultItems;

/**
* @param array $response
* @param ObjectManager $entityManager
*/
public function __construct(array $response, ObjectManager $entityManager)
{
$this->response = $response;
$this->entityManager = $entityManager;
public function __construct(
#[JMS\Exclude]
#[Ignore]
protected readonly array $response,
#[JMS\Exclude]
#[Ignore]
protected readonly ObjectManager $entityManager
) {
$this->position = 0;
$this->resultItems = null;
}

/**
* @return int
* @JMS\Groups({"search_results"})
* @JMS\VirtualProperty()
*/
#[JMS\Groups(["search_results"])]
#[JMS\VirtualProperty()]
public function getResultCount(): int
{
if (
Expand All @@ -62,10 +54,10 @@ public function getResultCount(): int
}

/**
* @return array
* @JMS\Groups({"search_results"})
* @JMS\VirtualProperty()
* @return array<SolrSearchResultItem>
*/
#[JMS\Groups(["search_results"])]
#[JMS\VirtualProperty()]
public function getResultItems(): array
{
if (null === $this->resultItems) {
Expand All @@ -74,26 +66,16 @@ public function getResultItems(): array
isset($this->response['response']['docs'])
) {
$this->resultItems = array_filter(array_map(
function ($item) {
function (array $item) {
$object = $this->getHydratedItem($item);
if (isset($this->response["highlighting"])) {
$key = 'object';
if ($object instanceof NodesSources) {
$key = 'nodeSource';
}
if ($object instanceof DocumentInterface) {
$key = 'document';
}
if ($object instanceof DocumentTranslation) {
$key = 'document';
$object = $object->getDocument();
}
return [
$key => $object,
'highlighting' => $this->getHighlighting($item['id']),
];
if (!\is_object($object)) {
return null;
}
return $object;
$highlighting = $this->getHighlighting($item['id']);
return new SolrSearchResultItem(
$object,
$highlighting
);
},
$this->response['response']['docs']
));
Expand All @@ -105,7 +87,7 @@ function ($item) {

/**
* Get highlighting for one field.
* This do not merge highlighting for all fields anymore.
* This does not merge highlighting for all fields anymore.
*
* @param string $id
* @return array<string, array>
Expand Down Expand Up @@ -143,10 +125,14 @@ protected function getHydratedItem(array $item): mixed
$item[SolariumNodeSource::IDENTIFIER_KEY]
);
case SolariumDocumentTranslation::DOCUMENT_TYPE:
return $this->entityManager->find(
$documentTranslation = $this->entityManager->find(
DocumentTranslation::class,
$item[SolariumDocumentTranslation::IDENTIFIER_KEY]
);
if (null === $documentTranslation) {
return null;
}
return $documentTranslation->getDocument();
}
}

Expand Down

0 comments on commit 00ebe1d

Please sign in to comment.