diff options
Diffstat (limited to 'www/crm/wp-content/plugins/civicrm/civicrm/ext/api4/Civi/Api4/Generic/Traits/DAOActionTrait.php')
-rw-r--r-- | www/crm/wp-content/plugins/civicrm/civicrm/ext/api4/Civi/Api4/Generic/Traits/DAOActionTrait.php | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/www/crm/wp-content/plugins/civicrm/civicrm/ext/api4/Civi/Api4/Generic/Traits/DAOActionTrait.php b/www/crm/wp-content/plugins/civicrm/civicrm/ext/api4/Civi/Api4/Generic/Traits/DAOActionTrait.php new file mode 100644 index 00000000..1c92906b --- /dev/null +++ b/www/crm/wp-content/plugins/civicrm/civicrm/ext/api4/Civi/Api4/Generic/Traits/DAOActionTrait.php @@ -0,0 +1,229 @@ +<?php +namespace Civi\Api4\Generic\Traits; + +use CRM_Utils_Array as UtilsArray; +use Civi\Api4\Utils\FormattingUtil; +use Civi\Api4\Query\Api4SelectQuery; + +trait DAOActionTrait { + + /** + * @return \CRM_Core_DAO|string + */ + protected function getBaoName() { + require_once 'api/v3/utils.php'; + return \_civicrm_api3_get_BAO($this->getEntityName()); + } + + /** + * Extract the true fields from a BAO + * + * (Used by create and update actions) + * @param object $bao + * @return array + */ + public static function baoToArray($bao) { + $fields = $bao->fields(); + $values = []; + foreach ($fields as $key => $field) { + $name = $field['name']; + if (property_exists($bao, $name)) { + $values[$name] = $bao->$name; + } + } + return $values; + } + + /** + * @return array|int + */ + protected function getObjects() { + $query = new Api4SelectQuery($this->getEntityName(), $this->getCheckPermissions()); + $query->select = $this->getSelect(); + $query->where = $this->getWhere(); + $query->orderBy = $this->getOrderBy(); + $query->limit = $this->getLimit(); + $query->offset = $this->getOffset(); + return $query->run(); + } + + /** + * Write a bao object as part of a create/update action. + * + * @param array $items + * The record to write to the DB. + * @return array + * The record after being written to the DB (e.g. including newly assigned "id"). + * @throws \API_Exception + */ + protected function writeObjects($items) { + $baoName = $this->getBaoName(); + + // Some BAOs are weird and don't support a straightforward "create" method. + $oddballs = [ + 'Address' => 'add', + 'GroupContact' => 'add', + 'Website' => 'add', + ]; + $method = UtilsArray::value($this->getEntityName(), $oddballs, 'create'); + if (!method_exists($baoName, $method)) { + $method = 'add'; + } + + $result = []; + + foreach ($items as $item) { + $entityId = UtilsArray::value('id', $item); + FormattingUtil::formatWriteParams($item, $this->getEntityName(), $this->getEntityFields()); + $this->formatCustomParams($item, $entityId); + $item['check_permissions'] = $this->getCheckPermissions(); + + $apiKeyPermission = $this->getEntityName() != 'Contact' || !$this->getCheckPermissions() || array_key_exists('api_key', $this->getEntityFields()) + || ($entityId && \CRM_Core_Permission::check('edit own api keys') && \CRM_Core_Session::getLoggedInContactID() == $entityId); + + if (!$apiKeyPermission && array_key_exists('api_key', $item)) { + throw new \Civi\API\Exception\UnauthorizedException('Permission denied to modify api key'); + } + + // For some reason the contact bao requires this + if ($entityId && $this->getEntityName() == 'Contact') { + $item['contact_id'] = $entityId; + } + + if ($this->getCheckPermissions() && $entityId) { + $this->checkContactPermissions($baoName, $item); + } + + if (method_exists($baoName, $method)) { + $createResult = $baoName::$method($item); + } + else { + $createResult = $this->genericCreateMethod($item); + } + + if (!$createResult) { + $errMessage = sprintf('%s write operation failed', $this->getEntityName()); + throw new \API_Exception($errMessage); + } + + if (!empty($this->reload) && is_a($createResult, 'CRM_Core_DAO')) { + $createResult->find(TRUE); + } + + // trim back the junk and just get the array: + $resultArray = $this->baoToArray($createResult); + + if (!$apiKeyPermission && array_key_exists('api_key', $resultArray)) { + unset($resultArray['api_key']); + } + + $result[] = $resultArray; + } + return $result; + } + + /** + * Fallback when a BAO does not contain create or add functions + * + * @param $params + * @return mixed + */ + private function genericCreateMethod($params) { + $baoName = $this->getBaoName(); + $hook = empty($params['id']) ? 'create' : 'edit'; + + \CRM_Utils_Hook::pre($hook, $this->getEntityName(), UtilsArray::value('id', $params), $params); + /** @var \CRM_Core_DAO $instance */ + $instance = new $baoName(); + $instance->copyValues($params, TRUE); + $instance->save(); + \CRM_Utils_Hook::post($hook, $this->getEntityName(), $instance->id, $instance); + + return $instance; + } + + /** + * @param array $params + * @param int $entityId + * @return mixed + */ + private function formatCustomParams(&$params, $entityId) { + $customParams = []; + + // $customValueID is the ID of the custom value in the custom table for this + // entity (i guess this assumes it's not a multi value entity) + foreach ($params as $name => $value) { + if (strpos($name, '.') === FALSE) { + continue; + } + + list($customGroup, $customField) = explode('.', $name); + + $customFieldId = \CRM_Core_BAO_CustomField::getFieldValue( + \CRM_Core_DAO_CustomField::class, + $customField, + 'id', + 'name' + ); + $customFieldType = \CRM_Core_BAO_CustomField::getFieldValue( + \CRM_Core_DAO_CustomField::class, + $customField, + 'html_type', + 'name' + ); + $customFieldExtends = \CRM_Core_BAO_CustomGroup::getFieldValue( + \CRM_Core_DAO_CustomGroup::class, + $customGroup, + 'extends', + 'name' + ); + + // todo are we sure we don't want to allow setting to NULL? need to test + if ($customFieldId && NULL !== $value) { + + if ($customFieldType == 'CheckBox') { + // this function should be part of a class + formatCheckBoxField($value, 'custom_' . $customFieldId, $this->getEntityName()); + } + + \CRM_Core_BAO_CustomField::formatCustomField( + $customFieldId, + $customParams, + $value, + $customFieldExtends, + NULL, // todo check when this is needed + $entityId, + FALSE, + FALSE, + TRUE + ); + } + } + + if ($customParams) { + $params['custom'] = $customParams; + } + } + + /** + * Check edit/delete permissions for contacts and related entities. + * + * @param $baoName + * @param $item + * @throws \Civi\API\Exception\UnauthorizedException + */ + protected function checkContactPermissions($baoName, $item) { + if ($baoName == 'CRM_Contact_BAO_Contact') { + $permission = $this->getActionName() == 'delete' ? \CRM_Core_Permission::DELETE : \CRM_Core_Permission::EDIT; + if (!\CRM_Contact_BAO_Contact_Permission::allow($item['id'], $permission)) { + throw new \Civi\API\Exception\UnauthorizedException('Permission denied to modify contact record'); + } + } + else { + // Fixme: decouple from v3 + require_once 'api/v3/utils.php'; + _civicrm_api3_check_edit_permissions($baoName, ['check_permissions' => 1] + $item); + } + } + +} |