/** * Attempts to retrieve the API entity name from any calling class. * * @param string|object $classNameOrObject * * @return string * @throws CRM_Core_Exception */ static function getEntityName($classNameOrObject) { require_once 'api/api.php'; $className = is_string($classNameOrObject) ? $classNameOrObject : get_class($classNameOrObject); // First try the obvious replacements $daoName = str_replace(array('_BAO_', '_Form_', '_Page_'), '_DAO_', $className); $shortName = CRM_Core_DAO_AllCoreTables::getBriefName($daoName); // If that didn't work, try a different pattern if (!$shortName) { list(, $parent, , $child) = explode('_', $className); $daoName = "CRM_{$parent}_DAO_{$child}"; $shortName = CRM_Core_DAO_AllCoreTables::getBriefName($daoName); } // If that didn't work, try a different pattern if (!$shortName) { $daoName = "CRM_{$parent}_DAO_{$parent}"; $shortName = CRM_Core_DAO_AllCoreTables::getBriefName($daoName); } // If that didn't work, try a different pattern if (!$shortName) { $daoName = "CRM_Core_DAO_{$child}"; $shortName = CRM_Core_DAO_AllCoreTables::getBriefName($daoName); } if (!$shortName) { throw new CRM_Core_Exception('Could not find api name for supplied class'); } return _civicrm_api_get_entity_name_from_camel($shortName); }
/** * Generic api wrapper used for quicksearch and autocomplete. * * @param array $apiRequest * * @return mixed */ function civicrm_api3_generic_getList($apiRequest) { $entity = _civicrm_api_get_entity_name_from_camel($apiRequest['entity']); $request = $apiRequest['params']; $meta = civicrm_api3_generic_getfields(array('action' => 'get') + $apiRequest, FALSE); // Hey api, would you like to provide default values? $fnName = "_civicrm_api3_{$entity}_getlist_defaults"; $defaults = function_exists($fnName) ? $fnName($request) : array(); _civicrm_api3_generic_getList_defaults($entity, $request, $defaults, $meta['values']); // Hey api, would you like to format the search params? $fnName = "_civicrm_api3_{$entity}_getlist_params"; $fnName = function_exists($fnName) ? $fnName : '_civicrm_api3_generic_getlist_params'; $fnName($request); $request['params']['check_permissions'] = !empty($apiRequest['params']['check_permissions']); $result = civicrm_api3($entity, 'get', $request['params']); // Hey api, would you like to format the output? $fnName = "_civicrm_api3_{$entity}_getlist_output"; $fnName = function_exists($fnName) ? $fnName : '_civicrm_api3_generic_getlist_output'; $values = $fnName($result, $request, $entity, $meta['values']); _civicrm_api3_generic_getlist_postprocess($result, $request, $values); $output = array('page_num' => $request['page_num']); // Limit is set for searching but not fetching by id if (!empty($request['params']['options']['limit'])) { // If we have an extra result then this is not the last page $last = $request['params']['options']['limit'] - 1; $output['more_results'] = isset($values[$last]); unset($values[$last]); } return civicrm_api3_create_success($values, $request['params'], $entity, 'getlist', CRM_Core_DAO::$_nullObject, $output); }
protected function execute(InputInterface $input, OutputInterface $output) { // load Civi to get access to civicrm_api_get_function_name $civicrm_api3 = $this->getContainer()->get('civicrm_api3'); if (!$civicrm_api3 || !$civicrm_api3->local) { $output->writeln("<error>Require access to local CiviCRM source tree. Configure civicrm_api3_conf_path.</error>"); return; } $ctx = array(); $ctx['type'] = 'module'; $ctx['basedir'] = rtrim(getcwd(), '/'); $basedir = new Path($ctx['basedir']); $info = new Info($basedir->string('info.xml')); $info->load($ctx); $attrs = $info->get()->attributes(); if ($attrs['type'] != 'module') { $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>'); return; } if (!preg_match('/^[A-Za-z0-9]+$/', $input->getArgument('<EntityName>'))) { throw new Exception("Entity name must be alphanumeric camel-case"); } $ctx['entityNameCamel'] = ucfirst($input->getArgument('<EntityName>')); $ctx['tableName'] = 'civicrm_' . strtolower($input->getArgument('<EntityName>')); if (function_exists('civicrm_api_get_function_name')) { $ctx['apiFunctionPrefix'] = strtolower(civicrm_api_get_function_name($ctx['entityNameCamel'], '', self::API_VERSION)); } elseif (function_exists('_civicrm_api_get_entity_name_from_camel')) { $ctx['apiFunctionPrefix'] = 'civicrm_api' . self::API_VERSION . '_' . _civicrm_api_get_entity_name_from_camel($ctx['entityNameCamel']) . '_' . $ctx['actionNameCamel']; } else { throw new Exception("Failed to determine proper API function name. Perhaps the API internals have changed?"); } $ctx['apiFile'] = $basedir->string('api', 'v3', $ctx['entityNameCamel'] . '.php'); $ctx['daoClassName'] = strtr($ctx['namespace'], '/', '_') . '_DAO_' . $input->getArgument('<EntityName>'); $ctx['daoClassFile'] = $basedir->string(strtr($ctx['daoClassName'], '_', '/') . '.php'); $ctx['baoClassName'] = strtr($ctx['namespace'], '/', '_') . '_BAO_' . $input->getArgument('<EntityName>'); $ctx['baoClassFile'] = $basedir->string(strtr($ctx['baoClassName'], '_', '/') . '.php'); $ctx['schemaFile'] = $basedir->string('xml', 'schema', $ctx['namespace'], $input->getArgument('<EntityName>') . '.xml'); $ctx['entityTypeFile'] = $basedir->string('xml', 'schema', $ctx['namespace'], $input->getArgument('<EntityName>') . '.entityType.php'); $ext = new Collection(); $ext->builders['dirs'] = new Dirs(array(dirname($ctx['apiFile']), dirname($ctx['daoClassFile']), dirname($ctx['baoClassFile']), dirname($ctx['schemaFile']))); $ext->builders['dirs']->save($ctx, $output); $ext->builders['api.php'] = new Template('CRMCivixBundle:Code:entity-api.php.php', $ctx['apiFile'], FALSE, $this->getContainer()->get('templating')); $ext->builders['bao.php'] = new Template('CRMCivixBundle:Code:entity-bao.php.php', $ctx['baoClassFile'], FALSE, $this->getContainer()->get('templating')); $ext->builders['entity.xml'] = new Template('CRMCivixBundle:Code:entity-schema.xml.php', $ctx['schemaFile'], FALSE, $this->getContainer()->get('templating')); if (!file_exists($ctx['entityTypeFile'])) { $mgdEntities = array(array('name' => $ctx['entityNameCamel'], 'class' => $ctx['daoClassName'], 'table' => $ctx['tableName'])); $header = "// This file declares a new entity type. For more details, see \"hook_civicrm_entityTypes\" at:\n" . "// http://wiki.civicrm.org/confluence/display/CRMDOC/Hook+Reference"; $ext->builders['entityType.php'] = new PhpData($ctx['entityTypeFile'], $header); $ext->builders['entityType.php']->set($mgdEntities); } $ext->init($ctx); $ext->save($ctx, $output); }
/** * Flush constant. * * Wrapper for Pseudoconstant methods. We use this so the calling function * doesn't need to know which class the Pseudoconstant is on * (some are on the Contribute_Pseudoconsant Class etc * * * @param $constant * * @return array * array reference of all relevant constant */ public static function flushConstant($constant) { $class = self::findConstantClass($constant); if ($class) { $class::flush(lcfirst($constant)); //@todo the rule is api functions should only be called from within the api - we // should move this function to a Core class $name = _civicrm_api_get_entity_name_from_camel($constant); CRM_Core_OptionGroup::flush($name); return TRUE; } }
/** * Generic api wrapper used for quicksearch and autocomplete * * @param $apiRequest array * @return mixed */ function civicrm_api3_generic_getList($apiRequest) { $entity = _civicrm_api_get_entity_name_from_camel($apiRequest['entity']); $request = $apiRequest['params']; _civicrm_api3_generic_getList_defaults($entity, $request); // Hey api, would you like to format the search params? $fnName = "_civicrm_api3_{$entity}_getlist_params"; $fnName = function_exists($fnName) ? $fnName : '_civicrm_api3_generic_getlist_params'; $fnName($request); $result = civicrm_api3($entity, 'get', $request['params']); // Hey api, would you like to format the output? $fnName = "_civicrm_api3_{$entity}_getlist_output"; $fnName = function_exists($fnName) ? $fnName : '_civicrm_api3_generic_getlist_output'; $values = $fnName($result, $request); $output = array('more_results' => isset($values[10]), 'page_num' => $request['page_num']); unset($values[10]); return civicrm_api3_create_success($values, $request['params'], $entity, 'getlist', CRM_Core_DAO::$_nullObject, $output); }
/** * @param int $id * @param $values * @param int $wildcard * @param bool $useEquals * * @param string $apiEntity * * @return array|null */ public static function &fixWhereValues($id, &$values, $wildcard = 0, $useEquals = FALSE, $apiEntity = NULL) { // skip a few search variables static $skipWhere = NULL; static $likeNames = NULL; $result = NULL; // Change camelCase EntityName to lowercase with underscores $apiEntity = _civicrm_api_get_entity_name_from_camel($apiEntity); if (CRM_Utils_System::isNull($values)) { return $result; } if (!$skipWhere) { $skipWhere = array('task', 'radio_ts', 'uf_group_id', 'component_mode', 'qfKey', 'operator', 'display_relationship_type'); } if (in_array($id, $skipWhere) || substr($id, 0, 4) == '_qf_' || substr($id, 0, 7) == 'hidden_') { return $result; } if ($apiEntity && substr($id, 0, strlen($apiEntity)) != $apiEntity && (substr($id, 0, 10) != 'financial_' && substr($id, 0, 8) != 'payment_')) { $id = $apiEntity . '_' . $id; } if (!$likeNames) { $likeNames = array('sort_name', 'email', 'note', 'display_name'); } // email comes in via advanced search // so use wildcard always if ($id == 'email') { $wildcard = 1; } if (!$useEquals && in_array($id, $likeNames)) { $result = array($id, 'LIKE', $values, 0, 1); } elseif (is_string($values) && strpos($values, '%') !== FALSE) { $result = array($id, 'LIKE', $values, 0, 0); } elseif ($id == 'group') { if (is_array($values)) { foreach ($values as $groupIds => $val) { $matches = array(); if (preg_match('/-(\\d+)$/', $groupIds, $matches)) { if (strlen($matches[1]) > 0) { $values[$matches[1]] = 1; unset($values[$groupIds]); } } } } else { $groupIds = explode(',', $values); unset($values); foreach ($groupIds as $groupId) { $values[$groupId] = 1; } } $result = array($id, 'IN', $values, 0, 0); } elseif ($id == 'contact_tags' || $id == 'tag') { if (!is_array($values)) { $tagIds = explode(',', $values); unset($values); foreach ($tagIds as $tagId) { $values[$tagId] = 1; } } $result = array($id, 'IN', $values, 0, 0); } elseif ($id == 'contact_type') { $result = array($id, 'IN', $values, 0, $wildcard); } else { $result = array($id, '=', $values, 0, $wildcard); } return $result; }
/** * Get information about fields for a given api request. * * Getfields information is used for documentation, validation, default setting * We first query the scheme using the $dao->fields function & then augment * that information by calling the _spec functions that apply to the relevant function * Note that we use 'unique' field names as described in the xml/schema files * for get requests & just field name for create. This is because some get functions * access multiple objects e.g. contact api accesses is_deleted from the activity * table & from the contact table * * @param array $apiRequest * Api request as an array. Keys are. * - entity: string * - action: string * - version: string * - function: callback (mixed) * - params: array, varies * * @param bool $unique * Determines whether to key by unique field names (only affects get-type) actions * * @return array * API success object */ function civicrm_api3_generic_getfields($apiRequest, $unique = TRUE) { static $results = array(); if (CRM_Utils_Array::value('cache_clear', $apiRequest['params'])) { $results = array(); // we will also clear pseudoconstants here - should potentially be moved to relevant BAO classes CRM_Core_PseudoConstant::flush(); if (!empty($apiRequest['params']['fieldname'])) { CRM_Utils_PseudoConstant::flushConstant($apiRequest['params']['fieldname']); } if (!empty($apiRequest['params']['option_group_id'])) { $optionGroupName = civicrm_api('option_group', 'getvalue', array('version' => 3, 'id' => $apiRequest['params']['option_group_id'], 'return' => 'name')); if (is_string($optionGroupName)) { CRM_Utils_PseudoConstant::flushConstant(_civicrm_api_get_camel_name($optionGroupName)); } } } $entity = $apiRequest['entity']; $lowercase_entity = _civicrm_api_get_entity_name_from_camel($entity); $subentity = CRM_Utils_Array::value('contact_type', $apiRequest['params']); $action = CRM_Utils_Array::value('action', $apiRequest['params']); $sequential = empty($apiRequest['params']['sequential']) ? 0 : 1; $apiRequest['params']['options'] = CRM_Utils_Array::value('options', $apiRequest['params'], array()); $optionsToResolve = (array) CRM_Utils_Array::value('get_options', $apiRequest['params']['options'], array()); if (!$action || $action == 'getvalue' || $action == 'getcount') { $action = 'get'; } // If no options, return results from cache if (!$apiRequest['params']['options'] && isset($results[$entity . $subentity]) && isset($action, $results[$entity . $subentity]) && isset($action, $results[$entity . $subentity][$sequential])) { return $results[$entity . $subentity][$action][$sequential]; } // defaults based on data model and API policy switch ($action) { case 'getfields': $values = _civicrm_api_get_fields($entity, FALSE, $apiRequest['params']); return civicrm_api3_create_success($values, $apiRequest['params'], $entity, 'getfields'); case 'create': case 'update': case 'replace': $unique = FALSE; case 'get': case 'getsingle': case 'getcount': case 'getstat': $metadata = _civicrm_api_get_fields($apiRequest['entity'], $unique, $apiRequest['params']); if (empty($metadata['id'])) { // if id is not set we will set it eg. 'id' from 'case_id', case_id will be an alias if (!empty($metadata[strtolower($apiRequest['entity']) . '_id'])) { $metadata['id'] = $metadata[$lowercase_entity . '_id']; unset($metadata[$lowercase_entity . '_id']); $metadata['id']['api.aliases'] = array($lowercase_entity . '_id'); } } else { // really the preference would be to set the unique name in the xml // question is which is a less risky fix this close to a release - setting in xml for the known failure // (note) or setting for all api where fields is returning 'id' & we want to accept 'note_id' @ the api layer // nb we don't officially accept note_id anyway - rationale here is more about centralising a now-tested // inconsistency $metadata['id']['api.aliases'] = array($lowercase_entity . '_id'); } break; case 'delete': $metadata = array('id' => array('title' => $entity . ' ID', 'api.required' => 1, 'api.aliases' => array($lowercase_entity . '_id'), 'type' => CRM_Utils_Type::T_INT)); break; // Note: adding setvalue case here instead of in a generic spec function because // some APIs override the generic setvalue fn which causes the generic spec to be overlooked. // Note: adding setvalue case here instead of in a generic spec function because // some APIs override the generic setvalue fn which causes the generic spec to be overlooked. case 'setvalue': $metadata = array('field' => array('title' => 'Field name', 'api.required' => 1, 'type' => CRM_Utils_Type::T_STRING), 'id' => array('title' => $entity . ' ID', 'api.required' => 1, 'type' => CRM_Utils_Type::T_INT), 'value' => array('title' => 'Value', 'description' => "Field value to set", 'api.required' => 1)); if (array_intersect(array('all', 'field'), $optionsToResolve)) { $options = civicrm_api3_generic_getfields(array('entity' => $entity, array('params' => array('action' => 'create')))); $metadata['field']['options'] = CRM_Utils_Array::collect('title', $options['values']); } break; default: // oddballs are on their own $metadata = array(); } // Normalize this for the sake of spec funcions $apiRequest['params']['options']['get_options'] = $optionsToResolve; // find any supplemental information $hypApiRequest = array('entity' => $apiRequest['entity'], 'action' => $action, 'version' => $apiRequest['version']); try { list($apiProvider, $hypApiRequest) = \Civi::service('civi_api_kernel')->resolve($hypApiRequest); if (isset($hypApiRequest['function'])) { $helper = '_' . $hypApiRequest['function'] . '_spec'; } else { // not implemented MagicFunctionProvider $helper = NULL; } } catch (\Civi\API\Exception\NotImplementedException $e) { $helper = NULL; } if (function_exists($helper)) { // alter $helper($metadata, $apiRequest); } foreach ($metadata as $fieldname => $fieldSpec) { // Ensure 'name' is set if (!isset($fieldSpec['name'])) { $metadata[$fieldname]['name'] = $fieldname; } _civicrm_api3_generic_get_metadata_options($metadata, $apiRequest, $fieldname, $fieldSpec); // Convert options to "sequential" format if ($sequential && !empty($metadata[$fieldname]['options'])) { $metadata[$fieldname]['options'] = CRM_Utils_Array::makeNonAssociative($metadata[$fieldname]['options']); } } $results[$entity][$action][$sequential] = civicrm_api3_create_success($metadata, $apiRequest['params'], $entity, 'getfields'); return $results[$entity][$action][$sequential]; }
/** * Create two entities and make sure we can fetch them individually by ID (e.g. using "contact_id=>2" * or "group_id=>4") * * @dataProvider entities_get * * limitations include the problem with avoiding loops when creating test objects - * hence FKs only set by createTestObject when required. e.g parent_id on campaign is not being followed through * Currency - only seems to support US */ public function testByIDAlias_get($entityName) { if (in_array($entityName, self::toBeSkipped_automock(TRUE))) { // $this->markTestIncomplete("civicrm_api3_{$Entity}_create to be implemented"); return; } $baoString = _civicrm_api3_get_DAO($entityName); if (empty($baoString)) { $this->markTestIncomplete("Entity [{$entityName}] cannot be mocked - no known DAO"); return; } $idFieldName = _civicrm_api_get_entity_name_from_camel($entityName) . '_id'; // create entities $baoObj1 = CRM_Core_DAO::createTestObject($baoString, array('currency' => 'USD')); $this->assertTrue(is_integer($baoObj1->id), 'check first id'); $this->deletableTestObjects[$baoString][] = $baoObj1->id; $baoObj2 = CRM_Core_DAO::createTestObject($baoString, array('currency' => 'USD')); $this->assertTrue(is_integer($baoObj2->id), 'check second id'); $this->deletableTestObjects[$baoString][] = $baoObj2->id; // fetch first by ID $result = civicrm_api($entityName, 'get', array('version' => 3, $idFieldName => $baoObj1->id)); $this->assertAPISuccess($result); $this->assertTrue(!empty($result['values'][$baoObj1->id]), 'Should find first object by id'); $this->assertEquals($baoObj1->id, $result['values'][$baoObj1->id]['id'], 'Should find id on first object'); $this->assertEquals(1, count($result['values'])); // fetch second by ID $result = civicrm_api($entityName, 'get', array('version' => 3, $idFieldName => $baoObj2->id)); $this->assertAPISuccess($result); $this->assertTrue(!empty($result['values'][$baoObj2->id]), 'Should find second object by id'); $this->assertEquals($baoObj2->id, $result['values'][$baoObj2->id]['id'], 'Should find id on second object'); $this->assertEquals(1, count($result['values'])); }
/** * Having a DAO object find the entity name * @param object $bao DAO being passed in * @return string */ function _civicrm_api_get_entity_name_from_dao($bao) { $daoName = str_replace("BAO", "DAO", get_class($bao)); return _civicrm_api_get_entity_name_from_camel(CRM_Core_DAO_AllCoreTables::getBriefName($daoName)); }
/** * @param int $id * @param $values * @param int $wildcard * @param bool $useEquals * * @param string $apiEntity * * @return array|null */ public static function &fixWhereValues($id, &$values, $wildcard = 0, $useEquals = FALSE, $apiEntity = NULL) { // skip a few search variables static $skipWhere = NULL; static $likeNames = NULL; $result = NULL; // Change camelCase EntityName to lowercase with underscores $apiEntity = _civicrm_api_get_entity_name_from_camel($apiEntity); if (CRM_Utils_System::isNull($values)) { return $result; } if (!$skipWhere) { $skipWhere = array('task', 'radio_ts', 'uf_group_id', 'component_mode', 'qfKey', 'operator'); } if (in_array($id, $skipWhere) || substr($id, 0, 4) == '_qf_' || substr($id, 0, 7) == 'hidden_') { return $result; } if ($apiEntity && substr($id, 0, strlen($apiEntity)) != $apiEntity) { $id = $apiEntity . '_' . $id; } if (!$likeNames) { $likeNames = array('relationship_target_name'); } if (!$useEquals && in_array($id, $likeNames)) { $result = array($id, 'LIKE', $values, 0, 1); } elseif (is_string($values) && strpos($values, '%') !== FALSE) { $result = array($id, 'LIKE', $values, 0, 0); } elseif ($id == 'relationship_type_id') { $result = array($id, 'IN', $values, 0, $wildcard); } else { $result = array($id, '=', $values, 0, $wildcard); } return $result; }
protected function execute(InputInterface $input, OutputInterface $output) { // load Civi to get access to civicrm_api_get_function_name $civicrm_api3 = $this->getContainer()->get('civicrm_api3'); if (!$civicrm_api3 || !$civicrm_api3->local) { $output->writeln("<error>--copy requires access to local CiviCRM source tree. Configure civicrm_api3_conf_path.</error>"); return; } $ctx = array(); $ctx['type'] = 'module'; $ctx['basedir'] = rtrim(getcwd(), '/'); $basedir = new Path($ctx['basedir']); $info = new Info($basedir->string('info.xml')); $info->load($ctx); $attrs = $info->get()->attributes(); if ($attrs['type'] != 'module') { $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>'); return; } if (!preg_match('/^[A-Za-z0-9]+$/', $input->getArgument('<EntityName>'))) { throw new Exception("Entity name must be alphanumeric camel-case"); } if (!preg_match('/^[A-Za-z0-9]+$/', $input->getArgument('<ActionName>'))) { throw new Exception("Action name must be alphanumeric camel-case"); } if ($input->getOption('schedule') && !in_array($input->getOption('schedule'), self::getSchedules())) { throw new Exception("Schedule must be one of: " . implode(', ', self::getSchedules())); } $ctx['entityNameCamel'] = ucfirst($input->getArgument('<EntityName>')); $ctx['actionNameCamel'] = ucfirst($input->getArgument('<ActionName>')); if (function_exists('civicrm_api_get_function_name')) { $ctx['apiFunction'] = strtolower(civicrm_api_get_function_name($ctx['entityNameCamel'], $ctx['actionNameCamel'], self::API_VERSION)); } elseif (function_exists('_civicrm_api_get_entity_name_from_camel')) { $ctx['apiFunction'] = 'civicrm_api' . self::API_VERSION . '_' . _civicrm_api_get_entity_name_from_camel($ctx['entityNameCamel']) . '_' . $ctx['actionNameCamel']; } else { throw new Exception("Failed to determine proper API function name. Perhaps the API internals have changed?"); } $ctx['apiFile'] = $basedir->string('api', 'v3', $ctx['entityNameCamel'], $ctx['actionNameCamel'] . '.php'); $ctx['apiCronFile'] = $basedir->string('api', 'v3', $ctx['entityNameCamel'], $ctx['actionNameCamel'] . '.mgd.php'); $dirs = new Dirs(array(dirname($ctx['apiFile']))); $dirs->save($ctx, $output); if (!file_exists($ctx['apiFile'])) { $output->writeln(sprintf('<info>Write %s</info>', $ctx['apiFile'])); file_put_contents($ctx['apiFile'], $this->getContainer()->get('templating')->render('CRMCivixBundle:Code:api.php.php', $ctx)); } else { $output->writeln(sprintf('<error>Skip %s: file already exists</error>', $ctx['apiFile'])); } if ($input->getOption('schedule')) { if (!file_exists($ctx['apiCronFile'])) { $mgdEntities = array(array('name' => 'Cron:' . $ctx['entityNameCamel'] . '.' . $ctx['actionNameCamel'], 'entity' => 'Job', 'params' => array('version' => 3, 'name' => sprintf('Call %s.%s API', $ctx['entityNameCamel'], $ctx['actionNameCamel']), 'description' => sprintf('Call %s.%s API', $ctx['entityNameCamel'], $ctx['actionNameCamel']), 'run_frequency' => $input->getOption('schedule'), 'api_entity' => $ctx['entityNameCamel'], 'api_action' => $ctx['actionNameCamel'], 'parameters' => ''))); $header = "// This file declares a managed database record of type \"Job\".\n" . "// The record will be automatically inserted, updated, or deleted from the\n" . "// database as appropriate. For more details, see \"hook_civicrm_managed\" at:\n" . "// http://wiki.civicrm.org/confluence/display/CRMDOC42/Hook+Reference"; $mgdBuilder = new PhpData($ctx['apiCronFile'], $header); $mgdBuilder->set($mgdEntities); $mgdBuilder->save($ctx, $output); } else { $output->writeln(sprintf('<error>Skip %s: file already exists</error>', $ctx['apiCronFile'])); } } $module = new Module($this->getContainer()->get('templating')); $module->loadInit($ctx); $module->save($ctx, $output); }
/** * Function to return the DAO of the function or Entity * @param String $name either a function of the api (civicrm_{entity}_create or the entity name * return the DAO name to manipulate this function * eg. "civicrm_api3_contact_create" or "Contact" will return "CRM_Contact_BAO_Contact" * @return mixed|string */ function _civicrm_api3_get_DAO($name) { if (strpos($name, 'civicrm_api3') !== FALSE) { $last = strrpos($name, '_'); // len ('civicrm_api3_') == 13 $name = substr($name, 13, $last - 13); } $name = _civicrm_api_get_camel_name($name, 3); if ($name == 'Individual' || $name == 'Household' || $name == 'Organization') { $name = 'Contact'; } // hack to deal with incorrectly named BAO/DAO - see CRM-10859 // FIXME: DAO should be renamed CRM_Mailing_DAO_MailingRecipients // but am not confident mailing_recipients is tested so have not tackled. if ($name == 'MailingRecipients') { return 'CRM_Mailing_DAO_Recipients'; } // FIXME: DAO should be renamed CRM_Mailing_DAO_MailingComponent if ($name == 'MailingComponent') { return 'CRM_Mailing_DAO_Component'; } // FIXME: DAO should be renamed CRM_ACL_DAO_AclRole if ($name == 'AclRole') { return 'CRM_ACL_DAO_EntityRole'; } // FIXME: DAO should be renamed CRM_SMS_DAO_SmsProvider // But this would impact SMS extensions so need to coordinate // Probably best approach is to migrate them to use the api and decouple them from core BAOs if ($name == 'SmsProvider') { return 'CRM_SMS_DAO_Provider'; } // FIXME: DAO names should follow CamelCase convention if ($name == 'Im' || $name == 'Acl') { $name = strtoupper($name); } $dao = CRM_Core_DAO_AllCoreTables::getFullName($name); if ($dao || !$name) { return $dao; } // Really weird apis can declare their own DAO name. Not sure if this is a good idea... if (file_exists("api/v3/{$name}.php")) { include_once "api/v3/{$name}.php"; } $daoFn = "_civicrm_api3_" . _civicrm_api_get_entity_name_from_camel($name) . "_DAO"; if (function_exists($daoFn)) { return $daoFn(); } return NULL; }
/** * Get information about fields for a given api request. Getfields information * is used for documentation, validation, default setting * We first query the scheme using the $dao->fields function & then augment * that information by calling the _spec functions that apply to the relevant function * Note that we use 'unique' field names as described in the xml/schema files * for get requests & just field name for create. This is because some get functions * access multiple objects e.g. contact api accesses is_deleted from the activity * table & from the contact table * * @param array $apiRequest api request as an array. Keys are * - entity: string * - action: string * - version: string * - function: callback (mixed) * - params: array, varies * @return array API success object */ function civicrm_api3_generic_getfields($apiRequest) { static $results = array(); if (CRM_Utils_Array::value('cache_clear', $apiRequest['params'])) { $results = array(); } $entity = _civicrm_api_get_camel_name($apiRequest['entity']); $lcase_entity = _civicrm_api_get_entity_name_from_camel($entity); $subentity = CRM_Utils_Array::value('contact_type', $apiRequest['params']); $action = strtolower(CRM_Utils_Array::value('action', $apiRequest['params'])); if ($action == 'getvalue' || $action == 'getvalue' || $action == 'getcount') { $action = 'get'; } if (empty($action)) { if (CRM_Utils_Array::value($entity . $subentity, $results) && CRM_Utils_Array::value('values', $results[$entity . $subentity])) { return $results[$entity . $subentity]; } else { $values = _civicrm_api_get_fields($entity); $results[$entity] = civicrm_api3_create_success($values, $apiRequest['params'], $entity, 'getfields'); return $results[$entity]; } } // determines whether to use unique field names - seem comment block above $unique = TRUE; if (isset($results[$entity . $subentity]) && CRM_Utils_Array::value($action, $results[$entity])) { return $results[$entity . $subentity][$action]; } // defaults based on data model and API policy switch ($action) { case 'getfields': $values = _civicrm_api_get_fields($entity, $apiRequest['params']); $results[$entity][$action] = civicrm_api3_create_success($values, $apiRequest['params'], $entity, 'getfields'); return $results[$entity][$action]; case 'create': case 'update': case 'replace': $unique = FALSE; case 'get': $metadata = _civicrm_api_get_fields($apiRequest['entity'], $unique, $apiRequest['params']); if (empty($metadata['id']) && !empty($metadata[$apiRequest['entity'] . '_id'])) { $metadata['id'] = $metadata[$lcase_entity . '_id']; $metadata['id']['api.aliases'] = array($lcase_entity . '_id'); unset($metadata[$lcase_entity . '_id']); } break; case 'delete': $metadata = array('id' => array('title' => 'Unique Identifier', 'api.required' => 1, 'api.aliases' => array($lcase_entity . '_id'))); break; default: // oddballs are on their own $metadata = array(); } // find any supplemental information $hypApiRequest = array('entity' => $apiRequest['entity'], 'action' => $action, 'version' => $apiRequest['version']); $hypApiRequest += _civicrm_api_resolve($hypApiRequest); $helper = '_' . $hypApiRequest['function'] . '_spec'; if (function_exists($helper)) { // alter $helper($metadata); } foreach ($metadata as $fieldname => $field) { if (array_key_exists('pseudoconstant', $field) && !CRM_Utils_Array::value('FKClassName', $field)) { $options = civicrm_api('constant', 'get', array('version' => 3, 'name' => $field['pseudoconstant'])); if (is_array(CRM_Utils_Array::value('values', $options))) { $metadata[$fieldname]['options'] = $options['values']; } } if (array_key_exists('enumValues', $field)) { $metadata[$fieldname]['options'] = explode(',', $field['enumValues']); } } $results[$entity][$action] = civicrm_api3_create_success($metadata, $apiRequest['params'], NULL, 'getfields'); return $results[$entity][$action]; }
/** * Call any nested api calls * * TODO: We don't really need this to be a separate function. */ protected function _civicrm_api_call_nested_api(&$params, &$result, $action, $entity, $version) { $entity = _civicrm_api_get_entity_name_from_camel($entity); //we don't need to worry about nested api in the getfields/getoptions actions, so just return immediately if (in_array(strtolower($action), array('getfields', 'getoptions'))) { return; } if (strtolower($action) == 'getsingle') { // I don't understand the protocol here, but we don't want // $result to be a recursive array // $result['values'][0] = $result; $oldResult = $result; $result = array('values' => array(0 => $oldResult)); } foreach ($params as $field => $newparams) { if ((is_array($newparams) || $newparams === 1) && $field != 'api.has_parent' && substr($field, 0, 3) == 'api') { // 'api.participant.delete' => 1 is a valid options - handle 1 instead of an array if ($newparams === 1) { $newparams = array('version' => $version); } // can be api_ or api. $separator = $field[3]; if (!($separator == '.' || $separator == '_')) { continue; } $subAPI = explode($separator, $field); $subaction = empty($subAPI[2]) ? $action : $subAPI[2]; $subParams = array('debug' => \CRM_Utils_Array::value('debug', $params)); $subEntity = $subAPI[1]; foreach ($result['values'] as $idIndex => $parentAPIValues) { if (strtolower($subEntity) != 'contact') { //contact spits the dummy at activity_id so what else won't it like? //set entity_id & entity table based on the parent's id & entity. e.g for something like //note if the parent call is contact 'entity_table' will be set to 'contact' & 'id' to the contact id from //the parent call. //in this case 'contact_id' will also be set to the parent's id $subParams["entity_id"] = $parentAPIValues['id']; $subParams['entity_table'] = 'civicrm_' . _civicrm_api_get_entity_name_from_camel($entity); $subParams[strtolower($entity) . "_id"] = $parentAPIValues['id']; } if (strtolower($entity) != 'contact' && \CRM_Utils_Array::value(strtolower($subEntity . "_id"), $parentAPIValues)) { //e.g. if event_id is in the values returned & subentity is event then pass in event_id as 'id' //don't do this for contact as it does some wierd things like returning primary email & //thus limiting the ability to chain email //TODO - this might need the camel treatment $subParams['id'] = $parentAPIValues[$subEntity . "_id"]; } if (\CRM_Utils_Array::value('entity_table', $result['values'][$idIndex]) == $subEntity) { $subParams['id'] = $result['values'][$idIndex]['entity_id']; } // if we are dealing with the same entity pass 'id' through (useful for get + delete for example) if (strtolower($entity) == strtolower($subEntity)) { $subParams['id'] = $result['values'][$idIndex]['id']; } $subParams['version'] = $version; if (!empty($params['check_permissions'])) { $subParams['check_permissions'] = $params['check_permissions']; } $subParams['sequential'] = 1; $subParams['api.has_parent'] = 1; if (array_key_exists(0, $newparams)) { $genericParams = $subParams; // it is a numerically indexed array - ie. multiple creates foreach ($newparams as $entityparams) { $subParams = array_merge($genericParams, $entityparams); _civicrm_api_replace_variables($subAPI[1], $subaction, $subParams, $result['values'][$idIndex], $separator); $result['values'][$result['id']][$field][] = civicrm_api($subEntity, $subaction, $subParams); if ($result['is_error'] === 1) { throw new \Exception($subEntity . ' ' . $subaction . 'call failed with' . $result['error_message']); } } } else { $subParams = array_merge($subParams, $newparams); _civicrm_api_replace_variables($subAPI[1], $subaction, $subParams, $result['values'][$idIndex], $separator); $result['values'][$idIndex][$field] = civicrm_api($subEntity, $subaction, $subParams); if (!empty($result['is_error'])) { throw new \Exception($subEntity . ' ' . $subaction . 'call failed with' . $result['error_message']); } } } } } if (strtolower($action) == 'getsingle') { $result = $result['values'][0]; } }
/** * Function to return the DAO of the function or Entity * @param String $name either a function of the api (civicrm_{entity}_create or the entity name * return the DAO name to manipulate this function * eg. "civicrm_api3_contact_create" or "Contact" will return "CRM_Contact_BAO_Contact" * @return mixed|string */ function _civicrm_api3_get_DAO($name) { if (strpos($name, 'civicrm_api3') !== FALSE) { $last = strrpos($name, '_'); // len ('civicrm_api3_') == 13 $name = substr($name, 13, $last - 13); } $name = _civicrm_api_get_camel_name($name, 3); if ($name == 'Individual' || $name == 'Household' || $name == 'Organization') { $name = 'Contact'; } //hack to deal with incorrectly named BAO/DAO - see CRM-10859 - // several of these have been removed but am not confident mailing_recipients is // tests so have not tackled. // correct approach for im is unclear if ($name == 'mailing_recipients' || $name == 'MailingRecipients') { return 'CRM_Mailing_BAO_Recipients'; } if (strtolower($name) == 'im') { return 'CRM_Core_BAO_IM'; } $dao = CRM_Core_DAO_AllCoreTables::getFullName($name); if ($dao || !$name) { return $dao; } // Really weird apis can declare their own DAO name. Not sure if this is a good idea... if (file_exists("api/v3/{$name}.php")) { include_once "api/v3/{$name}.php"; } $daoFn = "_civicrm_api3_" . _civicrm_api_get_entity_name_from_camel($name) . "_DAO"; if (function_exists($daoFn)) { return $daoFn(); } return NULL; }
function testFromCamel() { $cases = array('Contribution' => 'contribution', 'contribution' => 'contribution', 'OptionValue' => 'option_value', 'optionValue' => 'option_value', 'option_value' => 'option_value', 'UFJoin' => 'uf_join', 'ufJoin' => 'uf_join', 'uf_join' => 'uf_join'); foreach ($cases as $input => $expected) { $actual = _civicrm_api_get_entity_name_from_camel($input); $this->assertEquals($expected, $actual, sprintf('input=%s expected=%s actual=%s', $input, $expected, $actual)); } }
/** * Get documentation block. * * @param string $entity * @param string|null $action * @return array|bool * [docblock, code] */ private static function getDocBlock($entity, $action) { if (!$entity) { return FALSE; } $file = "api/v3/{$entity}.php"; $contents = file_get_contents($file, FILE_USE_INCLUDE_PATH); if (!$contents) { // Api does not exist return FALSE; } $docblock = $code = array(); // Fetch docblock for the api file if (!$action) { if (preg_match('#/\\*\\*\\n.*?\\n \\*/\\n#s', $contents, $docblock)) { return array($docblock[0], NULL, $file); } } else { $action = strtolower($action); $fnName = 'civicrm_api3_' . _civicrm_api_get_entity_name_from_camel($entity) . '_' . $action; // Support the alternate "1 file per action" structure $actionFile = "api/v3/{$entity}/" . ucfirst($action) . '.php'; $actionFileContents = file_get_contents("api/v3/{$entity}/" . ucfirst($action) . '.php', FILE_USE_INCLUDE_PATH); if ($actionFileContents) { $file = $actionFile; $contents = $actionFileContents; } // If action isn't in this file, try generic if (strpos($contents, "function {$fnName}") === FALSE) { $fnName = "civicrm_api3_generic_{$action}"; $file = "api/v3/Generic/" . ucfirst($action) . '.php'; $contents = file_get_contents($file, FILE_USE_INCLUDE_PATH); if (!$contents) { $file = "api/v3/Generic.php"; $contents = file_get_contents($file, FILE_USE_INCLUDE_PATH); } } if (preg_match('#(/\\*\\*(\\n \\*.*)*\\n \\*/\\n)function[ ]+' . $fnName . '#i', $contents, $docblock)) { // Fetch the code in a separate regex to preserve sanity preg_match("#^function[ ]+{$fnName}.*?^}#ism", $contents, $code); return array($docblock[1], $code[0], $file); } } }
/** * Decide what permissions to check for an api call * * @param $entity : (str) api entity * @param $action : (str) api action * @param $params : (array) api params * * @return array * Array of permissions to check for this entity-action combo */ function _civicrm_api3_permissions($entity, $action, &$params) { // FIXME: Lowercase entity_names are nonstandard but difficult to fix here // because this function invokes hook_civicrm_alterAPIPermissions $entity = _civicrm_api_get_entity_name_from_camel($entity); /** * @var array of permissions * * For each entity, we declare an array of permissions required for each action * The action is the array key, possible values: * * create: applies to create (with no id in params) * * update: applies to update, setvalue, create (with id in params) * * get: applies to getcount, getsingle, getvalue and other gets * * delete: applies to delete, replace * * meta: applies to getfields, getoptions, getspec * * default: catch-all for anything not declared * * Note: some APIs declare other actions as well * * Permissions should use arrays for AND and arrays of arrays for OR * @see CRM_Core_Permission::check for more documentation */ $permissions = array(); // These are the default permissions - if any entity does not declare permissions for a given action, // (or the entity does not declare permissions at all) - then the action will be used from here $permissions['default'] = array('meta' => array('access CiviCRM'), 'default' => array('administer CiviCRM')); // Note: Additional permissions in DynamicFKAuthorization $permissions['attachment'] = array('default' => array(array('access CiviCRM', 'access AJAX API'))); // Contact permissions $permissions['contact'] = array('create' => array('access CiviCRM', 'add contacts'), 'delete' => array('access CiviCRM', 'delete contacts'), 'get' => array(), 'update' => array(), 'getquick' => array(array('access CiviCRM', 'access AJAX API'))); // CRM-16963 - Permissions for country. $permissions['country'] = array('get' => array('access CiviCRM'), 'default' => array('administer CiviCRM')); // Contact-related data permissions. $permissions['address'] = array('default' => array()); $permissions['email'] = $permissions['address']; $permissions['phone'] = $permissions['address']; $permissions['website'] = $permissions['address']; $permissions['im'] = $permissions['address']; // @todo - implement CRM_Core_BAO_EntityTag::addSelectWhereClause and remove this heavy-handed restriction $permissions['entity_tag'] = array('get' => array('access CiviCRM', 'view all contacts'), 'default' => array('access CiviCRM', 'edit all contacts')); // @todo - ditto $permissions['note'] = $permissions['entity_tag']; // Allow non-admins to get and create tags to support tagset widget // Delete is still reserved for admins $permissions['tag'] = array('get' => array('access CiviCRM'), 'create' => array('access CiviCRM'), 'update' => array('access CiviCRM')); //relationship permissions $permissions['relationship'] = array('get' => array(), 'delete' => array('access CiviCRM', 'edit all contacts'), 'default' => array('access CiviCRM', 'edit all contacts')); // CRM-17741 - Permissions for RelationshipType. $permissions['relationship_type'] = array('get' => array('access CiviCRM'), 'default' => array('administer CiviCRM')); // Activity permissions $permissions['activity'] = array('delete' => array('access CiviCRM', 'delete activities'), 'default' => array('access CiviCRM', 'view all activities')); // Case permissions $permissions['case'] = array('create' => array('access CiviCRM', 'add cases'), 'delete' => array('access CiviCRM', 'delete in CiviCase'), 'default' => array(array('access my cases and activities', 'access all cases and activities'))); $permissions['case_contact'] = $permissions['case']; $permissions['case_type'] = array('default' => array('administer CiviCase'), 'get' => array(array('access my cases and activities', 'access all cases and activities'))); // Campaign permissions $permissions['campaign'] = array('get' => array('access CiviCRM'), 'default' => array(array('administer CiviCampaign', 'manage campaign'))); $permissions['survey'] = $permissions['campaign']; // Financial permissions $permissions['contribution'] = array('get' => array('access CiviCRM', 'access CiviContribute'), 'delete' => array('access CiviCRM', 'access CiviContribute', 'delete in CiviContribute'), 'completetransaction' => array('edit contributions'), 'default' => array('access CiviCRM', 'access CiviContribute', 'edit contributions')); $permissions['line_item'] = $permissions['contribution']; // Custom field permissions $permissions['custom_field'] = array('default' => array('administer CiviCRM', 'access all custom data')); $permissions['custom_group'] = $permissions['custom_field']; // Event permissions $permissions['event'] = array('create' => array('access CiviCRM', 'access CiviEvent', 'edit all events'), 'delete' => array('access CiviCRM', 'access CiviEvent', 'delete in CiviEvent'), 'get' => array('access CiviCRM', 'access CiviEvent', 'view event info'), 'update' => array('access CiviCRM', 'access CiviEvent', 'edit all events')); // Loc block is only used for events $permissions['loc_block'] = $permissions['event']; // File permissions $permissions['file'] = array('default' => array('access CiviCRM', 'access uploaded files')); $permissions['files_by_entity'] = $permissions['file']; // Group permissions $permissions['group'] = array('get' => array('access CiviCRM'), 'default' => array('access CiviCRM', 'edit groups')); $permissions['group_nesting'] = $permissions['group']; $permissions['group_organization'] = $permissions['group']; //Group Contact permission $permissions['group_contact'] = array('get' => array('access CiviCRM'), 'default' => array('access CiviCRM', 'edit all contacts')); // CiviMail Permissions $civiMailBasePerms = array('access CiviMail', 'create mailings', 'schedule mailings', 'approve mailings'); $permissions['mailing'] = array('get' => array('access CiviCRM', $civiMailBasePerms), 'delete' => array('access CiviCRM', $civiMailBasePerms, 'delete in CiviMail'), 'submit' => array('access CiviCRM', array('access CiviMail', 'schedule mailings')), 'default' => array('access CiviCRM', $civiMailBasePerms)); $permissions['mailing_group'] = $permissions['mailing']; $permissions['mailing_job'] = $permissions['mailing']; $permissions['mailing_recipients'] = $permissions['mailing']; $permissions['mailing_a_b'] = array('get' => array('access CiviCRM', 'access CiviMail'), 'delete' => array('access CiviCRM', 'access CiviMail', 'delete in CiviMail'), 'submit' => array('access CiviCRM', array('access CiviMail', 'schedule mailings')), 'default' => array('access CiviCRM', 'access CiviMail')); // Membership permissions $permissions['membership'] = array('get' => array('access CiviCRM', 'access CiviMember'), 'delete' => array('access CiviCRM', 'access CiviMember', 'delete in CiviMember'), 'default' => array('access CiviCRM', 'access CiviMember', 'edit memberships')); $permissions['membership_status'] = $permissions['membership']; $permissions['membership_type'] = $permissions['membership']; $permissions['membership_payment'] = array('create' => array('access CiviCRM', 'access CiviMember', 'edit memberships', 'access CiviContribute', 'edit contributions'), 'delete' => array('access CiviCRM', 'access CiviMember', 'delete in CiviMember', 'access CiviContribute', 'delete in CiviContribute'), 'get' => array('access CiviCRM', 'access CiviMember', 'access CiviContribute'), 'update' => array('access CiviCRM', 'access CiviMember', 'edit memberships', 'access CiviContribute', 'edit contributions')); // Participant permissions $permissions['participant'] = array('create' => array('access CiviCRM', 'access CiviEvent', 'register for events'), 'delete' => array('access CiviCRM', 'access CiviEvent', 'edit event participants'), 'get' => array('access CiviCRM', 'access CiviEvent', 'view event participants'), 'update' => array('access CiviCRM', 'access CiviEvent', 'edit event participants')); $permissions['participant_payment'] = array('create' => array('access CiviCRM', 'access CiviEvent', 'register for events', 'access CiviContribute', 'edit contributions'), 'delete' => array('access CiviCRM', 'access CiviEvent', 'edit event participants', 'access CiviContribute', 'delete in CiviContribute'), 'get' => array('access CiviCRM', 'access CiviEvent', 'view event participants', 'access CiviContribute'), 'update' => array('access CiviCRM', 'access CiviEvent', 'edit event participants', 'access CiviContribute', 'edit contributions')); // Pledge permissions $permissions['pledge'] = array('create' => array('access CiviCRM', 'access CiviPledge', 'edit pledges'), 'delete' => array('access CiviCRM', 'access CiviPledge', 'delete in CiviPledge'), 'get' => array('access CiviCRM', 'access CiviPledge'), 'update' => array('access CiviCRM', 'access CiviPledge', 'edit pledges')); //CRM-16777: Disable schedule reminder for user that have 'edit all events' and 'administer CiviCRM' permission. $permissions['action_schedule'] = array('update' => array(array('access CiviCRM', 'edit all events'))); $permissions['pledge_payment'] = array('create' => array('access CiviCRM', 'access CiviPledge', 'edit pledges', 'access CiviContribute', 'edit contributions'), 'delete' => array('access CiviCRM', 'access CiviPledge', 'delete in CiviPledge', 'access CiviContribute', 'delete in CiviContribute'), 'get' => array('access CiviCRM', 'access CiviPledge', 'access CiviContribute'), 'update' => array('access CiviCRM', 'access CiviPledge', 'edit pledges', 'access CiviContribute', 'edit contributions')); // Profile permissions $permissions['profile'] = array('get' => array()); $permissions['uf_group'] = array('create' => array('access CiviCRM', array('administer CiviCRM', 'manage event profiles')), 'get' => array('access CiviCRM'), 'update' => array('access CiviCRM', array('administer CiviCRM', 'manage event profiles'))); $permissions['uf_field'] = $permissions['uf_join'] = $permissions['uf_group']; $permissions['uf_field']['delete'] = array('access CiviCRM', array('administer CiviCRM', 'manage event profiles')); $permissions['option_value'] = $permissions['uf_group']; $permissions['option_group'] = $permissions['option_value']; $permissions['message_template'] = array('get' => array('access CiviCRM'), 'create' => array('edit message templates'), 'update' => array('edit message templates')); // Translate 'create' action to 'update' if id is set if ($action == 'create' && (!empty($params['id']) || !empty($params[$entity . '_id']))) { $action = 'update'; } // let third parties modify the permissions CRM_Utils_Hook::alterAPIPermissions($entity, $action, $params, $permissions); // Merge permissions for this entity with the defaults $perm = CRM_Utils_Array::value($entity, $permissions, array()) + $permissions['default']; // Return exact match if permission for this action has been declared if (isset($perm[$action])) { return $perm[$action]; } // Translate specific actions into their generic equivalents $snippet = substr($action, 0, 3); if ($action == 'replace' || $snippet == 'del') { // 'Replace' is a combination of get+create+update+delete; however, the permissions // on each of those will be tested separately at runtime. This is just a sniff-test // based on the heuristic that 'delete' tends to be the most closely guarded // of the necessary permissions. $action = 'delete'; } elseif ($action == 'setvalue' || $snippet == 'upd') { $action = 'update'; } elseif ($action == 'getfields' || $action == 'getfield' || $action == 'getspec' || $action == 'getoptions') { $action = 'meta'; } elseif ($snippet == 'get') { $action = 'get'; } return isset($perm[$action]) ? $perm[$action] : $perm['default']; }
/** * Here we map the profile fields as stored in the uf_field table to their 'real entity' * we also return the profile fieldname * * @param $field * * @return array */ function _civicrm_api3_map_profile_fields_to_entity(&$field) { $entity = $field['field_type']; $contactTypes = civicrm_api3('contact', 'getoptions', array('field' => 'contact_type')); if (in_array($entity, $contactTypes['values'])) { $entity = 'contact'; } $entity = _civicrm_api_get_entity_name_from_camel($entity); $locationFields = array('email' => 'email'); $fieldName = $field['field_name']; if (!empty($field['location_type_id'])) { if ($fieldName == 'email') { $entity = 'email'; } else { $entity = 'address'; } $fieldName .= '-' . $field['location_type_id']; } elseif (array_key_exists($fieldName, $locationFields)) { $fieldName .= '-Primary'; $entity = 'email'; } if (!empty($field['phone_type_id'])) { $fieldName .= '-' . $field['location_type_id']; $entity = 'phone'; } // @todo - sort this out! //here we do a hard-code list of known fields that don't map to where they are mapped to // not a great solution but probably if we looked in the BAO we'd find a scary switch statement // in a perfect world the uf_field table would hold the correct entity for each item // & only the relationships between entities would need to be coded $hardCodedEntityMappings = array('street_address' => 'address', 'street_number' => 'address', 'supplemental_address_1' => 'address', 'supplemental_address_2' => 'address', 'supplemental_address_3' => 'address', 'postal_code' => 'address', 'city' => 'address', 'email' => 'email', 'state_province' => 'address', 'country' => 'address', 'county' => 'address', 'financial_type' => 'contribution', 'total_amount' => 'contribution', 'receive_date' => 'contribution', 'payment_instrument' => 'contribution', 'check_number' => 'contribution', 'contribution_status_id' => 'contribution', 'soft_credit' => 'contribution', 'soft_credit_type' => 'contribution_soft', 'group' => 'group_contact', 'tag' => 'entity_tag'); if (array_key_exists($fieldName, $hardCodedEntityMappings)) { $entity = $hardCodedEntityMappings[$fieldName]; } return array($entity, $fieldName); }
/** * Get information about fields for a given api request. Getfields information * is used for documentation, validation, default setting * We first query the scheme using the $dao->fields function & then augment * that information by calling the _spec functions that apply to the relevant function * Note that we use 'unique' field names as described in the xml/schema files * for get requests & just field name for create. This is because some get functions * access multiple objects e.g. contact api accesses is_deleted from the activity * table & from the contact table * * @param array $apiRequest api request as an array. Keys are * - entity: string * - action: string * - version: string * - function: callback (mixed) * - params: array, varies * @return array API success object */ function civicrm_api3_generic_getfields($apiRequest) { static $results = array(); if (CRM_Utils_Array::value('cache_clear', $apiRequest['params'])) { $results = array(); // we will also clear pseudoconstants here - should potentially be moved to relevant BAO classes CRM_Core_PseudoConstant::flush(); if (!empty($apiRequest['params']['fieldname'])) { CRM_Utils_PseudoConstant::flushConstant($apiRequest['params']['fieldname']); } if (!empty($apiRequest['params']['option_group_id'])) { $optionGroupName = civicrm_api('option_group', 'getvalue', array('version' => 3, 'id' => $apiRequest['params']['option_group_id'], 'return' => 'name')); if (is_string($optionGroupName)) { CRM_Utils_PseudoConstant::flushConstant(_civicrm_api_get_camel_name($optionGroupName)); } } } $entity = _civicrm_api_get_camel_name($apiRequest['entity']); $lcase_entity = _civicrm_api_get_entity_name_from_camel($entity); $subentity = CRM_Utils_Array::value('contact_type', $apiRequest['params']); $action = strtolower(CRM_Utils_Array::value('action', $apiRequest['params'])); $sequential = empty($apiRequest['params']) ? 0 : 1; $apiOptions = CRM_Utils_Array::value('options', $apiRequest['params'], array()); if ($action == 'getvalue' || $action == 'getvalue' || $action == 'getcount') { $action = 'get'; } if (empty($action)) { $action = 'get'; } // determines whether to use unique field names - seem comment block above $unique = TRUE; if (empty($apiOptions) && isset($results[$entity . $subentity]) && isset($action, $results[$entity . $subentity]) && isset($action, $results[$entity . $subentity][$sequential])) { return $results[$entity . $subentity][$action][$sequential]; } // defaults based on data model and API policy switch ($action) { case 'getfields': $values = _civicrm_api_get_fields($entity, false, $apiRequest['params']); return civicrm_api3_create_success($values, $apiRequest['params'], $entity, 'getfields'); case 'create': case 'update': case 'replace': $unique = FALSE; case 'get': $metadata = _civicrm_api_get_fields($apiRequest['entity'], $unique, $apiRequest['params']); if (empty($metadata['id'])) { // if id is not set we will set it eg. 'id' from 'case_id', case_id will be an alias if (!empty($metadata[strtolower($apiRequest['entity']) . '_id'])) { $metadata['id'] = $metadata[$lcase_entity . '_id']; unset($metadata[$lcase_entity . '_id']); $metadata['id']['api.aliases'] = array($lcase_entity . '_id'); } } else { // really the preference would be to set the unique name in the xml // question is which is a less risky fix this close to a release - setting in xml for the known failure // (note) or setting for all api where fields is returning 'id' & we want to accept 'note_id' @ the api layer // nb we don't officially accept note_id anyway - rationale here is more about centralising a now-tested // inconsistency $metadata['id']['api.aliases'] = array($lcase_entity . '_id'); } break; case 'delete': $metadata = array('id' => array('title' => 'Unique Identifier', 'api.required' => 1, 'api.aliases' => array($lcase_entity . '_id'), 'type' => CRM_Utils_Type::T_INT)); break; case 'getoptions': $metadata = array('field' => array('title' => 'Field to retrieve options for', 'api.required' => 1), 'context' => array('title' => 'Context string')); break; default: // oddballs are on their own $metadata = array(); } // find any supplemental information $hypApiRequest = array('entity' => $apiRequest['entity'], 'action' => $action, 'version' => $apiRequest['version']); $hypApiRequest += _civicrm_api_resolve($hypApiRequest); $helper = '_' . $hypApiRequest['function'] . '_spec'; if (function_exists($helper)) { // alter $helper($metadata, $apiRequest); } $fieldsToResolve = (array) CRM_Utils_Array::value('get_options', $apiOptions, array()); foreach ($metadata as $fieldname => $fieldSpec) { _civicrm_api3_generic_get_metadata_options($metadata, $apiRequest['entity'], $fieldname, $fieldSpec, $fieldsToResolve); } $results[$entity][$action][$sequential] = civicrm_api3_create_success($metadata, $apiRequest['params'], NULL, 'getfields'); return $results[$entity][$action][$sequential]; }
/** * Fix values from query from/to something no-one cared enough to document. * * @param int $id * @param array $values * @param int $wildcard * @param bool $useEquals * * @param string $apiEntity * * @return array|null */ public static function fixWhereValues($id, &$values, $wildcard = 0, $useEquals = FALSE, $apiEntity = NULL) { // skip a few search variables static $skipWhere = NULL; static $likeNames = NULL; $result = NULL; // Change camelCase EntityName to lowercase with underscores $apiEntity = _civicrm_api_get_entity_name_from_camel($apiEntity); if (CRM_Utils_System::isNull($values)) { return $result; } if (!$skipWhere) { $skipWhere = array('task', 'radio_ts', 'uf_group_id', 'component_mode', 'qfKey', 'operator', 'display_relationship_type'); } if (in_array($id, $skipWhere) || substr($id, 0, 4) == '_qf_' || substr($id, 0, 7) == 'hidden_') { return $result; } if ($apiEntity && substr($id, 0, strlen($apiEntity)) != $apiEntity && (substr($id, 0, 10) != 'financial_' && substr($id, 0, 8) != 'payment_')) { $id = $apiEntity . '_' . $id; } if (!$likeNames) { $likeNames = array('sort_name', 'email', 'note', 'display_name'); } // email comes in via advanced search // so use wildcard always if ($id == 'email') { $wildcard = 1; } if (!$useEquals && in_array($id, $likeNames)) { $result = array($id, 'LIKE', $values, 0, 1); } elseif (is_string($values) && strpos($values, '%') !== FALSE) { $result = array($id, 'LIKE', $values, 0, 0); } elseif ($id == 'contact_type' || !empty($values) && is_array($values) && !in_array(key($values), CRM_Core_DAO::acceptedSQLOperators(), TRUE)) { $result = array($id, 'IN', $values, 0, $wildcard); } else { $result = array($id, '=', $values, 0, $wildcard); } return $result; }
/** * Check if the function is deprecated. * * @param string $entity * @param array $result * * @return string|array|null */ function _civicrm_api3_deprecation_check($entity, $result = array()) { if ($entity) { $apiFile = "api/v3/{$entity}.php"; if (CRM_Utils_File::isIncludable($apiFile)) { require_once $apiFile; } $lowercase_entity = _civicrm_api_get_entity_name_from_camel($entity); $fnName = "_civicrm_api3_{$lowercase_entity}_deprecation"; if (function_exists($fnName)) { return $fnName($result); } } }
/** * Decide what permissions to check for an api call * The contact must have all of the returned permissions for the api call to be allowed * * @param $entity: (str) api entity * @param $action: (str) api action * @param $params: (array) api params * * @return array of permissions to check for this entity-action combo */ function _civicrm_api3_permissions($entity, $action, &$params) { $entity = _civicrm_api_get_entity_name_from_camel($entity); $action = strtolower($action); /** * @var array of permissions * * For each entity, we declare an array of permissions required for each action * The action is the array key, possible values: * * create: applies to create (with no id in params) * * update: applies to update, setvalue, create (with id in params) * * get: applies to getcount, getsingle, getvalue and other gets * * delete: applies to delete, replace * * meta: applies to getfields, getoptions, getspec * * default: catch-all for anything not declared * * Note: some APIs declare other actions as well */ $permissions = array(); // These are the default permissions - if any entity does not declare permissions for a given action, // (or the entity does not declare permissions at all) - then the action will be used from here $permissions['default'] = array('meta' => array('access CiviCRM'), 'default' => array('administer CiviCRM')); // Contact permissions $permissions['contact'] = array('create' => array('access CiviCRM', 'add contacts'), 'delete' => array('access CiviCRM', 'delete contacts'), 'get' => array(), 'update' => array('access CiviCRM', 'edit all contacts'), 'getquick' => array(array('access CiviCRM', 'access AJAX API'))); // Contact-related data permissions $permissions['address'] = array('get' => array('access CiviCRM', 'view all contacts'), 'delete' => array('access CiviCRM', 'delete contacts'), 'default' => array('access CiviCRM', 'edit all contacts')); $permissions['email'] = $permissions['address']; $permissions['phone'] = $permissions['address']; $permissions['website'] = $permissions['address']; $permissions['im'] = $permissions['address']; $permissions['loc_block'] = $permissions['address']; $permissions['entity_tag'] = $permissions['address']; $permissions['note'] = $permissions['address']; // Activity permissions $permissions['activity'] = array('delete' => array('access CiviCRM', 'delete activities'), 'default' => array('access CiviCRM', 'view all activities')); // Case permissions $permissions['case'] = array('create' => array('access CiviCRM', 'add cases'), 'delete' => array('access CiviCRM', 'delete in CiviCase'), 'default' => array('access CiviCRM', 'access all cases and activities')); // Financial permissions $permissions['contribution'] = array('get' => array('access CiviCRM', 'access CiviContribute'), 'delete' => array('access CiviCRM', 'access CiviContribute', 'delete in CiviContribute'), 'completetransaction' => array('edit contributions'), 'default' => array('access CiviCRM', 'access CiviContribute', 'edit contributions')); $permissions['line_item'] = $permissions['contribution']; // Custom field permissions $permissions['custom_field'] = array('default' => array('administer CiviCRM', 'access all custom data')); $permissions['custom_group'] = $permissions['custom_field']; // Event permissions $permissions['event'] = array('create' => array('access CiviCRM', 'access CiviEvent', 'edit all events'), 'delete' => array('access CiviCRM', 'access CiviEvent', 'delete in CiviEvent'), 'get' => array('access CiviCRM', 'access CiviEvent', 'view event info'), 'update' => array('access CiviCRM', 'access CiviEvent', 'edit all events')); // File permissions $permissions['file'] = array('default' => array('access CiviCRM', 'access uploaded files')); $permissions['files_by_entity'] = $permissions['file']; // Group permissions $permissions['group'] = array('get' => array('access CiviCRM'), 'default' => array('access CiviCRM', 'edit groups')); $permissions['group_contact'] = $permissions['group']; $permissions['group_nesting'] = $permissions['group']; $permissions['group_organization'] = $permissions['group']; // Membership permissions $permissions['membership'] = array('get' => array('access CiviCRM', 'access CiviMember'), 'delete' => array('access CiviCRM', 'access CiviMember', 'delete in CiviMember'), 'default' => array('access CiviCRM', 'access CiviMember', 'edit memberships')); $permissions['membership_status'] = $permissions['membership']; $permissions['membership_type'] = $permissions['membership']; $permissions['membership_payment'] = array('create' => array('access CiviCRM', 'access CiviMember', 'edit memberships', 'access CiviContribute', 'edit contributions'), 'delete' => array('access CiviCRM', 'access CiviMember', 'delete in CiviMember', 'access CiviContribute', 'delete in CiviContribute'), 'get' => array('access CiviCRM', 'access CiviMember', 'access CiviContribute'), 'update' => array('access CiviCRM', 'access CiviMember', 'edit memberships', 'access CiviContribute', 'edit contributions')); // Participant permissions $permissions['participant'] = array('create' => array('access CiviCRM', 'access CiviEvent', 'register for events'), 'delete' => array('access CiviCRM', 'access CiviEvent', 'edit event participants'), 'get' => array('access CiviCRM', 'access CiviEvent', 'view event participants'), 'update' => array('access CiviCRM', 'access CiviEvent', 'edit event participants')); $permissions['participant_payment'] = array('create' => array('access CiviCRM', 'access CiviEvent', 'register for events', 'access CiviContribute', 'edit contributions'), 'delete' => array('access CiviCRM', 'access CiviEvent', 'edit event participants', 'access CiviContribute', 'delete in CiviContribute'), 'get' => array('access CiviCRM', 'access CiviEvent', 'view event participants', 'access CiviContribute'), 'update' => array('access CiviCRM', 'access CiviEvent', 'edit event participants', 'access CiviContribute', 'edit contributions')); // Pledge permissions $permissions['pledge'] = array('create' => array('access CiviCRM', 'access CiviPledge', 'edit pledges'), 'delete' => array('access CiviCRM', 'access CiviPledge', 'delete in CiviPledge'), 'get' => array('access CiviCRM', 'access CiviPledge'), 'update' => array('access CiviCRM', 'access CiviPledge', 'edit pledges')); $permissions['pledge_payment'] = array('create' => array('access CiviCRM', 'access CiviPledge', 'edit pledges', 'access CiviContribute', 'edit contributions'), 'delete' => array('access CiviCRM', 'access CiviPledge', 'delete in CiviPledge', 'access CiviContribute', 'delete in CiviContribute'), 'get' => array('access CiviCRM', 'access CiviPledge', 'access CiviContribute'), 'update' => array('access CiviCRM', 'access CiviPledge', 'edit pledges', 'access CiviContribute', 'edit contributions')); // Profile permissions $permissions['profile'] = array('get' => array()); $permissions['uf_group'] = array('get' => array('access CiviCRM')); $permissions['uf_field'] = $permissions['uf_group']; // Translate 'create' action to 'update' if id is set if ($action == 'create' && (!empty($params['id']) || !empty($params[$entity . '_id']))) { $action = 'update'; } // let third parties modify the permissions CRM_Utils_Hook::alterAPIPermissions($entity, $action, $params, $permissions); // Merge permissions for this entity with the defaults $perm = CRM_Utils_Array::value($entity, $permissions, array()) + $permissions['default']; // Return exact match if permission for this action has been declared if (isset($perm[$action])) { return $perm[$action]; } // Translate specific actions into their generic equivalents $snippet = substr($action, 0, 3); if ($action == 'replace' || $snippet == 'del') { // 'Replace' is a combination of get+create+update+delete; however, the permissions // on each of those will be tested separately at runtime. This is just a sniff-test // based on the heuristic that 'delete' tends to be the most closesly guarded // of the necessary permissions. $action = 'delete'; } elseif ($action == 'setvalue' || $snippet == 'upd') { $action = 'update'; } elseif ($action == 'getfields' || $action == 'getspec' || $action == 'getoptions') { $action = 'meta'; } elseif ($snippet == 'get') { $action = 'get'; } return isset($perm[$action]) ? $perm[$action] : $perm['default']; }
/** * Create test generated example in api/v3/examples. * * To turn this off (e.g. on the server) set * define(DONT_DOCUMENT_TEST_CONFIG ,1); * in your settings file * * @param string $entity * @param string $action * @param array $params * Array as passed to civicrm_api function. * @param array $result * Array as received from the civicrm_api function. * @param string $testFunction * Calling function - generally __FUNCTION__. * @param string $testFile * Called from file - generally __FILE__. * @param string $description * Descriptive text for the example file. * @param string $exampleName * Name for this example file (CamelCase) - if omitted the action name will be substituted. */ private function documentMe($entity, $action, $params, $result, $testFunction, $testFile, $description = "", $exampleName = NULL) { if (defined('DONT_DOCUMENT_TEST_CONFIG') && DONT_DOCUMENT_TEST_CONFIG) { return; } $entity = _civicrm_api_get_camel_name($entity); $action = strtolower($action); if (empty($exampleName)) { // Attempt to convert lowercase action name to CamelCase. // This is clunky/imperfect due to the convention of all lowercase actions. $exampleName = CRM_Utils_String::convertStringToCamel($action); $knownPrefixes = array('Get', 'Set', 'Create', 'Update', 'Send'); foreach ($knownPrefixes as $prefix) { if (strpos($exampleName, $prefix) === 0 && $prefix != $exampleName) { $exampleName[strlen($prefix)] = strtoupper($exampleName[strlen($prefix)]); } } } $this->tidyExampleResult($result); if (isset($params['version'])) { unset($params['version']); } // Format multiline description as array $desc = array(); if (is_string($description) && strlen($description)) { foreach (explode("\n", $description) as $line) { $desc[] = trim($line); } } $smarty = CRM_Core_Smarty::singleton(); $smarty->assign('testFunction', $testFunction); $smarty->assign('function', _civicrm_api_get_entity_name_from_camel($entity) . "_{$action}"); $smarty->assign('params', $params); $smarty->assign('entity', $entity); $smarty->assign('testFile', basename($testFile)); $smarty->assign('description', $desc); $smarty->assign('result', $result); $smarty->assign('action', $action); global $civicrm_root; if (file_exists($civicrm_root . '/tests/templates/documentFunction.tpl')) { if (!is_dir($civicrm_root . "/api/v3/examples/{$entity}")) { mkdir($civicrm_root . "/api/v3/examples/{$entity}"); } $f = fopen($civicrm_root . "/api/v3/examples/{$entity}/{$exampleName}.php", "w+b"); fwrite($f, $smarty->fetch($civicrm_root . '/tests/templates/documentFunction.tpl')); fclose($f); } }
/** * Create a single or multiple entity ref field. * @param string $name * @param string $label * @param array $props * Mix of html and widget properties, including:. * - select - params to give to select2 widget * - entity - defaults to contact * - create - can the user create a new entity on-the-fly? * Set to TRUE if entity is contact and you want the default profiles, * or pass in your own set of links. @see CRM_Core_BAO_UFGroup::getCreateLinks for format * note that permissions are checked automatically * - api - array of settings for the getlist api wrapper * note that it accepts a 'params' setting which will be passed to the underlying api * - placeholder - string * - multiple - bool * - class, etc. - other html properties * @param bool $required * * @return HTML_QuickForm_Element */ public function addEntityRef($name, $label = '', $props = array(), $required = FALSE) { require_once "api/api.php"; $config = CRM_Core_Config::singleton(); // Default properties $props['api'] = CRM_Utils_Array::value('api', $props, array()); $props['entity'] = _civicrm_api_get_entity_name_from_camel(CRM_Utils_Array::value('entity', $props, 'contact')); $props['class'] = ltrim(CRM_Utils_Array::value('class', $props, '') . ' crm-form-entityref'); if ($props['entity'] == 'contact' && isset($props['create']) && !(CRM_Core_Permission::check('edit all contacts') || CRM_Core_Permission::check('add contacts'))) { unset($props['create']); } $props['placeholder'] = CRM_Utils_Array::value('placeholder', $props, $required ? ts('- select %1 -', array(1 => ts(str_replace('_', ' ', $props['entity'])))) : ts('- none -')); $defaults = array(); if (!empty($props['multiple'])) { $defaults['multiple'] = TRUE; } $props['select'] = CRM_Utils_Array::value('select', $props, array()) + $defaults; $this->formatReferenceFieldAttributes($props); return $this->add('text', $name, $label, $props, $required); }
/** * Determine the function name for a given API request. * * @param string $entity * API entity name. * @param string $action * API action name. * @param int $version * API version. * * @return string */ protected function getFunctionName($entity, $action, $version) { $entity = _civicrm_api_get_entity_name_from_camel($entity); return 'civicrm_api' . $version . '_' . $entity . '_' . $action; }
/** * Call any nested api calls. * * TODO: We don't really need this to be a separate function. * @param \Civi\API\Kernel $apiKernel * @param $params * @param $result * @param $action * @param $entity * @param $version * @throws \Exception */ protected function callNestedApi($apiKernel, &$params, &$result, $action, $entity, $version) { $lowercase_entity = _civicrm_api_get_entity_name_from_camel($entity); // We don't need to worry about nested api in the getfields/getoptions // actions, so just return immediately. if (in_array($action, array('getfields', 'getfield', 'getoptions'))) { return; } if ($action == 'getsingle') { // I don't understand the protocol here, but we don't want // $result to be a recursive array // $result['values'][0] = $result; $oldResult = $result; $result = array('values' => array(0 => $oldResult)); } foreach ($params as $field => $newparams) { if ((is_array($newparams) || $newparams === 1) && $field != 'api.has_parent' && substr($field, 0, 3) == 'api') { // 'api.participant.delete' => 1 is a valid options - handle 1 // instead of an array if ($newparams === 1) { $newparams = array('version' => $version); } // can be api_ or api. $separator = $field[3]; if (!($separator == '.' || $separator == '_')) { continue; } $subAPI = explode($separator, $field); $subaction = empty($subAPI[2]) ? $action : $subAPI[2]; $subParams = array('debug' => \CRM_Utils_Array::value('debug', $params)); $subEntity = _civicrm_api_get_entity_name_from_camel($subAPI[1]); foreach ($result['values'] as $idIndex => $parentAPIValues) { if ($subEntity != 'contact') { //contact spits the dummy at activity_id so what else won't it like? //set entity_id & entity table based on the parent's id & entity. //e.g for something like note if the parent call is contact //'entity_table' will be set to 'contact' & 'id' to the contact id //from the parent call. in this case 'contact_id' will also be //set to the parent's id if (!($subEntity == 'line_item' && $lowercase_entity == 'contribution' && $action != 'create')) { $subParams["entity_id"] = $parentAPIValues['id']; $subParams['entity_table'] = 'civicrm_' . $lowercase_entity; } $crm16084 = FALSE; if ($subEntity == 'relationship' && $lowercase_entity == 'contact') { // if a relationship call is chained to a contact call, we need // to check whether contact_id_a or contact_id_b for the // relationship is given. If so, don't add an extra subParam // "contact_id" => parent_id. // See CRM-16084. foreach (array_keys($newparams) as $key) { if (substr($key, 0, 11) == 'contact_id_') { $crm16084 = TRUE; break; } } } if (!$crm16084) { $subParams[$lowercase_entity . "_id"] = $parentAPIValues['id']; } } if ($entity != 'Contact' && \CRM_Utils_Array::value(strtolower($subEntity . "_id"), $parentAPIValues)) { //e.g. if event_id is in the values returned & subentity is event //then pass in event_id as 'id' don't do this for contact as it //does some weird things like returning primary email & //thus limiting the ability to chain email //TODO - this might need the camel treatment $subParams['id'] = $parentAPIValues[$subEntity . "_id"]; } if (\CRM_Utils_Array::value('entity_table', $result['values'][$idIndex]) == $subEntity) { $subParams['id'] = $result['values'][$idIndex]['entity_id']; } // if we are dealing with the same entity pass 'id' through // (useful for get + delete for example) if ($lowercase_entity == $subEntity) { $subParams['id'] = $result['values'][$idIndex]['id']; } $subParams['version'] = $version; if (!empty($params['check_permissions'])) { $subParams['check_permissions'] = $params['check_permissions']; } $subParams['sequential'] = 1; $subParams['api.has_parent'] = 1; if (array_key_exists(0, $newparams)) { $genericParams = $subParams; // it is a numerically indexed array - ie. multiple creates foreach ($newparams as $entityparams) { $subParams = array_merge($genericParams, $entityparams); _civicrm_api_replace_variables($subParams, $result['values'][$idIndex], $separator); $result['values'][$idIndex][$field][] = $apiKernel->run($subEntity, $subaction, $subParams); if ($result['is_error'] === 1) { throw new \Exception($subEntity . ' ' . $subaction . 'call failed with' . $result['error_message']); } } } else { $subParams = array_merge($subParams, $newparams); _civicrm_api_replace_variables($subParams, $result['values'][$idIndex], $separator); $result['values'][$idIndex][$field] = $apiKernel->run($subEntity, $subaction, $subParams); if (!empty($result['is_error'])) { throw new \Exception($subEntity . ' ' . $subaction . 'call failed with' . $result['error_message']); } } } } } if ($action == 'getsingle') { $result = $result['values'][0]; } }
function _civicrm_api_get_entity_name_from_dao($bao) { $daoName = str_replace("BAO", "DAO", get_class($bao)); $dao = array(); require 'CRM/Core/DAO/.listAll.php'; $daos = array_flip($dao); return _civicrm_api_get_entity_name_from_camel($daos[$daoName]); }