diff --git a/app/src/Controller/StandardController.php b/app/src/Controller/StandardController.php index f6bc44c90..4fa75e2fe 100644 --- a/app/src/Controller/StandardController.php +++ b/app/src/Controller/StandardController.php @@ -551,7 +551,7 @@ public function index() { if(!empty($searchableAttributes)) { // Here we iterate over the attributes, and we add a new where clause for each one - foreach(array_keys($searchableAttributes) as $attribute) { + foreach($searchableAttributes as $attribute => $options) { if(!empty($this->request->getQuery($attribute))) { $query = $table->whereFilter($query, $attribute, $this->request->getQuery($attribute)); } elseif (!empty($this->request->getQuery($attribute . "_starts_at")) diff --git a/app/src/Lib/Traits/SearchFilterTrait.php b/app/src/Lib/Traits/SearchFilterTrait.php index 2dff433ce..e0d9b2e95 100644 --- a/app/src/Lib/Traits/SearchFilterTrait.php +++ b/app/src/Lib/Traits/SearchFilterTrait.php @@ -67,7 +67,8 @@ public function getSearchableAttributes(string $controller, string $vv_tz=null): $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' => isset($f['active']) ? $f['active'] : true + 'active' => isset($f['active']) ? $f['active'] : true, + 'model' => $f['model'] ]; } } @@ -132,6 +133,27 @@ public function whereFilter(\Cake\ORM\Query $query, string $attribute, string|ar return $query; } + if(isset($this->searchFilters[$attribute]['model'])) { + $changelog_fk = strtolower(Inflector::underscore($this->searchFilters[$attribute]['model'])) . '_id'; + $fk = strtolower(Inflector::underscore(Inflector::singularize($this->_alias))) . '_id'; + $mtable_name = Inflector::tableize(Inflector::pluralize($this->searchFilters[$attribute]['model'])); + $mtable_alias = Inflector::pluralize($this->searchFilters[$attribute]['model']); + $query->join([$mtable_alias => [ + 'table' => $mtable_name, + 'conditions' => [ + $mtable_alias . '.' . $fk . '=' . $this->_alias . '.id', + $mtable_alias . '.' . 'deleted IS NOT TRUE', + $mtable_alias . '.' . $changelog_fk . ' IS NULL' + ], + 'type' => 'INNER' + ]]); + } + + // Prepend the Model name to the attribute + $attributeWithModelPrefix = isset($this->searchFilters[$attribute]['model']) ? + Inflector::pluralize($this->searchFilters[$attribute]['model']) . '.' . $attribute : + $this->_alias . '.' . $attribute; + $search = $q; $sub = false; // Primitive types @@ -139,29 +161,32 @@ public function whereFilter(\Cake\ORM\Query $query, string $attribute, string|ar if( $this->searchFilters[$attribute]['type'] == "string") { $search = "%" . $search . "%"; $sub = true; + // Search type } elseif(in_array($this->searchFilters[$attribute]['type'], $search_types, true)) { - return $query->where([$attribute => $search]); + return $query->where([$attributeWithModelPrefix => $search]); + // Date } elseif($this->searchFilters[$attribute]['type'] == "date") { // Parse the date string with FrozenTime to improve error handling - return $query->where([$attribute => FrozenTime::parseDate($search, 'y-M-d')]); + return $query->where([$attributeWithModelPrefix => FrozenTime::parseDate($search, 'y-M-d')]); + // Timestamp } elseif( $this->searchFilters[$attribute]['type'] == "timestamp") { // Date between dates if(!empty($search[0]) && !empty($search[1])) { - return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attribute, $search) { - return $exp->between($attribute, "'" . $search[0] . "'", "'" . $search[1] . "'"); + return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attributeWithModelPrefix, $search) { + return $exp->between($attributeWithModelPrefix, "'" . $search[0] . "'", "'" . $search[1] . "'"); }); // The starts at is non-empty. So the data should be greater than the starts_at date } elseif(!empty($search[0]) && empty($search[1])) { - return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attribute, $search) { - return $exp->gte("'" . FrozenTime::parse($search[0]) . "'", $attribute); + return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attributeWithModelPrefix, $search) { + return $exp->gte("'" . FrozenTime::parse($search[0]) . "'", $attributeWithModelPrefix); }); // The ends at is non-empty. So the data should be less than the ends at date } elseif(!empty($search[1]) && empty($search[0])) { - return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attribute, $search) { - return $exp->lte("'" . FrozenTime::parse($search[1]) . "'", $attribute); + return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attributeWithModelPrefix, $search) { + return $exp->lte("'" . FrozenTime::parse($search[1]) . "'", $attributeWithModelPrefix); }); } else { // We return everything @@ -171,8 +196,8 @@ public function whereFilter(\Cake\ORM\Query $query, string $attribute, string|ar } // String values - return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attribute, $search, $sub) { - $lower = $query->func()->lower([$attribute => 'identifier']); + return $query->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) use ($attributeWithModelPrefix, $search, $sub) { + $lower = $query->func()->lower([$attributeWithModelPrefix => 'identifier']); return ($sub) ? $exp->like($lower, strtolower($search)) : $exp->eq($lower, strtolower($search)); }); diff --git a/app/src/Model/Table/PeopleTable.php b/app/src/Model/Table/PeopleTable.php index 7347a53b8..5c0ddafa9 100644 --- a/app/src/Model/Table/PeopleTable.php +++ b/app/src/Model/Table/PeopleTable.php @@ -158,22 +158,22 @@ public function initialize(array $config): void { $this->setFilterConfig([ 'family' => [ 'type' => 'relatedModel', - 'model' => 'names', + 'model' => 'Name', 'active' => true ], 'given' => [ 'type' => 'relatedModel', - 'model' => 'names', + 'model' => 'Name', 'active' => true ], 'mail' => [ 'type' => 'relatedModel', - 'model' => 'email_addresses', + 'model' => 'EmailAddress', 'active' => true ], 'identifier' => [ 'type' => 'relatedModel', - 'model' => 'identifiers', + 'model' => 'Identifier', 'active' => true ], 'timezone' => [