Skip to content

fix-enrollment-attributes-broken-viewFix attribute collector/enrollment flow configuration tabs associatio… #359

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
8 changes: 2 additions & 6 deletions app/src/Controller/AppController.php
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,10 @@ public function getCOID(): ?int {
*/
public function getCurrentTable(): \Cake\ORM\Table
{
/** @var string $modelsName */
$modelsName = $this->getName();
$plugin = $this->getPlugin();

$alias = $this->getPlugin() !== null
? $this->getPlugin() . '.' . $modelsName
: $modelsName;

return $this->fetchTable($alias);
return $this->fetchTable(StringUtilities::getQualifiedName($plugin, $modelsName));
}


Expand Down
2 changes: 1 addition & 1 deletion app/src/Controller/StandardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ public function index() {
$this->set('vv_permission_set', $this->RegistryAuth->calculatePermissionsForResultSet($resultSet));

// Default index view title is model name
[$title, , ] = StringUtilities::entityAndActionToTitle($resultSet, $modelsName, 'index');
[$title, , ] = StringUtilities::entityAndActionToTitle(null, $modelsName, 'index');
$this->set('vv_title', $title);

// Let the view render
Expand Down
44 changes: 39 additions & 5 deletions app/src/Controller/StandardEnrollerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,45 @@ public function beforeRender(\Cake\Event\EventInterface $event) {

if(!empty($link->value)) {
$currentTable = $this->getCurrentTable();
$efsTable = $currentTable->getAssociation('EnrollmentFlowSteps')->getTarget();

$this->set('vv_bc_parent_obj', $efsTable->get($link->value));
$this->set('vv_bc_parent_displayfield', $efsTable->getDisplayField());
$this->set('vv_bc_parent_primarykey', $efsTable->getPrimaryKey());
// Not all enroller plugin tables have a direct EnrollmentFlowSteps association
if (method_exists($currentTable, 'hasAssociation')
&& $currentTable->hasAssociation('EnrollmentFlowSteps')) {

$efsTable = $currentTable->getAssociation('EnrollmentFlowSteps')->getTarget();

$this->set('vv_bc_parent_obj', $efsTable->get($link->value));
$this->set('vv_bc_parent_displayfield', $efsTable->getDisplayField());
$this->set('vv_bc_parent_primarykey', $efsTable->getPrimaryKey());
} else {
// Two-hop case: foreign key from $link (e.g. attribute_collector_id)
// -> AttributeCollectors
// -> EnrollmentFlowSteps
// Useful for deeply nested enrollment configuration objects.
if (!empty($link->attr)) {
// Derive the table class name from the foreign key name
$fkClassName = StringUtilities::foreignKeyToClassName($link->attr); // e.g. 'AttributeCollectors'

// Qualify with plugin if present
$tableAlias = !empty($link->plugin)
? $link->plugin . '.' . $fkClassName // e.g. 'CoreEnroller.AttributeCollectors'
: $fkClassName;

$attributeCollectorsTable = TableRegistry::getTableLocator()->get($tableAlias);

// Load the intermediate object (AttributeCollector, in your case)
$collector = $attributeCollectorsTable->get((int)$link->value);

// From the AttributeCollector, go up to the EnrollmentFlowStep
if (!empty($collector->enrollment_flow_step_id)) {
$efsTable = TableRegistry::getTableLocator()->get('EnrollmentFlowSteps');
$step = $efsTable->get((int)$collector->enrollment_flow_step_id);

$this->set('vv_bc_parent_obj', $step);
$this->set('vv_bc_parent_displayfield', $efsTable->getDisplayField());
$this->set('vv_bc_parent_primarykey', $efsTable->getPrimaryKey());
}
}
}
}

return parent::beforeRender($event);
Expand Down
64 changes: 44 additions & 20 deletions app/src/Lib/Util/StringUtilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,17 @@ public static function entityToClassName($entity): string {
// $classPath will be something like App\Model\Entity\Name, but we want to return "Names"
$classPath = get_class($entity);

return self::classPathClassName($classPath);
}

/**
* Extracts and pluralizes the class name from a fully qualified class path.
*
* @param string $classPath Fully qualified class path (eg: App\Model\Entity\Name)
* @return string Pluralized class name (eg: Names)
* @since COmanage Registry v5.2.0
*/
public static function classPathClassName(string $classPath): string {
return Inflector::pluralize(substr($classPath, strrpos($classPath, '\\')+1));
}

Expand Down Expand Up @@ -285,13 +296,15 @@ public static function entityAndActionToTitle($entity,
[$plugin, $modelsName] = explode('.', $modelPath, 2);
}

if($entity == null && !empty($plugin)) {
$count = $action == 'index' ? 99 : 1;
return [__d($domain, "controller.$modelsName", [$count]), '', ''];
} elseif($entity === null) {
$count = $action == 'index' ? 99 : 1;
return [__d($domain, "{$modelPath}.{$action}", [$count]), '', ''];
// Index view → use the controller plural form (token 99 convention)
if($action === 'index') {
if(!empty($plugin)) {
$domain = StringUtilities::pluginToTextDomain($plugin);
return [__d($domain, "controller.$modelsName", [99]), '', ''];
}
return [__d('controller', $modelsName, [99]), '', ''];
}

// Base table and default message IDs for translation
$linkTable = TableRegistry::getTableLocator()->get($modelPath);
$msgId = "{$action}.a"; // eg: "edit.a"
Expand All @@ -308,25 +321,20 @@ public static function entityAndActionToTitle($entity,
// If the entity actually belongs to a different model than the provided $modelsName,
// switch to that table and adjust the default message id pattern accordingly.
// This is necessary for TAB oriented views
if(Inflector::singularize(self::entityToClassName($entity)) !== Inflector::singularize($modelsName)) {
if(
$entity !== null
&& Inflector::singularize(self::entityToClassName($entity)) !== Inflector::singularize($modelsName)
) {
$linkTable = TableRegistry::getTableLocator()->get(self::entityToClassName($entity));
// If modelPath and action are equal, don’t concatenate (preserve legacy behavior)
$msgId = $modelPath === $action ? $modelPath : "{$modelPath}.{$action}";
}

// 2) No action → default to the controller label for the model (singular)
// No action → default to the controller label for the model (singular)
if($action === null) {
return [__d('controller', $modelsName), '', ''];
}

// 3) Index view → use the controller plural form (token 99 convention)
if($action === 'index') {
if(!empty($plugin)) {
return [__d($domain, "controller.$modelsName", [99]), '', ''];
}
return [__d('controller', $modelsName, [99]), '', ''];
}

// Add/Edit/View
// The MVEA Models have an entityId. The one from the parent model.
// We need to have a condition for this and exclude it.
Expand All @@ -338,7 +346,7 @@ public static function entityAndActionToTitle($entity,
$display = $entity->$field ?? null;
}

// 6) Edit/View-like case for an existing entity with a usable display
// Edit/View-like case for an existing entity with a usable display
// Title: translate with override key first; if not found, fall back to default key.
// Super/Sub titles: set to the display (needed for External IDs in UI).
if (
Expand All @@ -354,7 +362,7 @@ public static function entityAndActionToTitle($entity,
return [$title, $supertitle, $subtitle];
}

// 7) Fallbacks:
// Fallbacks:
// - New entities (no id),
// - Add/Delete actions,
// - Or we simply lack a display.
Expand All @@ -372,7 +380,7 @@ public static function entityAndActionToTitle($entity,
* @param string $domain Translation domain to use
* @param string $overrideKey Primary translation key to try first
* @param string $fallbackKey Fallback translation key if override not found
* @param string $value Value to substitute in translation
* @param string|int $value Value to substitute in translation
* @return string Translated string using either override or fallback key
* @since COmanage Registry v5.2.0
*/
Expand Down Expand Up @@ -415,6 +423,22 @@ public static function foreignKeyToController(string $s): string {
return Inflector::underscore(Inflector::pluralize(substr($s, 0, strlen($s)-3)));
}


/**
* Get the fully qualified name by combining plugin and name with a dot separator.
*
* @param string|null $plugin Plugin name, or null if no plugin
* @param string $name Base name to qualify
* @return string Qualified name in format "Plugin.Name" or just "Name" if no plugin
* @since COmanage Registry v5.2.0
*/
public static function getQualifiedName(?string $plugin, string $name): string
{
return $plugin !== null && $plugin !== ''
? $plugin . '.' . $name
: $name;
}

/**
* Localize a controller name, accounting for plugins.
*
Expand Down Expand Up @@ -452,7 +476,7 @@ public static function qualifyModelPath(string $modelPath, ?string $plugin): str
if (empty($plugin) || str_starts_with($modelPath, $plugin . '.')) {
return $modelPath;
}
return $plugin . '.' . $modelPath;
return self::getQualifiedName($plugin, $modelPath);;
}

/**
Expand Down