Previously output from a DAO-based Get would be run through an unserializer/type-converter.
This applies that same conversion to DAO-based create/update ops.
use Civi\Api4\Event\PostSelectQueryEvent;
use Civi\Api4\Query\Api4SelectQuery;
use Civi\Api4\Utils\ArrayInsertionUtil;
+use Civi\Api4\Utils\FormattingUtil;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
*/
class PostSelectQuerySubscriber implements EventSubscriberInterface {
- private $contactFieldsToRemove = [];
-
/**
* @inheritdoc
*/
return $results;
}
- $this->formatFieldValues($results, $query->getApiFieldSpec(), $query->getEntity());
+ FormattingUtil::formatOutputValues($results, $query->getApiFieldSpec(), $query->getEntity());
// Group the selects to avoid queries for each field
$groupedSelects = $this->getNtoManyJoinSelects($query);
$fields[array_pop($name)] = $field->toArray();
}
if ($fields) {
- $this->formatFieldValues($joinResults, $fields, $join->getEntity());
- }
- }
-
- /**
- * Unserialize values and convert to correct type
- *
- * @param array $results
- * @param array $fields
- * @param string $entity
- */
- protected function formatFieldValues(&$results, $fields, $entity) {
- foreach ($results as &$result) {
- // Remove inapplicable contact fields
- if ($entity === 'Contact' && !empty($result['contact_type'])) {
- \CRM_Utils_Array::remove($result, $this->contactFieldsToRemove($result['contact_type']));
- }
- foreach ($result as $field => $value) {
- $dataType = $fields[$field]['data_type'] ?? NULL;
- if (!empty($fields[$field]['serialize'])) {
- if (is_string($value)) {
- $result[$field] = $value = \CRM_Core_DAO::unSerializeField($value, $fields[$field]['serialize']);
- foreach ($value as $key => $val) {
- $result[$field][$key] = $this->convertDataType($val, $dataType);
- }
- }
- }
- else {
- $result[$field] = $this->convertDataType($value, $dataType);
- }
- }
- }
- }
-
- /**
- * @param mixed $value
- * @param string $dataType
- * @return mixed
- */
- protected function convertDataType($value, $dataType) {
- if (isset($value)) {
- switch ($dataType) {
- case 'Boolean':
- return (bool) $value;
-
- case 'Integer':
- return (int) $value;
-
- case 'Money':
- case 'Float':
- return (float) $value;
- }
+ FormattingUtil::formatOutputValues($joinResults, $fields, $join->getEntity());
}
- return $value;
}
/**
return $subResults;
}
- /**
- * @param string $contactType
- * @return array
- */
- private function contactFieldsToRemove($contactType) {
- if (!isset($this->contactFieldsToRemove[$contactType])) {
- $this->contactFieldsToRemove[$contactType] = [];
- foreach (\CRM_Contact_DAO_Contact::fields() as $field) {
- if (!empty($field['contactType']) && $field['contactType'] != $contactType) {
- $this->contactFieldsToRemove[$contactType][] = $field['name'];
- }
- }
- }
- return $this->contactFieldsToRemove[$contactType];
- }
-
}
namespace Civi\Api4\Generic\Traits;
-use CRM_Utils_Array as UtilsArray;
use Civi\Api4\Utils\FormattingUtil;
use Civi\Api4\Query\Api4SelectQuery;
$result = [];
foreach ($items as $item) {
- $entityId = UtilsArray::value('id', $item);
+ $entityId = $item['id'] ?? NULL;
FormattingUtil::formatWriteParams($item, $this->getEntityName(), $this->entityFields());
$this->formatCustomParams($item, $entityId);
$item['check_permissions'] = $this->getCheckPermissions();
$result[] = $resultArray;
}
+ FormattingUtil::formatOutputValues($result, $this->entityFields(), $this->getEntityName());
return $result;
}
$baoName = $this->getBaoName();
$hook = empty($params['id']) ? 'create' : 'edit';
- \CRM_Utils_Hook::pre($hook, $this->getEntityName(), UtilsArray::value('id', $params), $params);
+ \CRM_Utils_Hook::pre($hook, $this->getEntityName(), $params['id'] ?? NULL, $params);
/** @var \CRM_Core_DAO $instance */
$instance = new $baoName();
$instance->copyValues($params, TRUE);
throw new \API_Exception("Invalid field '$key' in where clause.");
}
- FormattingUtil::formatValue($value, $fieldSpec, $this->getEntity());
+ FormattingUtil::formatInputValue($value, $fieldSpec, $this->getEntity());
$sql_clause = \CRM_Core_DAO::createSQLFilter("`$table_name`.`$column_name`", [$operator => $value]);
if ($sql_clause === NULL) {
namespace Civi\Api4\Utils;
-use CRM_Utils_Array as UtilsArray;
-
require_once 'api/v3/utils.php';
class FormattingUtil {
if ($value === 'null') {
$value = 'Null';
}
- FormattingUtil::formatValue($value, $field, $entity);
+ self::formatInputValue($value, $field, $entity);
// Ensure we have an array for serialized fields
if (!empty($field['serialize'] && !is_array($value))) {
$value = (array) $value;
* Ex: 'Contact', 'Domain'
* @throws \API_Exception
*/
- public static function formatValue(&$value, $fieldSpec, $entity) {
+ public static function formatInputValue(&$value, $fieldSpec, $entity) {
if (is_array($value)) {
foreach ($value as &$val) {
- self::formatValue($val, $fieldSpec, $entity);
+ self::formatInputValue($val, $fieldSpec, $entity);
}
return;
}
- $fk = UtilsArray::value('fk_entity', $fieldSpec);
- if ($fieldSpec['name'] == 'id') {
- $fk = $entity;
- }
- $dataType = UtilsArray::value('data_type', $fieldSpec);
+ $fk = $fieldSpec['name'] == 'id' ? $entity : $fieldSpec['fk_entity'] ?? NULL;
if ($fk === 'Domain' && $value === 'current_domain') {
$value = \CRM_Core_Config::domainID();
}
}
- switch ($dataType) {
+ switch ($fieldSpec['data_type'] ?? NULL) {
case 'Timestamp':
$value = date('Y-m-d H:i:s', strtotime($value));
break;
}
}
+ /**
+ * Unserialize raw DAO values and convert to correct type
+ *
+ * @param array $results
+ * @param array $fields
+ * @param string $entity
+ * @throws \CRM_Core_Exception
+ */
+ public static function formatOutputValues(&$results, $fields, $entity) {
+ foreach ($results as &$result) {
+ // Remove inapplicable contact fields
+ if ($entity === 'Contact' && !empty($result['contact_type'])) {
+ \CRM_Utils_Array::remove($result, self::contactFieldsToRemove($result['contact_type']));
+ }
+ foreach ($result as $field => $value) {
+ $dataType = $fields[$field]['data_type'] ?? ($field == 'id' ? 'Integer' : NULL);
+ if (!empty($fields[$field]['serialize'])) {
+ if (is_string($value)) {
+ $result[$field] = $value = \CRM_Core_DAO::unSerializeField($value, $fields[$field]['serialize']);
+ foreach ($value as $key => $val) {
+ $result[$field][$key] = self::convertDataType($val, $dataType);
+ }
+ }
+ }
+ else {
+ $result[$field] = self::convertDataType($value, $dataType);
+ }
+ }
+ }
+ }
+
+ /**
+ * @param mixed $value
+ * @param string $dataType
+ * @return mixed
+ */
+ public static function convertDataType($value, $dataType) {
+ if (isset($value)) {
+ switch ($dataType) {
+ case 'Boolean':
+ return (bool) $value;
+
+ case 'Integer':
+ return (int) $value;
+
+ case 'Money':
+ case 'Float':
+ return (float) $value;
+ }
+ }
+ return $value;
+ }
+
+ /**
+ * @param string $contactType
+ * @return array
+ */
+ public static function contactFieldsToRemove($contactType) {
+ if (!isset(\Civi::$statics[__CLASS__][__FUNCTION__][$contactType])) {
+ \Civi::$statics[__CLASS__][__FUNCTION__][$contactType] = [];
+ foreach (\CRM_Contact_DAO_Contact::fields() as $field) {
+ if (!empty($field['contactType']) && $field['contactType'] != $contactType) {
+ \Civi::$statics[__CLASS__][__FUNCTION__][$contactType][] = $field['name'];
+ }
+ }
+ }
+ return \Civi::$statics[__CLASS__][__FUNCTION__][$contactType];
+ }
+
}
});
} else if (dataType === 'Boolean') {
$el.attr('placeholder', ts('- select -')).crmSelect2({allowClear: false, multiple: multi, placeholder: ts('- select -'), data: [
- {id: '1', text: ts('Yes')},
- {id: '0', text: ts('No')}
+ {id: 'true', text: ts('Yes')},
+ {id: 'false', text: ts('No')}
]});
}
} else if (dataType === 'Integer' && !multi) {
if ($key == 'add_contact_to_group' or $key == 'group') {
continue;
}
- $expected = $this->params[$key];
$received = $result['values'][$result['id']][$key];
+ if ($key == 'group_type' && $version == 4) {
+ $received = implode(',', $received);
+ }
+ $expected = $this->params[$key];
$this->assertEquals($expected, $received, "The string '$received' does not equal '$expected' for key '$key' in line " . __LINE__);
}
}
if ($key == 'add_contact_to_group' or $key == 'group') {
continue;
}
- $this->assertEquals($result['values'][$result['id']][$key], $params[$key], $key . " doesn't match " . $value);
+ $received = $result['values'][$result['id']][$key];
+ if ($key == 'group_type' && $version == 4) {
+ $received = implode(',', $received);
+ }
+ $this->assertEquals($received, $params[$key], $key . " doesn't match " . $value);
}
$this->assertEquals($result['values'][$this->_ufGroupId]['add_to_group_id'], $params['add_contact_to_group']);