Afform - Delegated API calls should use a security helper
[civicrm-core.git] / ext / afform / core / Civi / Api4 / Action / Afform / AbstractProcessor.php
1 <?php
2
3 namespace Civi\Api4\Action\Afform;
4
5 use Civi\Afform\FormDataModel;
6 use Civi\Api4\Generic\Result;
7
8 /**
9 * Shared functionality for form submission processing.
10 * @package Civi\Api4\Action\Afform
11 */
12 abstract class AbstractProcessor extends \Civi\Api4\Generic\AbstractAction {
13
14 /**
15 * Form name
16 * @var string
17 * @required
18 */
19 protected $name;
20
21 /**
22 * Arguments present when loading the form
23 * @var array
24 */
25 protected $args;
26
27 protected $_afform;
28
29 /**
30 * @var \Civi\Afform\FormDataModel
31 * List of entities declared by this form.
32 */
33 protected $_formDataModel;
34
35 /**
36 * @param \Civi\Api4\Generic\Result $result
37 * @throws \API_Exception
38 */
39 public function _run(Result $result) {
40 // This will throw an exception if the form doesn't exist
41 $this->_afform = (array) civicrm_api4('Afform', 'get', ['checkPermissions' => FALSE, 'where' => [['name', '=', $this->name]]], 0);
42 $this->_formDataModel = new FormDataModel($this->_afform['layout']);
43 $this->checkPermissions();
44 $this->validateArgs();
45 $result->exchangeArray($this->processForm());
46 }
47
48 /**
49 * Strip out arguments that are not allowed on this form
50 */
51 protected function validateArgs() {
52 $rawArgs = $this->args;
53 $entities = $this->_formDataModel->getEntities();
54 $this->args = [];
55 foreach ($rawArgs as $arg => $val) {
56 if (!empty($entities[$arg]['url-autofill'])) {
57 $this->args[$arg] = $val;
58 }
59 }
60 }
61
62 /**
63 * Assert that the current form submission is authorized.
64 *
65 * @throws \Civi\API\Exception\UnauthorizedException
66 */
67 protected function checkPermissions() {
68 if ($this->getCheckPermissions()) {
69 if (!\CRM_Core_Permission::check("@afform:" . $this->_afform['name'])) {
70 throw new \Civi\API\Exception\UnauthorizedException("Authorization failed: Cannot process form " . $this->_afform['name']);
71 }
72 }
73 }
74
75 /**
76 * @return array
77 */
78 abstract protected function processForm();
79
80 /**
81 * @param $mainEntityName
82 * @param $joinEntityName
83 * @param $mainEntityId
84 * @return array
85 * @throws \API_Exception
86 */
87 protected static function getJoinWhereClause($mainEntityName, $joinEntityName, $mainEntityId) {
88 $params = [];
89 if (self::fieldExists($joinEntityName, 'entity_id')) {
90 $params[] = ['entity_id', '=', $mainEntityId];
91 if (self::fieldExists($joinEntityName, 'entity_table')) {
92 $params[] = ['entity_table', '=', 'civicrm_' . _civicrm_api_get_entity_name_from_camel($mainEntityName)];
93 }
94 }
95 else {
96 $mainEntityField = _civicrm_api_get_entity_name_from_camel($mainEntityName) . '_id';
97 $params[] = [$mainEntityField, '=', $mainEntityId];
98 }
99 return $params;
100 }
101
102 /**
103 * Check if a field exists for a given entity
104 *
105 * @param $entityName
106 * @param $fieldName
107 * @return bool
108 * @throws \API_Exception
109 */
110 public static function fieldExists($entityName, $fieldName) {
111 if (empty(\Civi::$statics[__CLASS__][__FUNCTION__][$entityName])) {
112 $fields = civicrm_api4($entityName, 'getFields', [
113 'checkPermissions' => FALSE,
114 'action' => 'create',
115 'select' => ['name'],
116 'includeCustom' => FALSE,
117 ]);
118 \Civi::$statics[__CLASS__][__FUNCTION__][$entityName] = $fields->column('name');
119 }
120 return in_array($fieldName, \Civi::$statics[__CLASS__][__FUNCTION__][$entityName]);
121 }
122
123 }