From dc86f88118f4eda1b55b3a7fef3182c127e07e26 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Thu, 2 May 2013 18:54:49 -0700 Subject: [PATCH] Add buildOptions method CRM-12464 ---------------------------------------- * CRM-12464: http://issues.civicrm.org/jira/browse/CRM-12464 --- CRM/Contact/BAO/Contact.php | 23 +++++ CRM/Core/BAO/Address.php | 47 +++++++++ CRM/Core/DAO.php | 14 +++ tests/phpunit/CRM/Core/FieldOptionsTest.php | 103 ++++++++++++++++++++ xml/schema/Core/Address.xml | 19 +++- 5 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 tests/phpunit/CRM/Core/FieldOptionsTest.php diff --git a/CRM/Contact/BAO/Contact.php b/CRM/Contact/BAO/Contact.php index dc50c8254f..b6aedf1fc2 100644 --- a/CRM/Contact/BAO/Contact.php +++ b/CRM/Contact/BAO/Contact.php @@ -2979,6 +2979,29 @@ LEFT JOIN civicrm_address add2 ON ( add1.master_id = add2.id ) } } + /** + * Get options for a given contact field. + * @see CRM_Core_DAO::buildOptions + * + * TODO: Should we always assume chainselect? What fn should be responsible for controlling that flow? + * TODO: In context of chainselect, what to return if e.g. a country has no states? + * + * @param String $fieldName + * @param String $context: e.g. "search" "edit" "create" "view" + * @param Array $props: whatever is known about this dao object + */ + public static function buildOptions($fieldName, $context = NULL, $props = array()) { + $params = array(); + // Special logic for fields whose options depend on context or properties + switch ($fieldName) { + case 'contact_sub_type': + if (!empty($props['contact_type'])) { + $params['condition'] = "parent_id = (SELECT id FROM civicrm_contact_type WHERE name='{$props['contact_type']}')"; + } + break; + } + return CRM_Core_PseudoConstant::get(__CLASS__, $fieldName, $params); + } /** * Delete a contact-related object that has an 'is_primary' field diff --git a/CRM/Core/BAO/Address.php b/CRM/Core/BAO/Address.php index e0dfada412..ac90857042 100644 --- a/CRM/Core/BAO/Address.php +++ b/CRM/Core/BAO/Address.php @@ -1149,4 +1149,51 @@ SELECT is_primary, static function del($id) { return CRM_Contact_BAO_Contact::deleteObjectWithPrimary('Address', $id); } + + /** + * Get options for a given address field. + * @see CRM_Core_DAO::buildOptions + * + * TODO: Should we always assume chainselect? What fn should be responsible for controlling that flow? + * TODO: In context of chainselect, what to return if e.g. a country has no states? + * + * @param String $fieldName + * @param String $context: e.g. "search" "edit" "create" "view" + * @param Array $props: whatever is known about this dao object + */ + public static function buildOptions($fieldName, $context = NULL, $props = array()) { + $params = array(); + // Special logic for fields whose options depend on context or properties + switch ($fieldName) { + // Filter state_province list based on chosen country or site defaults + case 'state_province_id': + if (empty($props['country_id'])) { + $config = CRM_Core_Config::singleton(); + if (!empty($config->provinceLimit)) { + $props['country_id'] = $config->provinceLimit; + } + else { + $props['country_id'] = $config->defaultContactCountry; + } + } + if (!empty($props['country_id'])) { + $params['condition'] = 'country_id IN (' . implode(',', (array) $props['country_id']) . ')'; + } + break; + // Filter country list based on site defaults + case 'country_id': + $config = CRM_Core_Config::singleton(); + if (!empty($config->countryLimit) && is_array($config->countryLimit)) { + $params['condition'] = 'id IN (' . implode(',', $config->countryLimit) . ')'; + } + break; + // Filter county list based on chosen state + case 'county_id': + if (!empty($props['state_province_id'])) { + $params['condition'] = 'state_province_id IN (' . implode(',', (array) $props['state_province_id']) . ')'; + } + break; + } + return CRM_Core_PseudoConstant::get(__CLASS__, $fieldName, $params); + } } diff --git a/CRM/Core/DAO.php b/CRM/Core/DAO.php index ea8b5db65f..23b47be3a5 100644 --- a/CRM/Core/DAO.php +++ b/CRM/Core/DAO.php @@ -1767,5 +1767,19 @@ EOS; return $default; } } + + /** + * Get options for the called BAO object's field. + * This function can be overridden by each BAO to add more logic related to context. + * + * @param String $fieldName + * @param String $context: e.g. "search" "edit" "create" "view" + * @param Array $props: whatever is known about this bao object + */ + public static function buildOptions($fieldName, $context = NULL, $props = array()) { + // If a given bao does not override this function, it can still be called on that bao + $baoName = get_called_class(); + return CRM_Core_PseudoConstant::get($baoName, $fieldName); + } } diff --git a/tests/phpunit/CRM/Core/FieldOptionsTest.php b/tests/phpunit/CRM/Core/FieldOptionsTest.php new file mode 100644 index 0000000000..302947d595 --- /dev/null +++ b/tests/phpunit/CRM/Core/FieldOptionsTest.php @@ -0,0 +1,103 @@ + 'FieldOptions', + 'description' => 'Tests for field-specific option values', + 'group' => 'Core', + ); + } + + function setUp() { + parent::setUp(); + } + + /** + * Assure CRM_Core_PseudoConstant::get() is working properly for a range of + * DAO fields having a tag in the XML schema. + */ + function testOptionValues() { + /** + * baoName/field combinations to test + * Format: array[BAO Name] = $properties, where properties is an array whose + * named members can be: + * - fieldName: the SQL column name within the DAO table. + * - sample: Any one value which is expected in the list of option values. + * - context: Context to pass + * - props: Object properties to pass + * - exclude: Any one value which should not be in the list. + * - max: integer (default = 10) maximum number of option values expected. + */ + $fields = array( + 'CRM_Core_BAO_Address' => array( + array( + 'fieldName' => 'state_province_id', + 'sample' => 'California', + 'max' => 60, + 'props' => array('country_id' => 1228), + ), + ), + 'CRM_Contact_BAO_Contact' => array( + array( + 'fieldName' => 'contact_sub_type', + 'sample' => 'Team', + 'exclude' => 'Organization', + 'props' => array('contact_type' => 'Organization'), + ), + ), + ); + + foreach ($fields as $baoName => $baoFields) { + foreach ($baoFields as $field) { + $message = "BAO name: '{$baoName}', field: '{$field['fieldName']}'"; + + $props = CRM_Utils_Array::value('props', $field, array()); + $optionValues = $baoName::buildOptions($field['fieldName'], 'test', $props); + $this->assertNotEmpty($optionValues, $message); + + // Ensure sample value is contained in the returned optionValues. + $this->assertContains($field['sample'], $optionValues, $message); + + // Exclude test + if (!empty($field['exclude'])) { + $this->assertNotContains($field['exclude'], $optionValues, $message); + } + + // Ensure count of optionValues is not extraordinarily high. + $max = CRM_Utils_Array::value('max', $field, 10); + $this->assertLessThanOrEqual($max, count($optionValues), $message); + } + } + } +} diff --git a/xml/schema/Core/Address.xml b/xml/schema/Core/Address.xml index 409179064d..548478756d 100644 --- a/xml/schema/Core/Address.xml +++ b/xml/schema/Core/Address.xml @@ -190,7 +190,12 @@ county_id int unsigned Which County does this address belong to. - 1.1 + + civicrm_county
+ id + name +
+ 1.1 county_id @@ -207,6 +212,11 @@ State int unsigned Which State_Province does this address belong to. + + civicrm_state_province
+ id + name +
1.1 @@ -253,7 +263,12 @@ Country int unsigned Which Country does this address belong to. - 1.1 + + civicrm_country
+ id + name +
+ 1.1 country_id -- 2.25.1