PageRenderTime 27ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/sites/all/modules/contrib/civicrm/ext/api4/Civi/Api4/Generic/Traits/DAOActionTrait.php

https://gitlab.com/virtualrealms/d7civicrm
PHP | 229 lines | 148 code | 32 blank | 49 comment | 34 complexity | 59e83b1f6990eb4c012d312398548bdb MD5 | raw file
  1. <?php
  2. namespace Civi\Api4\Generic\Traits;
  3. use CRM_Utils_Array as UtilsArray;
  4. use Civi\Api4\Utils\FormattingUtil;
  5. use Civi\Api4\Query\Api4SelectQuery;
  6. trait DAOActionTrait {
  7. /**
  8. * @return \CRM_Core_DAO|string
  9. */
  10. protected function getBaoName() {
  11. require_once 'api/v3/utils.php';
  12. return \_civicrm_api3_get_BAO($this->getEntityName());
  13. }
  14. /**
  15. * Extract the true fields from a BAO
  16. *
  17. * (Used by create and update actions)
  18. * @param object $bao
  19. * @return array
  20. */
  21. public static function baoToArray($bao) {
  22. $fields = $bao->fields();
  23. $values = [];
  24. foreach ($fields as $key => $field) {
  25. $name = $field['name'];
  26. if (property_exists($bao, $name)) {
  27. $values[$name] = $bao->$name;
  28. }
  29. }
  30. return $values;
  31. }
  32. /**
  33. * @return array|int
  34. */
  35. protected function getObjects() {
  36. $query = new Api4SelectQuery($this->getEntityName(), $this->getCheckPermissions());
  37. $query->select = $this->getSelect();
  38. $query->where = $this->getWhere();
  39. $query->orderBy = $this->getOrderBy();
  40. $query->limit = $this->getLimit();
  41. $query->offset = $this->getOffset();
  42. return $query->run();
  43. }
  44. /**
  45. * Write a bao object as part of a create/update action.
  46. *
  47. * @param array $items
  48. * The record to write to the DB.
  49. * @return array
  50. * The record after being written to the DB (e.g. including newly assigned "id").
  51. * @throws \API_Exception
  52. */
  53. protected function writeObjects($items) {
  54. $baoName = $this->getBaoName();
  55. // Some BAOs are weird and don't support a straightforward "create" method.
  56. $oddballs = [
  57. 'Address' => 'add',
  58. 'GroupContact' => 'add',
  59. 'Website' => 'add',
  60. ];
  61. $method = UtilsArray::value($this->getEntityName(), $oddballs, 'create');
  62. if (!method_exists($baoName, $method)) {
  63. $method = 'add';
  64. }
  65. $result = [];
  66. foreach ($items as $item) {
  67. $entityId = UtilsArray::value('id', $item);
  68. FormattingUtil::formatWriteParams($item, $this->getEntityName(), $this->getEntityFields());
  69. $this->formatCustomParams($item, $entityId);
  70. $item['check_permissions'] = $this->getCheckPermissions();
  71. $apiKeyPermission = $this->getEntityName() != 'Contact' || !$this->getCheckPermissions() || array_key_exists('api_key', $this->getEntityFields())
  72. || ($entityId && \CRM_Core_Permission::check('edit own api keys') && \CRM_Core_Session::getLoggedInContactID() == $entityId);
  73. if (!$apiKeyPermission && array_key_exists('api_key', $item)) {
  74. throw new \Civi\API\Exception\UnauthorizedException('Permission denied to modify api key');
  75. }
  76. // For some reason the contact bao requires this
  77. if ($entityId && $this->getEntityName() == 'Contact') {
  78. $item['contact_id'] = $entityId;
  79. }
  80. if ($this->getCheckPermissions() && $entityId) {
  81. $this->checkContactPermissions($baoName, $item);
  82. }
  83. if (method_exists($baoName, $method)) {
  84. $createResult = $baoName::$method($item);
  85. }
  86. else {
  87. $createResult = $this->genericCreateMethod($item);
  88. }
  89. if (!$createResult) {
  90. $errMessage = sprintf('%s write operation failed', $this->getEntityName());
  91. throw new \API_Exception($errMessage);
  92. }
  93. if (!empty($this->reload) && is_a($createResult, 'CRM_Core_DAO')) {
  94. $createResult->find(TRUE);
  95. }
  96. // trim back the junk and just get the array:
  97. $resultArray = $this->baoToArray($createResult);
  98. if (!$apiKeyPermission && array_key_exists('api_key', $resultArray)) {
  99. unset($resultArray['api_key']);
  100. }
  101. $result[] = $resultArray;
  102. }
  103. return $result;
  104. }
  105. /**
  106. * Fallback when a BAO does not contain create or add functions
  107. *
  108. * @param $params
  109. * @return mixed
  110. */
  111. private function genericCreateMethod($params) {
  112. $baoName = $this->getBaoName();
  113. $hook = empty($params['id']) ? 'create' : 'edit';
  114. \CRM_Utils_Hook::pre($hook, $this->getEntityName(), UtilsArray::value('id', $params), $params);
  115. /** @var \CRM_Core_DAO $instance */
  116. $instance = new $baoName();
  117. $instance->copyValues($params, TRUE);
  118. $instance->save();
  119. \CRM_Utils_Hook::post($hook, $this->getEntityName(), $instance->id, $instance);
  120. return $instance;
  121. }
  122. /**
  123. * @param array $params
  124. * @param int $entityId
  125. * @return mixed
  126. */
  127. private function formatCustomParams(&$params, $entityId) {
  128. $customParams = [];
  129. // $customValueID is the ID of the custom value in the custom table for this
  130. // entity (i guess this assumes it's not a multi value entity)
  131. foreach ($params as $name => $value) {
  132. if (strpos($name, '.') === FALSE) {
  133. continue;
  134. }
  135. list($customGroup, $customField) = explode('.', $name);
  136. $customFieldId = \CRM_Core_BAO_CustomField::getFieldValue(
  137. \CRM_Core_DAO_CustomField::class,
  138. $customField,
  139. 'id',
  140. 'name'
  141. );
  142. $customFieldType = \CRM_Core_BAO_CustomField::getFieldValue(
  143. \CRM_Core_DAO_CustomField::class,
  144. $customField,
  145. 'html_type',
  146. 'name'
  147. );
  148. $customFieldExtends = \CRM_Core_BAO_CustomGroup::getFieldValue(
  149. \CRM_Core_DAO_CustomGroup::class,
  150. $customGroup,
  151. 'extends',
  152. 'name'
  153. );
  154. // todo are we sure we don't want to allow setting to NULL? need to test
  155. if ($customFieldId && NULL !== $value) {
  156. if ($customFieldType == 'CheckBox') {
  157. // this function should be part of a class
  158. formatCheckBoxField($value, 'custom_' . $customFieldId, $this->getEntityName());
  159. }
  160. \CRM_Core_BAO_CustomField::formatCustomField(
  161. $customFieldId,
  162. $customParams,
  163. $value,
  164. $customFieldExtends,
  165. NULL, // todo check when this is needed
  166. $entityId,
  167. FALSE,
  168. FALSE,
  169. TRUE
  170. );
  171. }
  172. }
  173. if ($customParams) {
  174. $params['custom'] = $customParams;
  175. }
  176. }
  177. /**
  178. * Check edit/delete permissions for contacts and related entities.
  179. *
  180. * @param $baoName
  181. * @param $item
  182. * @throws \Civi\API\Exception\UnauthorizedException
  183. */
  184. protected function checkContactPermissions($baoName, $item) {
  185. if ($baoName == 'CRM_Contact_BAO_Contact') {
  186. $permission = $this->getActionName() == 'delete' ? \CRM_Core_Permission::DELETE : \CRM_Core_Permission::EDIT;
  187. if (!\CRM_Contact_BAO_Contact_Permission::allow($item['id'], $permission)) {
  188. throw new \Civi\API\Exception\UnauthorizedException('Permission denied to modify contact record');
  189. }
  190. }
  191. else {
  192. // Fixme: decouple from v3
  193. require_once 'api/v3/utils.php';
  194. _civicrm_api3_check_edit_permissions($baoName, ['check_permissions' => 1] + $item);
  195. }
  196. }
  197. }