CRM-20312 Add indices to DAO classes
authorAidan Saunders <aidan.saunders@squiffle.uk>
Tue, 4 Apr 2017 22:56:29 +0000 (10:56 +1200)
committereileen <emcnaughton@wikimedia.org>
Wed, 5 Apr 2017 03:05:27 +0000 (15:05 +1200)
CRM/Core/BAO/SchemaHandler.php
CRM/Core/CodeGen/DAO.php
CRM/Core/CodeGen/Specification.php
CRM/Core/DAO/AllCoreTables.php
tests/phpunit/CRM/Core/DAO/AllCoreTablesTest.php
xml/templates/dao.tpl

index 9886c4378d1836dd4cdb734218ca9d00001b31f0..83c34d5852f6e162f281a9c8daa3685b7888d906 100644 (file)
@@ -644,4 +644,18 @@ MODIFY      {$columnName} varchar( $length )
     return FALSE;
   }
 
+  /**
+   * Add index signature hash to DAO file calculation.
+   *
+   * @param string $table table name
+   * @param array $indices index array spec
+   */
+  public static function addIndexSignature($table, &$indices) {
+    foreach ($indices as $indexName => $index) {
+      $indices[$indexName]['sig'] = $table . "::" .
+        (array_key_exists('unique', $index) ? $index['unique'] : 0) . "::" .
+        implode("::", $index['field']);
+    }
+  }
+
 }
index 83c2c449d73dce4290d21353f1777da9570c1f0f..f0c6eec087958fe6b94c41981ad2ecf0d69df767 100644 (file)
@@ -62,6 +62,12 @@ class CRM_Core_CodeGen_DAO extends CRM_Core_CodeGen_BaseTask {
 
     $template = new CRM_Core_CodeGen_Util_Template('php');
     $template->assign('table', $this->tables[$this->name]);
+    if (empty($this->tables[$this->name]['index'])) {
+      $template->assign('indicesPhp', var_export(array(), 1));
+    }
+    else {
+      $template->assign('indicesPhp', var_export($this->tables[$this->name]['index'], 1));
+    }
     $template->assign('genCodeChecksum', $this->getTableChecksum());
     $template->run('dao.tpl', $this->getAbsFileName());
   }
@@ -75,6 +81,12 @@ class CRM_Core_CodeGen_DAO extends CRM_Core_CodeGen_BaseTask {
     if (!$this->raw) {
       $template = new CRM_Core_CodeGen_Util_Template('php');
       $template->assign('table', $this->tables[$this->name]);
+      if (empty($this->tables[$this->name]['index'])) {
+        $template->assign('indicesPhp', var_export(array(), 1));
+      }
+      else {
+        $template->assign('indicesPhp', var_export($this->tables[$this->name]['index'], 1));
+      }
       $template->assign('genCodeChecksum', 'NEW');
       $this->raw = $template->fetch('dao.tpl');
     }
index 34d43015f0b1bce9d8253d57ad11224a846560f3..7184d738d2bd1c6bad8213aba24de569eaa79483 100644 (file)
@@ -242,6 +242,7 @@ class CRM_Core_CodeGen_Specification {
 
         $this->getIndex($indexXML, $fields, $index);
       }
+      CRM_Core_BAO_SchemaHandler::addIndexSignature($name, $index);
       $table['index'] = &$index;
     }
 
index 31987ffa43c734377401861664e3c0f0cee6d847..f70d2a5bedf091e67a22e2c05fba705d3af063f2 100644 (file)
@@ -108,6 +108,70 @@ class CRM_Core_DAO_AllCoreTables {
     return self::$tables;
   }
 
+  /**
+   * @return array
+   *   List of indices.
+   */
+  public static function indices($localize = TRUE) {
+    $indices = array();
+    self::init();
+    foreach (self::$daoToClass as $class) {
+      if (is_callable(array($class, 'indices'))) {
+        $indices[$class::getTableName()] = $class::indices($localize);
+      }
+    }
+    return $indices;
+  }
+
+  /**
+   * Modify indices to account for localization options.
+   *
+   * @param CRM_Core_DAO $class DAO class
+   * @param array $originalIndices index definitions before localization
+   *
+   * @return array
+   *   index definitions after localization
+   */
+  public static function multilingualize($class, $originalIndices) {
+    $domain = new CRM_Core_DAO_Domain();
+    $domain->find(TRUE);
+    $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
+    if (CRM_Utils_System::isNull($locales)) {
+      return $originalIndices;
+    }
+    $classFields = $class::fields();
+
+    $finalIndices = array();
+    foreach ($originalIndices as $index) {
+      if ($index['localizable']) {
+        foreach ($locales as $locale) {
+          $localIndex = $index;
+          $localIndex['name'] .= "_" . $locale;
+          $fields = array();
+          foreach ($localIndex['field'] as $field) {
+            $baseField = explode('(', $field);
+            if ($classFields[$baseField[0]]['localizable']) {
+              // field name may have eg (3) at end for prefix length
+              // last_name => last_name_fr_FR
+              // last_name(3) => last_name_fr_FR(3)
+              $fields[] = preg_replace('/^([^(]+)(\(\d+\)|)$/', '${1}_' . $locale . '${2}', $field);
+            }
+            else {
+              $fields[] = $field;
+            }
+          }
+          $localIndex['field'] = $fields;
+          $finalIndices[$localIndex['name']] = $localIndex;
+        }
+      }
+      else {
+        $finalIndices[$index['name']] = $index;
+      }
+    }
+    CRM_Core_BAO_SchemaHandler::addIndexSignature(self::getTableForClass($class), $finalIndices);
+    return $finalIndices;
+  }
+
   /**
    * @return array
    *   Mapping from brief-names to class-names.
index e93c8b1d799697689a17b4d5e511716ac857faba..7503e5a1060f240c01e9ade51847c9037082267a 100644 (file)
@@ -53,4 +53,155 @@ class CRM_Core_DAO_AllCoreTablesTest extends CiviUnitTestCase {
     parent::tearDown();
   }
 
+  /**
+   * Test CRM_Core_DAO_AllCoreTables::indices() function.
+   *
+   * Ensure indices are listed correctly with and without localization
+   */
+  public function testIndices() {
+    // civicrm_group UI_title is localizable
+    // Check indices without localization
+    $indices = CRM_Core_DAO_AllCoreTables::indices(FALSE);
+    $this->assertEquals($indices['civicrm_group']['UI_title']['name'], 'UI_title');
+    $this->assertEquals($indices['civicrm_group']['UI_title']['sig'], 'civicrm_group::1::title');
+
+    // Not sure how we should be setting the locales, but this works for testing purposes
+    $domain = new CRM_Core_DAO_Domain();
+    $domain->find(TRUE);
+    $domain->locales = implode(CRM_Core_DAO::VALUE_SEPARATOR, array('en_UK', 'fr_FR'));
+    $domain->save();
+
+    // Check indices with localization
+    $indices = CRM_Core_DAO_AllCoreTables::indices(TRUE);
+    $this->assertEquals($indices['civicrm_group']['UI_title_en_UK']['name'], 'UI_title_en_UK');
+    $this->assertEquals($indices['civicrm_group']['UI_title_en_UK']['sig'], 'civicrm_group::1::title_en_UK');
+
+    $this->assertEquals($indices['civicrm_group']['UI_title_fr_FR']['name'], 'UI_title_fr_FR');
+    $this->assertEquals($indices['civicrm_group']['UI_title_fr_FR']['sig'], 'civicrm_group::1::title_fr_FR');
+  }
+
+  /**
+   * Check CRM_Core_DAO_AllCoreTables::multilingualize()
+   */
+  public function testMultilingualize() {
+    // in civicrm_group, title is localizable, name is not
+    $originalIndices = array(
+      'test_index1' => array(
+        'name' => 'test_index1',
+        'field' => array(
+          'name',
+        ),
+        'localizable' => 0,
+      ),
+      'test_index2' => array(
+        'name' => 'test_index2',
+        'field' => array(
+          'title',
+        ),
+        'localizable' => 1,
+      ),
+      'test_index3' => array(
+        'name' => 'test_index3',
+        'field' => array(
+          'name(3)',
+        ),
+        'localizable' => 0,
+      ),
+      'test_index4' => array(
+        'name' => 'test_index4',
+        'field' => array(
+          'title(4)',
+        ),
+        'localizable' => 1,
+      ),
+      'test_index5' => array(
+        'name' => 'test_index5',
+        'field' => array(
+          'title(4)',
+          'name(3)',
+        ),
+        'localizable' => 1,
+      ),
+    );
+
+    $expectedIndices = array(
+      'test_index1' => array(
+        'name' => 'test_index1',
+        'field' => array(
+          'name',
+        ),
+        'localizable' => 0,
+        'sig' => 'civicrm_group::0::name',
+      ),
+      'test_index2_en_UK' => array(
+        'name' => 'test_index2_en_UK',
+        'field' => array(
+          'title_en_UK',
+        ),
+        'localizable' => 1,
+        'sig' => 'civicrm_group::0::title_en_UK',
+      ),
+      'test_index2_fr_FR' => array(
+        'name' => 'test_index2_fr_FR',
+        'field' => array(
+          'title_fr_FR',
+        ),
+        'localizable' => 1,
+        'sig' => 'civicrm_group::0::title_fr_FR',
+      ),
+      'test_index3' => array(
+        'name' => 'test_index3',
+        'field' => array(
+          'name(3)',
+        ),
+        'localizable' => 0,
+        'sig' => 'civicrm_group::0::name(3)',
+      ),
+      'test_index4_en_UK' => array(
+        'name' => 'test_index4_en_UK',
+        'field' => array(
+          'title_en_UK(4)',
+        ),
+        'localizable' => 1,
+        'sig' => 'civicrm_group::0::title_en_UK(4)',
+      ),
+      'test_index4_fr_FR' => array(
+        'name' => 'test_index4_fr_FR',
+        'field' => array(
+          'title_fr_FR(4)',
+        ),
+        'localizable' => 1,
+        'sig' => 'civicrm_group::0::title_fr_FR(4)',
+      ),
+      'test_index5_en_UK' => array(
+        'name' => 'test_index5_en_UK',
+        'field' => array(
+          'title_en_UK(4)',
+          'name(3)',
+        ),
+        'localizable' => 1,
+        'sig' => 'civicrm_group::0::title_en_UK(4)::name(3)',
+      ),
+      'test_index5_fr_FR' => array(
+        'name' => 'test_index5_fr_FR',
+        'field' => array(
+          'title_fr_FR(4)',
+          'name(3)',
+        ),
+        'localizable' => 1,
+        'sig' => 'civicrm_group::0::title_fr_FR(4)::name(3)',
+      ),
+    );
+
+    // Not sure how we should be setting the locales, but this works for testing purposes
+    $domain = new CRM_Core_DAO_Domain();
+    $domain->find(TRUE);
+    $domain->locales = implode(CRM_Core_DAO::VALUE_SEPARATOR, array('en_UK', 'fr_FR'));
+    $domain->save();
+
+    // needs a real DAO so use Group
+    $newIndices = CRM_Core_DAO_AllCoreTables::multilingualize('CRM_Contact_DAO_Group', $originalIndices);
+    $this->assertEquals($newIndices, $expectedIndices);
+  }
+
 }
index 22720d039a21ee92190cd68ef17d6e03de0c46a2..4ba882ad1e69bb0d7b99668336052d00ec369ba8 100644 (file)
@@ -263,6 +263,11 @@ class {$table.className} extends CRM_Core_DAO {ldelim}
             return $r;
       {rdelim}
 
+      /**
+       * Returns the list of indices
+       */
+      public static function indices($localize = TRUE) {ldelim}
+        $indices = {$indicesPhp};
+        return ($localize && !empty($indices)) ? CRM_Core_DAO_AllCoreTables::multilingualize(__CLASS__, $indices) : $indices;
+      {rdelim}
 {rdelim}
-
-