diff --git a/app/src/Lib/Traits/TableMetaTrait.php b/app/src/Lib/Traits/TableMetaTrait.php index 0d3c4edb0..91f5f914c 100644 --- a/app/src/Lib/Traits/TableMetaTrait.php +++ b/app/src/Lib/Traits/TableMetaTrait.php @@ -73,9 +73,13 @@ public function bindPluginRelations() { $activeModels = $Plugins->getActivePluginModels('all'); foreach(array_keys($activeModels) as $entryPointModelName) { - $PluginTable = TableRegistry::getTableLocator()->get($entryPointModelName); - // Not all Entry Point Models are Tables (eg: Jobs). + $tableClassName = \Cake\Core\App::className($entryPointModelName, 'Model/Table', 'Table'); + if(!$tableClassName) { + continue; + } + + $PluginTable = TableRegistry::getTableLocator()->get($entryPointModelName); if(method_exists($PluginTable, 'getHasManyPluginRelations')) { $pluginRelations = $PluginTable->getHasManyPluginRelations($tableName); @@ -93,7 +97,37 @@ public function bindPluginRelations() { $config['className'] = $r['targetModel']; } - $this->hasMany($alias, $config); + $assocAlias = $alias; + if (strpos($alias, '.') !== false) { + // CakePHP will strip the plugin prefix when assigning the alias key. + // For example, 'CoreApi.MatchCallbacks' becomes 'MatchCallbacks'. + $assocAlias = explode('.', $alias, 2)[1]; + } + + // If another plugin defines a relation with the same base name + // (e.g., 'OtherApi.MatchCallbacks' also becoming 'MatchCallbacks'), + // it causes an "Association alias is already set" conflict. + // To prevent this overlap, we inspect the existing alias's target class. + // If the classes differ, we dynamically generate a unique alias + // (e.g., 'OtherApiMatchCallbacks') by prepending the plugin name. + if ($this->associations()->has($assocAlias)) { + $existing = $this->associations()->get($assocAlias); + $expectedClassName = $config['className'] ?? $r['targetModel']; + + if ($existing->getClassName() !== $expectedClassName) { + $newAlias = str_replace('.', '', $r['targetModel']); + if ($alias !== $r['targetModel']) { + $newAlias .= $alias; + } + + $config['className'] = $r['targetModel']; + if (!$this->associations()->has($newAlias)) { + $this->hasMany($newAlias, $config); + } + } + } else { + $this->hasMany($alias, $config); + } } } }