In most cases the
values refer to the database fields by the database field name.
- In some cases the field may be qualified with a
:denoting that data about the field is displayed
- In some cases the field may be extended with a
.to join to another entity
- In some cases calculated fields will be exposed
Calculated Fields are fields that are determined from other data. A few important things to remember:
- they are a feature of APIv4 and so are not present in APIv3 or via BAO's.
- they are not retrieved unless specifically requested as they can be expensive.
- they are available as tokens, for example when sending email, and anywhere else APIv4 is used, such as SearchKit.
Calculated fields can be based on:
- a single field:
Contact.age is calculated from the
Contact.birth_date field and the current date.
- multiple fields from the same record:
Contribution.tax_exclusive_amount is the difference of
- a sub-query or join using other tables:
Contribution.balance_amount is calculated by a query on other financial tables.
Calculated Fields are specified in
GetSpecProvider files. Look at the existing ones for examples in
The SpecProvider has 3 main parts:
- the field definition - creating a
applies() function - limiting which entities and actions this applies to.
- the SQL string - defining how to calculate the new field (but see below for Entity Refs).
When developing these Calculated Fields, use the debug feature of API4 Explorer to see the generated SQL.
One powerful feature of Calculated Fields is the ability to use them as Entity References if the calculated value is a foreign key. All of the referenced entity's fields can be accessed without further definition of those fields.
So for example, the Calculated Field
Contact.address_primary links to the Contact's primary address (determined by joining to the
civicrm_address table) which then provides access to
The SQL string defining the join for a reference like this moves to a file in
For an example, study the implementation of
Note that a cache clear is needed after making changes to the
Core Calculated Fields¶
This section contains a listing of Calculated Fields in core. Use them as inspiration!
Activity.case_id- provides the case that an activity is linked to
Activity.assignee_contact_id- contacts related to the activity
Address.proximity- (Filter) determines whether an address is within a given distance of a location (see example)
Contact.age_years- age of a contact (based on
birth_date) in years
Contact.groups- (Filter) determines whether a contact belongs to any of the specified groups
Contact.address_primary, address_billing, email_primary, email_billing, phone_primary, phone_billing, im_primary, im_billing- addresses associated with a contact
Contribution.paid_amount- amount paid
Contribution.tax_exclusive_amount- total amount less the tax amount
Domain.is_active- is this the current active domain
MessageTemplate.master_id- the original version of a MessageTemplate if it has been modified
Filters vs Fields
Most calculated fields can be used in any part of the query (SELECT, ORDER BY, HAVING, etc) but fields designaged as type '(Filter)' can only be used in the WHERE clause.