Skip to content

Commit

Permalink
Self-filtering option for individual filter
Browse files Browse the repository at this point in the history
  • Loading branch information
k-samuel committed Dec 1, 2023
1 parent 7b6d108 commit 9a36114
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 6 deletions.
11 changes: 11 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

### v3.2.1 (xx.11.2023)

Self-filtering option for individual filter (disabled by default). [Feature Request](https://github.com/k-samuel/faceted-search/issues/37)
Advanced configuration for AggregationQuery, if enabled, then result for filter can contain only filter values.
Useful for cases with ValueIntersectionFilter (AND condition).
```php
$filters[] = (new ValueIntersectionFilter('size', [12,32]))->selfFiltering(true);
```



### v3.2.0 (29.11.2023)

- ValueIntersectionFilter added [Feature Request](https://github.com/k-samuel/faceted-search/issues/33)
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "k-samuel/faceted-search",
"version": "3.2.0",
"version": "3.2.1",
"type": "library",
"description": "PHP Faceted search",
"keywords": ["php","faceted search"],
Expand Down
27 changes: 27 additions & 0 deletions src/Filter/AbstractFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ abstract class AbstractFilter implements FilterInterface
*/
protected $value;

/**
* Self filtering is disabled by default
* @var boolean
*/
protected bool $selfFiltering = false;

/**
* AbstractFilter constructor.
* @param string $fieldName
Expand Down Expand Up @@ -86,4 +92,25 @@ public function getValue()
* @inheritDoc
*/
abstract public function filterInput(array $facetedData, array &$inputIdKeys, array $excludeRecords): void;

/**
* Enable/Disable self-filtering for current filter, disabled by default.
* Used in AggregationQuery
* @param bool $enabled
* @return self
*/
public function selfFiltering(bool $enabled): self
{
$this->selfFiltering = $enabled;
return $this;
}

/**
* Get self-filtering flag
* @return boolean
*/
public function getSelfFiltering(): bool
{
return $this->selfFiltering;
}
}
7 changes: 7 additions & 0 deletions src/Filter/FilterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,11 @@ public function getFieldName(): string;
* @return void
*/
public function filterInput(array $facetedData, array &$inputIdKeys, array $excludeRecords): void;

/**
* Get self-filtering flag
*
* @return bool
*/
public function getSelfFiltering(): bool;
}
21 changes: 17 additions & 4 deletions src/Index/Index.php
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,22 @@ private function aggregationScan(
): array {
$result = [];
$cacheCount = count($resultCache);

$indexedFilters = [];
foreach ($filters as $filter) {
$indexedFilters[$filter->getFieldName()] = $filter;
}

/**
* @var array<int|string,array<int>> $filterValues
*/
foreach ($this->scanner->scan($this->storage) as $filterName => $filterValues) {

$needSelfFiltering = false;
if ($selfFiltering != false || (isset($indexedFilters[$filterName]) && $indexedFilters[$filterName]->getSelfFiltering())) {
$needSelfFiltering = true;
}

/**
* @var string $filterName
*/
Expand All @@ -247,15 +259,16 @@ private function aggregationScan(
if ($cacheCount > 1) {
// optimization with cache of findRecordsMap
// do not apply self filtering
if ($selfFiltering == false) {
$skipKey = $filterName;
} else {
if ($needSelfFiltering) {
$skipKey = null;
} else {
$skipKey = $filterName;
}

$recordIds = $this->mergeFilters($resultCache, $skipKey);
} else {
// Selecting a self-filtering scenario
if ($selfFiltering) {
if ($needSelfFiltering) {
$recordIds = $this->scanner->findRecordsMap($this->storage, $filters, $input, $exclude);
} else {
$recordIds = $this->scanner->findRecordsMap($this->storage, [], $input, $exclude);
Expand Down
4 changes: 4 additions & 0 deletions src/Query/AggregationQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ public function selfFiltering(bool $enabled): self
return $this;
}

/**
* Get self-filtering flag
* @return boolean
*/
public function getSelfFiltering(): bool
{
return $this->selfFiltering;
Expand Down
36 changes: 35 additions & 1 deletion tests/unit/Filter/ValueIntersectionFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ public function testAggregate(): void
new ValueIntersectionFilter('first_usage', ['wildlife', 'weddings', 'portraits']),
])->countItems()->sort()->selfFiltering(true);


$index = $this->getIndex(Factory::ARRAY_STORAGE);
$result = $index->aggregate($query1);
$this->assertEquals([
Expand Down Expand Up @@ -221,4 +220,39 @@ public function testAggregate(): void
$result = $index->aggregate($query4);
$this->assertEquals([], $result);
}

public function testSelfFiltering(): void
{
$query1 = (new AggregationQuery())->filters([
new ValueIntersectionFilter('first_usage', ['streetphoto', 'portraits', 'weddings']),
])->countItems()->sort()->selfFiltering(true);

$query2 = (new AggregationQuery())->filters([
(new ValueIntersectionFilter('first_usage', ['streetphoto', 'portraits', 'weddings']))->selfFiltering(true)
])->countItems()->sort();


$index = $this->getIndex(Factory::ARRAY_STORAGE);
$result = $index->aggregate($query1);
$result2 = $index->aggregate($query2);

$expected = [
'brand' => [
'Digma' => 1,
],
'first_usage' => [
'portraits' => 1,
'streetphoto' => 1,
'weddings' => 1,

],
'second_usage' => [
'streetphoto' => 1,
'portraits' => 1,
],
];

$this->assertEquals($expected, $result);
$this->assertEquals($expected, $result2);
}
}

0 comments on commit 9a36114

Please sign in to comment.