From 28497db17644c04734b200a95d8f7e34ee222cfa 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 | 78 +++++++----------------- app/src/Lib/Traits/TableMetaTrait.php | 61 ++++++++++++++++++ app/src/Model/Table/CousTable.php | 5 -- app/src/Model/Table/TypesTable.php | 5 -- app/templates/element/filter.php | 7 ++- 5 files changed, 89 insertions(+), 67 deletions(-) diff --git a/app/src/Lib/Traits/SearchFilterTrait.php b/app/src/Lib/Traits/SearchFilterTrait.php index 6a13472f9..3fcac4f23 100644 --- a/app/src/Lib/Traits/SearchFilterTrait.php +++ b/app/src/Lib/Traits/SearchFilterTrait.php @@ -29,36 +29,12 @@ namespace App\Lib\Traits; +use Cake\Utility\Inflector; + 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 $attribute - return $attribute; - } - + /** * Obtain the set of permitted search attributes. * @@ -67,37 +43,28 @@ 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"), + // todo: Probably the following line is redundant but i am leaving it for now + 'label' => (__d('field', $column) ?? Inflector::humanize($column)), + 'caseSensitive' => false, + ]; + + // 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. * @@ -110,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..0f8b42329 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,63 @@ 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', + // '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/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; }