-
-
Save G-Rath/934fabe5ed91fefe61d6f3e656527cd5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* A object that provides a predicate for filtering based on | |
* comparing a given value against a search term in some way. | |
*/ | |
interface FieldFilterer | |
{ | |
/** | |
* Compares the given `$value` against the search `$term`. | |
* | |
* The actual comparison is an implementation detail. | |
* | |
* @param $value | |
* @param $term | |
* | |
* @return bool | |
*/ | |
static function shouldKeep($value, $term): bool; | |
} | |
/** | |
* Filterer that returns `true` if the `$value` contains the given `$term`. | |
*/ | |
class ContainsStringFilterer implements FieldFilterer | |
{ | |
/** | |
* @inheritDoc | |
* | |
* @param string $value | |
* @param string $term | |
* | |
* @return bool | |
*/ | |
static function shouldKeep($value, $term): bool | |
{ | |
return strpos($value, $term) !== FALSE; | |
} | |
} | |
/** | |
* Filterer that never returns `true`, meaning nothing is kept. | |
*/ | |
class NeverFilterer implements FieldFilterer | |
{ | |
static function shouldKeep($value, $term): bool | |
{ | |
return false; | |
} | |
} | |
/** | |
* Filterer that always returns `true`, meaning everything is kept. | |
*/ | |
class AlwaysFilterer implements FieldFilterer | |
{ | |
static function shouldKeep($value, $term): bool | |
{ | |
return true; | |
} | |
} | |
class FilterRules | |
{ | |
private $collections = [ | |
'events' => [ | |
'tags' => ContainsStringFilterer::class | |
] | |
]; | |
/** | |
* Gets all the fields that are configured with `FieldFilterer`s for the given `$collection` | |
* | |
* @param string $collection | |
* | |
* @return FieldFilterer[] | |
*/ | |
public function getFilterableFields(string $collection): array | |
{ | |
if (!isset($this->collections[$collection])) { | |
return []; | |
} | |
return $this->collections[$collection]; | |
} | |
/** | |
* Filters the `$entities` of the named `$collection` based on the provided `$terms`, | |
* using filterers configured for specific fields. | |
* | |
* @param string $collection the name of the collection. | |
* @param array &$entities the entities to filter. | |
* @param array $filters an array of terms associated with the field they should be compared to. | |
*/ | |
public function filterEntities(string $collection, array &$entities, array $filters): void | |
{ | |
// only use the filterers for fields that are in `$filters` | |
$filterers = array_filter( | |
$this->getFilterableFields($collection), | |
function (string $field) use ($filters) { | |
return isset($filters[$field]); | |
}, | |
ARRAY_FILTER_USE_KEY | |
); | |
foreach ($entities as $key => $entity) { | |
if (!$this->shouldKeepEntity($entity, $filterers, $filters)) { | |
unset($entities[$key]); | |
} | |
} | |
} | |
/** | |
* Checks if the given `entity` should be kept, based on the result of all the `$filterers`. | |
* | |
* @param $entity | |
* @param FieldFilterer[] $filterers an array of `FieldFilterer`s associated with the field they be compared to. | |
* @param array $filters an array of terms associated with the field they should be compared to. | |
* | |
* @return bool | |
*/ | |
private function shouldKeepEntity($entity, array $filterers, array $filters): bool | |
{ | |
foreach ($filterers as $field => $filterer) { | |
if (!isset($filters[$field])) { | |
// trigger_error maybe ...? | |
continue; | |
} // just in case | |
if (!$filterer::shouldKeep($entity[$field], $filters[$field])) { | |
return false; | |
} | |
} | |
return true; | |
} | |
} | |
$filterRules = new FilterRules(); | |
// remove the filter terms we want to filter against, otherwise cockpit won't include them in after for us | |
$app->on('collections.find.before', function (string $collection, array &$options) use ($filterRules) { | |
/* | |
array(1) { | |
["filter"]=> | |
array(2) { | |
["status"]=> | |
string(9) "Published" | |
["tags"]=> | |
string(12) "Storytelling" | |
} | |
} | |
*/ | |
if (!isset($options['filter'])) { | |
return; | |
} | |
foreach ($filterRules->getFilterableFields($collection) as $field => $filterer) { | |
unset($options['filter'][$field]); | |
} | |
}); | |
// filters the $entities further based on defined FilterRules | |
$app->on('collections.find.after', function (string $collection, array &$entities) use ($filterRules) { | |
/* | |
array(2) { | |
["token"]=> | |
string(30) "<private>" | |
["filter"]=> | |
array(2) { | |
["status"]=> | |
string(9) "Published" | |
["tags"]=> | |
string(12) "Storytelling" | |
} | |
} | |
*/ | |
if (!isset($_REQUEST['filter'])) { | |
return; | |
} | |
$filters = $_REQUEST['filter']; | |
$filterRules->filterEntities($collection, $entities, $filters); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment