Add buildOptions method CRM-12464
authorColeman Watts <coleman@civicrm.org>
Fri, 3 May 2013 01:54:49 +0000 (18:54 -0700)
committerColeman Watts <coleman@civicrm.org>
Thu, 30 May 2013 05:13:22 +0000 (22:13 -0700)
----------------------------------------
* CRM-12464:
  http://issues.civicrm.org/jira/browse/CRM-12464

CRM/Contact/BAO/Contact.php
CRM/Core/BAO/Address.php
CRM/Core/DAO.php
tests/phpunit/CRM/Core/FieldOptionsTest.php [new file with mode: 0644]
xml/schema/Core/Address.xml

index dc50c8254f923f409600ae4c291f89f76a7f3ce3..b6aedf1fc272301d1747622770bb8f2cf0853418 100644 (file)
@@ -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
index e0dfada412df8162f2352b63a93a60e19da7e7be..ac90857042fed5dd7ffdb19a584dcd5778f0e439 100644 (file)
@@ -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);
+  }
 }
index ea8b5db65f61947f0e1dad403bc3470f9f3240fd..23b47be3a588610fee831268135199701a6df4bd 100644 (file)
@@ -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 (file)
index 0000000..302947d
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.3                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2013                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+*/
+
+require_once 'CiviTest/CiviUnitTestCase.php';
+
+/**
+ * Tests for linking to resource files
+ */
+class CRM_Core_FieldOptionsTest extends CiviUnitTestCase {
+  function get_info() {
+    return array(
+      'name'    => '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 <pseudoconstant> 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);
+      }
+    }
+  }
+}
index 409179064d25da77caec59130db8b8a164c33206..548478756dc017c433d619ea19aaba04b98b0d1e 100644 (file)
       <name>county_id</name>
       <type>int unsigned</type>
       <comment>Which County does this address belong to.</comment>
-       <add>1.1</add>
+      <pseudoconstant>
+        <table>civicrm_county</table>
+        <keyColumn>id</keyColumn>
+        <labelColumn>name</labelColumn>
+      </pseudoconstant>
+      <add>1.1</add>
   </field>
   <foreignKey>
        <name>county_id</name>
       <title>State</title>
       <type>int unsigned</type>
       <comment>Which State_Province does this address belong to.</comment>
+      <pseudoconstant>
+        <table>civicrm_state_province</table>
+        <keyColumn>id</keyColumn>
+        <labelColumn>name</labelColumn>
+      </pseudoconstant>
       <add>1.1</add>
   </field>
   <foreignKey>
       <title>Country</title>
       <type>int unsigned</type>
       <comment>Which Country does this address belong to.</comment>
-       <add>1.1</add>
+      <pseudoconstant>
+        <table>civicrm_country</table>
+        <keyColumn>id</keyColumn>
+        <labelColumn>name</labelColumn>
+      </pseudoconstant>
+      <add>1.1</add>
   </field>
   <foreignKey>
        <name>country_id</name>