3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
17 trait CRM_Core_Form_EntityFormTrait
{
20 * The id of the object being edited / created.
27 * The entity subtype ID (eg. for Relationship / Activity)
31 protected $_entitySubTypeId = NULL;
34 * Get entity fields for the entity to be added to the form.
38 public function getEntityFields() {
39 return $this->entityFields
;
43 * Explicitly declare the form context.
45 public function getDefaultContext() {
50 * Get entity fields for the entity to be added to the form.
54 public function getDeleteMessage() {
55 return $this->deleteMessage
;
59 * Set the delete message.
61 * We do this from the constructor in order to do a translation.
63 public function setDeleteMessage() {
67 * Set entity fields to be assigned to the form.
69 protected function setEntityFields() {
73 * Get the entity id being edited.
77 public function getEntityId() {
84 * @param int $id The entity ID
86 public function setEntityId($id) {
91 * Should custom data be suppressed on this form.
95 protected function isSuppressCustomData() {
100 * Get the entity subtype ID being edited
104 public function getEntitySubTypeId() {
105 return $this->_entitySubTypeId
;
109 * Set the entity subtype ID being edited
113 public function setEntitySubTypeId($subTypeId) {
114 $this->_entitySubTypeId
= $subTypeId;
118 * If the custom data is in the submitted data (eg. added via ajax loaded form) add to form.
120 public function addCustomDataToForm() {
121 if ($this->isSuppressCustomData()) {
124 $customisableEntities = CRM_Core_SelectValues
::customGroupExtends();
125 if (isset($customisableEntities[$this->getDefaultEntity()])) {
126 CRM_Custom_Form_CustomData
::addToForm($this, $this->getEntitySubTypeId());
131 * Build the form object.
133 public function buildQuickEntityForm() {
134 if ($this->isDeleteContext()) {
135 $this->buildDeleteForm();
138 $this->applyFilter('__ALL__', 'trim');
139 $this->addEntityFieldsToTemplate();
140 $this->assign('entityFields', $this->entityFields
);
141 $this->assign('entityID', $this->getEntityId());
142 $this->assign('entityInClassFormat', strtolower(str_replace('_', '-', $this->getDefaultEntity())));
143 $this->assign('entityTable', CRM_Core_DAO_AllCoreTables
::getTableForClass(CRM_Core_DAO_AllCoreTables
::getFullName($this->getDefaultEntity())));
144 $this->addCustomDataToForm();
145 $this->addFormButtons();
147 if ($this->isViewContext()) {
153 * Build the form for any deletion.
155 protected function buildDeleteForm() {
156 $this->assign('deleteMessage', $this->getDeleteMessage());
157 $this->addFormButtons();
161 * Add relevant buttons to the form.
163 protected function addFormButtons() {
164 if ($this->isViewContext() ||
$this->_action
& CRM_Core_Action
::PREVIEW
) {
168 'name' => ts('Done'),
177 'name' => $this->isDeleteContext() ?
ts('Delete') : ts('Save'),
182 'name' => ts('Cancel'),
189 * Get the defaults for the entity.
191 protected function getEntityDefaults() {
192 $defaults = $moneyFields = [];
194 if (!$this->isDeleteContext() &&
195 $this->getEntityId()) {
196 $params = ['id' => $this->getEntityId()];
197 $baoName = $this->_BAOName
;
198 $baoName::retrieve($params, $defaults);
200 foreach ($this->entityFields
as $entityFieldName => $fieldSpec) {
201 $value = CRM_Utils_Request
::retrieveValue($fieldSpec['name'], $this->getValidationTypeForField($fieldSpec['name']));
202 if ($value !== FALSE && $value !== NULL) {
203 $defaults[$fieldSpec['name']] = $value;
205 // Store a list of fields with money formatters
206 if (CRM_Utils_Array
::value('formatter', $fieldSpec) == 'crmMoney') {
207 $moneyFields[] = $entityFieldName;
210 if (!empty($defaults['currency'])) {
211 // If we have a money formatter we need to pass the specified currency or it will render as the default
212 foreach ($moneyFields as $entityFieldName) {
213 $this->entityFields
[$entityFieldName]['formatterParam'] = $defaults['currency'];
217 // Assign again as we may have modified above
218 $this->assign('entityFields', $this->entityFields
);
223 * Get the validation rule to apply to a function.
225 * Alphanumeric is designed to always be safe & for now we just return
226 * that but in future we can use tighter rules for types like int, bool etc.
228 * @param string $fieldName
230 * @return string|int|bool
232 protected function getValidationTypeForField($fieldName) {
233 switch ($this->metadata
[$fieldName]['type']) {
234 case CRM_Utils_Type
::T_BOOLEAN
:
238 return 'Alphanumeric';
243 * Set translated fields.
245 * This function is called from the class constructor, allowing us to set
246 * fields on the class that can't be set as properties due to need for
247 * translation or other non-input specific handling.
249 protected function setTranslatedFields() {
250 $this->setEntityFields();
251 $this->setDeleteMessage();
252 $metadata = civicrm_api3($this->getDefaultEntity(), 'getfields', ['action' => 'create']);
253 $this->metadata
= $metadata['values'];
254 foreach ($this->metadata
as $fieldName => $spec) {
255 if (isset($this->entityFields
[$fieldName])) {
256 if ($spec['localizable']) {
257 $this->entityFields
[$fieldName]['is_add_translate_dialog'] = TRUE;
259 if (empty($spec['html']['type'])) {
260 $this->entityFields
[$fieldName]['not-auto-addable'] = TRUE;
267 * Add defined entity field to template.
269 protected function addEntityFieldsToTemplate() {
270 foreach ($this->getEntityFields() as $fieldSpec) {
271 if (empty($fieldSpec['not-auto-addable'])) {
272 $element = $this->addField($fieldSpec['name'], [], CRM_Utils_Array
::value('required', $fieldSpec), FALSE);
273 if (!empty($fieldSpec['is_freeze'])) {
281 * Is the form being used in the context of a deletion.
283 * (For some reason rather than having separate forms Civi overloads one form).
287 protected function isDeleteContext() {
288 return ($this->_action
& CRM_Core_Action
::DELETE
);
292 * Is the form being used in the context of a view.
296 protected function isViewContext() {
297 return ($this->_action
& CRM_Core_Action
::VIEW
);
300 protected function setEntityFieldsMetadata() {
301 foreach ($this->entityFields
as $field => &$props) {
302 if (!empty($props['not-auto-addable'])) {
303 // We can't load this field using metadata
306 if ($field != 'id' && $this->isDeleteContext()) {
307 // Delete forms don't generally present any fields to edit
311 if (empty($props['action'])) {
312 $props['action'] = $this->getApiAction();
314 $fieldSpec = civicrm_api3($this->getDefaultEntity(), 'getfield', $props);
315 $fieldSpec = $fieldSpec['values'];
316 if (!isset($props['description']) && isset($fieldSpec['description'])) {
317 $props['description'] = $fieldSpec['description'];