diff --git a/app/config/bootstrap.php b/app/config/bootstrap.php index bba87c600..93e4c292f 100644 --- a/app/config/bootstrap.php +++ b/app/config/bootstrap.php @@ -250,7 +250,9 @@ // \Cake\Utility\Inflector::rules('uninflected', ['dontinflectme']); \Cake\Utility\Inflector::rules('irregular', ['co_terms_and_condition' => 'co_terms_and_conditions']); +\Cake\Utility\Inflector::rules('uninflected', ['co_terms_and_conditions' => 'co_terms_and_conditions']); \Cake\Utility\Inflector::rules('irregular', ['cou' => 'cous']); +\Cake\Utility\Inflector::rules('uninflected', ['cous' => 'cous']); \Cake\Utility\Inflector::rules('irregular', ['meta' => 'meta']); /* diff --git a/app/src/Lib/Traits/SearchFilterTrait.php b/app/src/Lib/Traits/SearchFilterTrait.php index c1641cb45..b6ba84e60 100644 --- a/app/src/Lib/Traits/SearchFilterTrait.php +++ b/app/src/Lib/Traits/SearchFilterTrait.php @@ -85,7 +85,7 @@ public function addJoins(Query $query, string $attribute, ServerRequest $request return $query; } - $parentTable = $this->_alias; + $parentTable = $this->getAlias(); $joinAssociations = []; // Iterate over the dot notation and add the joins in the correct order // People.Names @@ -183,13 +183,25 @@ public function expressionsConstructor(Query $query, QueryExpression $exp, strin } // Prepend the Model name to the attribute - $modelPrefix = $this->_alias; + $modelPrefix = $this->getAlias(); if(isset($this->searchFilters[$attribute]['model'])) { $associationNamesPath = explode('.', $this->searchFilters[$attribute]['model']); $modelPrefix = Inflector::pluralize(end($associationNamesPath)); } - $attributeWithModelPrefix = $modelPrefix . '.' . $attribute; + /** + * Build a qualified attribute name. This is required for queries/associations that are beyond the + * first level. e.g. People.PersonRoles.Cous + * If the attribute matches the model's foreign-key pattern (eg, cou_id for Cous), + * return ".id"; otherwise ".". + */ + $expectedFk = StringUtilities::classNameToForeignKey($modelPrefix); + if (strcasecmp($attribute, $expectedFk) === 0) { + // Attribute is the FK to this model -> target the model's primary key + $attributeWithModelPrefix = $modelPrefix . '.id'; + } else { + $attributeWithModelPrefix = $modelPrefix . '.' . $attribute; + } $search = $q; diff --git a/app/src/Model/Table/PeopleTable.php b/app/src/Model/Table/PeopleTable.php index af25f5a44..a0f386752 100644 --- a/app/src/Model/Table/PeopleTable.php +++ b/app/src/Model/Table/PeopleTable.php @@ -204,7 +204,11 @@ public function initialize(array $config): void { 'types' => [ 'type' => 'type', 'attribute' => 'Names.type' - ] + ], + 'cous' => [ + 'type' => 'select', + 'model' => 'Cous' + ], ]); // XXX expand/revise this as needed to work best with looking up the related models @@ -244,7 +248,13 @@ public function initialize(array $config): void { 'model' => 'People', 'active' => false, 'order' => 99 - ] + ], + 'cou_id' => [ + 'type' => 'select', + 'model' => 'PersonRoles.Cous', + 'active' => true, + 'order' => 7 + ], ]); $this->setTabsConfig( diff --git a/app/src/View/Helper/FilterHelper.php b/app/src/View/Helper/FilterHelper.php index b6258bb14..74bda0c5c 100644 --- a/app/src/View/Helper/FilterHelper.php +++ b/app/src/View/Helper/FilterHelper.php @@ -33,6 +33,7 @@ use Cake\Collection\Collection; use Cake\ORM\TableRegistry; use Cake\Utility\Hash; +use Cake\Utility\Inflector; use Cake\View\Helper; class FilterHelper extends Helper @@ -176,4 +177,37 @@ public function getFullName(int $personId): string $person = $ModelTable->primaryName($personId); return "{$person->given} {$person->family}"; } + + /** + * Normalize the filter button title for display. + * 1) Build initial title via humanize(underscore(label-source)) + * 2) If the title is a sequence of capital letters separated by single spaces (e.g., "C O U"), + * remove all spaces -> "COU" + * 3) If the title is CamelCase with no spaces (e.g., "ThisIsAName"), + * insert a space before each capital and trim. + * + * @param string $rawLabel + * @return string + */ + public function buildFilterButtonTitle(string $rawLabel): string + { + // Humanize + $filterTitle = Inflector::humanize( + Inflector::underscore($rawLabel) + ); + + // If like "C O U" (series of capital letters separated by spaces), collapse spaces -> "COU" + if (preg_match('/^[A-Z](?:\s[A-Z])+$/', $filterTitle) === 1) { + return str_replace(' ', '', $filterTitle); + } + + // If CamelCase with no spaces, insert spaces before capitals and trim + if (!str_contains($filterTitle, ' ') && preg_match('/[A-Z]/', $filterTitle) === 1) { + // Insert a space before every capital letter except the first character + $filterTitle = preg_replace('/(?Filter->buildFilterButtonTitle( + $vv_searchable_attributes[$key]['label'] ?? $columns[$key]['label'] +); ?>