Support `EntityFile` bridges for files in custom fields
As dicussed in the Chat:
@jensschuppe:
We have custom fields of type File on activities.
EntityFile
records should be the bridge betweenFile
andActivity
, right? Records are, however, a bridge to the custom group's table incivicrm_entity_file
, withcivicrm_entity_file.entity_id
being mapped tocivicrm_value_*.entity_id
. Is this correct? Shouldn't this be a record withentity_table
=civicrm_activity
andentity_id
=civicrm_activity.id
instead? How would I be able to retrieve a file's URL whenFile.get
withurl
in the select requires aJOIN
to the activity withEntityFile
as a bridge?The
entity_table
for theEntityFile
record is being set here for custom fields. This means it is impossible to join fromFile
to the entity the custom field is attached to via the API, right?
I agree with you entityFile should store the activity id not the custom id.
Although... then it might be confused as an attachment?
The
EntityFile
table is kinda funky. For entities that have attachments, that table serves as the only record of that attachment.But for custom fields, the custom field also stores the file id, so the
EntityFile
record is actually redundant.I see the code you're referencing though. Api4 assumes that
EntityFile
is a bridge to the main entity and it calculates the url from there. I guess that only works for attachments, and for custom fields it needs to do it a different way.I agree with you entityFile should store the activity id not the custom id.
Although... then it might be confused as an attachment?
The
EntityFile
table is kinda funky. For entities that have attachments, that table serves as the only record of that attachment.But for custom fields, the custom field also stores the file id, so the
EntityFile
record is actually redundant.I see the code you're referencing though. Api4 assumes that
EntityFile
is a bridge to the main entity and it calculates the url from there. I guess that only works for attachments, and for custom fields it needs to do it a different way.
I agree with you entityFile should store the activity id not the custom id.
It actually stores the activity ID, not the custom value record ID (the
entity_id
column value of thecivicrm_value_*
table, not itsid
column value), it's just theentity_table
column ofcivicrm_entity_file
that's notcivicrm_activity
butcivicrm_value_*
…I see the code you're referencing though. Api4 assumes that
EntityFile
is a bridge to the main entity and it calculates the url from there. I guess that only works for attachments, and for custom fields it needs to do it a different way.So what makes a file actually an attachment - I always assumed that's only a term describing which entity a file belongs to. So technically, a file in a custom field belongs to the custom field, but a custom field always belongs to an entity, so the file would always belong to that entity … also, the code setting
entity_table
tocivicrm_value_*
is within an API3 function used by theAttachment
API, so I guess such files are Attachments as well …?If
EntityFile
is not necessary for keeping the relationship between the custom field and the file (as that is duplicating the field value which is the file ID), does anything depend on thecivicrm_value_*
table being referenced instead of e. g.civicrm_activity
?Currently, the file's URL can not be retrieved via API4, as
\Civi\Api4\Service\Spec\Provider\FileGetSpecProvider::renderFileUrl()
explicitly requires an explicit join with theEntityFile
bridge, which can't be done when theEntityFile
record is not bridging to thecivicrm_activity
table. Did I get you right that you'd prefer adjusting API4File.get
API, allowing bridging files to entities via custom fields?I agree with you entityFile should store the activity id not the custom id.
Although... then it might be confused as an attachment?
@coleman Can you help me understand what differentiates an attachment from a file in a custom field? And what would be the best approach to actually storing the entity's ID in
EntityFile
instead of the custom field ID (or maybe providing support for files in custom fields via the API4EntityFile
bridge)
Attachments are entity files with no associated custom field. E.g an activity can have up to 3 attachments. These are files uploaded that are "attached" to the activity. They are linked to is via the
civicrm_entity_file
table.
So I think there should be special handling of files in custom file fields in \Civi\Api4\Query\Api4SelectQuery::getBridgeRefs()
or \CRM_Core_Reference_Dynamic::getTargetEntities()
, so that those can be retrieved via API4 with the EntityFile
bridge. The usage of civicrm_entity_file
records is different in that they reference the CustomValue's entity_id
instead of the id
column, so basically the record is a JOIN to the actual entity the custom field is attached to (Contact, Activity, etc.). The EntityFile
bridge could thus support those to be dynamically joined.
Currently, API4 File.get
can not use the EntityFile
bridge to the actual entities the file "belongs" to, as civicrm_entity_file
does not have civicrm_contact
, civicrm_activity
, etc. in its entity_table
column, but the custom value table of the custom field. However, entity_id
holds the contact's/activity's ID, not the custom value ID.