Skip to content

Commit

Permalink
Merge pull request #43 from netgen/NGSTACK-361_siblings_content_id_lo…
Browse files Browse the repository at this point in the history
…cation_id_2

NGSTACK-361: add ContentId and LocationId criteria with extended operator support
  • Loading branch information
pspanja authored Oct 7, 2020
2 parents bda8ae5 + d0c505b commit b512408
Show file tree
Hide file tree
Showing 23 changed files with 946 additions and 14 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Only a list of features is provided here, see
[documentation](https://netgen-ezplatform-search-extra.readthedocs.io)
for more details.

- `ContentId` and `LocationId` criteria with support for range operators (`solr`, `legacy`)

Supported operators are: `EQ`, `IN`, `GT`, `GTE`, `LT`, `LTE`, `BETWEEN`.

- [`Visible`](https://github.com/netgen/ezplatform-search-extra/blob/master/lib/API/Values/Content/Query/Criterion/Visible.php) criterion (`solr`, `legacy`),
usable in both Content and Location search. The criterion works on compound visiblity of Content and Location objects:
the Content is visible if it's marked as visible; the Location is visible if it's marked as visible, is not hidden by
Expand Down
35 changes: 35 additions & 0 deletions lib/API/Values/Content/Query/Criterion/ContentId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

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

use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\Operator;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\Operator\Specifications;

/**
* A criterion that matches Content based on its ID.
*/
class ContentId extends Criterion
{
/**
* @param string $operator One of the Operator constants
* @param int|int[] $value One or more Content IDs that must be matched
*/
public function __construct(string $operator, $value)
{
parent::__construct(null, $operator, $value);
}

public function getSpecifications(): array
{
return [
new Specifications(Operator::EQ, Specifications::FORMAT_SINGLE, Specifications::TYPE_INTEGER),
new Specifications(Operator::IN, Specifications::FORMAT_ARRAY, Specifications::TYPE_INTEGER),
new Specifications(Operator::GT, Specifications::FORMAT_SINGLE, Specifications::TYPE_INTEGER),
new Specifications(Operator::GTE, Specifications::FORMAT_SINGLE, Specifications::TYPE_INTEGER),
new Specifications(Operator::LT, Specifications::FORMAT_SINGLE, Specifications::TYPE_INTEGER),
new Specifications(Operator::LTE, Specifications::FORMAT_SINGLE, Specifications::TYPE_INTEGER),
new Specifications(Operator::BETWEEN, Specifications::FORMAT_ARRAY, Specifications::TYPE_INTEGER, 2),
];
}
}
35 changes: 35 additions & 0 deletions lib/API/Values/Content/Query/Criterion/LocationId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

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

use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\Operator;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\Operator\Specifications;

/**
* A criterion that matches Location based on its ID.
*/
class LocationId extends Criterion
{
/**
* @param string $operator One of the Operator constants
* @param int|int[] $value One or more Location IDs that must be matched
*/
public function __construct(string $operator, $value)
{
parent::__construct(null, $operator, $value);
}

public function getSpecifications(): array
{
return [
new Specifications(Operator::EQ, Specifications::FORMAT_SINGLE, Specifications::TYPE_INTEGER),
new Specifications(Operator::IN, Specifications::FORMAT_ARRAY, Specifications::TYPE_INTEGER),
new Specifications(Operator::GT, Specifications::FORMAT_SINGLE, Specifications::TYPE_INTEGER),
new Specifications(Operator::GTE, Specifications::FORMAT_SINGLE, Specifications::TYPE_INTEGER),
new Specifications(Operator::LT, Specifications::FORMAT_SINGLE, Specifications::TYPE_INTEGER),
new Specifications(Operator::LTE, Specifications::FORMAT_SINGLE, Specifications::TYPE_INTEGER),
new Specifications(Operator::BETWEEN, Specifications::FORMAT_ARRAY, Specifications::TYPE_INTEGER, 2),
];
}
}
63 changes: 63 additions & 0 deletions lib/Core/Search/Legacy/Query/Common/CriterionHandler/ContentId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

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

use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Query\QueryBuilder;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\Operator;
use eZ\Publish\Core\Search\Legacy\Content\Common\Gateway\CriteriaConverter;
use eZ\Publish\Core\Search\Legacy\Content\Common\Gateway\CriterionHandler;
use Netgen\EzPlatformSearchExtra\API\Values\Content\Query\Criterion\ContentId as ContentIdCriterion;
use RuntimeException;

/**
* @see \Netgen\EzPlatformSearchExtra\API\Values\Content\Query\Criterion\ContentId
*/
final class ContentId extends CriterionHandler
{
public function accept(Criterion $criterion): bool
{
return $criterion instanceof ContentIdCriterion;
}

public function handle(
CriteriaConverter $converter,
QueryBuilder $queryBuilder,
Criterion $criterion,
array $languageSettings
): string {
$column = 'c.id';

switch ($criterion->operator) {
case Operator::EQ:
case Operator::IN:
return $queryBuilder->expr()->in($column, $criterion->value);

case Operator::GT:
case Operator::GTE:
case Operator::LT:
case Operator::LTE:
$operatorFunction = $this->comparatorMap[$criterion->operator];

return $queryBuilder->expr()->$operatorFunction(
$column,
$queryBuilder->createNamedParameter(reset($criterion->value), ParameterType::INTEGER)
);

case Operator::BETWEEN:
return $this->dbPlatform->getBetweenExpression(
$column,
$queryBuilder->createNamedParameter($criterion->value[0], ParameterType::INTEGER),
$queryBuilder->createNamedParameter($criterion->value[1], ParameterType::INTEGER)
);

default:
throw new RuntimeException(
"Unknown operator '{$criterion->operator}' for ContentId criterion handler."
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

declare(strict_types=1);

namespace Netgen\EzPlatformSearchExtra\Core\Search\Legacy\Query\Content\CriterionHandler;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Query\QueryBuilder;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\Operator;
use eZ\Publish\Core\Search\Legacy\Content\Common\Gateway\CriteriaConverter;
use eZ\Publish\Core\Search\Legacy\Content\Common\Gateway\CriterionHandler;
use Netgen\EzPlatformSearchExtra\API\Values\Content\Query\Criterion\LocationId as LocationIdCriterion;
use RuntimeException;

/**
* @see \Netgen\EzPlatformSearchExtra\API\Values\Content\Query\Criterion\LocationId
*/
final class LocationId extends CriterionHandler
{
public function accept(Criterion $criterion)
{
return $criterion instanceof LocationIdCriterion;
}

public function handle(
CriteriaConverter $converter,
QueryBuilder $queryBuilder,
Criterion $criterion,
array $languageSettings
) {
$column = 'node_id';
$subSelect = $this->connection->createQueryBuilder();

switch ($criterion->operator) {
case Operator::EQ:
case Operator::IN:
$expression = $queryBuilder->expr()->in($column, $criterion->value);

break;

case Operator::GT:
case Operator::GTE:
case Operator::LT:
case Operator::LTE:
$operatorFunction = $this->comparatorMap[$criterion->operator];
$expression = $queryBuilder->expr()->$operatorFunction(
$column,
$queryBuilder->createNamedParameter(reset($criterion->value), ParameterType::INTEGER)
);

break;

case Operator::BETWEEN:
$expression = $this->dbPlatform->getBetweenExpression(
$column,
$queryBuilder->createNamedParameter($criterion->value[0], ParameterType::INTEGER),
$queryBuilder->createNamedParameter($criterion->value[1], ParameterType::INTEGER)
);

break;

default:
throw new RuntimeException(
"Unknown operator '{$criterion->operator}' for LocationId criterion handler."
);
}

$subSelect->select('contentobject_id')->from('ezcontentobject_tree')->where($expression);

return $queryBuilder->expr()->in('c.id', $subSelect->getSQL());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

namespace Netgen\EzPlatformSearchExtra\Core\Search\Legacy\Query\Location\CriterionHandler;

use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Query\QueryBuilder;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\Operator;
use eZ\Publish\Core\Search\Legacy\Content\Common\Gateway\CriteriaConverter;
use eZ\Publish\Core\Search\Legacy\Content\Common\Gateway\CriterionHandler;
use Netgen\EzPlatformSearchExtra\API\Values\Content\Query\Criterion\LocationId as LocationIdCriterion;
use RuntimeException;

/**
* @see \Netgen\EzPlatformSearchExtra\API\Values\Content\Query\Criterion\LocationId
*/
final class LocationId extends CriterionHandler
{
public function accept(Criterion $criterion): bool
{
return $criterion instanceof LocationIdCriterion;
}

public function handle(
CriteriaConverter $converter,
QueryBuilder $queryBuilder,
Criterion $criterion,
array $languageSettings
) {
$column = 't.node_id';

switch ($criterion->operator) {
case Operator::EQ:
case Operator::IN:
return $queryBuilder->expr()->in($column, $criterion->value);

case Operator::GT:
case Operator::GTE:
case Operator::LT:
case Operator::LTE:
$operatorFunction = $this->comparatorMap[$criterion->operator];

return $queryBuilder->expr()->$operatorFunction(
$column,
$queryBuilder->createNamedParameter(reset($criterion->value), ParameterType::INTEGER)
);

case Operator::BETWEEN:
return $this->dbPlatform->getBetweenExpression(
$column,
$queryBuilder->createNamedParameter($criterion->value[0], ParameterType::INTEGER),
$queryBuilder->createNamedParameter($criterion->value[1], ParameterType::INTEGER)
);

default:
throw new RuntimeException(
"Unknown operator '{$criterion->operator}' for LocationId criterion handler."
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

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

use eZ\Publish\SPI\Persistence\Content as SPIContent;
use eZ\Publish\SPI\Persistence\Content\Location\Handler as LocationHandler;
use eZ\Publish\SPI\Search\Field;
use eZ\Publish\SPI\Search\FieldType\IntegerField;
use eZ\Publish\SPI\Search\FieldType\MultipleIntegerField;
use EzSystems\EzPlatformSolrSearchEngine\FieldMapper\ContentFieldMapper;

class ContentAndLocationIdFieldMapper extends ContentFieldMapper
{
/**
* @var \eZ\Publish\SPI\Persistence\Content\Location\Handler
*/
protected $locationHandler;

/**
* @param \eZ\Publish\SPI\Persistence\Content\Location\Handler $locationHandler
*/
public function __construct(LocationHandler $locationHandler)
{
$this->locationHandler = $locationHandler;
}

public function accept(SPIContent $content): bool
{
return true;
}

public function mapFields(SPIContent $content): array
{
$locations = $this->locationHandler->loadLocationsByContent($content->versionInfo->contentInfo->id);
$locationIds = [];

foreach ($locations as $location) {
$locationIds[] = $location->id;
}

return [
new Field(
'ng_content_id',
$content->versionInfo->contentInfo->id,
new IntegerField()
),
new Field(
'ng_location_id',
$locationIds,
new MultipleIntegerField()
),
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

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

use eZ\Publish\SPI\Persistence\Content\Location as SPILocation;
use eZ\Publish\SPI\Search\Field;
use eZ\Publish\SPI\Search\FieldType\IntegerField;
use EzSystems\EzPlatformSolrSearchEngine\FieldMapper\LocationFieldMapper;

class LocationIdFieldMapper extends LocationFieldMapper
{
public function accept(SPILocation $location): bool
{
return true;
}

public function mapFields(SPILocation $location): array
{
return [
new Field(
'ng_location_id',
$location->id,
new IntegerField()
),
];
}
}
Loading

0 comments on commit b512408

Please sign in to comment.