Skip to content

CFM-291_Groups_Cous_extra_filtering_options #185

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/resources/locales/en_US/field.po
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ msgstr "Email"
msgid "ends_at"
msgstr "Ends at:"

msgid "ends_at.tz"
msgstr "Ends at ({0})"

msgid "extension"
msgstr "Extension"

Expand Down Expand Up @@ -243,6 +246,9 @@ msgstr "Sponsor"
msgid "starts_at"
msgstr "Starts at:"

msgid "starts_at.tz"
msgstr "Starts at ({0})"

msgid "state"
msgstr "State"

Expand Down
5 changes: 4 additions & 1 deletion app/resources/locales/en_US/information.po
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,7 @@ msgid "plugin.active.only"
msgstr "Active, Cannot Be Disabled"

msgid "plugin.inactive"
msgstr "Inactive"
msgstr "Inactive"

msgid "table.list"
msgstr "{0} List"
6 changes: 6 additions & 0 deletions app/resources/locales/en_US/operation.po
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ msgstr "Apply Database Schema"
msgid "assign"
msgstr "Assign"

msgid "any"
msgstr "Any"

msgid "cancel"
msgstr "Cancel"

Expand Down Expand Up @@ -144,6 +147,9 @@ msgstr "Logout"
msgid "next"
msgstr "Next"

msgid "none"
msgstr "None"

msgid "page.display"
msgstr "Display records"

Expand Down
6 changes: 4 additions & 2 deletions app/src/Lib/Traits/IndexQueryTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public function getIndexQuery(bool $pickerMode = false, array $requestParams = [
$link = $this->getPrimaryLink(true);
// Initialize the Query Object
$query = $table->find();
// Get a pointer to my expressions list
// Get a pointer to my expression list
$newexp = $query->newExpr();
// The searchable attributes can have an AND or an OR conjunction. The first one is used from the filtering block
// while the second one from the picker vue module.
Expand All @@ -159,6 +159,8 @@ public function getIndexQuery(bool $pickerMode = false, array $requestParams = [
$this->viewBuilder()
->getVar('vv_tz'));

// Pass any additional field filter confiration in the view
$this->set('vv_searchable_attributes_extras', $table->getSearchFiltersExtras());
if(!empty($searchableAttributes)) {
$this->set('vv_searchable_attributes', $searchableAttributes);

Expand Down Expand Up @@ -195,7 +197,7 @@ public function getIndexQuery(bool $pickerMode = false, array $requestParams = [
// Specific expressions per view
$query = match($requestParams['for'] ?? '') {
// GroupMembers Add view: We need to filter the active members
'GroupMembers' => $query->leftJoinWith('GroupMembers', fn($q) => $q->where(['GroupMembers.group_id' => (int)$requestParams['groupid'] ?? -1]))
'GroupMembers' => $query->leftJoinWith('GroupMembers', fn($q) => $q->where(['GroupMembers.group_id' => (int)($requestParams['groupid'] ?? -1)]))
->where($this->getTableLocator()->get('GroupMembers')->checkValidity($query))
->where(fn(QueryExpression $exp, Query $query) => $exp->isNull('GroupMembers.' . StringUtilities::classNameToForeignKey($table->getAlias()))),
// Just return the query
Expand Down
82 changes: 63 additions & 19 deletions app/src/Lib/Traits/SearchFilterTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

namespace App\Lib\Traits;

use App\Lib\Util\StringUtilities;
use Bake\Utility\Model\AssociationFilter;
use Cake\Database\Expression\QueryExpression;
use Cake\Http\ServerRequest;
Expand All @@ -37,9 +38,25 @@
use Cake\I18n\FrozenTime;

trait SearchFilterTrait {
// Array (and configuration) of permitted search filters
/**
* Array (and configuration) of permitted search filters
*
* @var array
*/
private array $searchFilters = [];
// Optional filter configuration that dictates display state and allows for related models

/**
* Extra Configurations for each filter
*
* @var array
*/
private array $searchFiltersExtras = [];

/**
* Optional filter configuration that dictates display state and allows for related models
*
* @var array
*/
private array $filterConfig = [];

/**
Expand Down Expand Up @@ -167,21 +184,30 @@ public function expressionsConstructor(Query $query, QueryExpression $exp, strin

$attributeWithModelPrefix = $modelPrefix . '.' . $attribute;


$search = $q;
// Use the `lower` function to apply uniformity for the search
$lower = $query->func()->lower([$attributeWithModelPrefix => 'identifier']);

// Handle special expression functions here
if(\in_array($search, ['isnull', 'isnotnull'])) {
return match($search) {
'isnull' => $exp->isNull($attributeWithModelPrefix),
'isnotnull' => $exp->isNotNull($attributeWithModelPrefix)
};
}


// XXX Strings and Enums are not treated the same. Enums require an exact match but strings
// are partially/non-case sensitive matched
// are partially/non-case sensitive matched
return match ($this->searchFilters[$attribute]['type']) {
'string' => $exp->like($lower, strtolower('%' . $search . '%')),
// Use the `lower` function to apply uniformity for the search
'string' => $exp->like($query->func()->lower([$attributeWithModelPrefix => 'identifier']),
strtolower('%' . $search . '%')),
'integer',
'boolean',
'parent' => $exp->add([$attributeWithModelPrefix => $search]),
'date' => $exp->add([$attributeWithModelPrefix => FrozenTime::parseDate($search, 'y-M-d')]),
'timestamp' => $this->constructDateComparisonClause($exp, $attributeWithModelPrefix, $search),
default => $exp->eq($lower, strtolower($search))
default => $exp->eq($query->func()->lower([$attributeWithModelPrefix => 'identifier']),
strtolower($search))
};
}

Expand Down Expand Up @@ -209,16 +235,24 @@ public function getSearchableAttributes(string $controller, string $vv_tz=null):
// Gather up related models defined in the $filterConfig
// XXX For now, we'll list these first - but we should probably provide a better way to order these.
foreach ($filterConfig as $field => $f) {
if($f['type'] == 'relatedModel') {
$fieldName = Inflector::classify(Inflector::underscore($field));
$this->searchFilters[$field] = [
'type' => 'string', // XXX for now - this needs to be looked up.
'label' => \App\Lib\Util\StringUtilities::columnKey($fieldName, $field, $vv_tz, true),
'active' => $f['active'] ?? true,
'model' => $f['model'],
'order' => $f['order']
];
$fieldName = Inflector::classify(Inflector::underscore($field));

if(isset($f['extras'])) {
$this->searchFiltersExtras[$field] = $f['extras'];
continue;
}

$filterType = $f['type'] ?? 'string';
if(\in_array($f['type'], ['isNull', 'isNotNull'])) {
$filterType = 'boolean';
}
$this->searchFilters[$field] = [
'type' => $filterType,
'label' => $f['label'] ?? StringUtilities::columnKey($fieldName, $field, $vv_tz, true),
'active' => $f['active'] ?? true,
'model' => $f['model'],
'order' => $f['order']
];
}

foreach ($this->filterMetadataFields() as $column => $type) {
Expand All @@ -239,7 +273,7 @@ public function getSearchableAttributes(string $controller, string $vv_tz=null):

$attribute = [
'type' => $type,
'label' => \App\Lib\Util\StringUtilities::columnKey($modelname, $column, $vv_tz, true),
'label' => StringUtilities::columnKey($modelname, $column, $vv_tz, true),
'active' => $fieldIsActive,
'order' => 99 // this is the default
];
Expand Down Expand Up @@ -270,7 +304,7 @@ public function getSearchableAttributes(string $controller, string $vv_tz=null):
}

/**
* Set explicilty defined filter configuration defined in the table class.
* Set explicit defined filter configuration defined in the table class.
*
* @since COmanage Registry v5.0.0
*/
Expand All @@ -279,4 +313,14 @@ public function setFilterConfig(array $filterConfig): void {
$this->filterConfig = $filterConfig;
}

/**
* Get field extra configurations calculated in getSearchableAttributes
*
* @since COmanage Registry v5.0.0
*/
public function getSearchFiltersExtras(): array
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trivially minor nit: we've not been following this curly brace convention (on its own line) anywhere else, so let's not start now. :-)

return $this->searchFiltersExtras;
}

}
2 changes: 1 addition & 1 deletion app/src/Lib/Util/FunctionUtilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class FunctionUtilities {
* // Chain of methods
* 'getRequest',
* 'getQuery' => [
* // parameter name => parameter value, We are taking advantage the named parameters feature
* // parameter name => parameter value, We are taking advantage of the named parameters feature
* 'name' =>'group_id'
* ],
* ]
Expand Down
23 changes: 23 additions & 0 deletions app/src/Model/Table/CousTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,29 @@ public function initialize(array $config): void {
'index' => ['platformAdmin', 'coAdmin']
]
]);

$this->setFilterConfig([
'identifier' => [
'type' => 'string',
'model' => 'Identifiers',
'active' => true,
'order' => 4
],
'parent_id' => [
// We want to keep the default column configuration and add extra functionality.
// Here the extra functionality is additional to select options since the parent_id
// is of type select
// XXX If the extras key is present, no other provided key will be evaluated. The rest
// of the configuration will be expected from the TableMetaTrait::filterMetadataFields()
'extras' => [
'options' => [
'isnotnull' => __d('operation','any'),
'isnull' => __d('operation','none'),
__d('information','table.list', 'COUs') => '@DATA@',
]
]
]
]);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions app/src/Model/Table/GroupMembersTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,13 @@ public function initialize(array $config): void {

$this->setFilterConfig([
'family' => [
'type' => 'relatedModel',
'type' => 'string',
'model' => 'People.Names',
'active' => true,
'order' => 2
],
'given' => [
'type' => 'relatedModel',
'type' => 'string',
'model' => 'People.Names',
'active' => true,
'order' => 1
Expand Down
38 changes: 20 additions & 18 deletions app/src/Model/Table/GroupNestingsTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,26 @@ public function initialize(array $config): void {
]
]);

$this->setAutoViewVars([
'groupMembers' => [
'type' => 'auxiliary',
'model' => 'GroupMembers',
'whereEval' => [
// Where Clause column name
'GroupMembers.group_id' => [
// Chain of methods that will construct the whereClause condition value
// Method that accepts no parameters
'getRequest',
// Method that accepts only one parameter
// getQuery(name: 'group_id')
'getQuery' => [
'name' =>'group_id'
]
]
]
]]);
// XXX Keeping for functionality reference
// $this->setAutoViewVars([
// 'groupMembers' => [
// 'type' => 'auxiliary',
// 'model' => 'GroupMembers',
// 'whereEval' => [
// // Where Clause column name
// 'GroupMembers.group_id' => [
// // Chain of methods that will construct the whereClause condition value
// // Method that accepts no parameters
// 'getRequest',
// // Method that accepts only one parameter
// // getQuery(name: 'group_id')
// 'getQuery' => [
// 'name' =>'group_id'
// ]
// ]
// ]
// ]]);

}

/**
Expand Down
2 changes: 1 addition & 1 deletion app/src/Model/Table/GroupsTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public function initialize(array $config): void {

$this->setFilterConfig([
'identifier' => [
'type' => 'relatedModel',
'type' => 'string',
'model' => 'Identifiers',
'active' => true,
'order' => 4
Expand Down
50 changes: 35 additions & 15 deletions app/src/Model/Table/IdentifiersTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
namespace App\Model\Table;

use Cake\Event\EventInterface;
use Cake\ORM\Query;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use \App\Lib\Enum\SuspendableStatusEnum;
Expand Down Expand Up @@ -191,24 +192,43 @@ public function localAfterSave(\Cake\Event\EventInterface $event, \Cake\Datasour
/**
* Look up a Person ID from an identifier and identifier type ID.
* Only active Identifiers can be used for lookups.
*
* @since COmanage Registry v5.0.0
* @param int $typeId Identifier Type ID
* @param string $identifier Identifier
*
* @param int $typeId Identifier Type ID
* @param string $identifier Identifier
* @param int|null $coId CO Id
* @param bool $login The identifier is login enabled
*
* @return int Person ID
* @throws Cake\Datasource\Exception\RecordNotFoundException
* @since COmanage Registry v5.0.0
*/

public function lookupPerson(int $typeId, string $identifier): int {
$id = $this->find()
->where([
'identifier' => $identifier,
'type_id' => $typeId,
'status' => SuspendableStatusEnum::Active,
'person_id IS NOT NULL'
])
->firstOrFail();

public function lookupPerson(int $typeId, string $identifier, ?int $coId, bool $login=false): int {
$whereClause = [
'identifier' => $identifier,
'status' => SuspendableStatusEnum::Active,
'person_id IS NOT NULL'
];

if($typeId) {
$whereClause['type_id'] = $typeId;
}

if($login) {
$whereClause['login'] = true;
}

$query = $this->find()
->where($whereClause);

if($coId) {
$query->matching(
'People',
fn(QueryExpression $exp, Query $query) => $query->where(['People.co_id' => $coId])
);
}

$id = $query->firstOrFail();

return $id->person_id;
}

Expand Down
Loading