Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • documentation/docs/dev
  • totten/dev
  • bgm/dev
  • ivan_compucorp/dev
  • seamuslee/dev
  • artfulrobot/dev
  • ufundo/dev
  • wmortada/dev
  • lucky091588/dev
  • DaveD/dev
  • jtwyman/dev
  • rukkykofi/dev
  • JonGold/dev
  • jaapjansma/developer-docs
  • alainb/dev
  • noah/dev
  • justinfreeman/dev
  • pradeep/dev
  • larssg/dev
  • eileen/dev
  • darrick/dev
  • mattwire/dev
  • colemanw/dev
  • homotechsual/dev
  • JoeMurray/dev
  • maynardsmith/dev
  • kurund/dev
  • rocxa/dev
  • AllenShaw/dev
  • bradleyt/dev
  • chrisgaraffa/dev
  • martin.w/dev
  • herbdool/dev
  • MattTrim1/dev
  • Detlev/dev
  • ErikHommel/dev
  • brienne/devdocs
  • pminf/dev
  • SarahFG/dev
  • ayduns/dev
  • JKingsnorth/dev
  • ginkgomzd/dev
  • nicol/dev
  • almeidam/dev
  • arthurm/dev
  • damilare/dev
  • semseysandor/dev
  • major/devdocs
  • usha.makoa/dev
  • yurg/dev
  • shaneonabike/dev
  • andie/dev
  • mmyriam/dev
  • gngn/dev
  • florian-dieckmann/dev
  • jade/dev
  • luke.stewart/dev
  • vinaygawade/dev
58 results
Show changes
Showing
with 1688 additions and 324 deletions
# APIv3 REST
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/rest.md) is recommended.
## Overview
!!! tip "Get started with APIv3 Explorer"
CiviCRM has a built-in tool for working with APIv3 (`Support => Developer => APIv3 Explorer`). You may use
this to generate complete HTTP/REST examples that are tuned to your instance of CiviCRM.
This documentation provides a deeper explanation of the HTTP/REST interface.
CiviCRM APIv3 provides HTTP/REST bindings, enabling remote applications to read and write data. To use it, we must understand the end-point URLs, the
authentication protocols, and the API data.
??? question "Is APIv3 a REST-ful interface?"
HTTP-based APIs are sometimes described as "REST-ful" if they closely follow certain HTTP conventions. CiviCRM APIv3 is not REST-ful.
Never-the-less, it is generally used for reading and writing resource records, and (by tradition) the subsystem is referred to as "REST".
## Examples
As we review the structure of an APIv3 REST call, it may help to have a few examples. Here is a representative example:
```
1: GET https://www.example.org/sites/all/modules/civicrm/extern/rest.php
2: ?key=ABCD1234&api_key=ZYXW9876
3: &entity=Contact&action=get&json=%7B%22id%22%3A10%7D
```
In line 1, we see an *end-point URL*. Line 2 provides the *authentication* parameters. Line 3 conveys the specific API call ([entity, action, parameters](usage.md)).
Similar elements should appear in any API call, but the content of each can differ. Here is another example:
```
1: POST https://crm.example.org/civicrm/ajax/rest
2: Authorization: Basic dXNlcjpwYXNz
3: X-Requested-With: XMLHttpRequest
4:
5: entity=Activity&action=create&json=%7B%22subject%22%3A%22hello%22%7D
```
Here, we have a different *end-point URL* (line 1) along with a different *authentication* style (line 2). The specific API also differs (line 5).
## Compatibility
As we proceed through this chapter, we will consider different API features. When choosing which features to use, you may wish to consult back to this compatibility matrix.
| End-Point URL | `civicrm/ajax/*` | `extern/rest.php`(deprecated) | `WP REST` |
|--|--|--|--|
| APIv3 | **Yes** | **Yes** | **Yes** |
| APIv4 | **Yes** | No | No |
| Authentication: AuthX | **Yes** (v5.36+) | No | No |
| Authentication: Session-Cookie | **Yes** | No | No |
| Authentication: Traditional Keys | **Yes** (v5.47+) | **Yes** | **Yes** |
| CMS: Backdrop | **Yes** | **Yes** | No |
| CMS: Drupal 7 | **Yes** | **Yes** | No |
| CMS: Drupal 8+ | **Yes** | Unofficial, Deprecated | No |
| CMS: Joomla | Partial | **Yes** | No |
| CMS: WordPress | **Yes** | Deprecated | **Yes** (v5.25+) |
## End-Point URL
!!! tip "For help choosing an end-point, see also: [Compatibility](#compatibility)"
All requests should be submitted to an APIv3 end-point URL.
Requests are typically submitted with HTTP POST, but read-only operations may use HTTP GET.
You may choose among a handful of end-point URLs. Expand the sections below for more detailed information.
??? example "APIv3 REST via normal HTTP route: `civicrm/ajax/rest`"
The `civicrm/ajax/rest` end-point works like any regular page in CiviCRM. On Drupal, Backdrop, and some WordPress deployments, you may access it with a clean URL.
```
https://example.org/civicrm/ajax/rest
```
In other deployments, you may need a verbose URL - such as these WordPress and Joomla URLs:
```
https://wordpress.example.org/wp-admin/admin.php?page=CiviCRM&q=civicrm/ajax/rest
https://joomla.example.org/administrator/index.php?option=com_civicrm&task=civicrm/ajax/rest
```
The `civicrm/ajax/rest` end-point is frequently used for browser-based API calls ("AJAX"). In newer versions (CiviCRM v5.36+), it can also be used for remote applications.
Stylisitcally, this is similar to [APIv4 REST](../v4/rest.md) end-point.
??? example "APIv3 REST via standalone script: `extern/rest.php`"
!!! warning "As of v5.47+, there should be no reason to use `extern/rest.php` - other end-points should be more compatible and more featureful. See [APIv3 Changelog](changes.md#restendpoint) for migration notes."
The `extern/rest.php` end-point is a standalone PHP script. It generally lives in the CiviCRM source tree, although the location will depend on the specific deployment.
```
## Typical Backdrop URL
https://example.org/modules/civicrm/extern/rest.php
## Typical Drupal 7 URL
https://example.org/sites/all/modules/civicrm/extern/rest.php
## Typical Joomla URL
https://example.org/administrator/components/com_civicrm/civicrm/extern/rest.php`
## Typical WordPress URL
https://example.org/wp-content/plugins/civicrm/civicrm/extern/rest.php
```
This end-point is broadly compatibile with many *versions* (CiviCRM v3+). However, it is incompatible with APIv4 and with some *environments*.
Specifically, Drupal 8+ and some configurations of WordPress have difficulty with it.
??? example "APIv3 REST via WordPress service"
[WP REST](wp-rest.md) (CiviCRM v5.25+) replaces all `extern/*.php` scripts with WordPress-optimized equivalents. These end-points support
clean URLs, and they provide wider compatibility with more WordPress environments.
```
## Typical WP REST URL
https://example.com/wp-json/civicrm/v3/rest
```
## Authentication
!!! tip "For help choosing an authentication protocol, see also: [Compatibility](#compatibility)"
Every request for APIv3 should include authentication details. These may be submitted in a few forms.
??? example "Authenticate via AuthX (API Key, JWT, Username/Password)"
The core extension "AuthX" (v5.36+) provides extended authentication support. If configured, [it can accept credentials in several different formats](../../framework/authx.md), such as:
```
/* Conventional HTTP header */
Authorization: Bearer MY_API_KEY
Authorization: Bearer MY_JSON_WEB_TOKEN
Authorization: Basic B64(USER:PASS)
/* Civi HTTP header */
X-Civi-Auth: Bearer MY_API_KEY
X-Civi-Auth: Bearer MY_JSON_WEB_TOKEN
X-Civi-Auth: Basic B64(USER:PASS)
/* HTTP parameter */
?_authx=Bearer+MY_API_KEY
?_authx=Bearer+MY_JSON_WEB_TOKEN
?_authx=Basic+B64(USER:PASS)
```
AuthX is compatible with normal CiviCRM routes like `civicrm/ajax/rest`.
??? example "Authenticate via CMS session/cookie"
Browser-based users typically access CiviCRM by logging in to a colocated CMS (Drupal, WordPress, etc). This process creates a session-cookie which
authenticates the user.
This style of authentication is important for AJAX. However, for remote applications, this style can be problematic because (a) each CMS has a different
login process and (b) site-builders often customize the login experience.
??? example "Authenticate via traditional REST keys"
CiviCRM v4+ supports authentication using a combination of *two* keys. A valid request must present both keys as URL parameters. For example:
```
?key=THE_SITE_KEY
&api_key=MY_API_KEY
```
The [site key](https://docs.civicrm.org/sysadmin/en/latest/setup/secret-keys/#civicrm_site_key) is a general pre-requisite, and it will be the
same for all traditional REST users. The [API key](https://docs.civicrm.org/sysadmin/en/latest/setup/api-keys/) uniquely identifies the
user or agent making the request.
Support for traditional REST keys is limited to specific end-points and versions:
| End-Point URL | Support Traditional REST Keys? |
| -- | -- |
| `civicrm/ajax/rest` | Yes (v5.47+) |
| `extern/rest.php` | Yes (All versions) |
| WP REST | Yes (v5.25+) |
## X-Requested-With
To ensure broad compatibility, APIv3 REST clients should set this HTTP header:
```http
X-Requested-With: XMLHttpRequest
```
The header is not required for all requests, but sometimes it is required, and there is generally no harm to
setting it.
For more complete details, see [Cross-Site Request Forgery (CSRF)](../../security/csrf.md) and specifically
[CSRF: APIv3/APIv4 REST](../../security/csrf.md#rest).
## API Data
As you may recall, APIv3 is built around the triplet [(`$entity`, `$action`, `$params`)](usage.md), e.g.
```php
$result = civicrm_api3($entity, $action, $params);
$result = civicrm_api3('Contact', 'get', ['id' => 10]);
```
The triplet corresponds to three HTTP parameters (`&entity=`, `&action=`, and `&json=`). If we adapt the
above example and apply appropriate escaping rules, the corresponding HTTP parameters will be:
```
&entity=Contact
&action=get
&json=%7B%22id%22%3A10%7D
```
!!! tip "Even if there are no `$params`, one should pass a placeholder value for `&json=1`."
??? warning "Deprecated: Extra Key-Value Parameters"
Any unrecognized parameters in the URL are passed through to the `$params`. The previous example could be written as:
```
&entity=Contact
&action=get
&id=10
```
This format looks easy, and it is retained for backward compatibility. Never-the-less, JSON is recommended because:
* Extra params cannot accurately indicate special values (`true`, `false`, `null`, `[]`, `{}`).
* Extra params are prone to naming conflicts (e.g. if an API requires an input `$params['action']`).
* Extra params require special encoding for nested fields (e.g. `&options[limit]=25&options[offset]=50`).
JSON addresses all these issues, and it has very broad support across many tools/environments/clients.
## Response
The response will be a JSON document, e.g.
```javascript
{
"is_error": 0,
"version": 3,
"count": 1,
"values": [
{
"contact_id": "10",
"contact_type": "Individual",
"contact_sub_type": "",
"display_name": "Example Person",
...
```
??? warning "Deprecated: XML Responses"
If you omit the `&json=...` parameter, then the APIv3 REST will send responses in XML format. This is retained for
backward compatibility, but JSON format is generally recommended.
!!! example "Example: XML response after searching for contact"
```xml
<?xml version="1.0"?>
<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Result>
<contact_id>1</contact_id>
<contact_type>Individual</contact_type>
<sort_name>Doe, John</sort_name>
<display_name>John G Doe</display_name>
<do_not_email>0</do_not_email>
<do_not_phone>0</do_not_phone>
<do_not_mail>0</do_not_mail>
<do_not_trade>0</do_not_trade>
<is_opt_out>0</is_opt_out>
<home_URL>[http://www.example.com]</home_URL>
<preferred_mail_format>Both</preferred_mail_format>
<first_name>John</first_name>
<middle_name>G</middle_name>
<last_name>Doe</last_name>
<is_deceased>0</is_deceased>
<email_id>2</email_id>
<email>jdoe@example.com</email>
<on_hold>0</on_hold>
</Result>
...
<Result>
<contact_id>N</contact_id>
<contact_type>Individual</contact_type>
<sort_name>test@example.org</sort_name>
<display_name>test@example.org</display_name>
<do_not_email>0</do_not_email>
<do_not_phone>0</do_not_phone>
<do_not_mail>0</do_not_mail>
<do_not_trade>0</do_not_trade>
<is_opt_out>0</is_opt_out>
<preferred_mail_format>Both</preferred_mail_format>
<is_deceased>0</is_deceased>
<email_id>4</email_id>
<email>test@example.org</email>
<on_hold>0</on_hold>
</Result>
</ResultSet>
```
!!! example "Example: XML response to creating a new contact"
```xml
<?xml version="1.0"?>
<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Result>
<contact_id>4</contact_id>
<is_error>0</is_error>
</Result>
</ResultSet>
```
# API Usage
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/usage.md) is recommended.
Every API call consists of three elements: the *entity*, *action*, and
*parameters*. For example, consider a few commonly-used entities along
with the supported actions and parameters:
......@@ -12,7 +15,7 @@ with the supported actions and parameters:
| <code>Address</code> | A street-address related <br /> to a contact. |<code>create</code><br/><code>get</code><br/><code>delete</code><br/>| <code>contact\_id</code>, <br /> <code>street\_address</code> <br /> <code>city</code> <br /> <code>state\_province\_id</code> <br /> <code>country\_id</code> |
(*For full, up-to-date details about specific entities and parameters, use the
[API Explorer](/api/index.md#api-explorer).*)
[API Explorer](../index.md#api-explorer).*)
The API is available in many different environments (such as PHP, REST, and
Javascript), and the notation differs slightly in each environment.
......@@ -80,11 +83,9 @@ for usability:
- Errors are reported as PHP exceptions. You may catch the exceptions or
(by default) allow them to bubble up.
*Note*: If you're writing a Drupal module, a Joomla extension, a WordPress
plugin, or a standalone script, then you may need to **bootstrap** CiviCRM
before using the API. See the examples in [Bootstrap Reference].
[Bootstrap Reference](/framework/bootstrap.md)
!!! note "Use Outside of CiviCRM"
If you're writing a Drupal module, a Joomla extension, a WordPress plugin, or a standalone script, then you may need to [bootstrap](../../framework/bootstrap.md) CiviCRM before using the API.
## PHP (class.api.php)
......@@ -148,11 +149,11 @@ http://www.example.com/civicrm/ajax/rest
```
Obviously you should substitute your site in! You can explore the syntax
and options available using the [API Explorer](/api/index.md#api-explorer).
and options available using the [API Explorer](../index.md#api-explorer).
Please note that the REST interface is subject to [API Security](/security/permissions.md#api-permissions).
Please note that the REST interface is subject to [API Security](../../security/permissions.md#api-permissions).
For more details, see [REST interface](/api/interfaces.md#rest).
For more details, see [REST interface](interfaces.md#rest).
## AJAX
......@@ -161,11 +162,11 @@ For more details, see [REST interface](/api/interfaces.md#rest). 
CRM.api3('entity', 'action', [params], [statusMessage]);
```
If you pass `true` in as the `StatusMessage` param, it will display the default status message. This is useful when doing things such as adding tags to contacts or similar. If you wish to do further work based on the result of the API call (e.g use the results from a GET call) you will need to use the [done method](http://api.jquery.com/deferred.done/) to listen for the event. For example:
If you pass `true` in as the `StatusMessage` param, it will display the default status message. This is useful when doing things such as adding tags to contacts or similar. If you wish to do further work based on the result of the API call (e.g use the results from a GET call) you will need to use the [then method](http://api.jquery.com/deferred.then/) to listen for the event. For example:
```javascript
CRM.api3('entity_tag', 'create', {contact_id:123, tag_id:42})
.done(function(result) {
.then(function(result) {
console.log(result);
});
```
......@@ -177,7 +178,7 @@ var params = [
['email', 'get', {contact_id: 123}],
['phone', 'get', {phone: '555-5555'}]
];
CRM.api3(params).done(function(result) {
CRM.api3(params).then(function(result) {
console.log('email result is:', result[0]);
console.log('phone result is:', result[1]);
});
......@@ -191,7 +192,7 @@ var params = {
two: ['phone', 'getoptions', {field: 'phone_type_id', sequential: 1}],
three: ['phone', 'get']
};
CRM.api3(params).done(function(result) {
CRM.api3(params).then(function(result) {
console.log('email result is:', result.one);
console.log('phone options are:', result.two);
console.log('phone get result is:', result.three);
......@@ -200,8 +201,8 @@ CRM.api3(params).done(function(result) {
The AJAX interface is automatically available for web-pages generated through CiviCRM (such as standard CiviCRM web-pages, CiviCRM extensions and custom CiviCRM templates).
The AJAX interface could be made available to other parts of the same website (e.g. a Drupal module or WordPress widget) by calling `CRM_Core_Resources::singleton()->addCoreResources()`
from php. Please note that the AJAX interface is subject to [API Security](/security/permissions.md#api-permissions)
The AJAX interface could be made available to other parts of the same website (e.g. a Drupal module or WordPress widget) by calling `Civi::resources()->addCoreResources()`
from php. Please note that the AJAX interface is subject to [API Security](../../security/permissions.md#api-permissions)
and [Same Origin Policy](http://en.wikipedia.org/wiki/Same_origin_policy). To use it from an external site or application, see the REST interface documentation.
## Smarty
......@@ -215,7 +216,7 @@ The smarty call is to add extra information, therefore *create* or *delete*
actions don't make sense in this case.
For more details, see
[Smarty API interface](/api/interfaces.md#smarty-api-interface).
[Smarty API interface](interfaces.md#smarty-api-interface).
## Scheduled jobs
Any API call can be configured to be run as a scheduled job. These can be configured in the UI under Administer->System Settings->Scheduled jobs. Usually API calls run this way are written with the intent that they be run as scheduled jobs - e.g those with the Job entity or provided by payment processors to run recurring payments.
......@@ -252,7 +253,7 @@ cv api contact.get first_name=Alice last_name=Roberts
## API Security
API has security measures built in depending on the way the API is called that can also be turned off or on. API Permissions are also able to be altered via hook. More information on API Security can be found in the [Security Documentation](/security/permissions.md).
API has security measures built in depending on the way the API is called that can also be turned off or on. API Permissions are also able to be altered via hook. More information on API Security can be found in the [Security Documentation](../../security/permissions.md).
## API Lookups by Username
......
# CiviCRM WP REST API Wrapper
!!! warning "APIv3 Deprecation"
API version 3 is now deprecated. [Version 4](../v4/rest.md) is recommended.
Starting in CiviCRM Version 5.25 CiviCRM's [extern](https://github.com/civicrm/civicrm-core/tree/master/extern) scripts have been exposed as WordPress REST endpoints.
Requirements:
- PHP 7.1+
- WordPress 4.7+
- CiviCRM version 5.25
## Endpoints
1. `civicrm/v3/rest` - a wrapper around `civicrm_api3()`
**Parameters**:
- `key` - **required**, the site key
- `api_key` - **required**, the contact api key
- `entity` - **required**, the API entity
- `action` - **required**, the API action
- `json` - **optional**, json formatted string with the API parameters/arguments, or `1` as in `json=1`
It mimics CiviCRM's REST [interface](interfaces.md), by default all calls to `civicrm/v3/rest` return XML formatted results. To get `json` formatted results pass `json=1` or a json formatted string with the API parameters, like in example 2 below.
**Examples**:
1. `https://example.com/wp-json/civicrm/v3/rest?entity=Contact&action=get&key=<site_key>&api_key=<api_key>&group=Administrators`
2. `https://example.com/wp-json/civicrm/v3/rest?entity=Contact&action=get&key=<site_key>&api_key=<api_key>&json={"group": "Administrators"}`
2. `civicrm/v3/url` - a substitution for `civicrm/extern/url.php` to track when links in mailings are clicked.
3. `civicrm/v3/open` - a substitution for `civicrm/extern/open.php` to track when recipients open mailings.
4. `civicrm/v3/authorizeIPN` - a substitution for `civicrm/extern/authorizeIPN.php` (for testing Authorize.net as per [docs](https://docs.civicrm.org/sysadmin/en/latest/setup/payment-processors/authorize-net/#shell-script-testing-method))
**_Note_**: this endpoint has **not been tested**
5. `civicrm/v3/ipn` - a substitution for `civicrm/extern/ipn.php` (for PayPal Standard and Pro live transactions)
**_Note_**: this endpoint has **not been tested**
6. `civicrm/v3/cxn` - a substitution for `civicrm/extern/cxn.php`
7. `civicrm/v3/pxIPN` - a substitution for `civicrm/extern/pxIPN.php`
**_Note_**: this endpoint has **not been tested**
8. `civicrm/v3/widget` - a substitution for `civicrm/extern/widget.php`
9. `civicrm/v3/soap` - a substitution for `civicrm/extern/soap.php`
**_Note_**: this endpoint has **not been tested**
## Settings
It is recommened to use the hook included in the code to replace the mailing url via the WP REST API. To do this create a plugin that includes the following:
```php
add_filter( 'civi_wp_rest/plugin/replace_mailing_tracking_urls', '__return_true' )
```
Creating a standalone functionality plugin is recommended. You can read the [WP docs on Writing a plugin](https://codex.wordpress.org/Writing_a_Plugin), there is a good tutorial on a [Functionality Plugin at ccs-tricks](https://css-tricks.com/wordpress-functionality-plugins/)
Alternatively, but not recommended. you can set the `CIVICRM_WP_REST_REPLACE_MAILING_TRACKING` constant to `true` to replace mailing url and open tracking calls with their counterpart REST endpoints, `civicrm/v3/url` and `civicrm/v3/open`.
_Note: use this setting with caution, it may affect performance on large mailings, see `CiviCRM_WP_REST\Civi\Mailing_Hooks` class._
# APIv4 Actions
Most entities support the following actions:
With a few exceptions, most API Entities support a basic set of _CRUD_ (create, read, update, delete) actions,
along with some _metadata_ actions to retrieve information about the structure of the entity.
## Create
!!! tip "API Explorer"
The easiest way to see which actions are available for each entity is to browse the [**API Explorer**](../api/#api-explorer),
which shows all available entities, their actions, and the parameters for each action.
Insert new records into the database.
*Most entities support the following actions:*
## Update
## Read Actions
Update records in the database.
* **`get`**
## Delete
Search for records using SQL-like parameters (`select`, `where`, `having`, `join`, `orderBy`, `limit`).
For most entities, `get` includes advanced features such as [joins](explicit-joins.md).
Delete one or more records. Requires an explicit `id`. If you want to skip the 'recycle bin' for entities that support undelete (e.g. contacts) you should set `$param['skip_undelete'] => 1);`
* **`autocomplete`**
## Get
Used to populate EntityReference autocomplete results, this action calls `SearchDisplay::run`
which in turn calls the `get` action.
Search for records
* **`export`**
## GetFields
Available only for [Managed Entity](managed.md) types, outputs code which can be used to package and distribute a record in an extension.
Fetch entity metadata, i.e. the list of fields supported by the entity. There is now an option that you can pass in for get fields which is `loadOptions`. This is the equivilant of the apiv3 getoptions API call. When used for any field that specifies a pseudoconstant it will return the relevant options in an options key. You can also pass in an option `IncludeCustom` which will specifiy whether to include the relevant custom fields for that entity or not.
## Write Actions
## Replace
* **`create`**
Replace an old set of records with a new or modified set of records. (For example, replace the set of "Phone" numbers with a different set of "Phone" numbers.).
Insert a single new record into the database.
* **`update`**
Update one or more existing records with new values. If an `id` is not supplied, then query params are required to search for records to update.
* **`save`**
Given an array of records, either `create` or `update` each one. By default the presence of an `id` determines whether an existing record will be updated.
The `match` param gives finer control over this, and lets you specify one or more fields; if a single existing record matches *all* of them, it will be updated instead of a new record created. For example you can `save` an array of contacts and specify
`['external_id']` as the `match` param, which will update contacts with matching `external_id`s.
* **`delete`**
Delete one or more records based on query parameters. Some entities, including `Contact`, implement "Soft Delete", in which case the `delete` action's default behavior is to give records an intermediate "trashed" status. For these entities, set `useTrash = FALSE` to delete records permanently.
* **`replace`**
Replace an existing set of records with a new or modified set of records. For example, replace a group of `Phone` numbers for a given `Contact`.
!!! warning
Replace includes an implicit delete action - use with care & test well before using in production.
## Save
* **`revert`**
Available only for [Managed Entity](managed.md) types, resets a record to its original packaged state.
## Metadata Actions
* **`checkAccess`**
Check if current user is authorized to perform a specified action on a given record.
* **`getActions`**
Returns a list of actions avaiable for a given entity.
* **`getFields`**
Fetch the list of fields supported by the entity, including [custom fields](custom-data.md).
Optionally load the [option-lists](pseudoconstants.md) for fields.
## Other Entity-Specific Actions
Create or update one or more records
Some entities provide extra actions. For example, `Afform::submit` or `SearchDisplay::run`.
To discover all available actions for an entity, use the `getActions` API action.
\ No newline at end of file
# APIv4 Architecture
*This guide is intended for anyone wishing to extend the CiviCRM API itself, either in core or in their own extension.*
!!! tip "Example extension"
As you read this, you can also follow-along with a live demo in the API Explorer by installing the [APIv4 Example Extension](https://lab.civicrm.org/extensions/api4example/).
## API Entity Classes
Every API entity is a class which inherits from [`\Civi\Api4\Generic\AbstractEntity`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/AbstractEntity.php). Each class serves the following purposes:
1. Declare the API entity by its existence.
- You can declare a new API (e.g. FooBar) simply by placing the class `\Civi\Api4\FooBar` in the `/Civi/Api4` directory of your extension, as long as it inherits from `\Civi\Api4\Generic\AbstractEntity`.
2. Provide factory functions for that entity's **Actions**.
3. A `getInfo` function which returns an array of metadata about the entity. In most cases `getInfo` from the base class does not need to be overridden.
4. An optional function `permissions`. This function should contain any specific permissions or overrides to the `meta` or `default` permissions necessary for the entity.
The function must return an array in a [suitable format](../../security/permissions.md#apiv4). The following example would allow the `get` action to anyone with `access CiviEntity` permission, and also shows how to override `meta` and `default` permissions:
```php
return [
// for meta actions e.g. getActions, getFields etc
'meta' => [<some permission>]
// To be used for all actions where there isn't a specific permission set
'default' => [<some permission>],
'get' => ['access CiviEntity'],
];
```
Further information on permissions is defined in the [security chapter](../../security/permissions.md#apiv4).
## API Action Classes
Every API action is a class which inherits from [`\Civi\Api4\Generic\AbstractAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/AbstractAction.php). It has two functions:
1. Store the parameters of the API call.
- Every `protected` class var is considered a parameter (unless it starts with an underscore).
- The `$version` parameter refers to the API version (4) and cannot be changed.
- The `$_entityName` and `$_actionName` vars are set when the Action object is constructed (by the Entity class factory fn, see above). The underscore makes them hidden parameters as they cannot be changed.
- Adding a `protected` var to your Action named e.g. `$thing` will automatically:
- Provide a getter/setter (via `__call` MagicMethod) named `getThing()` and `setThing()`.
- Expose the param in the API Explorer (be sure to add a doc-block as it displays in the help panel).
- Require a value for the param if you add the `@required` annotation.
2. Define a `_run()` function to execute the call and return the results.
- The `_run()` function is invoked by `execute()`
- It gets passed a `Result` object into which it places an array of values to be returned.
## The Result Class
An API [`Result`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/Result.php) is a PHP ArrayObject. It has three functions:
1. Store the results of the API call (accessible via ArrayAccess).
2. Store metadata like the Entity & Action names.
- Some actions extend the Result object to store extra metadata. For example [`BasicReplaceAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicReplaceAction.php) returns [`\Civi\Api4\Result\ReplaceResult`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Result/ReplaceResult.php) which includes the additional `$deleted` property to list any items deleted by the operation.
3. Provide convenience methods like `$result->first()` and `$result->indexBy($field)`.
## Class Inheritance
![Inheritance](../../img/api4/inheritance-community-chest.jpg)
To reduce code duplication and enforce consistency, APIv4 uses PHP class inheritance extensively.
Compare these (slightly simplified) examples:
<!-- Would be nice if Markdown made it easier to do side-by-side comparison... -->
<table>
<thead>
<tr>
<th>APIv3 Website.php</th>
<th>APIv4 Website.php</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<pre class="codehilite">
function civicrm_api3_website_get($params) {
return _civicrm_api3_basic_get('Website', $params);
}
function civicrm_api3_website_create($params) {
return _civicrm_api3_basic_create('Website', $params);
}
function civicrm_api3_website_delete($params) {
return _civicrm_api3_basic_delete('Website', $params);
}
</pre>
</td>
<td>
<pre class="codehilite">
namespace Civi\Api4;
class Website extends Generic\DAOEntity {
}
</pre>
</td>
</tr>
</tbody>
</table>
*Website* is a typical CRUD API using generic functions to perform actions on the `civicrm_website` table.
The v3 file needed a function for each action, resulting in a lot of duplicate code across API files.
By taking advantage of class inheritance, APIv4 reduces this boilerplate to nothing; factory functions for the standard set of actions are inherited from `Civi\Api4\Generic\DAOEntity`.
### Entity Base Classes
![Entity Inheritance Diagram](../../img/api4/APIv4-entity-inheritance.svg)
There are three ways to implement an APIv4 entity:
1. **Extend DAOEntity:** for entities with a database table and `DAO` class. E.g. the *Contact* API entity corresponds to the
`CRM_Conatact_DAO_Contact` class and the `civicrm_contact` database table.
They extend from [`Civi\Api4\Generic\DAOEntity`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOEntity.php)
and thus inherit the standard set of DAO actions.
2. **Extend BasicEntity:** to start with a [basic set of CRUD actions](architecture/#basic-actions),
use [`Civi\Api4\Generic\BasicEntity`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicEntity.php)
as the base class. You do not need a DAO or even a database table for this type of entity; just supply a php
function to read, write and delete records and the API will handle CRUD functionality.
3. **Extend AbstractEntity:** for the most flexible type of entity use the [`\Civi\Api4\Generic\AbstractEntity`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/AbstractEntity.php) class directly.
This gives you the flexibility to implement any actions, using any datasource.
These APIs are not required to implement any action except `GetFields`.
See the [APIv4 example extension](https://lab.civicrm.org/extensions/api4example/) for a working demonstration.
### Action Class Hierarchy
To standardize parameter names and reduce code duplication, each action class inherits from an abstract parent.
![Action Inheritance Diagram](../../img/api4/APIv4-action-inheritance.svg)
### DAO Actions
All DAO entities provide factory functions for
[`DAOGetFieldsAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOGetFieldsAction.php),
[`DAOGetAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOGetAction.php),
[`DAOCreateAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOCreateAction.php),
[`DAOUpdateAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOUpdateAction.php),
[`DAOSaveAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAOSaveAction.php),
[`DAODeleteAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/DAODeleteAction.php), and
[`BasicReplaceAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicReplaceAction.php).
The Get action uses schema metadata to query the database and perform joins with other DAO entities. The Create, Delete, Save & Update actions call the core BAO methods to ensure hooks are invoked when writing to the database.
In most cases the action classes are used as-is, but it's also possible to override a DAO action to add/modify parameters or functionality.
It is also possible to add other ad-hoc actions to any entity;
e.g. [`Contact::getChecksum`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Action/Contact/GetChecksum.php) is an ad-hoc action added to the Contact entity.
### Building Your Own Actions
You can add arbitrary actions to any entity simply by defining a class which extends [`AbstractAction`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/AbstractAction.php)
or one of the Basic actions.
#### AbstractAction
[**`AbstractAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/AbstractAction.php)
is the base class for all API actions. Every action must, at minimum, extend this class.
For example, the [`Example::random()`](https://lab.civicrm.org/extensions/api4example/blob/master/Civi/Api4/Action/Example/Random.php) action extends this class directly.
Your custom action will define parameters as protected class properties, and implement a `_run` function to execute the action.
Before extending `AbstractAction` directly, consider if your action could benefit from the features provided by one of the Basic actions:
#### Basic Actions
These classes provide a framework for building custom API actions.
They are all used by the [`Civi\Api4\Generic\BasicEntity`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicEntity.php) class.
See the [Example entity](https://lab.civicrm.org/extensions/api4example/) for a working demonstration.
Each basic action is implemented by supplying a callback function to perform logic and return data;
the basic action class handles details like validating param input and formatting & filtering the result.
Basic Actions are designed to be used in 1 of 2 ways:
1. Your Entity's action function can construct the basic action directly, passing the callback into the constructor.
2. You can override the basic action class (e.g. for customizing the parameters). See [`Example::create()`](https://lab.civicrm.org/extensions/api4example/blob/master/Civi/Api4/Action/Example/Create.php).
- [**`BasicGetAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicGetAction.php):
Used to build actions whose purpose is fetching records. Parameters are `select`, `where`, `offset`, `limit`, and `orderBy`.
Its built-in array-query engine automatically filters/sorts the raw data returned by your callback according to the parameters.
Normally your callback can simply return an array of all existing records, but if performance is a concern, the functions `_itemsToGet()` and `_isFieldSelected()` can help you optimize your callback to only return results that are needed.
- [**`BasicCreateAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicCreateAction.php):
Used to create a new record. Parameters are `values`. Values will be passed into the callback via `writeRecord`, or you can override the `writeRecord` method in your custom create class.
See [`Example::create()`](https://lab.civicrm.org/extensions/api4example/blob/master/Civi/Api4/Action/Example/Create.php).
- [**`BasicUpdateAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicUpdateAction.php):
Used to update records based on a search query. Parameters are `values`, `reload`, `where`, `offset`, `limit`, and `orderBy`.
Internally calls `Get` to obtain records to update, so your entity must implement a get action.
Each will be passed into the callback via `writeRecord`, or you can override the `writeRecord` method in your custom update class.
- [**`BasicSaveAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicSaveAction.php):
Used to create or update multiple records. Parameters are `records`, `defaults`, and `reload`.
Each will be passed into the callback via `writeRecord`, or you can override the `writeRecord` method in your custom save class.
- [**`BasicBatchAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicBatchAction.php):
Used to perform an action on records based on a search query. Use this class, for example, to implement Delete.
Parameters are `where`, `offset`, `limit`, and `orderBy`.
Internally calls `Get` to obtain records, so your entity must implement a get action.
Each will be passed into the callback via `doTask`, or you can override the `doTask` method in your custom batch class.
`Delete` actions can implement the [`SoftDelete`](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/Traits/SoftDelete.php ) trait and default to marking records as "trashed" rather than permanently deleting them.
- [**`BasicReplaceAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicReplaceAction.php):
Used to replace a set of records. Parameters are `records`, `default`, `reload`, `where`, `offset`, `limit`, and `orderBy`.
Internally calls `Get` to obtain records and `Save` to write them, so your entity must implement those actions.
- [**`BasicGetFieldsAction`**](https://github.com/civicrm/civicrm-core/blob/master/Civi/Api4/Generic/BasicGetFieldsAction.php):
Metadata action returns a list of fields for your entity.
# APIv4 Chaining
It is possible to do two API calls at once with the first call feeding into the second. E.g. to create a contact with a contribution you can nest the contribution create into the contact create. Once the contact has been created it will action the contribution create using the id from the contact create as `contact_id`. Likewise you can ask for all activities or all contributions to be returned when you do a `get`.
Chaining lets you perform multiple API calls at once with the results of the outer call triggering additional api calls.
E.g. to create a contact with a contribution you can nest the contribution create into the contact create. Likewise you can ask for all activities or all contributions to be returned from `Contact::get`.
Note that there are a few supported syntaxes:
!!! tip "Chaining or Joins"
Chained API calls execute once per result. This can be very slow if the outer API call returns hundreds of records.
In that case, consider if you can achieve your goal using [Implicit](implicit-joins.md) or [Explicit Joins](explicit-joins.md) instead.
Object Oriented way
## Supported Syntaxes:
**Object Oriented:**
```php
$results = \Civi\Api4\Contact::create()
->addValue('contact_id', 'Individual')
->addValue('contact_type', 'Individual')
->addValue('display_name', 'BA Baracus')
->addChain('create_website', \Civi\Api4\Website::create()->setValues(['contact_id' => '$id', 'url' => 'example.com']))
->execute();
```
Traditional:
**Traditional:**
```php
civicrm_api('Contact', 'create', [
......@@ -29,33 +34,28 @@ civicrm_api('Contact', 'create', [
]);
```
If you have 2 websites to create you can pass them as separate key => array pairs just specify a unique array key in the chain array
If you have 2 websites to create you can pass them as separate key => array pairs; just specify a unique array key in the chain array.
Object Oriented way
```php
$results = \Civi\Api4\Contact::create()
->addValue('contact_id', 'Individual')
->addValue('display_name', 'BA Baracus')
\Civi\Api4\Contact::create()
->addChain('first_website', \Civi\Api4\Website::create()->setValues(['contact_id' => '$id', 'url' => 'example1.com']))
->addChain('second_website', \Civi\Api4\Website::create()->setValues(['contact_id' => '$id', 'url' => 'example2.com']))
->execute();
...
```
Traditional:
```php
civicrm_api('Contact', 'create', [
'version' => 4,
'values' => [
'contact_type' => 'Individual',
'display_name' => 'BA Baracus',
],
civicrm_api4('Contact', 'create', [
'chain' => [
'create_first website', ['Website', 'create', ['values' => ['url' => 'example1.com', 'contact_id' => '$id']]],
'create_second_website', ['Website', 'create', ['values' => ['url' => 'example2.com', 'contact_id' => '$id']]],
'first website', ['Website', 'create', ['values' => ['url' => 'example1.com', 'contact_id' => '$id']]],
'second_website', ['Website', 'create', ['values' => ['url' => 'example2.com', 'contact_id' => '$id']]],
],
]);
...
```
Note the use of "$id" in the examples above - any field returned by the outer call can be passed down to a chained call by prefixing it with a dollar sign. Even the results of other chains can be accessed in this way.
## Back-references
Note the use of `'$id'` in the examples above. Any field returned by the outer call can be passed down to a chained call by prefixing it with a dollar sign. Even the results of other chains can be accessed in this way.
# API v4 Changelog
# APIv4 Changelog
This page lists additions to the v4 api with each new release of CiviCRM Core.
*This page lists major or breaking changes to APIv4 with each new release of CiviCRM Core. Other update notes can be found elsewhere:*
Also see: [Differences Between Api v3 and v4](/api/v4/differences-with-v3.md).
- To find out the version an APIv4 entity was added, check the `@since` annotation at the top of the file, or in the help box of the Explorer.
- Detailed APIv4 changes not listed here are available in the [release notes for each version](https://lab.civicrm.org/dev/core/-/tree/master/release-notes).
- Also see: [Differences Between Api v3 and v4](../v4/differences-with-v3.md) and [Hooks Changelog](../../hooks/changes.md).
## Nothing here yet.
## CiviCRM 5.64
API v4 is brand new. No changes yet!
If using `Workflow.render` api (or the not-supported-for-external-use functions `CRM_Core_BAO_MessageTemplate::sendMessage`)
the ids in the `WorkflowMessage` (model) properties (variously called 'values' or 'modelProps') now use consistent non-freudian casing.
They are standardised on `contactID` rather than `contactId` etc. The `tokenProperties` still use freud-case (id rather than ID).
## CiviCRM 5.54
### 5.54 Autocomplete action added
This API action is used with Entity Autocomplete inputs, which replace the APIv3-based EntityRef widgets.
## CiviCRM 5.45
### 5.45 ManagedEntity trait added with `export` and `revert` actions
For details see [managed entity](https://github.com/civicrm/civicrm-core/pull/21955) and [export action](https://github.com/civicrm/civicrm-core/pull/22014) pull requests.
### 5.45 Contact::delete uses trash by default
For details see [pull request](https://github.com/civicrm/civicrm-core/pull/21232) and documentation on [write actions](../v4/actions.md#write-actions) and [basic actions](../v4/architecture.md#basic-actions).
### 5.45 SortableEntity trait added with auto-weight management
For details see [pull request](https://github.com/civicrm/civicrm-core/pull/22137).
### 5.45 Navigation entity treats `permission` field as array rather than string
For details see [pull request](https://github.com/civicrm/civicrm-core/pull/22160).
### 5.45 RelationshipCache entity now has `case_id` column
For details see [pull request](https://github.com/civicrm/civicrm-core/pull/21845).
## CiviCRM 5.43
### 5.43 Only fields declared in `getFields` returned by default.
Every API must declare a `getFields` action to define what fields are returned; as of 5.43 this list is used more strictly: When using SELECT(*) or ommitting SELECT, only declared fields of type "Field" will be returned. See [pull-request](https://github.com/civicrm/civicrm-core/pull/21438) for details.
### 5.43 Virtual entities supported via event in Entity::get.
It's now possible to define ad-hoc or virtual entities without their own DAO. See [pull-request](https://github.com/civicrm/civicrm-core/pull/21803) for details.
## CiviCRM 5.38
### 5.38 Implicit join syntax changed, old syntax deprecated.
As of 5.38 the API supports the syntax `contact_id.display_name` and the old `contact.display_name` is deprecated. See [pull request](https://github.com/civicrm/civicrm-core/pull/20130) for details.
## CiviCRM 5.29
### 5.29 Added `target_contact_id` and `assignee_contact_id` to `Activity.create` in the API explorer.
Each can take an array of contact IDs. This feature existed before version 5.29.0 but was previously not discoverable in the explorer.
For more information see the [commit to CiviCRM Core](https://github.com/civicrm/civicrm-core/commit/8c6a5fd64b).
### 5.29 Shortcut for setting checkPermissions e.g. `Contact::get(FALSE)`
For more information see the following [pull request](https://github.com/civicrm/civicrm-core/pull/17834).
## CiviCRM 5.23
### 5.23 `$index` param supports array input
CiviCRM 5.23 supports two new modes for the `$index` param - associative and non-associative array. See [CiviCRM Core PR #16257](https://github.com/civicrm/civicrm-core/pull/16257)
### 5.23 Converts field values to correct data type
The api historically returns everything as a raw string from the query instead of converting it to the correct variable type (bool, int, float). As of CiviCRM 5.23 this is fixed for all DAO-based entities. See [CiviCRM Core PR #16274](https://github.com/civicrm/civicrm-core/pull/16274)
### 5.23 Selects only relevant contact fields by default
The Contact entity in CiviCRM is divided into 3 major types: Individuals, Households and Organizations.
Not all contact fields apply to all contact types, e.g. the `sic_code` field is only used by Organizations,
and the `first_name` and `last_name` fields are only used by Individuals.
In CiviCRM 5.23 the schema has been augmented with metadata about which fields belong to which contact type, and Api4 now uses this
metadata to select only relevant fields. E.g. fetching a household with the api will not return the `first_name` or `organization_name` fields
as those will always be `null`.
### 5.23 Get actions support selecting fields by * wildcard
The `select` param now supports the `*` wildcard character for matching field names.
See [CiviCRM Core PR #16302](https://github.com/civicrm/civicrm-core/pull/16302).
### 5.23 Delete/Update do not throw error when 0 items found
For consistency across all "batch-style" actions that update/delete records based on a query,
the `Delete` and `Update` actions now simply return an empty result if no matches are found to act upon.
Previously they would throw an exception, which was similar to APIv3 behavior but inconsistent with other
APIv4 batch actions and SQL in general. See [CiviCRM Core PR #16374](https://github.com/civicrm/civicrm-core/pull/16374).
# APIv4 and Custom Data
CiviCRM has a flexible custom data system which allows nearly any entity to be extended. It comes in two distinct flavors: Single-record and Multi-record. For more background see the user guide chapter: [Creating Custom Fields](https://docs.civicrm.org/user/en/latest/organising-your-data/creating-custom-fields/).
CiviCRM has a flexible custom data system which allows nearly any entity to be extended by one or more custom groups. Custom groups come in two distinct flavors: Single-record and Multi-record.
For more background see the user guide chapter: [Creating Custom Fields](https://docs.civicrm.org/user/en/latest/organising-your-data/creating-custom-fields/).
## Single-Record Custom Data
Because single-record fields extend an entity 1-to-1, the API treats the custom fields as an extension of the regular fields. For example, normally an Event has fields like `id`, `title`, `start_date`, `end_date`, etc. Adding a custom group named "Event_Extra" and a field named "Room_number" would be accessible from the API as "Event_Extra.Room_number". You would retrieve it and set it as if it were any other field. Note that the `name` of a field is not to be confused with the `label` The API refers to custom groups/fields by name and not user-facing labels which are subject to translation and alteration.
Because single-record groups extend an entity 1-to-1, the API treats these custom fields as an extension of an entity's regular fields.
For example, normally an Event has fields like `id`, `title`, `start_date`, `end_date`, etc.
Adding a custom group named "Event_Extra" and a field named "Room_number" would be accessible from the API as `Event_Extra.Room_number`.
You would retrieve it and set it as if it were any other field.
!!! note "Implied Join"
Notice that the field name includes a dot, which is similar to the [implicit join syntax](implicit-joins.md).
Internally, the API adds joins to the query to fetch custom data from the appropriate tables.
!!! tip "Field Names"
The `name` of a field is not to be confused with the `label`. The API refers to custom groups/fields by name and not user-facing labels which are subject to translation and alteration.
### Filtering Custom Fields with options
Custom fields with options (select list, checkbox or radio) serialize the selected options in the database. When adding a `where` clause with the API, use `CONTAINS` rather than `IN` or `=`; in fact, the latter two will not work. This is unintuitive but filtering this way is much faster. The API is aware of the field serialization method so will avoid overlapping keys. And it automatically adds the value delimiters so there aren't false positives. For example, searching for an option named `color` will *not* return another option named `coloringbook`.
## Multi-Record Custom Data
......@@ -13,17 +28,17 @@ Multiple record custom data sets are treated by the API as entities, which work
**PHP (traditional):**
```php
civicrm_api4('Custom_Work_History', 'create', [
'values': ['entity_id': 202, 'Test_Field': 555]
'values' => ['entity_id' => 202, 'Test_Field' => 555],
]);
```
**Javascript:**
```javascript
CRM.api4('Custom_Work_History', 'create', {
values: {"entity_id":202, "Test_Field":555}
values: {entity_id: 202, Test_Field: 555}
});
```
**PHP (OO):** Note that the object-oriented style uses the `CustomValue` class:
**PHP (OO):** Note that the object-oriented style uses the `CustomValue` class and passes in the name of the custom group (without a `Custom_` prefix):
```php
\Civi\Api4\CustomValue::create('Work_History')
......@@ -31,6 +46,43 @@ CRM.api4('Custom_Work_History', 'create', {
->addValue('Test_Field', 555)
->execute();
```
## Wildcards
Get actions support wildcards in the SELECT clause, allowing you to select all fields from a custom group, or even all custom data for a given entity type.
### Get all fields from single-record group
```php
civicrm_api4('Contact', 'get', [
'select' => ['my_custom_group.*']
]);
```
### Get all core and custom fields
```php
civicrm_api4('Contact', 'get', [
'select' => ['*', 'custom.*']
]);
```
!!! warning "Warning: Join Limit"
Every custom group adds a join to the query. If a site contains a large number of custom groups,
this could potentially reach MySql's 61 join limit, causing a fatal error.
Therefore, selecting `custom.*` should only be done if the number of custom groups is known.
### Get all fields from multi-record group
This example uses an [explicit join](explicit-joins.md):
```php
civicrm_api4('Contact', 'get', [
'join' => [
['Custom_my_multi_group AS my_multi', 'LEFT'],
],
'select' => ['my_multi.*'],
]);
```
## Field Types and I/O Formats
......@@ -41,4 +93,7 @@ New custom fields can be configured to store different types of data (Text, Date
## Try It Out
Once you have created some custom data in your system, look for it in the API Explorer. Single-record data will appear as fields on the entities they extend, and multi-record data will appear in the list of entities (look under "C" alphabetically as they all start with the prefix "Custom_".
Once you have created some custom data in your system, look for it in the API Explorer. Single-record data will appear as fields on the entities they extend, and multi-record data will appear in the list of entities.
!!! tip "Finding Custom Entities"
In the Api Explorer look for your multi-record custom entities under "C" alphabetically as they all start with the prefix "Custom_".
......@@ -22,7 +22,7 @@ them, it may help to have a concrete example expressed in both APIv3 and APIv4:
<div class="codehilite"><pre>
1: $res = civicrm_api3('Contact', 'get', [
2: 'sequential' => 1,
3: 'check_permissions' => 0,
3: 'check_permissions' => 0, // default
4: 'first_name' => 'Bob',
5: 'return' => 'id,display_name',
6: 'options' => [
......@@ -39,84 +39,49 @@ them, it may help to have a concrete example expressed in both APIv3 and APIv4:
<td>
<em>Procedural-array style:</em><br/>
<div class="codehilite"><pre>
1: $res = civicrm_api4('Contact', 'get', [
1: $result = civicrm_api4('Contact', 'get', [
2: 'checkPermissions' => FALSE,
3: 'where' => [['first_name', '=', 'Bob']],
4: 'select' => ['id', 'display_name'],
&nbsp;
6: 'limit' => 2,
7: 'offset' => 2,
&nbsp;
9: ]);
10:
11: foreach ($res as $row) {
12: echo $row['display_name'];
13: }
5: 'limit' => 2,
6: 'offset' => 2,
7: ]);
8:
9: foreach ($result as $row) {
10: echo $row['display_name'];
11: }
</pre></div>
<em>Object-oriented style:</em><br/>
<div class="codehilite"><pre>
1: $res = \Civi\Api4\Contact::get()
1: $result = \Civi\Api4\Contact::get()
2: ->setCheckPermissions(FALSE)
3: ->addWhere(['first_name', '=', 'Bob'])
4: ->addSelect(['id', 'display_name'])
&nbsp;
6: ->setLimit(2)
7: ->setOffset(2)
&nbsp;
9: ->execute();
10:
11: foreach ($res as $row) {
12: echo $row['display_name'];
13: }
5: ->setLimit(2)
6: ->setOffset(2)
7: ->execute();
8:
9: foreach ($result as $row) {
10: echo $row['display_name'];
11: }
</pre></div>
</td>
</tr>
</tbody>
</table>
## API Wrapper
* APIv4 supports two notations in PHP:
* Procedural/array style: `civicrm_api4('Entity', 'action', $params)`
* Object-oriented style: `\Civi\Api4\Entity::action()->...->execute()`
* When using OOP style in an IDE, most actions and parameters can benefit from auto-completion and type-checking.
* `$checkPermissions` always defaults to `TRUE`. In APIv3, the default depended on the environment (`TRUE` in REST/Javascript; `FALSE` in PHP).
* A 4th param `index` controls how results are returned:
* Passing a string will index all results by that key e.g. `civicrm_api4('Contact', 'get', $params, 'id')` will index by id.
* Passing a number will return the result at that index e.g. `civicrm_api4('Contact', 'get', $params, 0)` will return the first result and is the same as `\Civi\Api4\Contact::get()->execute()->first()`. `-1` is the equivalent of `$result->last()`.
* When chaining API calls together, back-references to values from the main API call must be explicitly given (discoverable in the API Explorer).
## Actions
* For `Get`, the default `limit` has changed. If you send an API call without an explicit limit, then it will return *all* records. (In v3, it would silently apply a default of 25.) However, if you use the API Explorer, it will *recommend* a default limit of 25.
* The `Create` action is now only used for creating *new* items (no more implicit update by passing an id to v3 `create`).
* The `Save` action in v4 is most similar to v3's `create` - it accepts one or more records to create or update, infering the action based on the presence of `id` in each record.
* `Update` and `Delete` can be performed on multiple items at once by specifying a `where` clause, vs a single item by id in v3.
* `getsingle` is gone, use `$result->first()` or `index` `0`.
* `getoptions` is no longer a standalone action, but part of `getFields`.
## Output
* Output is an object (`Result` aka [`ArrayObject`](https://www.php.net/manual/en/class.arrayobject.php)) rather than a plain `array`.
* In PHP, you can iterate over the `ArrayObject` (`foreach ($myResult as $record)`), or you can call methods like `$result->first()` or `$result->indexBy('foo')`.
* By default, results are indexed sequentially (`0,1,2,3,...` - like APIv3's `sequential => 1`). You may optionally index by `id`, `name`, or any other field, as in:
* (Procedural-style; use `$index` parameter): `civicrm_api4('Contact', 'get', [], 'id')`
* (OOP-style; use `indexBy()` method): `\Civi\Api4\Contact::get()->execute()->indexBy('id')`
## Input
* Instead of a single `$params` array containing a mishmash of fields, options and parameters, each APIv4 parameter is distinct (see section on Params below).
* Custom fields are refered to by name rather than id. E.g. use `constituent_information.Most_Important_Issue` instead of `custom_4`.
APIv4 reflects the ongoing efforts present through the lifecycle of APIv3 toward uniform and discreet input parameters.
## Params
If you used early versions of APIv3, you might have written some code like this:
For a little history... If you used early versions of APIv3, you might have written some code like this:
```php
civicrm_api3('Contact', 'get', array(
'check_permissions' => 0,
'first_name' => 'Elizabeth',
'return' => 'id,display_name',
'rowCount' => 2,
'rowCount' => 1000,
'offset' => 2,
));
```
......@@ -154,7 +119,7 @@ civicrm_api4('Contact', 'get', [
'checkPermissions' => FALSE,
'where' => [['first_name', '=', 'Elizabeth']],
'select' => ['id', 'display_name'],
'limit' => 2,
'limit' => 1000,
'offset' => 2,
]);
```
......@@ -162,5 +127,36 @@ civicrm_api4('Contact', 'get', [
Key things to note:
* The `options` array is completely gone. The params array *is* the list of options.
* Most of the options in the params array have shared/generic implementations - ensuring consistent naming and behavior.
* The *data* fields (e.g. `id`, `display_name`, and `first_name`) no longer appear at the top. They always appear beneath some other option, such as `where` or `select`.
* Most items in the params array have shared/generic implementations - ensuring consistent naming and behavior for every api entity.
* The *data* fields (e.g. `id`, `display_name`, and `first_name`) no longer appear at the top. They always appear beneath some other param, such as `where` or `select`.
* In APIv3, it was possible (but deprecated) to call the API using a lower-case entity name (eg activity.get). This behavior has been removed in APIv4 and using lower-case entity names will cause an error. Use the proper CamelCase representation of the Entity name when making API calls.
## API Wrapper
* APIv4 supports two notations in PHP:
* Procedural/array style: `civicrm_api4('Entity', 'action', $params)`
* Object-oriented style: `\Civi\Api4\Entity::action()->...->execute()`
* When using OOP style in an IDE, most actions and parameters can benefit from auto-completion and type-checking.
* `$checkPermissions` always defaults to `TRUE`. In APIv3, the default depended on the environment (`TRUE` in REST/Javascript; `FALSE` in PHP).
* Instead of APIv3's `sequential` param, a more flexible `index` controls how results are returned. In traditional style is is the 4th parameter to the api function:
* Passing a string will index all results by that key e.g. `civicrm_api4('Contact', 'get', $params, 'id')` will index by id.
* Passing a number will return the result at that index e.g. `civicrm_api4('Contact', 'get', $params, 0)` will return the first result and is the same as `\Civi\Api4\Contact::get()->execute()->first()`. `-1` is the equivalent of `$result->last()`.
* When [chaining](../v4/chaining.md) API calls together, back-references to values from the main API call must be explicitly given (discoverable in the API Explorer).
## Actions
* For `get`, the default `limit` has changed. If you send an API call without an explicit limit, then it will return *all* records. (In v3, it would silently apply a default of 25.) However, if you use the API Explorer, it will *recommend* a default limit of 25.
* The `create` action is now only used for creating *new* items (no more implicit update by passing an id to v3 `create`).
* The `save` action in v4 is most similar to v3's `create`, with the difference that it takes an array of one or more records instead of a single record. Like APIv3's `create`, it infers the action based on the presence of `id` in each record.
* `Update` and `Delete` can be performed on multiple items at once by specifying a `where` clause, vs a single item by id in v3.
Unlike v3, they will not complain if no matching items are found to update/delete and will return an empty result instead of an error.
* `getsingle` is gone, use `$result->first()` or `index` `0`.
* `getoptions` is no longer a standalone action, but part of `getFields`.
* `replace` requires at least one value; if there are no values to replace, use `delete`.
## Output
* `Result` is an [`ArrayObject`](https://www.php.net/manual/en/class.arrayobject.php) rather than a plain `array`.
* In PHP, you can iterate over the `ArrayObject` (`foreach ($myResult as $record)`), or you can call methods like `$result->first()` or `$result->indexBy('foo')`.
* By default, results are indexed sequentially (`0,1,2,3,...` like APIv3's `sequential => 1`). You may optionally index by `id`, `name`, or any other field, as in:
* (Procedural-style; use `$index` parameter): `civicrm_api4('Contact', 'get', [], 'id')`
* (OOP-style; use `indexBy()` method): `\Civi\Api4\Contact::get()->execute()->indexBy('id')`
* Custom fields are refered to by name rather than id. E.g. use `constituent_information.Most_Important_Issue` instead of `custom_4`.
# APIv4 Explicit Joins
In a relational database, you often need to work with data from multiple entities (tables) at once.
If the simpler notations for [implicit join](implicit-joins.md) or [option transformation](pseudoconstants.md)
don't meet a need, you can use the explicit syntax to indicate exactly how 2 tables should be joined.
!!! note "Get Only"
Unlike the [implicit join](implicit-joins.md) and [option transformation](pseudoconstants.md)
syntaxes which work for both read and write operations, explicit joins only work for `get` actions.
!!! tip "Joins or Chaining"
There is some overlap between joins and [Chaining](chaining.md); in some cases either technique can accomplish the same thing.
Because chaining executes a new query for every result, joins are usually more efficient when given a choice between the two.
## Specifying a Join
An explicit join is defined as an array with the following properties:
1. `EnityName AS alias` - the alias can be any string of your choosing; it will be used as an identifier in other clauses (`ON`, `SELECT`, `WHERE`, `HAVING`, `ORDER BY`)
2. Join type (`LEFT`, `INNER` or `EXCLUDE`)
- **LEFT** joins make the related entity *optional* - rows from the main entity are always returned.
- **INNER** joins make the related entity *required* - rows from the main entity are only returned if the join is found.
- **EXCLUDE** only returns rows from the main entity are only returned if the join is *not* found.
3. `EntityBridge` *(optional)* name of bridge to use (not shown, see following section on EntityBridges)
4. One or more `ON` clause arrays; each is either a single clause with `[expression, operator, expression]`, or a conjunction (`AND`, `OR`, `NOT`) followed by sub-clauses.
```php
// Traditional Syntax:
civicrm_api4('Contact', 'get', [
'join' => [
[
'Participant AS participants', // Entity & alias
'LEFT', // Type of join
NULL, // entity bridge to use
['id', '=', 'participants.contact_id'], // ON clauses...
['participants.status_id:name', '=', "'Attended'"],
],
],
...
```
!!! tip "Quoting Strings in ON Clauses"
Unlike WHERE or HAVING, the ON clause can reference field names on either side of the operator, e.g. 'participants.contact_id'.
To specify a string literal like "Attended", place it in a second set of quotation marks (single or double).
Note that arrays of strings do not need extra quotes, as in the below example:
The OOP syntax has a sugar `addJoin` method which takes the name/alias and side as the first 2 arguments,
then an optional bridge (not shown, see following section on EntityBridges), and a variable number of clauses.
```php
// OOP Syntax:
Civi\Api4\Contact::get()
->addJoin(
'Participant AS participants',
'LEFT',
NULL,
['id', '=', 'participants.contact_id'],
['participants.status_id:name', 'IN', ['Registered', 'Attended']]
)
...
```
!!! note "Specifying 0 Clauses Deprecated"
If you pass 0 clauses to the join (e.g. `'join' => [['Participant AS participants', 'LEFT']]`)
The API will attempt to find an FK between the two entities and automatically add it to the ON clause for you.
Because this can lead to ambiguity and unexpected behavior, it is recommended to always explicitly give the FK fields
in the ON clause of your join, as do the above examples.
## GROUP BY and Aggregation
The relationship between joined entities is not necessarily 1-1. By default this will cause duplicate rows to be returned
for the main entity. For example, an API call to `Contact.get` with a join on `Email` will return the same contact 3 times
if they have 3 email addresses.
This example groups the results by `Contact.id` to return just one row per contact, and aggregates
their email addresses into an array:
```php
civicrm_api4('Contact', 'get', [
'select' => ['display_name', 'GROUP_CONCAT(email.email) AS emails'],
'join' => [
['Email AS email', 'LEFT', ['id', '=', 'email.contact_id']],
],
'groupBy' => ['id'],
...
```
## Using an EntityBridge
An *EntityBridge* is a small table whose primary purpose is to link two other entities together.
They exist because MySQL cannot directly link a row in one table to multiple rows in another.
The EntityBridge solves this by storing a row for every join. For example, a single activity can
have more than one target contact, so the `ActivityContact` stores a row for every `Contact` linked to an `Activity`.
APIv4 allows you to join two entities *through* an EntityBridge with a single join clause. Just add the name of the bridge API
in front of the join clauses:
```php
civicrm_api('Activity', 'get', [
'join' => [
[
"Contact AS target_contacts", // Entity & alias
"LEFT", // Type of join
"ActivityContact", // EntityBridge name
['id', "=", 'target_contacts.activity_id'], // ON clauses...
['target_contacts.record_type_id:name', '=', '"Activity Targets"'],
],
],
...
```
Notice that the ON clause specifies joining directly to the Contact entity, even though the fields
`activity_id` or `record_type_id` actually belong to `ActivityContact`. This is because behind the scenes,
the API combines the two, allowing you to treat the `Contact` entity as if it also has fields
belonging to the `ActivityContact` entity.
# APIv4 Fields
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](pseudoconstants.md)
- In some cases the field may be extended with a `.` [to join to another entity](implicit-joins.md)
- In some cases calculated fields will be exposed
## Calculated Fields
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 `Contribution.total_amount` and `Contribution.tax_amount`.
- 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 `<civi_root>/Civi/Api4/Service/Spec/Provider/*GetSpecProvider.php`
The SpecProvider has 3 main parts:
- the field definition - creating a `FieldSpec` object.
- the `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).
For a Calculated Field to be available through the API, the SpecProvider must be made discoverable. In an extension, one way to do this is to make your SpecProvider extend the `AutoService` interface, and [enable the `scan-classes` mixin](../../../framework/services/#registering-services). When developing an extension, the mixin can be enabled using `civix`:
```bash
civix mixin --enable=scan-classes@1
```
Using `scan-classes` may not be desirable for more complex/heavy extensions. Another way to make the SpecProvider discoverable is to register it individually with the CiviCRM container, with the tag `spec_provider`. For example, inside your extension's implementation of [hook_civicrm_container](../../hooks/hook_civicrm_container.md):
````php
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
function my_ext_civicrm_container(ContainerBuilder $container) {
$class = \Civi\Api4\Service\Spec\Provider\MyFieldGetSpecProvider::class;
$container->setDefinition($class, new Definition($class))
->setPublic(TRUE)
->addTag('spec_provider');
}
````
!!! tip "Hint"
When developing these Calculated Fields, use the debug feature of API4 Explorer to see the generated SQL.
### Calculated Fields in FormBuilder
To make your calculated field available as a filter on a [FormBuilder search form](../../../afform/overview/#afform-types), include an input type. For example:
````php
$field->setInputType('Select')
->setOptions([1 => 'One', 2 => 'Two']);
````
### Entity Refs
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 `Contact.address_primary.city`.
The SQL string defining the join for a reference like this moves to a file in `<civi_root>/Civi/Api4/Event/Subscriber/*SchemaMapSubscriber.php`
For an example, study the implementation of `Contact.address_primary` in `ContactGetSpecProvider.php` and `ContactSchemaMapSubscriber.php`
!!! tip "Reminder"
Note that a cache clear is needed after making changes to the `*SchemaMapSubscriber.php` files.
### 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.source_contact_id`, `Activity.target_contact_id`, `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](https://github.com/civicrm/civicrm-core/pull/23597))
- `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.balance_amount` - balance
- `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
!!! tip "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.
# APIv4 Implicit Joins
In a relational database, you often need to work with data from multiple entities (tables) at once.
APIv4 provides a simple syntax for automatically reading and writing from entities related by a foreign key:
**Read**
*Example: Get the title of an event's campaign to show to the user*
```php
Event::get()
->addSelect('campaign_id.title')
...
```
**Write**
*Example: Create an event linked to a campaign without needing to look up the campaign's ID*
```php
Event::create()
->addValue('campaign_id.name', 'My_Cool_Campaign')
...
```
These are called *implicit* because you do not need to tell the API to join tables, it does so automatically by looking at the foreign key of the `campaign_id` field.
For more complex use-cases, an [*explicit join*](explicit-joins.md) allows a greater flexibility and control for `get` actions.
!!! tip "Joins or Chaining"
There is some overlap between joins and [Chaining](chaining.md); in some cases either technique can accomplish the same thing.
Because chaining executes a new query for every result, joins are usually more efficient when given a choice between the two.
## Identifying fields eligible for a join
Using `getFields` with the following params will identify fields that are eligible for an API join, in this example for the `Contact` entity:
```php
Contact::getFields()
->addWhere('fk_entity', 'IS NOT EMPTY')
...
```
## Multiple joins
*Note: multiple joins are only available to `get` actions*
**Joining across the same foreign key multiple times:**
```php
civicrm_api4('Event', 'get', [
'select' => ['title', 'campaign_id.name', 'campaign_id.campaign_type_id'],
...
```
**Joining multiple levels deep:**
```php
Civi\Api4\Email::get()
->addSelect('contact_id.employer_id.display_name')
...
```
**Combining a join with an [option transformation](pseudoconstants.md):**
```php
Civi\Api4\Email::get()
->addSelect('contact_id.contact_type:label')
...
```
# API Joins
An API "get" action will typically return only the values of the entity requested. However, there are times when it is advantageous to returned data from a related entity. For instance, when querying the API for email addresses, you may want to return the name of the associated contact from the Contact entity.
The CiviCRM API supports two methods of returning data from associated entities; APIv4 Joins and [APIv4 Chaining](/api/v4/chaining.md). API joins provide higher performance by making a single SQL query with a [SQL join](https://dev.mysql.com/doc/refman/5.7/en/join.html), and are generally preferable to API chaining where available.
## Using an API Join
To use a join in an API call, specify the name of the field on which the join happens, a period, and the name of the field to reference.
For instance, to search for all primary emails, returning the email and joining to also return the contact's display name:
Object Oriented way:
```php
$result \Civi\Api4\Email::get()
->setSelect([
'contact.display_name',
'email',
])
->addWhere('is_primary', '=', 1)
->setLimit(25)
->setCheckPermissions(FALSE)
->execute();
```
Traditional:
```php
$result = civicrm_api4('Email', 'get', [
'select' => ["email", "contact.display_name"],
'where' => [
['is_primary', '=', 1],
],
'limit' => 25,
]);
```
Alternatively, to return email addresses of everyone whose last name is Smith by joining to the Contact entity:
Object Oriented way:
```php
$result \Civi\Api4\Email::get()
->addWhere('contact.last_name', '=', 'Smith')
->setLimit(25)
->setCheckPermissions(FALSE)
->execute();
```
Traditional:
```php
$result = civicrm_api4('Email', 'get', [
'where' => [
['contact.last_name', '=', "Smith"],
],
'limit' => 25,
]);
```
You can join multiple times in one query. For instance, to return a list of events, displaying their name, the name of the related campaign, and that campaign's type:
Object Oriented way:
```php
$result \Civi\Api4\Email::get()
->setSelect(['title', 'campaign.name', 'campaign.campaign_type_id'])
->setLimit(25)
->setCheckPermissions(FALSE)
->execute();
```
Traditional:
```php
$result = civicrm_api4('Event', 'get', [
'select' => ['title', 'campaign.name', 'campaign.campaign_type_id'],
));
```
!!! tip
Joins are available only with the [get](/api/v4/actions.md#get) action
## Identifying fields eligible for a join
It is possible to join an entity to any other entity if the [xml schema](/framework/database/schema-definition.md) identifies a [foreign key](/framework/database/schema-definition.md#table-foreignKey) or a [pseudoconstant](/framework/database/schema-definition.md#table-field-pseudoconstant). The [getfields](/api/v3/actions.md#getfields) action identifies
fields that are eligible for an API join.
# Managed APIv4 Entities
## Basics
Managed Entities are used to package configuration data with extensions.
For example, *menu items*, *custom fields* or *option values* all might be needed for the extension to function.
Documentation on creating managed records for use with extensions is in the [Extensions - Managed Entities](../../extensions/managed.md) chapter.
## ManagedEntity Trait
In order to be managed, the API entity class must `use` the `ManagedEntity` trait. This adds the following api actions:
- **[`revert`](actions.md#write-actions):** update the entity back to its original state as declared by the `.mgd.php` file or [hook_civicrm_managed](../../hooks/hook_civicrm_managed.md) data.
- **[`export`](actions.md#read-actions):** outputs configuration data for this and all linked entities, suitable for placing in a `.mgd.php` file. This api is called by the [`civix export` command](../../extensions/civix.md#export).
## Lifecycle
Managed entities are declared via [hook_civicrm_managed](../../hooks/hook_civicrm_managed.md), although it is more typical for
extensions to use `.mgd.php` files which are automatically loaded via mixin.
Once installed, Managed instances are tracked in a table in CiviCRM called `civicrm_managed`.
You can use `Civi\Api4\Managed::get()` to see what is in there (or make sure your entity has been added)
and use the APIv4 `reconcile` action to have the list of declared entities compared against what is
present in the `civicrm_managed` table - any that are missing will be created and depending on your update mode and cleanup mode they may be updated or deleted if the declaration has changed. Note that
you can declare Managed Entities using APIv4 or APIv3 but APIv4 is more robust as it can handle the
situation where a similar record already exists.
# APIv4 Pseudoconstants (Option Lists)
Some fields in CiviCRM are linked to an option list (aka *Pseudoconstant*). These fields are typically shown to the user
as checkboxes, radios, or a dropdown-select of options from the pseudoconstant list.
The API provides tools for working with such fields; so that downstream developers do not need to translate between database values and option properties.
## Option list properties
Each option in the list consists of attributes like `id`, `name`, `label`, `description`, `color` and `icon`.
For a complete list and description of each attribute see the framework chapter: [Pseudoconstant (Option List) Reference](../../framework/pseudoconstant.md#attributes).
## Which fields have option lists?
To find out which fields have option lists for a particular entity, use the `getFields` action from the API or API Explorer, e.g.
```php
civicrm_api4('Contact', 'getFields', [
'where' => [['options', '!=', FALSE]],
])
```
This will return a list of all fields for a given entity (in this example, "Contact") which have an option list.
## Retrieving an option list {:#retrieve}
If you need to retrieve the full option list for a field, use the `getFields` action and set the `loadOptions` parameter
to an array of the above properties you would like to retrieve. Try it in the API explorer, e.g.
```php
civicrm_api4('Contact', 'getFields', [
'where' => [['name', '=', 'contact_type']],
'loadOptions' => ['name', 'label', 'description'],
])->first();
```
This will load information about the `contact_type` field including the list of available options (names will be ['Individual', 'Household', 'Organization'], labels will be localized translations if the site is not in English).
!!! tip
Unless you are building a form and need to render an option list for the user to select, in most cases
you will not need to query `getFields` to e.g. match option ids to labels. The syntax below can automatically
perform such transformations.
## Option transformations
When reading or writing data from the API, a special suffix tells the API to transform between option ids and other properties. For example:
### Writing
```php
Activity::create()
->addValue('activity_type_id:name', 'Meeting')
...
```
Using this syntax saves you from needing to look up the id of an activity type.
It also makes your code more portable, as option ids can change from one database to another, but names are consistent.
### Reading
Get operations use the same syntax to reverse the lookup and transform an option id to another property.
```php
Activity::get()
->addSelect('*', 'activity_type_id:label', 'activity_type_id:icon')
...
```
This tells the API to return all fields (`*`) plus the label and icon of the activity type, giving the data needed for a user-facing display.
!!! note "Option Lists or Joins"
The syntax for option transformations looks very similar to [implicit joins](implicit-joins.md) (the difference being a colon instead of a dot). Your choice of which to use depends on the field.
For example, the Contact `gender_id` field has an option list but not a foreign key, so you must use the option syntax (`gender_id:label`).
But the Event `campaign_id` field has a foreign key instead of an option list, so you would use a join (`campaign_id.title`).
\ No newline at end of file
# APIv4 REST
## Overview
<!--
FIXME: When the explorer is updated, enable the comments about it...
!!! tip "Get started with APIv4 Explorer"
CiviCRM has a built-in tool for working with APIv4 (`Support => Developer => APIv4 Explorer`). You may use
this to generate complete HTTP/REST examples that are tuned to your instance of CiviCRM.
This documentation provides a deeper explanation of the HTTP/REST interface.
-->
CiviCRM APIv4 provides HTTP/REST bindings, enabling remote applications to read and write data.
As you may recall, the APIv4 architecture uses the triplet [(`$entity`, `$action`, `$params`)](usage.md), e.g.
```php
$result = civicrm_api4($entity, $action, $params);
$result = civicrm_api4('Contact', 'get', ['limit' => 10]);
```
A typical APIv4 REST request includes these three elements and an authentication credential. For example:
```
https://{$website}/civicrm/ajax/api4/{$entity}/{$action}
?params={$params}&_authx={$credential}
```
In the remaining sections, we will examine this formula more closesly - considering more concrete examples
and more precise descriptions of each part.
??? question "Is APIv4 a REST-ful interface?"
HTTP-based APIs are sometimes described as "REST-ful" if they closely follow certain HTTP conventions. CiviCRM APIv4 is more REST-ful than APIv3, but it is not strictly REST-ful.
Never-the-less, it is generally used for reading and writing resource records, and (by tradition) the subsystem is referred to as "REST".
## Examples
As we review the structure of an APIv4 REST call, it may help to have a few examples. Here is a representative example:
```
1: GET https://www.example.org/civicrm/ajax/api4/Contact/get
2: ?params=%7B%22where%22%3A%5B%5B%22id%22%2C%22%3D%22%2C22%5D%5D%7D
3: &_authx=ABCD1234
```
In line 1, we see an *end-point (base) URL* (`https://www.example.org/civicrm/ajax/api4`) along with entity and action (`Contact/get`). Line 2 conveys the specific API data-parameters (encoded as JSON form-data). Line 3 provides the *authentication* parameters.
Similar elements should appear in any API call, but the content of each can differ. Here is another example:
```
1: POST https://crm.example.org/civicrm/ajax/api4/OptionGroup/get
2: Authorization: Basic dXNlcjpwYXNz
3: X-Requested-With: XMLHttpRequest
4:
5: %7B%22where%22%3A%5B%5B%22name%22%2C%22%3D%22%2C%22activity_type%22%5D%5D%2C%22limit%22%3A25%2C%22debug%22%3Atrue%7D
```
Here, we have a different *end-point (base) URL* (line 1; `https://crm.example.org/civicrm/ajax/api4`) with a different entity and action (`OptionGroup/get`). Line 2 shows a different *authentication* style. The specific API data also differs (line 5).
## End-Point URL
All requests should be submitted to the CiviCRM route `civicrm/ajax/api4/{ENTITY}/{ACTION}`.
Requests are typically submitted with HTTP POST, but read-only operations may use HTTP GET.
??? info "Comparison: URLs on Backdrop, Drupal, Joomla, WordPress"
On Drupal, Backdrop, and some WordPress deployments, you may access it with a clean URL.
```
https://example.org/civicrm/ajax/rest
```
In other deployments, you may need a verbose URL - such as these WordPress and Joomla URLs:
```
https://wordpress.example.org/wp-admin/admin.php?page=CiviCRM&q=civicrm/ajax/rest
https://joomla.example.org/administrator/index.php?option=com_civicrm&task=civicrm/ajax/rest
```
The `civicrm/ajax/rest` end-point is frequently used for browser-based API calls ("AJAX"). In newer versions (CiviCRM v5.36+), it can also be used for remote applications.
Stylisitcally, this is similar to [APIv4 REST](../v4/rest.md) end-point.
## Authentication
Every request for APIv4 should include authentication details. These may be submitted in a few forms, such as:
```
/* HTTP parameter */
?_authx=Bearer+MY_API_KEY
?_authx=Bearer+MY_JSON_WEB_TOKEN
?_authx=Basic+B64(USER:PASS)
/* Civi HTTP header */
X-Civi-Auth: Bearer MY_API_KEY
X-Civi-Auth: Bearer MY_JSON_WEB_TOKEN
X-Civi-Auth: Basic B64(USER:PASS)
/* Conventional HTTP header */
Authorization: Bearer MY_API_KEY
Authorization: Bearer MY_JSON_WEB_TOKEN
Authorization: Basic B64(USER:PASS)
```
!!! tip "Which authentication forms can I use?"
By default, new AuthX deployments are configured to accept:
* __[Credentials](../../framework/authx.md#credentials)__: API keys or JSON Web Tokens (*Passwords are not accepted by default.*)
* __[Flows](../../framework/authx.md#flows)__: `?_authx=`, `X-Civi-Auth:`, or `Authorization:`
The system administrator may enable or disable support for each credential and flow.
Some hosting environments may have compatibility issues with `Authorization:`. If you need to communicate with
several different CiviCRM deployments, then `?_authx=` and `X-Civi-Auth:` may be more reliable.
For API keys and passwords, the user must have the matching permission (`authenticate with api key` or
`authenticate with password`).
## X-Requested-With
To ensure broad compatibility, APIv4 REST clients should set this HTTP header:
```http
X-Requested-With: XMLHttpRequest
```
The header is not required for all requests, but sometimes it is required, and there is generally no harm to
setting it.
For more complete details, see [Cross-Site Request Forgery (CSRF)](../../security/csrf.md) and specifically
[CSRF: APIv4/APIv4 REST](../../security/csrf.md#rest).
## Parameters
APIv4 `$params` are transmitted with JSON and URL encoding. Thus, if the PHP `$params` are:
```php
['limit' => 10]
```
Then the equivalent JSON will be:
```javascript
{"limit":10}
```
and the URL-encoded JSON will be:
```
%7B%22limit%22%3A10%7D
```
## Response
The response will be a JSON document. A well-formed response provides a list of `values`:
```javascript
{
"version": 4,
"count": 10,
"values": [
{
"contact_id": "1",
"contact_type": "Individual",
"contact_sub_type": "",
"display_name": "Example Person",
...
```
Alternatively, if there is an error, then it will be reported with `error_message` and `error_code`:
```javascript
{
"error_code": 0,
"error_message": "Api FakeEntity fakeAction version 4 does not exist.",
}
```
## History
* __CiviCRM v5.19__: Added HTTP bindings for APIv4 to `civicrm-core`. However, these were only available for
browser-based AJAX applications -- not for remote REST applications.
* __CiviCRM v5.36__: Added the [AuthX extension](../../framework/authx.md) to `civicrm-core`. This enabled REST-style
authentication for APIv4. However, configuring AuthX may require CLI interaction to update hidden settings.
* __CiviCRM v5.47__: Added the AuthX configuration screen, making it easier for more sysadmins to setup.
# APIv4 SET Operations
## Background
SQL **Set Operations** are ways of combining the results of multiple queries.
- **UNION ALL**: Combines the results of two or more SELECT statements into a single result set, eliminating duplicate rows.
- **UNION DISTINCT**: A UNION which eliminates duplicate rows.
- **INTERSECT**: Returns the common elements between two or more SELECT statements, resulting in a result set that contains only the shared rows.
- **EXCEPT**: Retrieves the rows from the first SELECT statement that are not present in the result set of the second SELECT statement, effectively finding the difference between the two result sets.
As of version 5.64, APIv4 adds support for UNION ALL and UNION DISTINCT. It does not yet support INTERSECT or EXCEPT because
the minimum version of MySql would need to be bumped to 8.0. Once that's done in a future version, those operations can be
supported as well.
## The `EntitySet` API
By calling the `EntitySet` API and adding 2 or more sets to combine, you effectively create a new entity/table which
can be operated on as a whole (SELECT, WHERE, HAVING, ORDER BY, LIMIT).
For example, you could UNION together a set of Contributions and Contribution Soft Credits,
then apply a GROUP BY clause to the combined results.
!!! warning Columns Must Match
Per the rules of SQL Set Operations, each set must have the same number of fields selected,
with matching data types.
They will be combined in that order (not by name) and the field names of the first set will be used for the entire EntitySet.
Try it yourself in the API Explorer:
![APIv4 Explorer EntitySet](../../img/api4/entityset-unions.png)
\ No newline at end of file
# APIv4 Usage
Every API call consists of three elements: the *entity*, *action*, and *parameters*. Some commonly used entities in CiviCRM include the following:
## API Input
| Entity | Description |
|------------|--------------------------------------------|
| `Contact` | An individual, organization, or household. |
| `Activity` | A phone call, meeting, or email message. that has occurred (or will occur) at a specific date and time. |
| `Address` | A street-address related to a contact. |
Every API call consists of three elements: the *entity*, *action*, and *parameters*:
Each entity supports a number of actions. Consider these samples with commonly-used actions and parameters for the `Contact` entity:
**Entity:** The "name" of the API.
CiviCRM entities include Contacts, Activities, Contributions, Events, etc.
Each API entity usually (but not always) corresponds to a table in the database (e.g. the Contact entity is the `civicrm_contact` table).
!!! info "Supported Entities"
The ongoing effort to port APIv3 entities to v4 is nearing completion.
For updates or to help port a new entity, see this [tracking issue](https://lab.civicrm.org/dev/core/-/issues/2486).
**Action:** The "verb" of the API. The [list of available actions](actions.md) varies for each entity, but most support
a set of CRUD actions to `create`, `get`, `update` & `delete`, etc.
**Parameters:** Settings or data to pass to the api function. Each action accepts a different set of parameters.
Consider these samples with commonly-used actions and parameters for the `Contact` entity:
| Action | Parameters | Description |
|----------|--------------------------------------|---------------------------------|
......@@ -16,102 +25,162 @@ Each entity supports a number of actions. Consider these samples with commonly-u
| `get` | `#!json {"where":[["last_name", "=", "Doe"]], "limit":25}` | Fetch the first 25 contacts with the last name "Doe" |
| `delete` | `#!json {"where":[["id", "=", 42]]}` | Delete the contact with id "42" |
(*For full, up-to-date details about specific entities and parameters, use the [API Explorer](/api/index.md#api-explorer).*)
!!! tip "API Explorer"
For full, up-to-date details about specific entities, actions and parameters, use the [API Explorer](../index.md#api-explorer).
!!! info
As of CiviCRM version 5.18, not all core entities have been added to APIv4. You should check the API Explorer to see which entities are available. If the entity you require is not available then please open a pull request against the [`civicrm-core` repository](https://github.com/civicrm/civicrm-core) to add the entity or open an [issue](https://lab.civicrm.org/dev/core) and request that the entity is added.
## API Output
The API is available in many different environments (such as PHP, REST, and JavaScript), and the notation differs slightly in each environment.
However, if you understand the canonical notation, then other environments will appear as small adaptations.
The API returns an array, with each item representing one record (also an array).
In PHP, this output is contained in an ArrayObject, which can be accessed like an array using e.g. `$result[0]` or `foreach ($result as ...)`.
Canonically, an API call is processed by the API kernel. The `$entity`, `$action`, and `$params` are passed as inputs, and an `arrayObject` is returned as output.
See the [php docs](https://www.php.net/manual/en/class.arrayobject.php) for a full list of methods ArrayObjects support
```php
$result = Civi::service('civi_api_kernel')->run('Contact', 'get', [
'version' => 4,
'where' => [
['first_name', '=', 'Alice'],
['last_name', '=', 'Roberts'],
],
]);
```
It also has the following methods in addition to or overriding the base ArrayObject:
The result of a successful API call typically looks like this:
- `$result->first()`: returns the first item, or NULL if not found.
- `$result->single()`: returns a single item, or throws an exception if not exactly one item was returned.
- `$result->last()`: returns the last item, or NULL if not found.
- `$result->itemAt($index)`: returns the item at a given index, or NULL if not found.
- `$result->indexBy($field)`: reindexes the array by the value of a field.
- `$result->column($field)`: flattens the array, discarding all but a single field (call this second if using in conjunction with `indexBy` to create a key=>value array).
- `$result->count()`: get the number of fetched (if LIMIT used) or matching results (if `row_count` included in select). See below.
- From CiviCRM 5.50+ `$result->countFetched()`: get the number of *fetched* results. If you used LIMIT this won't exceed that number (but could be less).
- From CiviCRM 5.50+ `$result->countMatched()`: get the total number of *matching* results. If you only fetched a subset (with LIMIT) you are required to add `row_count` to the select clause.
```json
[
{ /* DAO Object */ }
]
```
!!! Converting ArrayObject to a Real Array
If you need to use functions such as `is_array` on the result you can cast it you cast it to an array, `(array) $result`, or use the [`getArrayCopy()`](https://www.php.net/manual/en/arrayobject.getarraycopy.php) method.
The result of a failed API call typically looks like this:
### Counting results
```json
{
"error_code": 0
}
```
Prior to 5.50, there was just one count available via `count()`. From 5.50+ it is clearer to use one of the new methods instead: `countFetched()` and `countMatched()` because `count()` can return different counts based on a number of factors (see below). Note that the `rowCount` *property* should not be considered a public interface and any code using it directly should be migrated to use a method instead.
**TL;DR**: If you need to know the number of *matched* rows regardless of any fetch limit, you must add `row_count` to the select. You can do this by calling `selectRowCount()` (note that this will replace any prior selects).
e.g. consider the database contains 100 contacts and you're using the `Contact.get` API.
`$result = $api->addSelect('display_name')->execute()` will fetch the names of all contacts.
- `$result->countFetched()` will return 100.
- `$result->countMatched()` will return 100 too, since this is known as there was no limit.
- `$result->count()` will return 100.
`$result = $api->addSelect('display_name')->setLimit(10)->execute()` will fetch the names of 10 contacts.
- `$result->countFetched()` will return 10.
- `$result->countMatched()` will return throw an exception because it cannot be calculated from the result.
- `$result->count()` will return 10.
!!! info
Some parts of APIv4 differ significantly from APIv3, including the handling of `check_permissions` and the default limit for returned objects being removed. For details, refer to [Differences Between APIv3 and APIv4](/api/v4/differences-with-v3.md).
`$result = $api->selectRowCount()->addSelect('display_name')->setLimit(10)->execute()` will fetch the names of 10 contacts and also calculate the total matched.
- `$result->countFetched()` will return 10.
- `$result->countMatched()` will return 100.
- `$result->count()` will return 100.
## PHP
`$result = $api->selectRowCount()->execute()` will not fetch any records, but will make the count available:
- `$result->countFetched()` will return 0 (since we did not fetch any data rows).
- `$result->countMatched()` will return 100.
- `$result->count()` will return 100.
This is the most common way to call the API. There are two formats of API calls: an object-oriented approach and the more traditional procedural style.
`$result = $api->selectRowCount()->setLimit(10)->execute()` is a funny thing to do (set a limit for records without asking for records anyway) but it will behave as if you had not included the `setLimit()` clause, i.e. exactly as the last example.
### Object-Oriented (OOP)
`$result = $api->selectRowCount()->addSelect('display_name')->execute()` is strictly unnecessary since it fetches all records anyway, so the `selectRowCount()` is superfluous.
- `$result->countFetched()` will return 10.
- `$result->countMatched()` will return 100.
- `$result->count()` will return 100.
## Example
<iframe src="https://learn.civi.be/wp-admin/admin-ajax.php?action=h5p_embed&id=6" width="680" height="480" frameborder="0" allowfullscreen="allowfullscreen"></iframe>
## API Security
By default, APIv4 validates every action according to the permission level of the logged-in user.
This can be disabled only when calling via [PHP code](usage.md#php). API Permissions are also able to be altered via hook.
More information on API Security can be found in the [Security Documentation](../../security/permissions.md).
## API Interfaces
The API is available in many environments (such as PHP, CLI, and JavaScript), and the notation differs slightly in each language.
However, if you understand the canonical notation, then others will appear as small adaptations.
!!! note "Use Outside of CiviCRM"
If you're writing a Drupal module, a Joomla extension, a WordPress plugin, or a standalone script, then you may need to [bootstrap](../../framework/bootstrap.md) CiviCRM before using the API.
### PHP
This is the canonical API; all other environments are essentially wrappers around the PHP API.
There are two ways to call the api from PHP - which one you choose is a matter of convenience and personal preference.
For example, you may prefer OOP syntax because IDE code editors provide autocompletion.
Or if you need to work with the parameters as an array, traditional syntax will be more convenient.
![APIv4 PHP Examples](../../img/api4/Api4-PHP-Styles.svg)
#### Traditional (Procedural)
*The function `civicrm_api4($entity, $action, [$params], [$index])` accepts an array of parameters and returns the Result.*
```php
$contacts = \Civi\Api4\Contact::get()
->addWhere('last_name', '=', 'Adams')
->setLimit(25)
->execute();
$result = civicrm_api4('Contact', 'get', [
'where' => [
['last_name', '=', 'Adams'],
// Option transformation.
['gender_id:name', '=', 'Male'],
// Implicit join.
['employer_id.is_opt_out', '=', FALSE],
],
'limit' => 25,
]);
```
The API is first invoked using a static method in the form of `#!php Entity::action()`.
The returned object implements a number of helper methods like `#!php addWhere()`.
These helper methods use method chaining, which allows multiple methods to be chained together in one statement as shown above.
`$index` provides a convenient shorthand for reformatting the Result array. It has different modes depending on the variable type passed:
* **Integer:** return a single result array; e.g. `$index = 0` will return the first result, 1 will return the second, and -1 will return the last.
* **String:** index the results by a field value; e.g. `$index = "name"` will return an associative array with the field 'name' as keys.
* **Non-associative array:** return a single value from each result; e.g. `$index = ['title']` will return a non-associative array of strings - the 'title' field from each result.
* **Associative array:** a combination of the previous two modes; e.g. `$index = ['name' => 'title']` will return an array of strings - the 'title' field keyed by the 'name' field.
### Traditional (Procedural)
#### Object-Oriented (OOP)
*An `Action` class provides setter methods for each parameter. The `execute()` method returns the Result.*
```php
try {
$contacts = civicrm_api4('Contact', 'get', array(
'where' => [
['first_name', '=', 'Alice'],
['last_name', '=', 'Roberts'],
],
]);
}
catch (\API_Exception $e) {
$error = $e->getMessage();
}
printf("Found %d item(s)\n", count($contacts));
$result = \Civi\Api4\Contact::get()
->addWhere('last_name', '=', 'Adams')
->addWhere('gender_id:name', '=', 'Male')
->setLimit(25)
->execute();
```
This format matches the canonical format almost exactly, with a few improvements for usability:
!!! warning "Warning: Class names don't always match entity names!"
For example, the entity "Case" is a reserved word in PHP and therefore could not be the name of a class, so it had to be named something else ("CiviCase").
Internally, calling `civicrm_api4('Case', 'getFields')` will translate to `Civi\Api4\CiviCase::getFields`.
[Custom data entities](custom-data.md) are another example.
When writing generic functions that work with multiple entities, we strongly recommend against clever code like this: `call_user_func(['\Civi\Api4\' . $entity, 'get'], ...)`,
and suggest using this more reliable alternative: `civicrm_api4($entity, 'get', ...)`.
- The `version => 4` parameter is not required.
- Errors are reported as PHP exceptions. You may catch the exceptions or (by default) allow them to bubble up.
- You can immediately iterate over the contacts returned.
*Note*: If you're writing a Drupal module, a Joomla extension, a WordPress plugin, or a standalone script, then you may need to **bootstrap** CiviCRM before using the API. See the examples in [Bootstrap Reference](/framework/bootstrap.md).
### AJAX
## REST
APIv4 is not yet available via REST. This is being tracked in [dev/core#1310](https://lab.civicrm.org/dev/core/issues/1310).
The AJAX interface is automatically available for web-pages generated through CiviCRM (such as standard CiviCRM web-pages, CiviCRM extensions and custom CiviCRM templates).
## AJAX
Inputs are identical to the traditional PHP syntax:
```javascript
CRM.api4('entity', 'action', [params], [index]);
CRM.api4('entity', 'action', [params], [index])
```
If you wish to do further work based on the result of the API call (e.g use the results from a GET call) you will need to use the [done method](http://api.jquery.com/deferred.done/) to listen for the event. For example:
From an Angular app, use the service `crmApi4()` which has an identical signature but works within the `$scope.digest` lifecycle.
Both functions return a Promise, which resolves to a Result array.
```javascript
CRM.api4('EntityTag', 'create', {
values: {"entity_id":5, "tag_id":3}
CRM.api4('Contact', 'get', {
where: [
['last_name', '=', 'Adams'],
],
limit: 25
}).then(function(results) {
// do something with results array
}, function(failure) {
......@@ -119,31 +188,14 @@ CRM.api4('EntityTag', 'create', {
});
```
The AJAX interface is automatically available for web-pages generated through CiviCRM (such as standard CiviCRM web-pages, CiviCRM extensions and custom CiviCRM templates).
The AJAX interface could be made available to other parts of the same website (e.g. a Drupal module or WordPress widget) by calling `#!php CRM_Core_Resources::singleton()->addCoreResources()`
from PHP. Please note that the AJAX interface is subject to [API Security](/security/permissions.md#api-permissions)
and [Same Origin Policy](http://en.wikipedia.org/wiki/Same_origin_policy). To use it from an external site or application, see REST interface documentation.
## Smarty
APIv4 is not yet available as a Smarty function.
!!! note "Use on Non-CiviCRM Pages"
The AJAX interface could be made available to other parts of the same website (e.g. a Drupal module or WordPress widget) by calling `#!php Civi::resources()->addCoreResources()`
from PHP. Please note that the AJAX interface is subject to [API Security](../../security/permissions.md#api-permissions)
and [Same Origin Policy](http://en.wikipedia.org/wiki/Same_origin_policy).
## Scheduled jobs
### Command line
APIv4 is not yet available for scheduled jobs.
## Command line
### drush
APIv4 is not yet available as a drush command.
### wp-cli
APIv4 is not yet available as a wp-cli command.
### cv
#### cv
`cv` supports multiple input formats for APIv4. The API Explorer uses the JSON format in generated code:
......@@ -159,6 +211,18 @@ cv api4 Contact.get +w 'first_name = "Alice"' +w 'last_name = "Roberts"'
For more examples, refer to the output of `cv --help api4`.
## API Security
#### drush
API has security measures built in depending on the way the API is called that can also be turned off or on. API Permissions are also able to be altered via hook. More information on API Security can be found in the [Security Documentation](/security/permissions.md).
Adding `version=4` to a drush command will cause v4 api to be called rather than v3.
#### wp-cli
APIv4 is not yet available as a wp-cli command.
### Smarty
Because Smarty is an older technology, there are no plans to port the APIv3 smarty function to APIv4.
### Scheduled jobs
APIv4 is not yet available for scheduled jobs.
......@@ -32,11 +32,11 @@ Once you've written the requirements and specification document, you should go a
## Bugs
Before starting work on a bug, your first step should be to check the [issue tracking systems](/tools/issue-tracking.md) for any open issues before creating one yourself or working on a pull request.
Before starting work on a bug, your first step should be to check the [issue tracking systems](../tools/issue-tracking.md) for any open issues before creating one yourself or working on a pull request.
In order to reproduce the bug you can reproduce the issue in the appropriate [CiviCRM Sandbox](https://civicrm.org/sandboxes). Enabling debugging can help to get more details.
Make sure to check [the contribution guidelines](/core/contributing.md) for more information on how to create a pull request.
Make sure to check [the contribution guidelines](../core/contributing.md) for more information on how to create a pull request.
## Recommendations
......@@ -44,15 +44,15 @@ Make sure to check [the contribution guidelines](/core/contributing.md) for more
**Install the [buildkit](https://github.com/civicrm/civicrm-buildkit)**, ideally as a [vagrant virtual-machine](https://github.com/civicrm/civicrm-buildkit-vagrant) or using one of available `docker` images ([progressivetech](https://github.com/progressivetech/docker-civicrm-buildkit) or [EricBSchulz](https://github.com/ErichBSchulz/dcbk)). The buildkit is not an absolute requirement but it is definitely the fastest path to a good development experience!
**From the outset, [automate testing](/testing/index.md)**. In the current climate of rapid evolution of not just CiviCRM, but also it's myriad of dependencies, automated testing of PHP code with `phpunit` and javascript with tools like `karma` and `jasmine` is essential. Start all your work by considering how you will provide automated testing for it. Starting with the buildkit will make this much simpler for you to set up. Getting started with unit-testing may seem daunting and onerous when you start, but you will soon come to love the freedom it gives you. If you are unsure how to proceed with testing ask the [community](/basics/community.md).
**From the outset, [automate testing](../testing/index.md)**. In the current climate of rapid evolution of not just CiviCRM, but also it's myriad of dependencies, automated testing of PHP code with `phpunit` and javascript with tools like `karma` and `jasmine` is essential. Start all your work by considering how you will provide automated testing for it. Starting with the buildkit will make this much simpler for you to set up. Getting started with unit-testing may seem daunting and onerous when you start, but you will soon come to love the freedom it gives you. If you are unsure how to proceed with testing ask the [community](community.md).
**Create a native [extension](/extensions/index.md)**. If you have new functionality to add to CiviCRM, it probably belongs in an extension. "Native" extensions will install into all CiviCRM sites regardless of the underlying CMS used (Drupal, WordPress, Joomla or Backdrop), making it easy to share your extension with the CiviCRM community.
**Create a native [extension](../extensions/index.md)**. If you have new functionality to add to CiviCRM, it probably belongs in an extension. "Native" extensions will install into all CiviCRM sites regardless of the underlying CMS used (Drupal, WordPress, Joomla or Backdrop), making it easy to share your extension with the CiviCRM community.
**Use the [API](/api/index.md) and [hooks](/hooks/index.md)** to access and manage CiviCRM data in any patch, native extension, CMS module, or external program that you develop. The API will function as expected with every new release and backwards compatibility of the API is maintained for several versions of CiviCRM.
**Use the [API](../api/index.md) and [hooks](../hooks/index.md)** to access and manage CiviCRM data in any patch, native extension, CMS module, or external program that you develop. The API will function as expected with every new release and backwards compatibility of the API is maintained for several versions of CiviCRM.
**Avoid [hacking the core](/core/hacking.md)** of CiviCRM unless you understand the implications.
**Avoid [hacking the core](../core/hacking.md)** of CiviCRM unless you understand the implications.
**Follow the [Coding Standards](/standards/index.md)** for uniform structure that will make everyone's development work easier.
**Follow the [Coding Standards](../standards/index.md)** for uniform structure that will make everyone's development work easier.
## Make it happen
......
......@@ -2,23 +2,26 @@
## Languages and Services
- Unix-like environment (Linux, OS X, or a virtual machine)
- [PHP v5.3+](http://php.net/)
- [MySQL v5.1+](http://mysql.com/)
- [NodeJS](https://nodejs.org/)
- [Git](https://git-scm.com/)
- Recommended: Apache HTTPD v2.2+
- Recommended: Ruby/Rake
* Required
- Unix-like environment (Linux, OS X, or a virtual machine)
- [PHP v7.2+](http://php.net/) including the following extensions: `bcmath curl gd gettext imap intl imagick json mbstring openssl pdo_mysql phar posix soap zip`
- [MySQL v5.7.5+](http://mysql.com/) or [MariaDB 10.0.2+](https://mariadb.org/), including both client and server
- [NodeJS v8+](https://nodejs.org/)
- [Git](https://git-scm.com/)
* Recommended (for `civibuild` / `amp`):
- Apache HTTPD v2.2 or v2.4 including the `mod_rewrite` module and, on SUSE, possibly `mod_access_compat` (This list may not be exhaustive.)
Please also see [this Installation Guide page](https://docs.civicrm.org/installation/en/latest/general/requirements/) for more details on server configuration requirements to deploy CiviCRM installations using buildkit.
## Command Line
There are many ways to install MySQL, PHP, and other dependencies -- for example, `apt-get` and `yum` can download packages automatically; `php.net` and `mysql.com` provide standalone installers; and MAMP/XAMPP provide bundled installers.
Civi development should work with most packages -- but there's one proviso: ***the command-line must support standard commands*** (`php`, `mysql`, `node`, `git`, `bash`, etc).
Civi development should work with most packages -- with a priviso: ***the command-line must support standard command names*** (eg `git`, `php`, `node`, `mysql`, `mysqldump`, etc).
Some packages are configured properly out-of-the-box. (Linux distributions do a pretty good job of this.) Other packages require extra configuration steps.
Some environments (e.g. most Linux distributions) are configured properly out-of-the-box. Other environments (e.g. MAMP and XAMPP) may require configuring the `PATH`.
In subsequent steps, the download script will attempt to identify misconfigurations and display an appropriate message.
<!-- FIXME: There should be a link about diagnosing/fixing paths for third-party binaries. TLDR: `find / -name php -executable` and then update `PATH` via bashrc/bash_profile/whatever -->
## Buildkit
......@@ -26,4 +29,4 @@ The developer docs reference a large number of developer tools, such as `drush`
Many of these tools are commonly used by web developers, so you may have already installed a few. You could install all the tools individually -- but that takes a lot of work.
[civicrm-buildkit](/tools/buildkit.md) provides a script which downloads the full collection.
[civicrm-buildkit](../tools/buildkit.md) provides a script which downloads the full collection.