We are moving toward markdown in docblock comments. This is a step in that direction.
/**
* Format a docblock to be a bit more readable
- * Not a proper doc parser... patches welcome :)
+ *
+ * FIXME: APIv4 uses markdown in code docs. Switch to that.
*
* @param string $text
* @return string
// Extract code blocks - save for later to skip html conversion
$code = [];
- preg_match_all('#@code(.*?)@endcode#is', $text, $code);
- $text = preg_replace('#@code.*?@endcode#is', '<pre></pre>', $text);
+ preg_match_all('#(@code|```)(.*?)(@endcode|```)#is', $text, $code);
+ $text = preg_replace('#(@code|```)(.*?)(@endcode|```)#is', '<pre></pre>', $text);
// Convert @annotations to titles
$text = preg_replace_callback(
$text = nl2br($text);
// Add unformatted code blocks back in
- if ($code && !empty($code[1])) {
- foreach ($code[1] as $block) {
+ if ($code && !empty($code[2])) {
+ foreach ($code[2] as $block) {
$text = preg_replace('#<pre></pre>#', "<pre>$block</pre>", $text, 1);
}
}
* Generates acl clauses suitable for adding to WHERE or ON when doing an api.get for this entity
*
* Return format is in the form of fieldname => clauses starting with an operator. e.g.:
- * @code
+ * ```
* array(
* 'location_type_id' => array('IS NOT NULL', 'IN (1,2,3)')
* )
- * @endcode
+ * ```
*
* Note that all array keys must be actual field names in this entity. Use subqueries to filter on other tables e.g. custom values.
*
/**
* Placeholder page which generates a redirect
*
- * @code
+ * ```
* <item>
* <path>civicrm/admin/options/case_type</path>
* <page_callback>CRM_Core_Page_Redirect</page_callback>
* <page_arguments>url=civicrm/foo/bar?whiz=bang&passthru=%%passthru%%</page_arguments>
* </item>
- * @endcoe
+ * ```
*/
class CRM_Core_Page_Redirect extends CRM_Core_Page {
/**
* Add a snippet of content to a region.
*
- * @code
+ * ```
* CRM_Core_Region::instance('page-header')->add(array(
* 'markup' => '<div style="color:red">Hello!</div>',
* ));
* CRM_Core_Region::instance('page-header')->add(array(
* 'callback' => 'myextension_callback_function',
* ));
- * @endcode
+ * ```
*
* Note: This function does not perform any extra encoding of markup, script code, or etc. If
* you're passing in user-data, you must clean it yourself.
/**
* Temporarily assign a list of variables.
*
- * @code
+ * ```
* $smarty->pushScope(array(
* 'first_name' => 'Alice',
* 'last_name' => 'roberts',
* ));
* $html = $smarty->fetch('view-contact.tpl');
* $smarty->popScope();
- * @endcode
+ * ```
*
* @param array $vars
* (string $name => mixed $value).
*
* Example:
*
- * @code
+ * ```
* {tsScope x=1}
* Expect {$x}==1
* {tsScope x=2}
* {/tsScope}
* Expect {$x}==1
* {/tsScope}
- * @endcode
+ * ```
*
* @param array $params
* Must define 'name'.
/**
* Display the CiviCRM version
*
- * @code
+ * ```
* The version is {crmVersion}.
*
* {crmVersion redact=auto assign=ver}The version is {$ver}.
- * @endcode
+ * ```
*
* @param $params
* @param $smarty
*
* To ensure that they throw exceptions, use:
*
- * @code
+ * ```
* $errorScope = CRM_Core_TemporaryErrorScope::useException();
- * @endcode
+ * ```
*
* Note that relying on this is a code-smell: it can be
* safe to temporarily switch to exception
*
* Examples:
*
- * @code
+ * ```
* // Some business logic using the helper functions
* function my_business_logic() {
* CRM_Core_Transaction::create()->run(function($tx) {
* }
* }
*
- * @endcode
+ * ```
*
* Note: As of 4.6, the transaction manager supports both reference-counting and nested
* transactions (SAVEPOINTs). In the past, it only supported reference-counting. The two cases
* To ensure that PHP errors or unhandled exceptions are reported in JSON
* format, wrap this around your code. For example:
*
- * @code
+ * ```
* $errorContainer = new CRM_Queue_ErrorPolicy();
* $errorContainer->call(function() {
* ...include some files, do some work, etc...
* });
- * @endcode
+ * ```
*
* Note: Most of the code in this class is pretty generic vis-a-vis error
* handling -- except for 'reportError', whose message format is only
* different queue-providers may store the queue content in different
* ways (in memory, in SQL, or in an external service).
*
- * @code
+ * ```
* $queue = CRM_Queue_Service::singleton()->create(array(
* 'type' => 'interactive',
* 'name' => 'upgrade-tasks',
* $queue->releaseItem($item);
* }
* }
- * @endcode
+ * ```
*/
class CRM_Queue_Service {
* - "match-mandatory" will generate an error
* - "match" will allow action to proceed -- thus inserting a new record
*
- * @code
+ * ```
* $result = civicrm_api('contact', 'create', array(
* 'options' => array(
* 'match' => array('last_name', 'first_name')
* 'last_name' => 'Lebowski',
* 'nick_name' => 'The Dude',
* ));
- * @endcode
+ * ```
*
* @package CRM
* @copyright CiviCRM LLC https://civicrm.org/licensing
* Implement the "reload" option. This option can be used with "create" to force
* the API to reload a clean copy of the entity before returning the result.
*
- * @code
+ * ```
* $clean = civicrm_api('myentity', 'create', array(
* 'options' => array(
* 'reload' => 1
* ),
* ));
- * @endcode
+ * ```
*
* @package CRM
* @copyright CiviCRM LLC https://civicrm.org/licensing
/**
* Call a cleanup function when the current context shuts down.
*
- * @code
+ * ```
* function doStuff() {
* $ac = CRM_Utils_AutoClean::with(function(){
* MyCleanup::doIt();
* });
* ...
* }
- * @endcode
+ * ```
*
* @param mixed $callback
* @return CRM_Utils_AutoClean
* Temporarily swap values using callback functions, and cleanup
* when the current context shuts down.
*
- * @code
+ * ```
* function doStuff() {
* $ac = CRM_Utils_AutoClean::swap('My::get', 'My::set', 'tmpValue');
* ...
* }
- * @endcode
+ * ```
*
* @param mixed $getter
* Function to lookup current value.
/**
* Capture the output from the console, copy it to a file, and pass it on.
*
- * @code
+ * ```
* $tee = CRM_Utils_ConsoleTee::create()->start();
* echo "hello world";
* $tee->stop();
* assertEquals("hello world", file_get_contents($tee->getFileName()));
- * @endCode
+ * ```
*
* Loosely speaking, it serves a similar purpose to Unix `tee`.
*
* This is a quick-and-dirty way to define a vaguely-class-ish structure. It's non-performant, abnormal,
* and not a complete OOP system. Only use for testing/mocking.
*
- * @code
+ * ```
* $object = new CRM_Utils_FakeObject(array(
* 'doIt' => function() { print "It!\n"; }
* ));
* $object->doIt();
- * @endcode
+ * ```
*/
class CRM_Utils_FakeObject {
/**
* Temporarily change a global variable.
*
- * @code
+ * ```
* $globals = CRM_Utils_GlobalStack::singleton();
* $globals->push(array(
* '_GET' => array(
* ));
* ...do stuff...
* $globals->pop();
- * @endcode
+ * ```
*
* Note: for purposes of this class, we'll refer to the array passed into
* push() as a frame.
* If omitted, default to "array('civicrm/a')" for backward compat.
* For a utility that should only be loaded on-demand, use "array()".
* For a utility that should be loaded in all pages use, "array('*')".
- * @return null
- * the return value is ignored
*
- * @code
+ * ```
* function mymod_civicrm_angularModules(&$angularModules) {
* $angularModules['myAngularModule'] = array(
* 'ext' => 'org.example.mymod',
* 'basePages' => array('civicrm/a'),
* );
* }
- * @endcode
+ * ```
+ *
+ * @return null
+ * the return value is ignored
*/
public static function angularModules(&$angularModules) {
return self::singleton()->invoke(['angularModules'], $angularModules,
*
* @param \Civi\Angular\Manager $angular
*
- * @code
+ * ```
* function example_civicrm_alterAngular($angular) {
* $changeSet = \Civi\Angular\ChangeSet::create('mychanges')
* ->alterHtml('~/crmMailing/EditMailingCtrl/2step.html', function(phpQueryObject $doc) {
* );
* $angular->add($changeSet);
* }
- * @endCode
+ * ```
*/
public static function alterAngular($angular) {
$event = \Civi\Core\Event\GenericHookEvent::create([
/**
* Modify the CiviCRM container - add new services, parameters, extensions, etc.
*
- * @code
+ * ```
* use Symfony\Component\Config\Resource\FileResource;
* use Symfony\Component\DependencyInjection\Definition;
*
* $container->addResource(new FileResource(__FILE__));
* $container->setDefinition('mysvc', new Definition('My\Class', array()));
* }
- * @endcode
+ * ```
*
* Tip: The container configuration will be compiled/cached. The default cache
* behavior is aggressive. When you first implement the hook, be sure to
* @var array
* Description of export field mapping
*
- * @code
+ * ```
* 'exampleEntityMappingName' => array(
* 'data' => array(), // placeholder; this will get filled-in during execution
* 'name' => 'CustomGroup', // per-item XML tag name
* 'idNameFields' => array('id', 'name'), // name of the (local/autogenerated) "id" and (portable) "name" columns
* 'idNameMap' => array(), // placeholder; this will get filled-in during execution
* ),
- * @endcode
+ * ```
*/
protected $_xml;
/**
* Get the value of a SQL parameter.
*
- * @code
+ * ```
* $select['cid'] = 123;
* $select->where('contact.id = #cid');
* echo $select['cid'];
- * @endCode
+ * ```
*
* @param string $offset
* @return mixed
/**
* Set the value of a SQL parameter.
*
- * @code
+ * ```
* $select['cid'] = 123;
* $select->where('contact.id = #cid');
* echo $select['cid'];
- * @endCode
+ * ```
*
* @param string $offset
* @param mixed $value
* Dear God Why Do I Have To Write This (Dumb SQL Builder)
*
* Usage:
- * @code
+ * ```
* $del = CRM_Utils_SQL_Delete::from('civicrm_activity act')
* ->where('activity_type_id = #type', array('type' => 234))
* ->where('status_id IN (#statuses)', array('statuses' => array(1,2,3))
* 'value' => $form['foo']
* ))
* echo $del->toSQL();
- * @endcode
+ * ```
*
* Design principles:
* - Portable
* xor output. The notations for input and output interpolation are a bit different,
* and they may not be mixed.
*
- * @code
+ * ```
* // Interpolate on input. Set params when using them.
* $select->where('activity_type_id = #type', array(
* 'type' => 234,
* $select
* ->where('activity_type_id = #type')
* ->param('type', 234),
- * @endcode
+ * ```
*
* @package CRM
* @copyright CiviCRM LLC https://civicrm.org/licensing
* Dear God Why Do I Have To Write This (Dumb SQL Builder)
*
* Usage:
- * @code
+ * ```
* $select = CRM_Utils_SQL_Select::from('civicrm_activity act')
* ->join('absence', 'inner join civicrm_activity absence on absence.id = act.source_record_id')
* ->where('activity_type_id = #type', array('type' => 234))
* 'value' => $form['foo']
* ))
* echo $select->toSQL();
- * @endcode
+ * ```
*
* Design principles:
* - Portable
* xor output. The notations for input and output interpolation are a bit different,
* and they may not be mixed.
*
- * @code
+ * ```
* // Interpolate on input. Set params when using them.
* $select->where('activity_type_id = #type', array(
* 'type' => 234,
* $select
* ->where('activity_type_id = #type')
* ->param('type', 234),
- * @endcode
+ * ```
*
* @package CRM
* @copyright CiviCRM LLC https://civicrm.org/licensing
*
* FIXME: Add TTL support?
*
- * @code
+ * ```
* $signer = new CRM_Utils_Signer('myprivatekey', array('param1','param2'));
* $params = array(
* 'param1' => 'hello',
* $token = $signer->sign($params);
* ...
* assertTrue($signer->validate($token, $params));
- * @endcode
+ * ```
*/
class CRM_Utils_Signer {
/**
*
* For example, 'civicrm/contact/view?reset=1&cid=66' will be returned as:
*
- * @code
+ * ```
* array(
* 'path' => 'civicrm/contact/view',
* 'route' => 'civicrm.civicrm_contact_view',
* 'query' => array('reset' => '1', 'cid' => '66'),
* );
- * @endcode
+ * ```
*
* @param string $url
* The url to parse.
/**
* A central location for static variable storage.
* @var array
- * @code
+ * ```
* `Civi::$statics[__CLASS__]['foo'] = 'bar';
- * @endcode
+ * ```
*/
public static $statics = array();
* The ChainSubscriber looks for API parameters which specify a nested or
* chained API call. For example:
*
- * @code
+ * ```
* $result = civicrm_api('Contact', 'create', array(
* 'version' => 3,
* 'first_name' => 'Amy',
* 'location_type_id' => 123,
* ),
* ));
- * @endcode
+ * ```
*
* The ChainSubscriber looks for any parameters of the form "api.Email.create";
* if found, it issues the nested API call (and passes some extra context --
* A WhitelistRule is used to determine if an API call is authorized.
* For example:
*
- * @code
+ * ```
* new WhitelistRule(array(
* 'entity' => 'Contact',
* 'actions' => array('get','getsingle'),
* 'required' => array('contact_type' => 'Organization'),
* 'fields' => array('id', 'display_name', 'sort_name', 'created_date'),
* ));
- * @endcode
+ * ```
*
* This rule would allow API requests that attempt to get contacts of type "Organization",
* but only a handful of fields ('id', 'display_name', 'sort_name', 'created_date')
*
* The basic mailing query looks a bit like this (depending on configuration):
*
- * @code
+ * ```
* SELECT reminder.id AS reminderID, reminder.contact_id as contactID, ...
* FROM `civicrm_action_log` reminder
* ... JOIN `target_entity` e ON e.id = reminder.entity_id ...
* WHERE reminder.action_schedule_id = #casActionScheduleId
- * @endcode
+ * ```
*
* Listeners may modify the query. For example, suppose we want to load
* additional fields from the related 'foo' entity:
*
- * @code
+ * ```
* $event->query->join('foo', '!casMailingJoinType civicrm_foo foo ON foo.myentity_id = e.id')
* ->select('foo.bar_value AS bar');
- * @endcode
+ * ```
*
* There are several parameters pre-set for use in queries:
* - 'casActionScheduleId'
* to fire the reminders X days after the registration date. The
* MappingInterface::createQuery() could return a query like:
*
- * @code
+ * ```
* CRM_Utils_SQL_Select::from('civicrm_participant e')
* ->join('event', 'INNER JOIN civicrm_event event ON e.event_id = event.id')
* ->where('e.is_pay_later = 1')
* ->param('casDateField', 'e.register_date')
* ->param($defaultParams)
* ...etc...
- * @endcode
+ * ```
*
* In the RELATION_FIRST phase, RecipientBuilder adds a LEFT-JOIN+WHERE to find
* participants who have *not* yet received any reminder, and filters those
* The AngularLoader stops short of bootstrapping AngularJS. You may
* need to `<div ng-app="..."></div>` or `angular.bootstrap(...)`.
*
- * @code
+ * ```
* $loader = new AngularLoader();
* $loader->setPageName('civicrm/case/a');
* $loader->setModules(array('crmApp'));
* $loader->load();
- * @endCode
+ * ```
*
* @link https://docs.angularjs.org/guide/bootstrap
*/
* named "api-fields.json" which lists all the fields of
* all the API entities.
*
- * @code
+ * ```
* // Build a URL to `api-fields.json`.
* $url = \Civi::service('asset_builder')->getUrl('api-fields.json');
*
* $mimeType = 'application/json';
* $content = json_encode($fields);
* }
- * @endCode
+ * ```
*
* Assets can be parameterized. Each combination of ($asset,$params)
* will be cached separately. For example, we might want a copy of
* Simply pass the chosen entities into `getUrl()`, then update
* the definition to use `$params['entities']`, as in:
*
- * @code
+ * ```
* // Build a URL to `api-fields.json`.
* $url = \Civi::service('asset_builder')->getUrl('api-fields.json', array(
* 'entities' => array('Contact', 'Phone', 'Email', 'Address'),
* $mimeType = 'application/json';
* $content = json_encode($fields);
* }
- * @endCode
+ * ```
*
* Note: These assets are designed to hold non-sensitive data, such as
* aggregated JS or common metadata. There probably are ways to
* The event inspector is a development tool which provides metadata about events.
* It can be used for code-generators and documentation-generators.
*
- * @code
+ * ```
* $i = new CiviEventInspector();
* print_r(CRM_Utils_Array::collect('name', $i->getAll()));
- * @endCode
+ * ```
*
* An event definition includes these fields:
* - type: string, required. Ex: 'hook' or 'object'
* and methods. This requires some kind of mapping. `GenericHookEvent`
* maps each parameter to a field (using magic methods):
*
- * @code
+ * ```
* // Creating an event object.
* $event = GenericHookEvent::create(array(
* 'bar' => 'abc',
*
* // Dispatching an event.
* Civi::dispatcher()->dispatch('hook_civicrm_foo', $event);
- * @endCode
+ * ```
*
* Design Discussion:
*
* as an array, and all the returned values are merged into one big array.
* You can add and retrieve return-values using these methods:
*
- * @code
+ * ```
* $event->addReturnValues(array(...));
* foreach ($event->getReturnValues() as $retVal) { ... }
- * @endCode
+ * ```
*/
class GenericHookEvent extends \Symfony\Component\EventDispatcher\Event {
/**
* Recursively interpolate values.
*
- * @code
+ * ```
* $params = array('foo' => '@1');
* $this->interpolate($params, array('@1'=> $object))
* assert $data['foo'] == $object;
- * @endcode
+ * ```
*
* @param array $array
* Array which may or many not contain a mix of tokens.
/**
* Create a builder for the headless environment.
*
- * @return \Civi\Test\CiviEnvBuilder
- *
- * @code
+ * ```
* \Civi\Test::headless()->apply();
* \Civi\Test::headless()->sqlFile('ex.sql')->apply();
- * @endCode
+ * ```
+ *
+ * @return \Civi\Test\CiviEnvBuilder
*/
public static function headless() {
$civiRoot = dirname(__DIR__);
/**
* Create a builder for end-to-end testing on the live environment.
*
- * @return \Civi\Test\CiviEnvBuilder
- *
- * @code
+ * ```
* \Civi\Test::e2e()->apply();
* \Civi\Test::e2e()->install('foo.bar')->apply();
- * @endCode
+ * ```
+ *
+ * @return \Civi\Test\CiviEnvBuilder
*/
public static function e2e() {
$builder = new \Civi\Test\CiviEnvBuilder('CiviEnvBuilder');
* This interface allows you to subscribe to hooks as part of the test.
* Simply create an eponymous hook function (e.g. `hook_civicrm_post()`).
*
- * @code
+ * ```
* class MyTest extends \PHPUnit_Framework_TestCase implements \Civi\Test\HookInterface {
* public function hook_civicrm_post($op, $objectName, $objectId, &$objectRef) {
* echo "Running hook_civicrm_post\n";
* }
* }
- * @endCode
+ * ```
*
* At time of writing, there are a few limitations in how HookInterface is handled
* by CiviTestListener:
* The TokenRegisterEvent is fired when constructing a list of available
* tokens. Listeners may register by specifying the entity/field/label for the token.
*
- * @code
+ * ```
* $ev->entity('profile')
* ->register('viewUrl', ts('Default Profile URL (View Mode)')
* ->register('editUrl', ts('Default Profile URL (Edit Mode)');
* 'field' => 'viewUrl',
* 'label' => ts('Default Profile URL (View Mode)'),
* ));
- * @endcode
+ * ```
*
* Event name: 'civi.token.list'
*/
* A TokenValueEvent is fired to convert raw query data into mergeable
* tokens. For example:
*
- * @code
+ * ```
* $event = new TokenValueEvent($myContext, 'text/html', array(
* array('contact_id' => 123),
* array('contact_id' => 456),
* (1) When setting up a job, you may specify general/baseline info.
* This is called the "context" data. Here, we create two rows:
*
- * @code
+ * ```
* $proc->addRow()->context('contact_id', 123);
* $proc->addRow()->context('contact_id', 456);
- * @endCode
+ * ```
*
* (2) When defining a token (eg `{profile.viewUrl}`), you might read the
* context-data (`contact_id`) and set the token-data (`profile => viewUrl`):
*
- * @code
+ * ```
* foreach ($proc->getRows() as $row) {
* $row->tokens('profile', [
* 'viewUrl' => 'http://example.com/profile?cid=' . urlencode($row->context['contact_id'];
* ]);
* }
- * @endCode
+ * ```
*
* The context and tokens can be accessed using either methods or attributes.
*
- * @code
+ * ```
* # Setting context data
* $row->context('contact_id', 123);
* $row->context(['contact_id' => 123]);
*
* # Reading token data
* echo $row->tokens['profile']['viewUrl'];
- * @endCode
+ * ```
*
* Note: The methods encourage a "fluent" style. They were written for PHP 5.3
* (eg before short-array syntax was supported) and are fairly flexible about
*
* This class allows to consume the API, either from within a module that knows civicrm already:
*
- * @code
+ * ```
* require_once('api/class.api.php');
* $api = new civicrm_api3();
- * @endcode
+ * ```
*
* or from any code on the same server as civicrm
*
- * @code
+ * ```
* require_once('/your/civi/folder/api/class.api.php');
* // the path to civicrm.settings.php
* $api = new civicrm_api3 (array('conf_path'=> '/your/path/to/your/civicrm/or/joomla/site));
- * @endcode
+ * ```
*
* or to query a remote server via the rest api
*
- * @code
+ * ```
* $api = new civicrm_api3 (array ('server' => 'http://example.org',
* 'api_key'=>'theusersecretkey',
* 'key'=>'thesitesecretkey'));
- * @endcode
+ * ```
*
* No matter how initialised and if civicrm is local or remote, you use the class the same way.
*
- * @code
+ * ```
* $api->{entity}->{action}($params);
- * @endcode
+ * ```
*
* So, to get the individual contacts:
*
- * @code
+ * ```
* if ($api->Contact->Get(array('contact_type'=>'Individual','return'=>'sort_name,current_employer')) {
* // each key of the result array is an attribute of the api
* echo "\n contacts found " . $api->count;
* } else {
* echo $api->errorMsg();
* }
- * @endcode
+ * ```
*
* Or, to create an event:
*
- * @code
+ * ```
* if ($api->Event->Create(array('title'=>'Test','event_type_id' => 1,'is_public' => 1,'start_date' => 19430429))) {
* echo "created event id:". $api->id;
* } else {
* echo $api->errorMsg();
* }
- * @endcode
+ * ```
*
* To make it easier, the Actions can either take for input an
* associative array $params, or simply an id. The following two lines
* are equivalent.
*
- * @code
+ * ```
* $api->Activity->Get (42);
* $api->Activity->Get (array('id'=>42));
- * @endcode
+ * ```
*
*
* You can also get the result like civicrm_api does, but as an object
* instead of an array (eg $entity->attribute instead of
* $entity['attribute']).
*
- * @code
+ * ```
* $result = $api->result;
* // is the json encoded result
* echo $api;
- * @endcode
+ * ```
*/
class civicrm_api3 {
* file content.
* For core fields use "entity_table", for custom fields use "field_name"
*
- * @code
+ * ```
* // Create an attachment for a core field
* $result = civicrm_api3('Attachment', 'create', array(
* 'entity_table' => 'civicrm_activity',
* ));
* $attachment = $result['values'][$result['id']];
* echo sprintf("<a href='%s'>View %s</a>", $attachment['url'], $attachment['name']);
- * @endcode
+ * ```
*
- * @code
+ * ```
* // Create an attachment for a custom file field
* $result = civicrm_api3('Attachment', 'create', array(
* 'field_name' => 'custom_6',
* ));
* $attachment = $result['values'][$result['id']];
* echo sprintf("<a href='%s'>View %s</a>", $attachment['url'], $attachment['name']);
- * @endcode
+ * ```
*
- * @code
+ * ```
* // Move an existing file and save as an attachment
* $result = civicrm_api3('Attachment', 'create', array(
* 'entity_table' => 'civicrm_activity',
* ));
* $attachment = $result['values'][$result['id']];
* echo sprintf("<a href='%s'>View %s</a>", $attachment['url'], $attachment['name']);
- * @endcode
+ * ```
*
* Notes:
* - File content is not returned by default. One must specify 'return => content'.
*
* @param array $params
*
- * @code
+ * ```
* // REQUIRED for create:
* 'case_type_id' => int OR
* 'case_type' => str (provide one or the other)
* 'start_date' => str datestamp // defaults to: date('YmdHis')
* 'duration' => int // in minutes
* 'details' => str // html format
- * @endcode
+ * ```
*
* @throws API_Exception
* @return array
*
* @param array $params
*
- * @code
+ * ```
* //REQUIRED:
* 'id' => int
*
* //OPTIONAL
* 'move_to_trash' => bool (defaults to false)
- * @endcode
+ * ```
*
* @throws API_Exception
* @return mixed
* Expected keys are in format custom_fieldID:recordID or custom_groupName:fieldName:recordID.
*
* @example:
- * @code
+ * ```
* // entity ID. You do not need to specify entity type, we figure it out based on the fields you're using
* 'entity_id' => 123,
* // (omitting :id) inserts or updates a field in a single-valued group
* 'custom_some_group:my_field' => 'myinfo',
* // updates record ID 8 in my_other_field in multi-valued some_big_group
* 'custom_some_big_group:my_other_field:8' => 'myinfo',
- * @endcode
+ * ```
*
* @throws Exception
* @return array
*
* This api has a legacy/nonstandard signature.
* On success, the return array will be structured as follows:
- * @code
+ * ```
* array(
* "is_error" => 0,
* "version" => 3,
* "total_count" => integer
* )
* )
- * @endcode
+ * ```
*
* On failure, the return array will be structured as follows:
- * @code
+ * ```
* array(
* 'is_error' => 1,
* 'error_message' = string,
* 'error_data' = mixed or undefined
* )
- * @endcode
+ * ```
*
* @param array $params
* Input parameters:
* Create a batch of external API calls which can
* be executed concurrently.
*
- * @code
+ * ```
* $calls = $this->createExternalAPI()
* ->addCall('Contact', 'get', ...)
* ->addCall('Contact', 'get', ...)
* ...
* ->run()
* ->getResults();
- * @endcode
+ * ```
*
* @return \Civi\API\ExternalBatch
* @throws PHPUnit_Framework_SkippedTestError