Commit e6dda67a authored by eileen's avatar eileen

Prototype for metadata based fields on search screens.

This is a first step towards making search screens more metadata driven. It switches the activity_type_id field
to being metadata-added and adds support for activity_type_id=1 via the url.

The setting of defaults is more like 'normal' forms where they are loaded & can be changed in the UI
rather than 'search methods' where they only work in conjunction with 'force'
(which also still works).

This comes out of my concern that
a) we already have url defaults added badly on this form &
b) we have had more than one PR to add more defaults - eg. https://github.com/civicrm/civicrm-core/pull/12455

So I think we should define how we really want entity data to be used with search forms & move towards it.

Note also that the tpls for Contribution Search and one of the contact search panes have been amended to
be metadata driven. I haven't tried to align with that in this step but it should be down the track
parent a4e2c955
......@@ -433,15 +433,26 @@ class CRM_Activity_BAO_Query {
return $from;
}
/**
* Get the metadata for fields to be included on the activity search form.
*
* @todo ideally this would be a trait included on the activity search & advanced search
* rather than a static function.
*/
public static function getSearchFieldMetadata() {
$fields = ['activity_type_id'];
$metadata = civicrm_api3('Activity', 'getfields', [])['values'];
return array_intersect_key($metadata, array_flip($fields));
}
/**
* Add all the elements shared between case activity search and advanced search.
*
* @param CRM_Core_Form $form
* @param CRM_Core_Form_Search $form
*/
public static function buildSearchForm(&$form) {
$form->addSelect('activity_type_id',
array('entity' => 'activity', 'label' => ts('Activity Type(s)'), 'multiple' => 'multiple', 'option_url' => NULL, 'placeholder' => ts('- any -'))
);
$form->addSearchFieldMetadata(['Activity' => self::getSearchFieldMetadata()]);
$form->addFormFieldsFromMetadata();
CRM_Core_Form_Date::buildDateRange($form, 'activity_date', 1, '_low', '_high', ts('From'), FALSE, FALSE);
$form->addElement('hidden', 'activity_date_range_error');
......
......@@ -69,6 +69,13 @@ class CRM_Activity_Form_Search extends CRM_Core_Form_Search {
*/
protected $_ssID;
/**
* @return string
*/
public function getDefaultEntity() {
return 'Activity';
}
/**
* Processing needed for buildForm and later.
*/
......@@ -95,6 +102,8 @@ class CRM_Activity_Form_Search extends CRM_Core_Form_Search {
if ($this->_force) {
// If we force the search then merge form values with url values
// and set submit values to form values.
// @todo this is not good security practice. Instead define the fields in metadata & use
// getEntityDefaults.
$this->_formValues = array_merge((array) $this->_formValues, CRM_Utils_Request::exportValues());
$this->_submitValues = $this->_formValues;
}
......@@ -203,7 +212,6 @@ class CRM_Activity_Form_Search extends CRM_Core_Form_Search {
CRM_Contact_BAO_Query::processSpecialFormValue($this->_formValues, $specialParams, $changeNames);
}
$this->fixFormValues();
if (isset($this->_ssID) && empty($_POST)) {
......@@ -369,6 +377,8 @@ class CRM_Activity_Form_Search extends CRM_Core_Form_Search {
}
// Enable search activity by custom value
// @todo this is not good security practice. Instead define entity fields in metadata &
// use getEntity Defaults
$requestParams = CRM_Utils_Request::exportValues();
foreach (array_keys($requestParams) as $key) {
if (substr($key, 0, 7) != 'custom_') {
......@@ -396,6 +406,16 @@ class CRM_Activity_Form_Search extends CRM_Core_Form_Search {
return NULL;
}
/**
* This virtual function is used to set the default values of various form elements.
*
* @return array|NULL
* reference to the array of default values
*/
public function setDefaultValues() {
return array_merge($this->getEntityDefaults($this->getDefaultEntity()), $this->_formValues);
}
/**
* Return a descriptive name for the page, used in wizard header
*
......@@ -405,4 +425,8 @@ class CRM_Activity_Form_Search extends CRM_Core_Form_Search {
return ts('Find Activities');
}
protected function getEntityMetadata() {
return CRM_Activity_BAO_Query::getSearchFieldMetadata();
}
}
......@@ -101,6 +101,27 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
return $this->_taskList;
}
/**
* Metadata for fields on the search form.
*
* @var array
*/
protected $searchFieldMetadata = [];
/**
* @return array
*/
public function getSearchFieldMetadata() {
return $this->searchFieldMetadata;
}
/**
* @param array $searchFieldMetadata
*/
public function addSearchFieldMetadata($searchFieldMetadata) {
$this->searchFieldMetadata = array_merge($this->searchFieldMetadata, $searchFieldMetadata);
}
/**
* Common buildForm tasks required by all searches.
*/
......@@ -123,6 +144,65 @@ class CRM_Core_Form_Search extends CRM_Core_Form {
$this->addTaskMenu($tasks);
}
/**
* Add any fields described in metadata to the form.
*
* The goal is to describe all fields in metadata and handle from metadata rather
* than existing ad hoc handling.
*/
public function addFormFieldsFromMetadata() {
$this->_action = CRM_Core_Action::ADVANCED;
foreach ($this->getSearchFieldMetadata() as $entity => $fields) {
foreach ($fields as $fieldName => $fieldSpec) {
$this->addField($fieldName, ['entity' => $entity]);
}
}
}
/**
* Get the validation rule to apply to a function.
*
* Alphanumeric is designed to always be safe & for now we just return
* that but in future we can use tighter rules for types like int, bool etc.
*
* @param string $entity
* @param string $fieldName
*
* @return string
*/
protected function getValidationTypeForField($entity, $fieldName) {
switch ($this->getSearchFieldMetadata()[$entity][$fieldName]['type']) {
case CRM_Utils_Type::T_BOOLEAN:
return 'Boolean';
case CRM_Utils_Type::T_INT:
return 'CommaSeparatedIntegers';
default:
return 'Alphanumeric';
}
}
/**
* Get the defaults for the entity for any fields described in metadata.
*
* @param string $entity
*
* @return array
*/
protected function getEntityDefaults($entity) {
$defaults = [];
foreach ($this->getSearchFieldMetadata()[$entity] as $fieldSpec) {
if (empty($_POST[$fieldSpec['name']])) {
$value = CRM_Utils_Request::retrieveValue($fieldSpec['name'], $this->getValidationTypeForField($entity, $fieldSpec['name']), FALSE, NULL, 'GET');
if ($value !== FALSE) {
$defaults[$fieldSpec['name']] = $value;
}
}
}
return $defaults;
}
/**
* Add checkboxes for each row plus a master checkbox.
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment