Skip to content

Commit

Permalink
additional logging adjustments; add instance setup code
Browse files Browse the repository at this point in the history
  • Loading branch information
lcdservices committed Mar 18, 2012
1 parent 661c33e commit 8b689fa
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 4 deletions.
254 changes: 254 additions & 0 deletions civicrm/custom/php/CRM/Logging/Differ.php
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,254 @@
<?php

/*
+--------------------------------------------------------------------+
| CiviCRM version 4.1 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2011 |
+--------------------------------------------------------------------+
| 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 |
+--------------------------------------------------------------------+
*/

/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2011
* $Id$
*
*/

require_once 'CRM/Contribute/PseudoConstant.php';
require_once 'CRM/Core/PseudoConstant.php';

class CRM_Logging_Differ
{
private $db;
private $log_conn_id;
private $log_date;

function __construct($log_conn_id, $log_date)
{
$dsn = defined('CIVICRM_LOGGING_DSN') ? DB::parseDSN(CIVICRM_LOGGING_DSN) : DB::parseDSN(CIVICRM_DSN);
$this->db = $dsn['database'];
$this->log_conn_id = $log_conn_id;
$this->log_date = $log_date;
}

function diffsInTables($tables)
{
$diffs = array();
foreach ($tables as $table) {
$diff = $this->diffsInTable($table);
if (!empty($diff)) $diffs[$table] = $diff;
}
return $diffs;
}

function diffsInTable($table)
{
$diffs = array();

$params = array(
1 => array($this->log_conn_id, 'Integer'),
2 => array($this->log_date, 'String'),
);

// find ids in this table that were affected in the given connection (based on connection id and a ±10 s time period around the date)
$sql = "SELECT DISTINCT id FROM `{$this->db}`.`log_$table` WHERE log_conn_id = %1 AND log_date BETWEEN DATE_SUB(%2, INTERVAL 10 SECOND) AND DATE_ADD(%2, INTERVAL 10 SECOND)";
$dao = CRM_Core_DAO::executeQuery($sql, $params);
while ($dao->fetch()) {
$diffs = array_merge($diffs, $this->diffsInTableForId($table, $dao->id));
}

return $diffs;
}

private function diffsInTableForId($table, $id)
{
$diffs = array();

$params = array(
1 => array($this->log_conn_id, 'Integer'),
2 => array($this->log_date, 'String'),
3 => array($id, 'Integer'),
);

// look for the last change in the given connection that happended less than 10 seconds later than log_date to the given id to catch multi-query changes
$changedSQL = "SELECT * FROM `{$this->db}`.`log_$table` WHERE log_conn_id = %1 AND log_date < DATE_ADD(%2, INTERVAL 10 SECOND) AND id = %3 ORDER BY log_date DESC LIMIT 1";
$changed = $this->sqlToArray($changedSQL, $params);

// return early if nothing found
if (empty($changed)) return array();

switch ($changed['log_action']) {
case 'Delete':
// the previous state is kept in the current state, current should keep the keys and clear the values
$original = $changed;
foreach ($changed as &$val) $val = null;
$changed['log_action'] = 'Delete';
break;
case 'Insert':
// the previous state does not exist
$original = array();
break;
case 'Update':
// look for the previous state (different log_conn_id) of the given id
$originalSQL = "SELECT * FROM `{$this->db}`.`log_$table` WHERE log_conn_id != %1 AND log_date < %2 AND id = %3 ORDER BY log_date DESC LIMIT 1";
$original = $this->sqlToArray($originalSQL, $params);
break;
}

// populate $diffs with only the differences between $changed and $original
$skipped = array('log_action', 'log_conn_id', 'log_date', 'log_user_id');
foreach (array_keys(array_diff_assoc($changed, $original)) as $diff) {
if (in_array($diff, $skipped)) {
continue;
}

if ( CRM_Utils_Array::value($diff,$original) === CRM_Utils_Array::value($diff,$changed) ) {
continue;
}

$diffs[] = array(
'action' => $changed['log_action'],
'id' => $id,
'field' => $diff,
'from' => CRM_Utils_Array::value($diff,$original),
'to' => CRM_Utils_Array::value($diff,$changed),
);
}

return $diffs;
}

function titlesAndValuesForTable($table)
{
// static caches for subsequent calls with the same $table
static $titles = array();
static $values = array();

// FIXME: split off the table → DAO mapping to a GenCode-generated class
static $daos = array(
'civicrm_address' => 'CRM_Core_DAO_Address',
'civicrm_contact' => 'CRM_Contact_DAO_Contact',
'civicrm_email' => 'CRM_Core_DAO_Email',
'civicrm_im' => 'CRM_Core_DAO_IM',
'civicrm_openid' => 'CRM_Core_DAO_OpenID',
'civicrm_phone' => 'CRM_Core_DAO_Phone',
'civicrm_website' => 'CRM_Core_DAO_Website',
'civicrm_contribution' => 'CRM_Contribute_DAO_Contribution',
);

if (!isset($titles[$table]) or !isset($values[$table])) {

if (in_array($table, array_keys($daos))) {
// FIXME: these should be populated with pseudo constants as they
// were at the time of logging rather than their current values
$values[$table] = array(
'contribution_page_id' => CRM_Contribute_PseudoConstant::contributionPage(),
'contribution_status_id' => CRM_Contribute_PseudoConstant::contributionStatus(),
'contribution_type_id' => CRM_Contribute_PseudoConstant::contributionType(),
'country_id' => CRM_Core_PseudoConstant::country(),
'gender_id' => CRM_Core_PseudoConstant::gender(),
'location_type_id' => CRM_Core_PseudoConstant::locationType(),
'payment_instrument_id' => CRM_Contribute_PseudoConstant::paymentInstrument(),
'phone_type_id' => CRM_Core_PseudoConstant::phoneType(),
'preferred_communication_method' => CRM_Core_PseudoConstant::pcm(),
'preferred_language' => CRM_Core_PseudoConstant::languages(),
'prefix_id' => CRM_Core_PseudoConstant::individualPrefix(),
'provider_id' => CRM_Core_PseudoConstant::IMProvider(),
'state_province_id' => CRM_Core_PseudoConstant::stateProvince(),
'suffix_id' => CRM_Core_PseudoConstant::individualSuffix(),
'website_type_id' => CRM_Core_PseudoConstant::websiteType(),
);

require_once str_replace('_', DIRECTORY_SEPARATOR, $daos[$table]) . '.php';
eval("\$dao = new $daos[$table];");
foreach ($dao->fields() as $field) {
$titles[$table][$field['name']] = CRM_Utils_Array::value('title',$field);

if ($field['type'] == CRM_Utils_Type::T_BOOLEAN) {
$values[$table][$field['name']] = array('0' => ts('false'), '1' => ts('true'));
}
}
} elseif (substr($table, 0, 14) == 'civicrm_value_') {
list($titles[$table], $values[$table]) = $this->titlesAndValuesForCustomDataTable($table);
}
}

return array($titles[$table], $values[$table]);
}

private function sqlToArray($sql, $params)
{
$dao = CRM_Core_DAO::executeQuery($sql, $params);
$dao->fetch();
return $dao->toArray();
}

private function titlesAndValuesForCustomDataTable($table)
{
$titles = array();
$values = array();

$params = array(
1 => array($this->log_conn_id, 'Integer'),
2 => array($this->log_date, 'String'),
3 => array($table, 'String'),
);

$sql = "SELECT id, title FROM `{$this->db}`.log_civicrm_custom_group WHERE log_date <= %2 AND table_name = %3 ORDER BY log_date DESC LIMIT 1";
$cgDao = CRM_Core_DAO::executeQuery($sql, $params);
$cgDao->fetch();

$params[3] = array($cgDao->id, 'Integer');
$sql = "SELECT column_name, data_type, label, name, option_group_id FROM `{$this->db}`.log_civicrm_custom_field WHERE log_date <= %2 AND custom_group_id = %3 ORDER BY log_date";
$cfDao = CRM_Core_DAO::executeQuery($sql, $params);

while ($cfDao->fetch()) {
$titles[$cfDao->column_name] = "{$cgDao->title}: {$cfDao->label}";

switch ($cfDao->data_type) {
case 'Boolean':
$values[$cfDao->column_name] = array('0' => ts('false'), '1' => ts('true'));
break;
case 'String':
$values[$cfDao->column_name] = array();
if ( !empty( $cfDao->option_group_id ) ) {
$params[3] = array($cfDao->option_group_id, 'Integer');
$sql = "
SELECT label, value
FROM `{$this->db}`.log_civicrm_option_value
WHERE log_date <= %2
AND option_group_id = %3
ORDER BY log_date
";
$ovDao = CRM_Core_DAO::executeQuery($sql, $params);
while ($ovDao->fetch()) {
$values[$cfDao->column_name][$ovDao->value] = $ovDao->label;
}
}
break;
}
}

return array($titles, $values);
}
}
12 changes: 9 additions & 3 deletions civicrm/custom/php/CRM/Logging/Schema.php
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -311,9 +311,15 @@ private function deleteReports()
*/ */
public function isEnabled() public function isEnabled()
{ {
//return $this->tablesExist() and $this->triggersExist(); //NYSS alter how logging enabled is determined
$isEnabled = 0;
$config = CRM_Core_Config::singleton(); $config = CRM_Core_Config::singleton();
return $config->logging; if ( $this->tablesExist() &&
$this->triggersExist() &&
$config->logging ) {
$isEnabled = 1;
}
return $isEnabled;
} }


/** /**
Expand All @@ -330,7 +336,7 @@ private function tablesExist()
private function triggersExist() private function triggersExist()
{ {
// FIXME: probably should be a bit more thorough… // FIXME: probably should be a bit more thorough…
return (bool) CRM_Core_DAO::singleValueQuery("SHOW TRIGGERS LIKE 'civicrm_contact'"); return (bool) CRM_Core_DAO::singleValueQuery("SHOW TRIGGERS LIKE 'civicrm_domain'"); //NYSS
} }


//NYSS 5067 //NYSS 5067
Expand Down
3 changes: 3 additions & 0 deletions scripts/copyInstance.sh
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -112,4 +112,7 @@ echo "Loading Drupal database for instance $destinst with data from $temp_drup_f
$execSql --create -i $destinst --drupal || die 4 $execSql --create -i $destinst --drupal || die 4
$execSql -f $temp_drup_file -i $destinst --drupal || die 5 $execSql -f $temp_drup_file -i $destinst --drupal || die 5


echo "Creating Log database for instance $destinst"
$execSql --create -i $destinst --log || die 6

die 0 die 0
9 changes: 9 additions & 0 deletions scripts/deleteInstance.sh
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ fi
[ "$domain" ] || domain=`$readConfig --ig $instance base.domain` || domain="$DEFAULT_BASE_DOMAIN" [ "$domain" ] || domain=`$readConfig --ig $instance base.domain` || domain="$DEFAULT_BASE_DOMAIN"
db_civi_prefix=`$readConfig --ig $instance db.civicrm.prefix` || db_civi_prefix="$DEFAULT_DB_CIVICRM_PREFIX" db_civi_prefix=`$readConfig --ig $instance db.civicrm.prefix` || db_civi_prefix="$DEFAULT_DB_CIVICRM_PREFIX"
db_drup_prefix=`$readConfig --ig $instance db.drupal.prefix` || db_drup_prefix="$DEFAULT_DB_DRUPAL_PREFIX" db_drup_prefix=`$readConfig --ig $instance db.drupal.prefix` || db_drup_prefix="$DEFAULT_DB_DRUPAL_PREFIX"
db_log_prefix=`$readConfig --ig $instance db.log.prefix` || db_log_prefix="$DEFAULT_DB_LOG_PREFIX"
db_basename=`$readConfig --ig $instance db.basename` || db_basename="$instance" db_basename=`$readConfig --ig $instance db.basename` || db_basename="$instance"
drupal_rootdir=`$readConfig --ig $instance drupal.rootdir` || drupal_rootdir="$DEFAULT_DRUPAL_ROOTDIR" drupal_rootdir=`$readConfig --ig $instance drupal.rootdir` || drupal_rootdir="$DEFAULT_DRUPAL_ROOTDIR"
data_rootdir=`$readConfig --ig $instance data.rootdir` || data_rootdir="$DEFAULT_DATA_ROOTDIR" data_rootdir=`$readConfig --ig $instance data.rootdir` || data_rootdir="$DEFAULT_DATA_ROOTDIR"
Expand All @@ -63,6 +64,7 @@ if [ $force_ok -eq 0 ]; then
echo "Domain: $domain" echo "Domain: $domain"
echo "CiviCRM DB Prefix: $db_civi_prefix" echo "CiviCRM DB Prefix: $db_civi_prefix"
echo "Drupal DB Prefix: $db_drup_prefix" echo "Drupal DB Prefix: $db_drup_prefix"
echo "Log DB Prefix: $db_log_prefix"
echo "Drupal Root Directory: $drupal_rootdir" echo "Drupal Root Directory: $drupal_rootdir"
echo "Data Root Directory: $data_rootdir" echo "Data Root Directory: $data_rootdir"
if [ $db_only -ne 1 ]; then if [ $db_only -ne 1 ]; then
Expand All @@ -72,6 +74,7 @@ if [ $force_ok -eq 0 ]; then
if [ $files_only -ne 1 ]; then if [ $files_only -ne 1 ]; then
echo "Will delete DB: $db_drup_prefix$db_basename" echo "Will delete DB: $db_drup_prefix$db_basename"
echo "Will delete DB: $db_civi_prefix$db_basename" echo "Will delete DB: $db_civi_prefix$db_basename"
echo "Will delete DB: $db_log_prefix$db_basename"
fi fi
echo echo
echo -n "Are you sure that you want to delete instance $instance ([N]/y)? " echo -n "Are you sure that you want to delete instance $instance ([N]/y)? "
Expand Down Expand Up @@ -101,6 +104,12 @@ if [ $files_only -ne 1 ]; then
$execSql -c "drop database $db_civi_prefix$db_basename" $execSql -c "drop database $db_civi_prefix$db_basename"
) || errcode=$(($errcode | 4)) ) || errcode=$(($errcode | 4))
set +x set +x

echo "Deleting Log database for instance [$instance]"
( set -x
$execSql -c "drop database $db_log_prefix$db_basename"
) || errcode=$(($errcode | 4))
set +x
fi fi


exit $errcode exit $errcode
3 changes: 2 additions & 1 deletion scripts/execSql.sh
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ readConfig=$script_dir/readConfig.sh
. $script_dir/defaults.sh . $script_dir/defaults.sh


usage() { usage() {
echo "Usage: $prog [-f sqlFile | -c sqlCommand] [-d] [-t table] [-i instance] [-h host] [-u user] [-p password] [--column-names] [--quiet|-q] [--create] [--drupal] [dbName]" >&2 echo "Usage: $prog [-f sqlFile | -c sqlCommand] [-d] [-t table] [-i instance] [-h host] [-u user] [-p password] [--column-names] [--quiet|-q] [--create] [--drupal] [--log] [dbName]" >&2
} }


if [ $# -lt 1 ]; then if [ $# -lt 1 ]; then
Expand Down Expand Up @@ -53,6 +53,7 @@ while [ $# -gt 0 ]; do
--col*) colname_arg="--column-names" ;; --col*) colname_arg="--column-names" ;;
--create) create_db=1 ;; --create) create_db=1 ;;
--drupal) db_prefix_keyname=db.drupal.prefix; default_db_prefix="$DEFAULT_DB_DRUPAL_PREFIX" ;; --drupal) db_prefix_keyname=db.drupal.prefix; default_db_prefix="$DEFAULT_DB_DRUPAL_PREFIX" ;;
--log) db_prefix_keyname=db.log.prefix; default_db_prefix="$DEFAULT_DB_LOG_PREFIX" ;;
-*) echo "$prog: $1: Invalid option" >&2; exit 1 ;; -*) echo "$prog: $1: Invalid option" >&2; exit 1 ;;
*) dbname="$1" ;; *) dbname="$1" ;;
esac esac
Expand Down

0 comments on commit 8b689fa

Please sign in to comment.