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
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');
*/
protected $_ssID;
+ /**
+ * @return string
+ */
+ public function getDefaultEntity() {
+ return 'Activity';
+ }
+
/**
* Processing needed for buildForm and later.
*/
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;
}
CRM_Contact_BAO_Query::processSpecialFormValue($this->_formValues, $specialParams, $changeNames);
}
-
$this->fixFormValues();
if (isset($this->_ssID) && empty($_POST)) {
}
// 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_') {
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
*
return ts('Find Activities');
}
+ protected function getEntityMetadata() {
+ return CRM_Activity_BAO_Query::getSearchFieldMetadata();
+ }
+
}
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.
*/
$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.
*