Skip to content

Commit

Permalink
Merge pull request #45 from netgen/NGSTACK-249_content_name_sort_2
Browse files Browse the repository at this point in the history
NGSTACK-249: implement ContentName sort clause
  • Loading branch information
pspanja authored Oct 11, 2020
2 parents 90a3cfb + 520ea27 commit fed8cef
Show file tree
Hide file tree
Showing 9 changed files with 655 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Only a list of features is provided here, see
[documentation](https://netgen-ezplatform-search-extra.readthedocs.io)
for more details.

- [`ContentName`](https://github.com/netgen/ezplatform-search-extra/blob/master/lib/API/Values/Content/Query/SortClause/ContentName.php) sort that works on matched translation's Content name (`solr`, `legacy`)

- [`ContentId`](https://github.com/netgen/ezplatform-search-extra/blob/master/lib/API/Values/Content/Query/Criterion/ContentId.php) and [`LocationId`](https://github.com/netgen/ezplatform-search-extra/blob/master/lib/API/Values/Content/Query/Criterion/LocationId.php) criteria with support for range operators (`solr`, `legacy`)

Supported operators are: `EQ`, `IN`, `GT`, `GTE`, `LT`, `LTE`, `BETWEEN`.
Expand Down
19 changes: 19 additions & 0 deletions lib/API/Values/Content/Query/SortClause/ContentName.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Netgen\EzPlatformSearchExtra\API\Values\Content\Query\SortClause;

use eZ\Publish\API\Repository\Values\Content\Query;
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;

/**
* Sets sort direction on matched translation's Content name.
*/
final class ContentName extends SortClause
{
public function __construct(string $sortDirection = Query::SORT_ASC)
{
parent::__construct('translated_content_name', $sortDirection);
}
}
171 changes: 171 additions & 0 deletions lib/Core/Search/Legacy/Query/Common/SortClauseHandler/ContentName.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<?php

declare(strict_types=1);

namespace Netgen\EzPlatformSearchExtra\Core\Search\Legacy\Query\Common\SortClauseHandler;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Query\QueryBuilder;
use eZ\Publish\Core\Persistence\Legacy\Content\Gateway;
use eZ\Publish\Core\Search\Legacy\Content\Common\Gateway\SortClauseHandler;
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
use eZ\Publish\SPI\Persistence\Content\Language\Handler as LanguageHandler;
use Netgen\EzPlatformSearchExtra\API\Values\Content\Query\SortClause\ContentName as ContentNameSortClause;

class ContentName extends SortClauseHandler
{
protected $languageHandler;

public function __construct(Connection $connection, LanguageHandler $languageHandler)
{
parent::__construct($connection);

$this->languageHandler = $languageHandler;
}

public function accept(SortClause $sortClause): bool
{
return $sortClause instanceof ContentNameSortClause;
}

public function applySelect(QueryBuilder $query, SortClause $sortClause, int $number): array
{
$tableAlias = $this->getSortTableName($number);
$tableAlias = $this->connection->quoteIdentifier($tableAlias);
$columnAlias = $this->getSortColumnName($number);

$query->addSelect(sprintf('%s.name AS %s', $tableAlias, $columnAlias));

return [$columnAlias];
}

/**
* @param \Doctrine\DBAL\Query\QueryBuilder $query
* @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause $sortClause
* @param int $number
* @param array $languageSettings
*
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
*/
public function applyJoin(
QueryBuilder $query,
SortClause $sortClause,
int $number,
array $languageSettings
): void {
$tableAlias = $this->getSortTableName($number);
$tableAlias = $this->connection->quoteIdentifier($tableAlias);

$query->leftJoin(
'c',
Gateway::CONTENT_NAME_TABLE,
$tableAlias,
$query->expr()->and(
$query->expr()->eq('c.id', $tableAlias . '.contentobject_id'),
$query->expr()->eq('c.current_version', $tableAlias . '.content_version'),
$this->getLanguageCondition($query, $languageSettings, $tableAlias)
)
);
}

/**
* @param \Doctrine\DBAL\Query\QueryBuilder $query
* @param array $languageSettings
* @param string $contentNameTableName
*
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
*
* @return \Doctrine\DBAL\Query\Expression\CompositeExpression|string
*/
protected function getLanguageCondition(
QueryBuilder $query,
array $languageSettings,
string $contentNameTableName
) {
// 1. Use main language(s) by default
if (empty($languageSettings['languages'])) {
return $query->expr()->gt(
$this->dbPlatform->getBitAndComparisonExpression(
'c.initial_language_id',
$contentNameTableName . '.language_id'
),
$query->createNamedParameter(0, ParameterType::INTEGER)
);
}

// 2. Otherwise use prioritized languages
$leftSide = $this->dbPlatform->getBitAndComparisonExpression(
sprintf(
'c.language_mask - %s',
$this->dbPlatform->getBitAndComparisonExpression(
'c.language_mask',
$contentNameTableName . '.language_id'
)
),
$query->createNamedParameter(1, ParameterType::INTEGER)
);
$rightSide = $this->dbPlatform->getBitAndComparisonExpression(
$contentNameTableName . '.language_id',
$query->createNamedParameter(1, ParameterType::INTEGER)
);

for (
$index = count($languageSettings['languages']) - 1, $multiplier = 2;
$index >= 0;
$index--, $multiplier *= 2
) {
$languageCode = $languageSettings['languages'][$index];
$languageId = $this->languageHandler->loadByLanguageCode($languageCode)->id;

$addToLeftSide = $this->dbPlatform->getBitAndComparisonExpression(
sprintf(
'c.language_mask - %s',
$this->dbPlatform->getBitAndComparisonExpression(
'c.language_mask',
$contentNameTableName . '.language_id'
)
),
$query->createNamedParameter($languageId, ParameterType::INTEGER)
);
$addToRightSide = $this->dbPlatform->getBitAndComparisonExpression(
$contentNameTableName . '.language_id',
$query->createNamedParameter($languageId, ParameterType::INTEGER)
);

if ($multiplier > $languageId) {
$factor = $multiplier / $languageId;
/** @noinspection PhpStatementHasEmptyBodyInspection */
/** @noinspection MissingOrEmptyGroupStatementInspection */
/** @noinspection LoopWhichDoesNotLoopInspection */
for ($shift = 0; $factor > 1; $factor /= 2, $shift++) {}
$factorTerm = ' << ' . $shift;
$addToLeftSide .= $factorTerm;
$addToRightSide .= $factorTerm;
} elseif ($multiplier < $languageId) {
$factor = $languageId / $multiplier;
/** @noinspection PhpStatementHasEmptyBodyInspection */
/** @noinspection MissingOrEmptyGroupStatementInspection */
/** @noinspection LoopWhichDoesNotLoopInspection */
for ($shift = 0; $factor > 1; $factor /= 2, $shift++) {}
$factorTerm = ' >> ' . $shift;
$addToLeftSide .= $factorTerm;
$addToRightSide .= $factorTerm;
}

$leftSide = "$leftSide + ($addToLeftSide)";
$rightSide = "$rightSide + ($addToRightSide)";
}

return $query->expr()->and(
$query->expr()->gt(
$this->dbPlatform->getBitAndComparisonExpression(
'c.language_mask',
$contentNameTableName . '.language_id'
),
$query->createNamedParameter(0, ParameterType::INTEGER)
),
$query->expr()->lt($leftSide, $rightSide)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Netgen\EzPlatformSearchExtra\Core\Search\Solr\FieldMapper\ContentTranslation;

use eZ\Publish\SPI\Persistence\Content;
use eZ\Publish\SPI\Search\Field;
use eZ\Publish\SPI\Search\FieldType\StringField;
use EzSystems\EzPlatformSolrSearchEngine\FieldMapper\ContentTranslationFieldMapper;

class ContentNameFieldMapper extends ContentTranslationFieldMapper
{
public function accept(Content $content, $languageCode): bool
{
return true;
}

public function mapFields(Content $content, $languageCode): array
{
if (!isset($content->versionInfo->names[$languageCode])) {
return [];
}

return [
new Field(
'ng_content_name',
$content->versionInfo->names[$languageCode],
new StringField()
),
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Netgen\EzPlatformSearchExtra\Core\Search\Solr\Query\Common\SortClauseVisitor;

use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
use EzSystems\EzPlatformSolrSearchEngine\Query\SortClauseVisitor;
use Netgen\EzPlatformSearchExtra\API\Values\Content\Query\SortClause\ContentName as ContentNameClause;

class ContentName extends SortClauseVisitor
{
public function canVisit(SortClause $sortClause): bool
{
return $sortClause instanceof ContentNameClause;
}

public function visit(SortClause $sortClause): string
{
return 'ng_content_name_s' . $this->getDirection($sortClause);
}
}
9 changes: 9 additions & 0 deletions lib/Resources/config/search/legacy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,12 @@ services:
- '@ezpublish.persistence.connection'
tags:
- {name: ezpublish.search.legacy.gateway.criterion_handler.location}

netgen.search.legacy.query.common.sort_clause_handler.content_name:
class: Netgen\EzPlatformSearchExtra\Core\Search\Legacy\Query\Common\SortClauseHandler\ContentName
arguments:
- '@ezpublish.persistence.connection'
- '@ezpublish.spi.persistence.language_handler'
tags:
- {name: ezpublish.search.legacy.gateway.sort_clause_handler.content}
- {name: ezpublish.search.legacy.gateway.sort_clause_handler.location}
5 changes: 5 additions & 0 deletions lib/Resources/config/search/solr/field_mappers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ services:
tags:
- { name: ezpublish.search.solr.field_mapper.location }

netgen.search.solr.field_mapper.content_translation.content_name:
class: Netgen\EzPlatformSearchExtra\Core\Search\Solr\FieldMapper\ContentTranslation\ContentNameFieldMapper
tags:
- { name: ezpublish.search.solr.field_mapper.block_translation }

netgen.search.solr.field_mapper.content.content_and_location_id:
class: Netgen\EzPlatformSearchExtra\Core\Search\Solr\FieldMapper\Content\ContentAndLocationIdFieldMapper
arguments:
Expand Down
6 changes: 6 additions & 0 deletions lib/Resources/config/search/solr/sort_clause_visitors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@ services:
tags:
- {name: ezpublish.search.solr.query.content.sort_clause_visitor}
- {name: ezpublish.search.solr.query.location.sort_clause_visitor}

netgen.search.solr.query.common.sort_clause_visitor.content_name:
class: Netgen\EzPlatformSearchExtra\Core\Search\Solr\Query\Common\SortClauseVisitor\ContentName
tags:
- {name: ezpublish.search.solr.query.content.sort_clause_visitor}
- {name: ezpublish.search.solr.query.location.sort_clause_visitor}
Loading

0 comments on commit fed8cef

Please sign in to comment.