From 25002955cb17008218e2464929088d979653da54 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Tue, 7 Apr 2026 17:07:19 +0300 Subject: [PATCH] TabHelper::getDeepNestedId() fixes --- app/src/View/Helper/TabHelper.php | 77 +++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/app/src/View/Helper/TabHelper.php b/app/src/View/Helper/TabHelper.php index 5bef2078f..c3f8db031 100644 --- a/app/src/View/Helper/TabHelper.php +++ b/app/src/View/Helper/TabHelper.php @@ -139,41 +139,68 @@ public function constructLinkUrl(string $tab, string|int $curId, bool $isNested */ public function getDeepNestedId(array $linkFilter): ?int { + // Retrieve associated IDs for the current view $vv_associated_ids = $this->getView()->get('vv_associated_ids'); - // Get the foreign from the linkFilter + // Extract the first key from the link filter array (foreign key) $linkFilterForeignKey = array_key_first($linkFilter); - // Generate the ModelName and instantiate the linked Table - $modelName = StringUtilities::foreignKeyToClassName($linkFilterForeignKey); - $table = TableRegistry::getTableLocator()->get($modelName); - $pluralModelName = Inflector::pluralize($modelName); - $linkFilterId = $vv_associated_ids[$pluralModelName] - ?? current(array_filter($vv_associated_ids, fn($k) => str_ends_with($k, '.' . $pluralModelName), ARRAY_FILTER_USE_KEY)) + // Derive the model name and qualified model name from the foreign key + $modelName = StringUtilities::foreignKeyToClassName($linkFilterForeignKey); + $qualifiedModelName = StringUtilities::modelNameToQualifiedModelName($modelName); + $table = TableRegistry::getTableLocator()->get($qualifiedModelName); + + // Attempt to retrieve the ID from associated IDs using different possible keys + $linkFilterId = + $vv_associated_ids[$qualifiedModelName] + ?? $vv_associated_ids[$modelName] + ?? current(array_filter($vv_associated_ids, fn($k) => str_ends_with($k, '.' . $modelName), ARRAY_FILTER_USE_KEY)) ?: null; - if($linkFilterId !== null) { + // If an ID is found, return it as an integer + if ($linkFilterId !== null) { return (int)$linkFilterId; } - $foreignKeyId = -1; + + // Initialize variables to track foreign key and its ID + $foreignKeyId = null; $foreignKey = null; - // This means that we are working on deep nested associations and we need - // to fetch more data - $linkFilterSchema = $table->getSchema(); - foreach($linkFilterSchema->columns() as $column) { - // Check the foreign keys - if(str_ends_with($column, '_id')) { - $foreignKeytToTableName = Inflector::pluralize(StringUtilities::foreignKeyToClassName($column)); - if(isset($vv_associated_ids[$foreignKeytToTableName])) { - $foreignKeyId = $vv_associated_ids[$foreignKeytToTableName]; - $foreignKey = $column; - break; - } + + // Iterate through all schema columns to look for a valid foreign key + foreach ($table->getSchema()->columns() as $column) { + // Skip columns that do not end with '_id' + if (!str_ends_with($column, '_id')) { + continue; + } + + // Convert the foreign key column to model names + $fkModelName = StringUtilities::foreignKeyToClassName($column); + $fkQualifiedModelName = StringUtilities::modelNameToQualifiedModelName($fkModelName); + + // Check for a match in associated IDs + $candidateId = + $vv_associated_ids[$fkQualifiedModelName] + ?? $vv_associated_ids[$fkModelName] + ?? null; + + // If a match is found, set the foreign key ID and column, and break the loop + if ($candidateId !== null) { + $foreignKeyId = (int)$candidateId; + $foreignKey = $column; + break; } } - $id = $table->find()->where([$foreignKey => $foreignKeyId])->first()->id; - return(int)$id; + // If no valid foreign key or ID was found, return null + if ($foreignKey === null || $foreignKeyId === null) { + return null; + } + + // Query the database for the associated row using the foreign key + $row = $table->find()->where([$foreignKey => $foreignKeyId])->first(); + + // Return the ID from the row if found or null otherwise + return $row ? (int)$row->id : null; } /** @@ -398,7 +425,7 @@ public function getLinkFilter( [$plugin, $modelName] = explode('.', $tab); } - $modelsTable = TableRegistry::getTableLocator()->get($fullModelsName); + $modelsTable = TableRegistry::getTableLocator()->get(StringUtilities::modelNameToQualifiedModelName($fullModelsName)); $primary_link_list = $modelsTable->getPrimaryLinks(); $primary_link = null; if(count($primary_link_list) > 1) { @@ -519,7 +546,7 @@ public function setPluginName(?string $pluginName): void public function retrievePluginName(string $tab, int $curId): string { // Get the name of the Core Model - [$coreModel, $dummy] = explode('.', $tab); + $coreModel = substr($tab, 0, strrpos($tab, '.')); $ModelTable = TableRegistry::getTableLocator()->get($coreModel); $response = $ModelTable ->find()