4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
10 +--------------------------------------------------------------------+
16 * @copyright CiviCRM LLC https://civicrm.org/licensing
20 namespace Civi\Api4\Service\Spec
;
22 use Civi\Api4\Utils\CoreUtil
;
28 protected $defaultValue;
48 protected $description;
53 protected $required = FALSE;
58 protected $requiredIf;
78 protected $inputAttrs = [];
103 protected $permission;
108 protected $columnName;
111 * Aliases for the valid data types
115 public static $typeAliases = [
122 * @param string $name
123 * @param string $entity
124 * @param string $dataType
126 public function __construct($name, $entity, $dataType = 'String') {
127 $this->entity
= $entity;
128 $this->name
= $this->columnName
= $name;
129 $this->setDataType($dataType);
135 public function getDefaultValue() {
136 return $this->defaultValue
;
140 * @param mixed $defaultValue
144 public function setDefaultValue($defaultValue) {
145 $this->defaultValue
= $defaultValue;
153 public function getName() {
158 * @param string $name
162 public function setName($name) {
171 public function getTitle() {
176 * @param string $title
180 public function setTitle($title) {
181 $this->title
= $title;
189 public function getEntity() {
190 return $this->entity
;
196 public function getDescription() {
197 return $this->description
;
201 * @param string $description
205 public function setDescription($description) {
206 $this->description
= $description;
214 public function isRequired() {
215 return $this->required
;
219 * @param bool $required
223 public function setRequired($required) {
224 $this->required
= $required;
232 public function getRequiredIf() {
233 return $this->requiredIf
;
237 * @param bool $requiredIf
241 public function setRequiredIf($requiredIf) {
242 $this->requiredIf
= $requiredIf;
250 public function getDataType() {
251 return $this->dataType
;
260 public function setDataType($dataType) {
261 if (array_key_exists($dataType, self
::$typeAliases)) {
262 $dataType = self
::$typeAliases[$dataType];
265 if (!in_array($dataType, $this->getValidDataTypes())) {
266 throw new \
Exception(sprintf('Invalid data type "%s', $dataType));
269 $this->dataType
= $dataType;
277 public function getSerialize() {
278 return $this->serialize
;
282 * @param int|null $serialize
285 public function setSerialize($serialize) {
286 $this->serialize
= $serialize;
292 * @param array $permission
295 public function setPermission($permission) {
296 $this->permission
= $permission;
303 public function getPermission() {
304 return $this->permission
;
310 public function getInputType() {
311 return $this->inputType
;
315 * @param string $inputType
318 public function setInputType($inputType) {
319 $this->inputType
= $inputType;
327 public function getInputAttrs() {
328 return $this->inputAttrs
;
332 * @param array $inputAttrs
335 public function setInputAttrs($inputAttrs) {
336 $this->inputAttrs
= $inputAttrs;
342 * @return string|NULL
344 public function getHelpPre() {
345 return $this->helpPre
;
349 * @param string|NULL $helpPre
351 public function setHelpPre($helpPre) {
352 $this->helpPre
= is_string($helpPre) && strlen($helpPre) ?
$helpPre : NULL;
356 * @return string|NULL
358 public function getHelpPost() {
359 return $this->helpPost
;
363 * @param string|NULL $helpPost
365 public function setHelpPost($helpPost) {
366 $this->helpPost
= is_string($helpPost) && strlen($helpPost) ?
$helpPost : NULL;
370 * Add valid types that are not not part of \CRM_Utils_Type::dataTypes
374 private function getValidDataTypes() {
375 $extraTypes = ['Boolean', 'Text', 'Float', 'Url', 'Array'];
376 $extraTypes = array_combine($extraTypes, $extraTypes);
378 return array_merge(\CRM_Utils_Type
::dataTypes(), $extraTypes);
382 * @param array $values
383 * @param array|bool $return
386 public function getOptions($values = [], $return = TRUE) {
387 if (!isset($this->options
) ||
$this->options
=== TRUE) {
388 $fieldName = $this->getName();
390 if ($this instanceof CustomFieldSpec
) {
391 // buildOptions relies on the custom_* type of field names
392 $fieldName = sprintf('custom_%d', $this->getCustomFieldId());
395 // BAO::buildOptions returns a single-dimensional list, we call that first because of the hook contract,
396 // @see CRM_Utils_Hook::fieldOptions
397 // We then supplement the data with additional properties if requested.
398 $bao = CoreUtil
::getBAOFromApiName($this->getEntity());
399 $optionLabels = $bao::buildOptions($fieldName, NULL, $values);
401 if (!is_array($optionLabels) ||
!$optionLabels) {
402 $this->options
= FALSE;
405 $this->options
= \CRM_Utils_Array
::makeNonAssociative($optionLabels, 'id', 'label');
406 if (is_array($return)) {
407 self
::addOptionProps($bao, $fieldName, $values, $return);
411 return $this->options
;
415 * Supplement the data from
417 * @param \CRM_Core_DAO $baoName
418 * @param string $fieldName
419 * @param array $values
420 * @param array $return
422 private function addOptionProps($baoName, $fieldName, $values, $return) {
423 // FIXME: For now, call the buildOptions function again and then combine the arrays. Not an ideal approach.
424 // TODO: Teach CRM_Core_Pseudoconstant to always load multidimensional option lists so we can get more properties like 'color' and 'icon',
425 // however that might require a change to the hook_civicrm_fieldOptions signature so that's a bit tricky.
426 if (in_array('name', $return)) {
427 $props['name'] = $baoName::buildOptions($fieldName, 'validate', $values);
429 $return = array_diff($return, ['id', 'name', 'label']);
430 // CRM_Core_Pseudoconstant doesn't know how to fetch extra stuff like icon, description, color, etc., so we have to invent that wheel here...
432 $optionIds = implode(',', array_column($this->options
, 'id'));
433 $optionIndex = array_flip(array_column($this->options
, 'id'));
434 if ($this instanceof CustomFieldSpec
) {
435 $optionGroupId = \CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_CustomField', $this->getCustomFieldId(), 'option_group_id');
438 $dao = new $baoName();
439 $fieldSpec = $dao->getFieldSpec($fieldName);
440 $pseudoconstant = $fieldSpec['pseudoconstant'] ??
NULL;
441 $optionGroupName = $pseudoconstant['optionGroupName'] ??
NULL;
442 $optionGroupId = $optionGroupName ? \CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_OptionGroup', $optionGroupName, 'id', 'name') : NULL;
444 if (!empty($optionGroupId)) {
445 $extraStuff = \CRM_Core_BAO_OptionValue
::getOptionValuesArray($optionGroupId);
446 $keyColumn = $pseudoconstant['keyColumn'] ??
'value';
447 foreach ($extraStuff as $item) {
448 if (isset($optionIndex[$item[$keyColumn]])) {
449 foreach ($return as $ret) {
450 $this->options
[$optionIndex[$item[$keyColumn]]][$ret] = $item[$ret] ??
NULL;
456 // Fetch the abbr if requested using context: abbreviate
457 if (in_array('abbr', $return)) {
458 $props['abbr'] = $baoName::buildOptions($fieldName, 'abbreviate', $values);
459 $return = array_diff($return, ['abbr']);
461 // Fetch anything else (color, icon, description)
462 if ($return && !empty($pseudoconstant['table']) && \CRM_Utils_Rule
::commaSeparatedIntegers($optionIds)) {
463 $sql = "SELECT * FROM {$pseudoconstant['table']} WHERE id IN (%1)";
464 $query = \CRM_Core_DAO
::executeQuery($sql, [1 => [$optionIds, 'CommaSeparatedIntegers']]);
465 while ($query->fetch()) {
466 foreach ($return as $ret) {
467 if (property_exists($query, $ret)) {
468 $this->options
[$optionIndex[$query->id
]][$ret] = $query->$ret;
476 foreach ($this->options
as &$option) {
477 foreach ($props as $name => $prop) {
478 $option[$name] = $prop[$option['id']] ??
NULL;
485 * @param array|bool $options
489 public function setOptions($options) {
490 $this->options
= $options;
497 public function getFkEntity() {
498 return $this->fkEntity
;
502 * @param string $fkEntity
506 public function setFkEntity($fkEntity) {
507 $this->fkEntity
= $fkEntity;
515 public function getColumnName() {
516 return $this->columnName
;
520 * @param string $columnName
524 public function setColumnName($columnName) {
525 $this->columnName
= $columnName;
530 * @param array $values
533 public function toArray($values = []) {
535 foreach (get_object_vars($this) as $key => $val) {
536 $key = strtolower(preg_replace('/(?=[A-Z])/', '_$0', $key));
537 if (!$values ||
in_array($key, $values)) {