Commit | Line | Data |
---|---|---|
d84ae5f6 | 1 | <?php |
2 | /* | |
bc77d7c0 TO |
3 | +--------------------------------------------------------------------+ |
4 | | Copyright CiviCRM LLC. All rights reserved. | | |
5 | | | | |
6 | | This work is published under the GNU AGPLv3 license with some | | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
9 | +--------------------------------------------------------------------+ | |
d84ae5f6 | 10 | */ |
11 | ||
12 | /** | |
13 | * | |
14 | * @package CRM | |
ca5cec67 | 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
d84ae5f6 | 16 | */ |
d84ae5f6 | 17 | trait CRM_Core_Form_EntityFormTrait { |
d5e4784e | 18 | |
e57fc8ca MWMC |
19 | /** |
20 | * The id of the object being edited / created. | |
21 | * | |
22 | * @var int | |
23 | */ | |
24 | public $_id; | |
25 | ||
9f1073d2 MWMC |
26 | /** |
27 | * The entity subtype ID (eg. for Relationship / Activity) | |
28 | * | |
29 | * @var int | |
30 | */ | |
ed706f8d | 31 | protected $_entitySubTypeId = NULL; |
9f1073d2 | 32 | |
d84ae5f6 | 33 | /** |
34 | * Get entity fields for the entity to be added to the form. | |
35 | * | |
d5e4784e | 36 | * @return array |
d84ae5f6 | 37 | */ |
38 | public function getEntityFields() { | |
39 | return $this->entityFields; | |
40 | } | |
41 | ||
42 | /** | |
43 | * Explicitly declare the form context. | |
44 | */ | |
45 | public function getDefaultContext() { | |
46 | return 'create'; | |
47 | } | |
48 | ||
49 | /** | |
50 | * Get entity fields for the entity to be added to the form. | |
51 | * | |
d5e4784e | 52 | * @return string |
d84ae5f6 | 53 | */ |
54 | public function getDeleteMessage() { | |
55 | return $this->deleteMessage; | |
56 | } | |
57 | ||
379d6cd7 | 58 | /** |
59 | * Set the delete message. | |
60 | * | |
61 | * We do this from the constructor in order to do a translation. | |
62 | */ | |
63 | public function setDeleteMessage() { | |
64 | } | |
65 | ||
66 | /** | |
67 | * Set entity fields to be assigned to the form. | |
68 | */ | |
69 | protected function setEntityFields() { | |
70 | } | |
71 | ||
d84ae5f6 | 72 | /** |
73 | * Get the entity id being edited. | |
74 | * | |
75 | * @return int|null | |
76 | */ | |
77 | public function getEntityId() { | |
78 | return $this->_id; | |
79 | } | |
9f1073d2 | 80 | |
e57fc8ca MWMC |
81 | /** |
82 | * Set the entity ID | |
83 | * | |
84 | * @param int $id The entity ID | |
85 | */ | |
86 | public function setEntityId($id) { | |
87 | $this->_id = $id; | |
88 | } | |
89 | ||
f1105edc | 90 | /** |
91 | * Should custom data be suppressed on this form. | |
92 | * | |
93 | * @return bool | |
94 | */ | |
95 | protected function isSuppressCustomData() { | |
96 | return FALSE; | |
97 | } | |
98 | ||
9f1073d2 MWMC |
99 | /** |
100 | * Get the entity subtype ID being edited | |
101 | * | |
9f1073d2 MWMC |
102 | * @return int|null |
103 | */ | |
ed706f8d | 104 | public function getEntitySubTypeId() { |
9f1073d2 MWMC |
105 | return $this->_entitySubTypeId; |
106 | } | |
107 | ||
ed706f8d MWMC |
108 | /** |
109 | * Set the entity subtype ID being edited | |
110 | * | |
111 | * @param $subTypeId | |
112 | */ | |
113 | public function setEntitySubTypeId($subTypeId) { | |
114 | $this->_entitySubTypeId = $subTypeId; | |
115 | } | |
116 | ||
d84ae5f6 | 117 | /** |
118 | * If the custom data is in the submitted data (eg. added via ajax loaded form) add to form. | |
119 | */ | |
120 | public function addCustomDataToForm() { | |
f1105edc | 121 | if ($this->isSuppressCustomData()) { |
122 | return TRUE; | |
123 | } | |
d84ae5f6 | 124 | $customisableEntities = CRM_Core_SelectValues::customGroupExtends(); |
125 | if (isset($customisableEntities[$this->getDefaultEntity()])) { | |
ed706f8d | 126 | CRM_Custom_Form_CustomData::addToForm($this, $this->getEntitySubTypeId()); |
d84ae5f6 | 127 | } |
128 | } | |
129 | ||
130 | /** | |
131 | * Build the form object. | |
132 | */ | |
133 | public function buildQuickEntityForm() { | |
59c798c9 | 134 | if ($this->isDeleteContext()) { |
d84ae5f6 | 135 | $this->buildDeleteForm(); |
136 | return; | |
137 | } | |
138 | $this->applyFilter('__ALL__', 'trim'); | |
139 | $this->addEntityFieldsToTemplate(); | |
44e4605b EM |
140 | foreach ($this->entityFields as $index => $fields) { |
141 | $this->entityFields[$index] = array_merge([ | |
142 | 'template' => '', | |
143 | 'help' => [], | |
144 | 'pre_html_text' => '', | |
145 | 'post_html_text' => '', | |
146 | 'description' => '', | |
147 | 'documentation_link' => '', | |
148 | ], $fields); | |
149 | } | |
d84ae5f6 | 150 | $this->assign('entityFields', $this->entityFields); |
151 | $this->assign('entityID', $this->getEntityId()); | |
152 | $this->assign('entityInClassFormat', strtolower(str_replace('_', '-', $this->getDefaultEntity()))); | |
153 | $this->assign('entityTable', CRM_Core_DAO_AllCoreTables::getTableForClass(CRM_Core_DAO_AllCoreTables::getFullName($this->getDefaultEntity()))); | |
154 | $this->addCustomDataToForm(); | |
155 | $this->addFormButtons(); | |
48c242dc MWMC |
156 | |
157 | if ($this->isViewContext()) { | |
158 | $this->freeze(); | |
159 | } | |
d84ae5f6 | 160 | } |
161 | ||
162 | /** | |
163 | * Build the form for any deletion. | |
164 | */ | |
165 | protected function buildDeleteForm() { | |
166 | $this->assign('deleteMessage', $this->getDeleteMessage()); | |
167 | $this->addFormButtons(); | |
168 | } | |
169 | ||
170 | /** | |
171 | * Add relevant buttons to the form. | |
172 | */ | |
173 | protected function addFormButtons() { | |
48c242dc | 174 | if ($this->isViewContext() || $this->_action & CRM_Core_Action::PREVIEW) { |
be2fb01f | 175 | $this->addButtons([ |
518fa0ee SL |
176 | [ |
177 | 'type' => 'cancel', | |
178 | 'name' => ts('Done'), | |
179 | 'isDefault' => TRUE, | |
180 | ], | |
181 | ]); | |
d84ae5f6 | 182 | } |
183 | else { | |
be2fb01f | 184 | $this->addButtons([ |
518fa0ee SL |
185 | [ |
186 | 'type' => 'next', | |
187 | 'name' => $this->isDeleteContext() ? ts('Delete') : ts('Save'), | |
188 | 'isDefault' => TRUE, | |
189 | ], | |
190 | [ | |
191 | 'type' => 'cancel', | |
192 | 'name' => ts('Cancel'), | |
193 | ], | |
194 | ]); | |
d84ae5f6 | 195 | } |
196 | } | |
197 | ||
612215eb | 198 | /** |
199 | * Get the defaults for the entity. | |
200 | */ | |
201 | protected function getEntityDefaults() { | |
99e201e8 MWMC |
202 | $defaults = $moneyFields = []; |
203 | ||
48c242dc | 204 | if (!$this->isDeleteContext() && |
518fa0ee | 205 | $this->getEntityId()) { |
612215eb | 206 | $params = ['id' => $this->getEntityId()]; |
207 | $baoName = $this->_BAOName; | |
208 | $baoName::retrieve($params, $defaults); | |
209 | } | |
99e201e8 | 210 | foreach ($this->entityFields as $entityFieldName => $fieldSpec) { |
612215eb | 211 | $value = CRM_Utils_Request::retrieveValue($fieldSpec['name'], $this->getValidationTypeForField($fieldSpec['name'])); |
ea1cafad | 212 | if ($value !== FALSE && $value !== NULL) { |
612215eb | 213 | $defaults[$fieldSpec['name']] = $value; |
214 | } | |
99e201e8 | 215 | // Store a list of fields with money formatters |
48c242dc | 216 | if (CRM_Utils_Array::value('formatter', $fieldSpec) == 'crmMoney') { |
99e201e8 MWMC |
217 | $moneyFields[] = $entityFieldName; |
218 | } | |
219 | } | |
220 | if (!empty($defaults['currency'])) { | |
221 | // If we have a money formatter we need to pass the specified currency or it will render as the default | |
222 | foreach ($moneyFields as $entityFieldName) { | |
223 | $this->entityFields[$entityFieldName]['formatterParam'] = $defaults['currency']; | |
48c242dc | 224 | } |
612215eb | 225 | } |
99e201e8 | 226 | |
48c242dc MWMC |
227 | // Assign again as we may have modified above |
228 | $this->assign('entityFields', $this->entityFields); | |
612215eb | 229 | return $defaults; |
230 | } | |
231 | ||
232 | /** | |
233 | * Get the validation rule to apply to a function. | |
234 | * | |
235 | * Alphanumeric is designed to always be safe & for now we just return | |
236 | * that but in future we can use tighter rules for types like int, bool etc. | |
237 | * | |
238 | * @param string $fieldName | |
239 | * | |
240 | * @return string|int|bool | |
241 | */ | |
242 | protected function getValidationTypeForField($fieldName) { | |
243 | switch ($this->metadata[$fieldName]['type']) { | |
244 | case CRM_Utils_Type::T_BOOLEAN: | |
245 | return 'Boolean'; | |
246 | ||
247 | default: | |
248 | return 'Alphanumeric'; | |
249 | } | |
250 | } | |
251 | ||
d84ae5f6 | 252 | /** |
253 | * Set translated fields. | |
254 | * | |
255 | * This function is called from the class constructor, allowing us to set | |
256 | * fields on the class that can't be set as properties due to need for | |
257 | * translation or other non-input specific handling. | |
258 | */ | |
259 | protected function setTranslatedFields() { | |
260 | $this->setEntityFields(); | |
261 | $this->setDeleteMessage(); | |
262 | $metadata = civicrm_api3($this->getDefaultEntity(), 'getfields', ['action' => 'create']); | |
263 | $this->metadata = $metadata['values']; | |
264 | foreach ($this->metadata as $fieldName => $spec) { | |
265 | if (isset($this->entityFields[$fieldName])) { | |
266 | if ($spec['localizable']) { | |
267 | $this->entityFields[$fieldName]['is_add_translate_dialog'] = TRUE; | |
268 | } | |
797edf50 | 269 | if (empty($spec['html']['type'])) { |
d84ae5f6 | 270 | $this->entityFields[$fieldName]['not-auto-addable'] = TRUE; |
271 | } | |
272 | } | |
273 | } | |
274 | } | |
275 | ||
276 | /** | |
277 | * Add defined entity field to template. | |
278 | */ | |
279 | protected function addEntityFieldsToTemplate() { | |
280 | foreach ($this->getEntityFields() as $fieldSpec) { | |
281 | if (empty($fieldSpec['not-auto-addable'])) { | |
59c798c9 | 282 | $element = $this->addField($fieldSpec['name'], [], CRM_Utils_Array::value('required', $fieldSpec), FALSE); |
4d876348 | 283 | if (!empty($fieldSpec['is_freeze'])) { |
284 | $element->freeze(); | |
285 | } | |
d84ae5f6 | 286 | } |
287 | } | |
288 | } | |
289 | ||
59c798c9 | 290 | /** |
291 | * Is the form being used in the context of a deletion. | |
292 | * | |
293 | * (For some reason rather than having separate forms Civi overloads one form). | |
294 | * | |
295 | * @return bool | |
296 | */ | |
297 | protected function isDeleteContext() { | |
298 | return ($this->_action & CRM_Core_Action::DELETE); | |
299 | } | |
300 | ||
48c242dc MWMC |
301 | /** |
302 | * Is the form being used in the context of a view. | |
303 | * | |
304 | * @return bool | |
305 | */ | |
306 | protected function isViewContext() { | |
307 | return ($this->_action & CRM_Core_Action::VIEW); | |
308 | } | |
309 | ||
d5e4784e MWMC |
310 | protected function setEntityFieldsMetadata() { |
311 | foreach ($this->entityFields as $field => &$props) { | |
312 | if (!empty($props['not-auto-addable'])) { | |
313 | // We can't load this field using metadata | |
314 | continue; | |
315 | } | |
079c7954 CW |
316 | if ($field != 'id' && $this->isDeleteContext()) { |
317 | // Delete forms don't generally present any fields to edit | |
318 | continue; | |
319 | } | |
d5e4784e MWMC |
320 | // Resolve action. |
321 | if (empty($props['action'])) { | |
322 | $props['action'] = $this->getApiAction(); | |
323 | } | |
324 | $fieldSpec = civicrm_api3($this->getDefaultEntity(), 'getfield', $props); | |
325 | $fieldSpec = $fieldSpec['values']; | |
326 | if (!isset($props['description']) && isset($fieldSpec['description'])) { | |
327 | $props['description'] = $fieldSpec['description']; | |
328 | } | |
329 | } | |
330 | } | |
331 | ||
d84ae5f6 | 332 | } |