Using the CiviCRM Entity Reference Field submodule with Inline Entity Form
CiviCRM Entity Reference Field is a submodule of the CiviCRM Entity project, which tightly integrates CiviCRM data into Drupal by exposing API entities as Drupal entity types. One of the many advantages of installing the CiviCRM Entity module is the ability to use Drupal’s Entity Reference module to reference CiviCRM data from nodes, terms, or other entity types. Many people are using the Inline Entity Form module, which provides field widgets that allow creating, editing, or deleting referenced entity from the parent form.
If you reference CiviCRM contacts via an Entity Reference field and use Inline Entity Form, or use the Drupal Contact entity edit form at /civicrm-contact/[id]/edit
, it will often be the case that you’ll want to include the ability for the user to create or edit subsidiary CiviCRM entity types, such as the email, phone, and address entities.
The case of CiviCRM integration adds a caveat. A regular entity reference field stores a target entity id in a Drupal field table, in the Drupal database. CiviCRM Addresses are stored in the CiviCRM database, and can be created by users or admins in multiple different ways. In addition, Drupal and CiviCRM reference data in opposite ways. Drupal with its field model, “forward references”. That is the entity stores the ids of the child entities. If you reference a contact from a node, the node, via the field table, stores the id of the child. CiviCRM generally uses “back references.” The child entity will store the id of the parent entity. For example, the address entity has a contact_id column, and the parent contact id is stored there. To make the situation more interesting, this pattern is not consistently followed in CiviCRM, and occasionally you’ll have a “forward reference”. As Events store a location block id, and the location block references addresses.
We want the convenient and familiar interface of the Inline Entity Form/Entityreference combination, but we want to use the existing data from the CiviCRM tables, and not store target ids in Drupal field tables, while at the same time being flexible enough to go both ways. We want to make a square peg to fit into a round hole. What we needed was a “remote reference field”.
Apparently you need a jigsaw and a hammer and the ability to run forwards and backwards at the same time. I will admit that I borrowed heavily from the existing Entity Reference field, putting the jigsaw to it, and at the same time hammering in the inline entity form support (which requires the CiviCRM Entity Inline submodule).
The Drupal Field API is very powerful, and it turns out you can make field types that are disconnected from the standard Drupal field tables. The solution is CiviCRM Entity Reference Field. This module adds a new field type, CiviCRM Entity Reference, that can be added to any CiviCRM entity type.
We’ve successfully used this module for a variety of use cases, including:
- Referencing emails, addresses, phones from contacts
- Referencing participants from events
- Referencing relationships from contacts
- Referencing activities from contacts
- Referencing contacts from activities
- Referencing contacts from relationships
It is also possible to have CiviCRM Entity Reference (CER) fields on entities referenced by CER fields, so basically it can be nested.
The first use case of this was needing to edit Event addresses. In CiviCRM, Events reference location blocks, which in turn reference addresses. To edit profiles on Events, you need to reference UFJoin from Events. The UFJoin entity type needs a UFGroup reference field which needs to reference UFField. That case is especially interesting as that “line of reference” runs both forward and backwards from the UFGroup entity.
That’s the what and the why, here’s an example on how to use it.
Lets setup a CER that references Email addresses from the contact form at /civicrm-contact/[id]/edit
.
First go to the Manage Fields form for the CiviCRM Contact entity type. /admin/structure/civicrm-entity/civicrm_contact
Add a new field with label, “Email Addresses”, of type “CiviCRM Entity Reference”, with the “Inline Entity Form -- Multiple Values” field widget.
The configuring the field settings page that comes next is crucial.
- Choose “Unlimited” for “Number of values”
- Select “Email” for “Target Entity Type”
- Select “Email contact” for “Target ID Join Column”
- Select “ID” for “Host Source Column”
CiviCRM Entity Reference field has a load function which queries the CiviCRM database tables, instead of the default Drupal behavior which queries a field table. It needs to know which column in the target entity table to use to query with a column from the parent entity table. In this case the target entity table is civicrm_email, and the parent or host table is the civicrm_contact table. So we query the email table for all records where the contact_id column has the value of the id column from the parent contact table. You can use any column in the target entity table, but I’ve hard coded options for the Host Source Column for user experience purposes. There gets to be a lot of options and options often breed confusion. This could be opened up, if you need an additional host source id column option, make a feature request and it can be added.
After saving the field settings, the field instance settings form is next. Here configure some options for the Inline Entity Form Multiple Values widget.
For this example, check the “Allow users to add new entities.” and “Delete referenced entities when the parent entity is deleted.” checkboxes. Also check the “Override labels” checkbox, and enter “Email” for the “Singular Label”, and “Emails” for the “Plural Label”.
Save the settings.
The CER will now appear on every contact edit form.
Be aware there is one current limitation of this module. The inline entity form widgets are disabled on “add”. For most of the back referenced entities, you don’t have an id yet for the the parent entity, to store on the child. So if a CER targeting addresses on the contact form, the default form processing of Drupal would try to save the address first. The CiviCRM API requires the contact_id property, and will throw an exception. The contact_id field is not required in the CiviCRM schema though, because you can create addresses from the stock backend Event edit form, which will create a record with a NULL contact_id. Regardless, this is the problem with back references. Some work has been done to make it possible to use the Inline Entity Form - Single widget for child entities for contacts in the -dev version. Some of the “forward reference” lines of reference in CiviCRM could work, but the thought and development continues to overcome this limitation. It may be inconvenient to save the contact, then edit again to add emails, but the benefits of total Drupal integration can outweigh this slight UX drawback.
At Skvare, we will continue to push the envelope of superior Drupal/CiviCRM integration. If you have specific cases and want a customization or additional feature in the public module contact us now.