From f4cb71285bc404d7f21497f436641e3c4afb47cc Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Sun, 1 May 2022 15:18:20 +0300 Subject: [PATCH] Initial commit dynamic construct of Index filtering --- app/src/Lib/Traits/SearchFilterTrait.php | 76 +++++++----------------- app/src/Lib/Traits/TableMetaTrait.php | 65 ++++++++++++++++++++ app/src/Model/Table/CousTable.php | 5 -- app/src/Model/Table/TypesTable.php | 5 -- app/templates/ApiUsers/columns.inc | 3 + app/templates/element/filter.php | 7 ++- 6 files changed, 94 insertions(+), 67 deletions(-) diff --git a/app/src/Lib/Traits/SearchFilterTrait.php b/app/src/Lib/Traits/SearchFilterTrait.php index dd05c5fe3..616a389e8 100644 --- a/app/src/Lib/Traits/SearchFilterTrait.php +++ b/app/src/Lib/Traits/SearchFilterTrait.php @@ -34,33 +34,6 @@ trait SearchFilterTrait { // Array (and configuration) of permitted search filters private $searchFilters = array(); - - /** - * Determine the UI label for the specified attribute. - * - * @since COmanage Registry v5.0.0 - * @param string $attribute Attribute - * @return string Label - * @todo Merge this with _column_key from index.ctp - */ - - public function getLabel(string $attribute): string { - if(isset($this->searchFilters[$attribute]['label']) - && $this->searchFilters[$attribute]['label'] !== null) { - return $this->searchFilters[$attribute]['label']; - } - - // Try to construct a label from the language key. - $l = __d('field', $attribute); - - if($l != $attribute) { - return $l; - } - - // If we make it here, just return a pretty version of the $attribute name - return Inflector::humanize($attribute); - } - /** * Obtain the set of permitted search attributes. * @@ -69,37 +42,29 @@ public function getLabel(string $attribute): string { */ public function getSearchableAttributes(): array { - // Not every configuration element is necessary for the search form, and - // some need to be calculated, so we do that work here. - - $ret = []; - - foreach(array_keys($this->searchFilters) as $attr) { - $ret[ $attr ] = [ - 'label' => $this->getLabel($attr) + foreach ($this->filterMetadataFields() as $column => $type) { + // If the column is an array then we are accessing the Metadata fields. Skip + if(is_array($type)) { + continue; + } + $this->searchFilters[$column] = [ + 'substring' => ($type === "string"), + 'datetime' => ($type === "timestamp"), + // todo: Probably the following line is redundant but i am leaving it for now + 'label' => (__d('field', $column) ?? Inflector::humanize($column)), + 'caseSensitive' => true, // hardcoding for now + ]; + + // Not every configuration element is necessary for the search form, and + // some need to be calculated, so we do that work here. + $ret[ $column ] = [ + 'label' => (__d('field', $column) ?? Inflector::humanize($column)) ]; } - - return $ret; - } - - /** - * Add a permitted search filters. - * - * @since COmanage Registry v5.0.0 - * @param string $attribute Attribute that filtering is permitted on (database name) - * @param bool $caseSensitive Whether this attribute is case sensitive - * @param string $label Label for this search field, or null to autocalculate - * @param bool $substring Whether substring searching is permitted for this attribute - */ - - public function setSearchFilter(string $attribute, - bool $caseSensitive=false, - string $label=null, - bool $substring=true): void { - $this->searchFilters[$attribute] = compact('caseSensitive', 'label', 'substring'); + + return $ret ?? []; } - + /** * Build a query where() clause for the configured attribute. * @@ -112,6 +77,7 @@ public function setSearchFilter(string $attribute, public function whereFilter(\Cake\ORM\Query $query, string $attribute, string $q): object { if(!empty($this->searchFilters[$attribute])) { + // todo: move caseSensitive into filter block itself $cs = (isset($this->searchFilters[$attribute]['caseSensitive']) && $this->searchFilters[$attribute]['caseSensitive']); diff --git a/app/src/Lib/Traits/TableMetaTrait.php b/app/src/Lib/Traits/TableMetaTrait.php index f43e3cfce..41e27b584 100644 --- a/app/src/Lib/Traits/TableMetaTrait.php +++ b/app/src/Lib/Traits/TableMetaTrait.php @@ -29,6 +29,8 @@ namespace App\Lib\Traits; +use Cake\Utility\Inflector; + trait TableMetaTrait { // Does this Table represent Registry objects or configuration? private $confTable = false; @@ -54,4 +56,67 @@ public function getIsConfigurationTable() { public function setIsConfigurationTable(bool $confTable) { $this->confTable = $confTable; } + + + /** + * Filter metadata fields. + * + * @since COmanage Registry v5.0.0 + * @return array An array of columns distinguished in metadata and non-metadata + */ + + protected function filterMetadataFields() { + // Get the list of columns + $coltype = $this->getSchema()->typeMap(); + $entity = $this->getEntityClass(); + $entity_namespace = explode('\\', $entity); + $modelName = end($entity_namespace); + + // Get the list of belongs_to associations and construct an exclude array + $assc_keys = []; + foreach ($this->associations() as $assc) { + if($assc->type() === "manyToOne") { + $assc_keys[] = Inflector::underscore(Inflector::classify($assc->getClassName())) . "_id"; + } + } + // Map the model (eg: Person) to the changelog key (person_id) + $mfk = Inflector::underscore($modelName) . "_id"; + + + $meta_fields = [ + ...$assc_keys, + $mfk, + 'actor_identifier', + // 'provisioning_target_id', + 'created', // todo: I might need to revisit this. We might want to filter according to date in some occassions. Like petitions + 'deleted', + 'id', + 'modified', + 'revision', + 'lft', // XXX For now i skip lft.rght column for tree structures + 'rght', + // 'parent_id', // todo: We need to filter using the parent_id. This should be an enumerator and should apply for all the models that use TreeBehavior + 'api_key' + // 'source_ad_hoc_attribute_id', + // 'source_address_id', + // 'source_email_address_id', + // 'source_identifier_id', + // 'source_name_id', + // 'source_external_identity_id', + // 'source_telephone_number_id', + ]; + + $newa = array(); + foreach($coltype as $clmn => $type) { + if(in_array($clmn, $meta_fields,true)) { + // Move the value to metadata + $newa['meta'][$clmn] = $type; + } else { + // Just copy the value + $newa[$clmn] = $type; + } + } + + return $newa ?? []; + } } diff --git a/app/src/Model/Table/CousTable.php b/app/src/Model/Table/CousTable.php index 082ad40d6..1a8122ecb 100644 --- a/app/src/Model/Table/CousTable.php +++ b/app/src/Model/Table/CousTable.php @@ -72,11 +72,6 @@ public function initialize(array $config): void { $this->setPrimaryLink('co_id'); $this->setRequiresCO(true); - - // Set up the fields that may be filtered in the index view - $this->setSearchFilter('name', false, null, true); - $this->setSearchFilter('parent_id', true, null, false); - $this->setSearchFilter('description', false, null, true); $this->setPermissions([ // Actions that operate over an entity (ie: require an $id) diff --git a/app/src/Model/Table/TypesTable.php b/app/src/Model/Table/TypesTable.php index 856662495..a43558dd5 100644 --- a/app/src/Model/Table/TypesTable.php +++ b/app/src/Model/Table/TypesTable.php @@ -113,11 +113,6 @@ public function initialize(array $config): void { 'class' => 'SuspendableStatusEnum' ] ]); - - // Set up the fields that may be filtered in the index view - $this->setSearchFilter('display_name', false, null, true); - $this->setSearchFilter('attribute', true, null, false); - $this->setSearchFilter('statuses', false, null, true); $this->setPermissions([ // Actions that operate over an entity (ie: require an $id) diff --git a/app/templates/ApiUsers/columns.inc b/app/templates/ApiUsers/columns.inc index 29d9aef96..c03b5a56c 100644 --- a/app/templates/ApiUsers/columns.inc +++ b/app/templates/ApiUsers/columns.inc @@ -32,6 +32,9 @@ if($vv_cur_co->id == 1) { ]; } +// Turn on the search/filter box for this index view +$enableFiltering = true; + $indexColumns = [ 'username' => [ 'type' => 'link', diff --git a/app/templates/element/filter.php b/app/templates/element/filter.php index 33c25a691..b919b0ee6 100644 --- a/app/templates/element/filter.php +++ b/app/templates/element/filter.php @@ -105,11 +105,14 @@ 'required' => false, ]; - if(isset($$key)) { + // The populated variables are in plural while the column names are singular + // Convention: It is a prerequisite that the vvar should be the plural of the column name + $populated_vvar = Cake\Utility\Inflector::pluralize($key); + if(isset($$populated_vvar)) { // If we have an AutoViewVar matching the name of this key, // convert to a select $formParams['type'] = 'select'; - $formParams['options'] = $$key; + $formParams['options'] = $$populated_vvar; // Allow empty so a filter doesn't require (eg) SOR $formParams['empty'] = true; }