Affects: Group-Office 6.8.x (probably 25+ too)
FieldSet exposes its target entity by the short name (core_entity.name), but custom-field code resolves it via EntityType::findByName(), which is keyed by clientName. For any entity whose getClientName() differs from its short class name (e.g. a module entity returning PackageModuleEntity instead of EntityName to stay unique across packages), the lookup misses and custom fields on that entity are unusable.
Root cause
go/core/model/FieldSet.php — defineMapping():
->addQuery((new Query())->select("e.name AS entity")->join('core_entity', 'e', 'e.id = fs.entityId'));
That value feeds EntityType::findByName() in every consumer, e.g. Field::tableName():
$entityName = $fieldSet->getEntity(); // short name, e.g. "EntityName"
$entityType = EntityType::findByName($entityName);
if (!$entityType) {
throw new Exception("EntityType '$entityName' not found for custom field ...");
}
But findByName() resolves by client name — EntityType::getName() returns clientName, and the cache index is built from it:
public function getName(): string { return $this->clientName; } // EntityType
$cache['name'][$t->getName()] = $i; // getCache()
core_entity.name (short) and clientName diverge for any entity overriding getClientName(). Core/community entities work only because there name == clientName.
Reproduce
For an entity with getClientName() → e.g. "PackageModuleEntity" (so core_entity.name = "EntityName", clientName = "PackageModuleEntity"), add a custom field and trigger Field::tableName() (save the field / load an instance with custom fields):
Exception: EntityType 'EntityName' not found for custom field ...
EntityType::findByName("EntityName"); // false (short name — not indexed)
EntityType::findByName("PackageModuleEntity"); // EntityType (client name — indexed)
Fix
Expose the same identifier findByName() resolves — the client name (both then read core_entity.clientName, so they always agree; no change where name == clientName):
--- a/go/core/model/FieldSet.php
+++ b/go/core/model/FieldSet.php
@@ defineMapping()
- ->addQuery((new Query())->select("e.name AS entity")->join('core_entity', 'e', 'e.id = fs.entityId'));
+ ->addQuery((new Query())->select("e.clientName AS entity")->join('core_entity', 'e', 'e.id = fs.entityId'));
@@ defineFilters() 'entities'
- $criteria->andWhere('e.name', 'IN', $value);
+ $criteria->andWhere('e.clientName', 'IN', $value);
Affects: Group-Office 6.8.x (probably 25+ too)
FieldSetexposes its target entity by the short name (core_entity.name), but custom-field code resolves it viaEntityType::findByName(), which is keyed byclientName. For any entity whosegetClientName()differs from its short class name (e.g. a module entity returningPackageModuleEntityinstead ofEntityNameto stay unique across packages), the lookup misses and custom fields on that entity are unusable.Root cause
go/core/model/FieldSet.php—defineMapping():That value feeds
EntityType::findByName()in every consumer, e.g.Field::tableName():But
findByName()resolves by client name —EntityType::getName()returnsclientName, and the cache index is built from it:core_entity.name(short) andclientNamediverge for any entity overridinggetClientName(). Core/community entities work only because therename == clientName.Reproduce
For an entity with
getClientName()→ e.g."PackageModuleEntity"(socore_entity.name = "EntityName",clientName = "PackageModuleEntity"), add a custom field and triggerField::tableName()(save the field / load an instance with custom fields):Fix
Expose the same identifier
findByName()resolves — the client name (both then readcore_entity.clientName, so they always agree; no change wherename == clientName):