Skip to content
Merged
3 changes: 3 additions & 0 deletions config/services/search/search-services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ services:
Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchResultItem\LazyLoading\AssetLazyLoadingHandlerInterface:
class: Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchResultItem\LazyLoading\AssetLazyLoadingHandler

Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchService\RequiredByElementListServiceInterface:
class: Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchService\RequiredByElementListService

Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchResultItem\LazyLoading\DataObjectLazyLoadingHandlerInterface:
class: Pimcore\Bundle\GenericDataIndexBundle\Service\Search\SearchResultItem\LazyLoading\DataObjectLazyLoadingHandler

Expand Down
42 changes: 42 additions & 0 deletions src/Model/SearchIndex/HitData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);

/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/

namespace Pimcore\Bundle\GenericDataIndexBundle\Model\SearchIndex;

final readonly class HitData
{
public function __construct(
private string $id,
private string $elementType,
private string $index
) {
}

public function getId(): string
{
return $this->id;
}

public function getElementType(): string
{
return $this->elementType;
}

public function getIndex(): string
{
return $this->index;
}
}
49 changes: 45 additions & 4 deletions src/Repository/IndexQueueRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
namespace Pimcore\Bundle\GenericDataIndexBundle\Repository;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\Query\QueryBuilder as DBALQueryBuilder;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\NoResultException;
use Doctrine\ORM\QueryBuilder;
use Exception;
use Pimcore\Bundle\GenericDataIndexBundle\Entity\IndexQueue;
use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\IndexQueueOperation;
use Pimcore\Bundle\GenericDataIndexBundle\Model\SearchIndex\HitData;
use Pimcore\Bundle\GenericDataIndexBundle\Service\TimeServiceInterface;
use Pimcore\Bundle\GenericDataIndexBundle\Traits\LoggerAwareTrait;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
Expand Down Expand Up @@ -105,7 +108,7 @@ public function getUnhandledIndexQueueEntries(
/**
* @param IndexQueue[] $entries
*
* @throws \Doctrine\DBAL\Exception
* @throws DBALException
*/
public function deleteQueueEntries(array $entries): void
{
Expand Down Expand Up @@ -166,12 +169,12 @@ public function generateSelectQuery(
}

/**
* @throws \Doctrine\DBAL\Exception
* @throws DBALException
*/
public function enqueueBySelectQuery(DBALQueryBuilder $queryBuilder): void
{
$sql = <<<SQL
INSERT INTO
INSERT INTO
%s (elementId, elementType, elementIndexName, operation, operationTime, dispatched)
%s
ON DUPLICATE KEY
Expand All @@ -186,7 +189,45 @@ public function enqueueBySelectQuery(DBALQueryBuilder $queryBuilder): void
}

/**
* @throws \Doctrine\DBAL\Exception
* @throws DBALException
*
* @param HitData[] $enqueueItemList
*/
public function enqueueByItemList(array $enqueueItemList, IndexQueueOperation $operation, int $operationTime): void
{
if (empty($enqueueItemList)) {
return;
}

$sql = <<<SQL
INSERT INTO
%s (elementId, elementType, elementIndexName, operation, operationTime, dispatched)
VALUES %s
ON DUPLICATE KEY
UPDATE
operation = VALUES(operation),
operationTime = VALUES(operationTime),
dispatched = VALUES(dispatched)
SQL;

$values = [];
foreach ($enqueueItemList as $item) {
$values[] = sprintf(
'(%s, %s, %s, %s, %s, 0)',
$this->connection->quote($item->getId()),
$this->connection->quote($item->getElementType()),
$this->connection->quote($item->getIndex()),
$this->connection->quote($operation->value),
$operationTime
);
}
$this->connection->executeQuery(
sprintf($sql, IndexQueue::TABLE, implode(',', $values))
);
}

/**
* @throws DBALException
*/
public function dispatchItems(
int $limit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,4 @@ protected function throwInvalidFilterValueArgumentException(mixed $value, AssetM
)
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,4 @@ public function getInheritedData(

return $this->getInheritedData($parent, $objectId, $value, $key, $language, $callback);
}
}
}
7 changes: 4 additions & 3 deletions src/SearchIndexAdapter/DefaultSearch/DefaultSearchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Pimcore\Bundle\GenericDataIndexBundle\Exception\DefaultSearch\SearchFailedException;
use Pimcore\Bundle\GenericDataIndexBundle\Exception\SwitchIndexAliasException;
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Debug\SearchInformation;
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\DefaultSearchInterface;
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Search;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Interfaces\AdapterSearchInterface;
use Pimcore\Bundle\GenericDataIndexBundle\Model\SearchIndexAdapter\SearchResult;
Expand All @@ -37,9 +38,9 @@
*/
final class DefaultSearchService implements SearchIndexServiceInterface
{
private const INDEX_VERSION_ODD = 'odd';
public const INDEX_VERSION_ODD = 'odd';

private const INDEX_VERSION_EVEN = 'even';
public const INDEX_VERSION_EVEN = 'even';

use LoggerAwareTrait;

Expand Down Expand Up @@ -229,7 +230,7 @@ public function createPaginatedSearch(
int $page,
int $pageSize,
bool $aggregationsOnly = false
): AdapterSearchInterface {
): DefaultSearchInterface {
if ($aggregationsOnly) {
return new Search(
from: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@

namespace Pimcore\Bundle\GenericDataIndexBundle\SearchIndexAdapter\DefaultSearch\Search;

use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\FieldCategory;
use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\FieldCategory\SystemField;
use Pimcore\Bundle\GenericDataIndexBundle\Exception\InvalidArgumentException;
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\DefaultSearchInterface;
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Sort\FieldSort;
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\Sort\FieldSortList;
use Pimcore\Bundle\GenericDataIndexBundle\Model\SearchIndex\HitData;
use Pimcore\Bundle\GenericDataIndexBundle\Model\SearchIndexAdapter\SearchResultHit;
use Pimcore\Bundle\GenericDataIndexBundle\SearchIndexAdapter\SearchIndexServiceInterface;
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\SearchIndexConfigServiceInterface;

Expand Down Expand Up @@ -49,6 +52,26 @@ public function fetchAllIds(DefaultSearchInterface $search, string $indexName, b
return $this->doFetchIds($search, $indexName);
}

/**
* @return HitData[]
*/
public function fetchAllTypesAndIds(
DefaultSearchInterface $search,
string $indexName,
bool $sortById = true
): array {
$search = clone $search;
if ($sortById) {
$search->setSortList(new FieldSortList([new FieldSort(SystemField::ID->getPath())]));
}

if ($search->getSortList()->isEmpty()) {
throw new InvalidArgumentException('Search must have a sort defined to be able to fetch all ids');
}

return $this->doFetchIdsAndTypes($search, $indexName);
}

private function doFetchIds(DefaultSearchInterface $search, string $indexName, ?array $searchAfter = null): array
{
$search->setFrom(0);
Expand All @@ -66,6 +89,34 @@ private function doFetchIds(DefaultSearchInterface $search, string $indexName, ?
return $ids;
}

private function doFetchIdsAndTypes(
DefaultSearchInterface $search,
string $indexName,
?array $searchAfter = null
): array {
$search->setFrom(0);
$search->setSize($this->getPageSize());
$search->setSource([SystemField::ELEMENT_TYPE->getPath()]);
$search->setSearchAfter($searchAfter);
$searchResult = $this->searchIndexService->search($search, $indexName);
$hits = $searchResult->getHits();
$idsAndTypes = array_map(
static fn (SearchResultHit $item) =>
new HitData(
id: $item->getId(),
elementType: $item->getSource()[FieldCategory::SYSTEM_FIELDS->value][SystemField::ELEMENT_TYPE->value],
index: $item->getIndex(),
),
$hits
);
$lastHit = $searchResult->getLastHit();
if ($lastHit && (count($hits) === $this->getPageSize())) {
return array_merge($idsAndTypes, $this->doFetchIdsAndTypes($search, $indexName, $lastHit->getSort()));
}

return $idsAndTypes;
}

private function getPageSize(): int
{
$maxResultWindow = $this->searchIndexConfigService->getIndexSettings()['max_result_window'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,18 @@
namespace Pimcore\Bundle\GenericDataIndexBundle\SearchIndexAdapter\DefaultSearch\Search;

use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\DefaultSearchInterface;
use Pimcore\Bundle\GenericDataIndexBundle\Model\SearchIndex\HitData;

interface FetchIdsBySearchServiceInterface
{
public function fetchAllIds(DefaultSearchInterface $search, string $indexName, bool $sortById = true): array;

/**
* @return HitData[]
*/
public function fetchAllTypesAndIds(
DefaultSearchInterface $search,
string $indexName,
bool $sortById = true
): array;
}
3 changes: 2 additions & 1 deletion src/SearchIndexAdapter/SearchIndexServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
namespace Pimcore\Bundle\GenericDataIndexBundle\SearchIndexAdapter;

use Exception;
use Pimcore\Bundle\GenericDataIndexBundle\Model\DefaultSearch\DefaultSearchInterface;
use Pimcore\Bundle\GenericDataIndexBundle\Model\Search\Interfaces\AdapterSearchInterface;
use Pimcore\Bundle\GenericDataIndexBundle\Model\SearchIndexAdapter\SearchResult;

Expand Down Expand Up @@ -56,7 +57,7 @@ public function createPaginatedSearch(
int $page,
int $pageSize,
bool $aggregationsOnly = false
): AdapterSearchInterface;
): DefaultSearchInterface;

public function search(AdapterSearchInterface $search, string $indexName): SearchResult;

Expand Down
15 changes: 15 additions & 0 deletions src/Service/ElementService.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\ElementType;
use Pimcore\Bundle\GenericDataIndexBundle\Exception\InvalidElementTypeException;
use Pimcore\Model\Asset;
use Pimcore\Model\DataObject;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Model\Document;
use Pimcore\Model\Element\ElementInterface;

/**
* @internal
Expand All @@ -47,6 +49,19 @@ public function getElementByType(int $id, string $type): Asset|AbstractObject|Do
};
}

/**
* @throws InvalidElementTypeException
*/
public function getElementType(ElementInterface $element): ElementType
{
return match (true) {
$element instanceof Asset => ElementType::ASSET,
$element instanceof Document => ElementType::DOCUMENT,
$element instanceof DataObject => ElementType::DATA_OBJECT,
default => throw new InvalidElementTypeException('Invalid element type: ' . $element->getType())
};
}

public function classDefinitionExists(string $name): bool
{
try {
Expand Down
7 changes: 7 additions & 0 deletions src/Service/ElementServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

namespace Pimcore\Bundle\GenericDataIndexBundle\Service;

use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\ElementType;
use Pimcore\Bundle\GenericDataIndexBundle\Exception\InvalidElementTypeException;
use Pimcore\Model\Asset;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Model\Document;
use Pimcore\Model\Element\ElementInterface;

/**
* @internal
Expand All @@ -33,5 +35,10 @@ interface ElementServiceInterface
*/
public function getElementByType(int $id, string $type): Asset|AbstractObject|Document|null;

/**
* @throws InvalidElementTypeException
*/
public function getElementType(ElementInterface $element): ElementType;

public function classDefinitionExists(string $name): bool;
}
10 changes: 5 additions & 5 deletions src/Service/Search/SearchService/Asset/AssetSearchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ public function search(
AssetSearchInterface $assetSearch,
PermissionTypes $permissionType = PermissionTypes::LIST
): AssetSearchResult {
$assetSearch = $this->searchHelper->addSearchRestrictions(
$search = $this->searchHelper->addSearchRestrictions(
search: $assetSearch,
userPermission: UserPermissionTypes::ASSETS->value,
workspaceType: AssetWorkspace::WORKSPACE_TYPE,
permissionType: $permissionType
);

$searchResult = $this->searchHelper->performSearch(
search: $assetSearch,
search: $search,
indexName: $this->assetTypeAdapter->getAliasIndexName()
);

Expand All @@ -75,12 +75,12 @@ public function search(
items: $this->searchHelper->hydrateSearchResultHits(
$searchResult,
$childrenCounts,
$assetSearch->getUser()
$search->getUser()
),
pagination: $this->paginationInfoService->getPaginationInfoFromSearchResult(
searchResult: $searchResult,
page: $assetSearch->getPage(),
pageSize: $assetSearch->getPageSize()
page: $search->getPage(),
pageSize: $search->getPageSize()
),
aggregations: $searchResult->getAggregations(),
);
Expand Down
Loading
Loading