Merge pull request #3614 from eileenmcnaughton/CRM-14951
[civicrm-core.git] / CRM / Logging / Schema.php
index 877be2dad162fafbe664af121c99e4476aee7881..d733c8446781fb29ef9c1973d6c54cc8bcf77ee4 100644 (file)
@@ -1,9 +1,9 @@
 <?php
 /*
  +--------------------------------------------------------------------+
- | CiviCRM version 4.4                                                |
+ | CiviCRM version 4.5                                                |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2013                                |
+ | Copyright CiviCRM LLC (c) 2004-2014                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
@@ -28,7 +28,7 @@
 /**
  *
  * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2013
+ * @copyright CiviCRM LLC (c) 2004-2014
  * $Id$
  *
  */
@@ -70,13 +70,14 @@ AND    TABLE_NAME LIKE 'civicrm_%'
       $this->tables[] = $dao->TABLE_NAME;
     }
 
-    // do not log temp import, cache and log tables
+    // do not log temp import, cache, menu and log tables
     $this->tables = preg_grep('/^civicrm_import_job_/', $this->tables, PREG_GREP_INVERT);
     $this->tables = preg_grep('/_cache$/', $this->tables, PREG_GREP_INVERT);
     $this->tables = preg_grep('/_log/', $this->tables, PREG_GREP_INVERT);
     $this->tables = preg_grep('/^civicrm_task_action_temp_/', $this->tables, PREG_GREP_INVERT);
     $this->tables = preg_grep('/^civicrm_export_temp_/', $this->tables, PREG_GREP_INVERT);
     $this->tables = preg_grep('/^civicrm_queue_/', $this->tables, PREG_GREP_INVERT);
+    $this->tables = preg_grep('/^civicrm_menu/', $this->tables, PREG_GREP_INVERT); //CRM-14672
 
     // do not log civicrm_mailing_event* tables, CRM-12300
     $this->tables = preg_grep('/^civicrm_mailing_event_/', $this->tables, PREG_GREP_INVERT);
@@ -207,7 +208,7 @@ AND    TABLE_NAME LIKE 'log_civicrm_%'
       $this->fixSchemaDifferencesForALL();
     }
     // invoke the meta trigger creation call
-    CRM_Core_DAO::triggerRebuild();
+    CRM_Core_DAO::triggerRebuild(NULL, TRUE);
   }
 
   /**
@@ -245,7 +246,7 @@ AND    TABLE_NAME LIKE 'log_civicrm_%'
 
     // for any obsolete columns (not null) we just make the column nullable.
     if (!empty($cols['OBSOLETE'])) {
-      $create = $this->_getCreateQuery("log_{$table}");
+      $create = $this->_getCreateQuery("`{$this->db}`.log_{$table}");
       foreach ($cols['OBSOLETE'] as $col) {
         $line = $this->_getColumnQuery($col, $create);
         // This is just going to make a not null column to nullable
@@ -260,6 +261,11 @@ AND    TABLE_NAME LIKE 'log_civicrm_%'
     return TRUE;
   }
 
+  /**
+   * @param $table
+   *
+   * @return array
+   */
   private function _getCreateQuery($table) {
     $dao = CRM_Core_DAO::executeQuery("SHOW CREATE TABLE {$table}");
     $dao->fetch();
@@ -267,6 +273,12 @@ AND    TABLE_NAME LIKE 'log_civicrm_%'
     return $create;
   }
 
+  /**
+   * @param $col
+   * @param $createQuery
+   *
+   * @return array|mixed|string
+   */
   private function _getColumnQuery($col, $createQuery) {
     $line = preg_grep("/^  `$col` /", $createQuery);
     $line = rtrim(array_pop($line), ',');
@@ -275,12 +287,16 @@ AND    TABLE_NAME LIKE 'log_civicrm_%'
     return $line;
   }
 
+  /**
+   * @param bool $rebuildTrigger
+   */
   function fixSchemaDifferencesForAll($rebuildTrigger = FALSE) {
     $diffs = array();
     foreach ($this->tables as $table) {
       if (empty($this->logs[$table])) {
         $this->createLogTableFor($table);
-      } else {
+      }
+      else {
         $diffs[$table] = $this->columnsWithDiffSpecs($table, "log_$table");
       }
     }
@@ -300,6 +316,11 @@ AND    TABLE_NAME LIKE 'log_civicrm_%'
    * so there's no need for a default timestamp and therefore we remove such default timestamps
    * also eliminate the NOT NULL constraint, since we always copy and schema can change down the road)
    */
+  /**
+   * @param $query
+   *
+   * @return mixed
+   */
   function fixTimeStampAndNotNullSQL($query) {
     $query = str_ireplace("TIMESTAMP NOT NULL", "TIMESTAMP NULL", $query);
     $query = str_ireplace("DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP", '', $query);
@@ -339,15 +360,14 @@ AND    TABLE_NAME LIKE 'log_civicrm_%'
   /**
    * Get an array of column names of the given table.
    */
-  private function columnsOf($table) {
+  private function columnsOf($table, $force = FALSE) {
     static $columnsOf = array();
 
     $from = (substr($table, 0, 4) == 'log_') ? "`{$this->db}`.$table" : $table;
 
-    if (!isset($columnsOf[$table])) {
-      CRM_Core_Error::ignoreException();
+    if (!isset($columnsOf[$table]) || $force) {
+      $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
       $dao = CRM_Core_DAO::executeQuery("SHOW COLUMNS FROM $from");
-      CRM_Core_Error::setCallback();
       if (is_a($dao, 'DB_Error')) {
         return array();
       }
@@ -371,7 +391,7 @@ AND    TABLE_NAME LIKE 'log_civicrm_%'
         $dao = new CRM_Contact_DAO_Contact();
         $civiDB = $dao->_database;
       }
-      CRM_Core_Error::ignoreException();
+      $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
       // NOTE: W.r.t Performance using one query to find all details and storing in static array is much faster
       // than firing query for every given table.
       $query = "
@@ -379,7 +399,6 @@ SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEF
 FROM   INFORMATION_SCHEMA.COLUMNS
 WHERE  table_schema IN ('{$this->db}', '{$civiDB}')";
       $dao = CRM_Core_DAO::executeQuery($query);
-      CRM_Core_Error::setCallback();
       if (is_a($dao, 'DB_Error')) {
         return array();
       }
@@ -399,6 +418,12 @@ WHERE  table_schema IN ('{$this->db}', '{$civiDB}')";
     return $columnSpecs[$table];
   }
 
+  /**
+   * @param $civiTable
+   * @param $logTable
+   *
+   * @return array
+   */
   function columnsWithDiffSpecs($civiTable, $logTable) {
     $civiTableSpecs = $this->columnSpecsOf($civiTable);
     $logTableSpecs  = $this->columnSpecsOf($logTable);
@@ -412,17 +437,21 @@ WHERE  table_schema IN ('{$this->db}', '{$civiDB}')";
     // NOTE: we consider only those columns for modifications where there is a spec change, and that the column definition
     // wasn't deliberately modified by fixTimeStampAndNotNullSQL() method.
     foreach ($civiTableSpecs as $col => $colSpecs) {
+      if (!isset($logTableSpecs[$col]) || !is_array($logTableSpecs[$col]) ) {
+        $logTableSpecs[$col] = array();
+      }
+
       $specDiff = array_diff($civiTableSpecs[$col], $logTableSpecs[$col]);
       if (!empty($specDiff) && $col != 'id' && !array_key_exists($col, $diff['ADD'])) {
         // ignore 'id' column for any spec changes, to avoid any auto-increment mysql errors
-        if ($civiTableSpecs[$col]['DATA_TYPE'] != $logTableSpecs[$col]['DATA_TYPE']) {
+        if ($civiTableSpecs[$col]['DATA_TYPE'] != CRM_Utils_Array::value('DATA_TYPE', $logTableSpecs[$col])) {
           // if data-type is different, surely consider the column
           $diff['MODIFY'][] = $col;
-        } else if ($civiTableSpecs[$col]['IS_NULLABLE'] != $logTableSpecs[$col]['IS_NULLABLE'] &&
+        } else if ($civiTableSpecs[$col]['IS_NULLABLE'] != CRM_Utils_Array::value('IS_NULLABLE', $logTableSpecs[$col]) &&
           $logTableSpecs[$col]['IS_NULLABLE'] == 'NO') {
           // if is-null property is different, and log table's column is NOT-NULL, surely consider the column
           $diff['MODIFY'][] = $col;
-        } else if ($civiTableSpecs[$col]['COLUMN_DEFAULT'] != $logTableSpecs[$col]['COLUMN_DEFAULT'] &&
+        } else if ($civiTableSpecs[$col]['COLUMN_DEFAULT'] != CRM_Utils_Array::value('COLUMN_DEFAULT', $logTableSpecs[$col]) &&
           !strstr($civiTableSpecs[$col]['COLUMN_DEFAULT'], 'TIMESTAMP')) {
           // if default property is different, and its not about a timestamp column, consider it
           $diff['MODIFY'][] = $col;
@@ -530,7 +559,12 @@ COLS;
     return (bool) CRM_Core_DAO::singleValueQuery("SHOW TRIGGERS LIKE 'civicrm_contact'");
   }
 
-  function triggerInfo(&$info, $tableName = NULL) {
+  /**
+   * @param $info
+   * @param null $tableName
+   * @param bool $force
+   */
+  function triggerInfo(&$info, $tableName = NULL, $force = FALSE) {
     // check if we have logging enabled
     $config =& CRM_Core_Config::singleton();
     if (!$config->logging) {
@@ -550,7 +584,7 @@ COLS;
 
     // logging is enabled, so now lets create the trigger info tables
     foreach ($tableNames as $table) {
-      $columns = $this->columnsOf($table);
+      $columns = $this->columnsOf($table, $force);
 
       // only do the change if any data has changed
       $cond = array( );