function handle(&$params) { $app =& Dataface_Application::getInstance(); $record =& $app->getRecord(); $context = array(); if (!$record) { return PEAR::raiseError("No record is currently selected", DATAFACE_E_ERROR); } $history_tablename = $record->_table->tablename . '__history'; if (!Dataface_Table::tableExists($history_tablename)) { $context['error'] = PEAR::raiseError("This record has no history yet recorded.", DATAFACE_E_NOTICE); } else { import('Dataface/HistoryTool.php'); $history_tool = new Dataface_HistoryTool(); $history_log = $history_tool->getHistoryLog($record); $context['log'] =& $history_log; // let's make a query string for the current record //current_record_qstr $keys = array_keys($record->_table->keys()); $qstr = array(); foreach ($keys as $key) { $qstr[] = urlencode('--__keys__[' . $key . ']') . '=' . urlencode($record->strval($key)); } $context['current_record_qstr'] = implode('&', $qstr); } df_display($context, 'Dataface_RecordHistory.html'); }
function handle(&$params) { if (!@$_POST['history__id']) { return PEAR::raiseError("No history id specified", DATAFACE_E_ERROR); } $historyid = $_POST['history__id']; if (!preg_match('/\\d+/', $historyid)) { return PEAR::raiseError("Invalid history id provided.", DATAFACE_E_ERROR); } $app =& Dataface_Application::getInstance(); $record =& $app->getRecord(); if (!$record) { return PEAR::raiseError("No record was specified", DATAFACE_E_ERROR); } import("Dataface/HistoryTool.php"); $ht = new Dataface_HistoryTool(); $hrecord = $ht->getRecordById($record->_table->tablename, $historyid); // make sure that this history record matches the current record. $keys = array_keys($record->_table->keys()); if ($record->strvals($keys) != $hrecord->strvals($keys)) { return PEAR::raiseError("Attempt to restore record history from unmatching history record.", DATAFACE_E_ERROR); } // Now that we are convinced that we have the correct record, we can restore it. if (@$_POST['-fieldname']) { $fieldname = $_POST['-fieldname']; } else { $fieldname = null; } $res = $ht->restore($record, $historyid, $fieldname, true); if (PEAR::isError($res)) { return $res; } $url = false; //$app->getPreviousUrl(true); if (@$_POST['-locationid']) { $url = DATAFACE_SITE_HREF . '?' . $app->decodeLocation($_POST['-locationid']); } if (!$url) { // If the url is not specified we will just create a url to return // to the specified record's history listing. $url = $record->getURL('-action=history'); } if ($fieldname) { $msg = "Field '{$fieldname}' successfully restored to its value from '" . $hrecord->strval('history__modified') . "'."; } else { $msg = "Record successfully restored to its value from '" . $hrecord->strval('history__modified') . "'."; } $url .= "&--msg=" . urlencode($msg); header('Location: ' . $url); exit; }
function handle(&$params) { $app =& Dataface_Application::getInstance(); if (!@$_GET['history__id']) { return PEAR::raiseError('No history id supplied', DATAFACE_E_ERROR); } $historyid = $_GET['history__id']; $query =& $app->getQuery(); $table = $query['-table']; import('Dataface/HistoryTool.php'); $ht = new Dataface_HistoryTool(); if (@$_GET['-show_changes']) { $record = $ht->getDiffs($table, $historyid); } else { $record = $ht->getRecordById($table, $historyid); } if (!$record) { return PEAR::raiseError("No history record for table {$table} with history id {$historyid} could be found", DATAFACE_E_ERROR); } if (PEAR::isError($record)) { return $record; } $context = array('history_record' => &$record); $context['table_record'] = new Dataface_Record($table, $record->vals()); $t =& Dataface_Table::loadTable($table); $numfields = count($t->fields()); $pts = 0; $ppf = array(); foreach ($t->fields() as $field) { if ($t->isText($field['name'])) { $pts += 5; $ppf[$field['name']] = $pts; } else { $pts++; $ppf[$field['name']] = $pts; } } $firstField = null; $threshold = floatval(floatval($pts) / floatval(2)); foreach ($t->fields() as $field) { if ($ppf[$field['name']] >= $threshold) { $firstField = $field['name']; break; } } $context['first_field_second_col'] = $firstField; $context['changes'] = @$_GET['-show_changes']; $context['table'] =& $t; df_display($context, 'Dataface_HistoryRecordDetails.html'); }
/** * Writes the values in the table to the database. * * @param tablename An optional tablename in case this record is not being placed in * the standard table. For example, the record could be placed into an import * table. * @param array $keys Optional array of keys to look up record to write to. * @param string $tablename The name of the table to write to, if not this table. * This is useful for writing to import tables or other * tables with identical schema. * @param boolean $secure Whether to check permissions or not. */ function write(&$record, $keys = null, $tablename = null, $secure = false) { // The vetoSecurity flag allows us to make changes to a record without // the fields being filtered for security checks when they are saved. // Since we may want to change or add values to a record in the // beforeSave type triggers, and we probably don't want these changes // checked by security, we should use this flag to make all changes // in these triggers immune to security checks. // We return the veto setting to its former state after this method // finishes. //$oldVeto = $record->vetoSecurity; //$record->vetoSecurity = true; //$parentRecord =& $record->getParentRecord(); $app =& Dataface_Application::getInstance(); //$parentIO =& $this->getParentIO(); if (!is_a($record, "Dataface_Record")) { trigger_error(df_translate('scripts.Dataface.IO.write.ERROR_PARAMETER_1', "Dataface_IO::write() requires first parameter to be of type 'Dataface_Record' but received '" . get_class($record) . "\n<br>", array('class' => get_class($record))) . Dataface_Error::printStackTrace(), E_USER_ERROR); } if ($tablename === null and $this->_altTablename !== null) { $tablename = $this->_altTablename; } if ($this->fireTriggers) { $res = $this->fireBeforeSave($record); if (PEAR::isError($res)) { //$record->vetoSecurity = $oldVeto; return $res; } } if ($this->recordExists($record, $keys, $this->tablename($tablename))) { $res = $this->_update($record, $keys, $this->tablename($tablename), $secure); } else { $res = $this->_insert($record, $this->tablename($tablename), $secure); } if (PEAR::isError($res)) { if (Dataface_Error::isDuplicateEntry($res)) { /* * Duplicate entries we will propogate up so that the application can decide what to do. */ //$record->vetoSecurity = $oldVeto; return $res; } $res->addUserInfo(df_translate('scripts.Dataface.IO.write.ERROR_SAVING', "Error while saving record of table '" . $this->_table->tablename . "' in Dataface_IO::write() on line " . __LINE__ . " of file " . __FILE__, array('tablename' => $this->_table->tablename, 'line' => __LINE__, 'file' => __FILE__))); //$record->vetoSecurity = $oldVeto; return $res; } // Now we take care of the transient relationship fields. // Transient relationship fields aren't actually stored in the record // itself, they are stored as related records. foreach ($record->_table->transientFields() as $tfield) { if (!isset($tfield['relationship'])) { continue; } if (!$record->valueChanged($tfield['name'])) { continue; } $trelationship =& $record->_table->getRelationship($tfield['relationship']); if (!$trelationship or PEAR::isError($trelationship)) { // We couldn't find the specified relationship. //$record->vetoSecurity = $oldVeto; return $trelationship; } $orderCol = $trelationship->getOrderColumn(); if (PEAR::isError($orderCol)) { $orderCol = null; } $tval = $record->getValue($tfield['name']); if ($tfield['widget']['type'] == 'grid') { //echo "here";exit; $tval_existing = array(); $tval_new = array(); $tval_new_existing = array(); $torder = 0; foreach ($tval as $trow) { $trow['__order__'] = $torder++; if (isset($trow['__id__']) and preg_match('/^new:/', $trow['__id__'])) { $tval_new_existing[] = $trow; } else { if (isset($trow['__id__']) and $trow['__id__'] != 'new') { $tval_existing[$trow['__id__']] = $trow; } else { if (isset($trow['__id__']) and $trow['__id__'] == 'new') { $tval_new[] = $trow; } } } } // The transient field was loaded so we can go about saving the // changes/ $trecords =& $record->getRelatedRecordObjects($tfield['relationship'], 'all'); if (!is_array($trecords) or PEAR::isError($trecords)) { error_log('Failed to get related records for record ' . $record->getId() . ' in its relationship ' . $tfield['relationship']); unset($tval); unset($orderCol); unset($tval_new); unset($torder); unset($trelationship); unset($tval_existing); continue; } // Update the existing records in the relationship. // We use the __id__ parameter in each row for this. //echo "About to save related records"; foreach ($trecords as $trec) { $tid = $trec->getId(); if (isset($tval_existing[$tid])) { $tmp = new Dataface_RelatedRecord($trec->_record, $tfield['relationship'], $trec->getValues()); $tmp->setValues($tval_existing[$tid]); $changed = false; foreach ($tval_existing[$tid] as $k1 => $v1) { if ($tmp->isDirty($k1)) { $changed = true; break; } } if ($changed) { $trec->setValues($tval_existing[$tid]); if ($orderCol) { $trec->setValue($orderCol, $tval_existing[$tid]['__order__']); } //echo "Saving ";print_r($trec->vals()); $res_t = $trec->save($this->lang, $secure); if (PEAR::isError($res_t)) { return $res_t; error_log('Failed to save related record ' . $trec->getId() . ' while saving transient field ' . $tfield['name'] . ' in record ' . $record->getId() . '. The error returned was : ' . $res_t->getMessage()); } } else { if ($orderCol and $record->checkPermission('reorder_related_records', array('relationship' => $tfield['relationship']))) { $trec->setValue($orderCol, $tval_existing[$tid]['__order__']); $res_t = $trec->save($this->lang, false); // we don't need this to be secure if (PEAR::isError($res_t)) { return $res_t; error_log('Failed to save related record ' . $trec->getId() . ' while saving transient field ' . $tfield['name'] . ' in record ' . $record->getId() . '. The error returned was : ' . $res_t->getMessage()); } } } unset($tmp); } else { } unset($trec); unset($tid); unset($res_t); } //exit; // Now add new records (specified by __id__ field being 'new' foreach ($tval_new as $tval_to_add) { $temp_rrecord = new Dataface_RelatedRecord($record, $tfield['relationship'], array()); $temp_rrecord->setValues($tval_to_add); if ($orderCol) { $temp_rrecord->setValue($orderCol, $tval_to_add['__order__']); } $res_t = $this->addRelatedRecord($temp_rrecord, $secure); if (PEAR::isError($res_t)) { error_log('Failed to save related record ' . $temp_rrecord->getId() . ' while saving transient field ' . $tfield['name'] . ' in record ' . $record->getId() . '. The error returned was : ' . $res_t->getMessage()); } unset($temp_rrecord); unset($res_t); } // Now add new existing records (specified by __id__ field being 'new:<recordid>' foreach ($tval_new_existing as $tval_to_add) { $tid = preg_replace('/^new:/', '', $tval_to_add['__id__']); $temp_record = df_get_record_by_id($tid); if (PEAR::isError($temp_record)) { return $temp_record; } if (!$temp_record) { return PEAR::raiseError("Failed to load existing record with ID {$tid}."); } $temp_rrecord = new Dataface_RelatedRecord($record, $tfield['relationship'], $temp_record->vals()); $temp_rrecord->setValues($tval_to_add); if ($orderCol) { $temp_rrecord->setValue($orderCol, $tval_to_add['__order__']); } $res_t = $this->addExistingRelatedRecord($temp_rrecord, $secure); if (PEAR::isError($res_t)) { error_log('Failed to save related record ' . $temp_rrecord->getId() . ' while saving transient field ' . $tfield['name'] . ' in record ' . $record->getId() . '. The error returned was : ' . $res_t->getMessage()); } unset($temp_rrecord); unset($res_t); } // Now we delete the records that were deleted // we use the __deleted__ field. if (isset($tval['__deleted__']) and is_array($tval['__deleted__']) and $trelationship->supportsRemove()) { $tdelete_record = $trelationship->isOneToMany(); foreach ($tval['__deleted__'] as $del_id) { if ($del_id == 'new') { continue; } $drec = Dataface_IO::getByID($del_id); if (PEAR::isError($drec) or !$drec) { unset($drec); continue; } $this->removeRelatedRecord($drec, $tdelete_record, $secure); unset($drec); } } unset($trecords); } else { if ($tfield['widget']['type'] == 'checkbox') { // Load existing records in the relationship $texisting =& $record->getRelatedRecordObjects($tfield['relationship'], 'all'); if (!is_array($texisting) or PEAR::isError($texisting)) { error_log('Failed to get related records for record ' . $record->getId() . ' in its relationship ' . $tfield['relationship']); unset($tval); unset($orderCol); unset($tval_new); unset($torder); unset($trelationship); unset($tval_existing); continue; } $texistingIds = array(); foreach ($texisting as $terec) { $texistingIds[] = $terec->getId(); } // Load currently checked records $tchecked = array(); $tcheckedRecords = array(); $tcheckedIds = array(); $tcheckedId2ValsMap = array(); foreach ($tval as $trkey => $trval) { // $trval is in the form key1=val1&size=key2=val2 parse_str($trval, $trquery); $trRecord = new Dataface_RelatedRecord($record, $tfield['relationship'], $trquery); $trRecords[] =& $trRecord; $tcheckedIds[] = $tid = $trRecord->getId(); $checkedId2ValsMap[$tid] = $trquery; unset($trRecord); unset($trquery); } // Now we have existing ids in $texistingIds // and checked ids in $tcheckedIds // See which records we need to have removed $tremoves = array_diff($texistingIds, $tcheckedIds); $tadds = array_diff($tcheckedIds, $texistingIds); foreach ($tremoves as $tid) { $trec = df_get_record_by_id($tid); $res = $this->removeRelatedRecord($trec, false, $secure); if (PEAR::isError($res)) { return $res; } unset($trec); } foreach ($tadds as $tid) { $trecvals = $checkedId2ValsMap[$tid]; $trec = new Dataface_RelatedRecord($record, $tfield['relationship'], $trecvals); $res = $this->addExistingRelatedRecord($trec, $secure); if (PEAR::isError($res)) { return $res; } unset($trec, $trecvals); } unset($tadds); unset($tremoves); unset($tcheckedIds, $tcheckedId2ValsMap); unset($tcheckedRecords); unset($tchecked); unset($texistingIds); unset($texisting); } } unset($tval); unset($trelationship); } if ($this->fireTriggers) { $res2 = $this->fireAfterSave($record); if (PEAR::isError($res2)) { //$record->vetoSecurity = $oldVeto; return $res2; } } if (isset($app->_conf['history']) and @$app->_conf['history']['enabled'] || !isset($app->_conf['history']['enabled'])) { // History is enabled ... let's save this record in our history. import('Dataface/HistoryTool.php'); $historyTool = new Dataface_HistoryTool(); $historyTool->logRecord($record, $this->getHistoryComments($record), $this->lang); } if (isset($app->_conf['_index']) and @$app->_conf['_index'][$record->table()->tablename]) { // If indexing is enabled, we index the record so that it is // searchable by natural language searching. // The Dataface_Index class takes care of whether or not this // record should be indexed. import('Dataface/Index.php'); $index = new Dataface_Index(); $index->indexRecord($record); } // It seems to me that we should be setting a new snapshot at this point. //$record->clearSnapshot(); $record->setSnapshot(); self::touchTable($this->_table->tablename); //$record->vetoSecurity = $oldVeto; return $res; }
/** * Returns the changes for a given record in a particular language, since * a given version number. * @param Dataface_Record &$record The record we are interested in. * @param string $language 2-digit language code * @param float $version <major_version>.<minor_version> * @param string $fieldname Optional field name to get changes for. * @returns mixed Either a Dataface_Record object with the changes, or * a string with the changes for $fieldname. * */ function getChanges(&$record, $version, $lang = null, $fieldname = null) { $app = Dataface_Application::getInstance(); if (!isset($lang)) { $lang = $app->_conf['lang']; } list($major_version, $minor_version) = explode('.', $version); $trecord = $this->getTranslationRecord($record, $lang); import('Dataface/HistoryTool.php'); $ht = new Dataface_HistoryTool(); $hrecord = $ht->searchArchives($trecord, array('major_version' => $major_version, 'minor_version' => $minor_version), $lang); $modified = $hrecord->strval('history__modified'); return $ht->getDiffsByDate($record, $modified, null, $lang, $fieldname); }
/** * Writes the values in the table to the database. * * @param tablename An optional tablename in case this record is not being placed in * the standard table. For example, the record could be placed into an import * table. * @param array $keys Optional array of keys to look up record to write to. * @param string $tablename The name of the table to write to, if not this table. * This is useful for writing to import tables or other * tables with identical schema. * @param boolean $secure Whether to check permissions or not. * @param boolean $forceNew If true, it forces an insert rather than an update. */ function write(&$record, $keys = null, $tablename = null, $secure = false, $forceNew = false) { // The vetoSecurity flag allows us to make changes to a record without // the fields being filtered for security checks when they are saved. // Since we may want to change or add values to a record in the // beforeSave type triggers, and we probably don't want these changes // checked by security, we should use this flag to make all changes // in these triggers immune to security checks. // We return the veto setting to its former state after this method // finishes. //$oldVeto = $record->vetoSecurity; //$record->vetoSecurity = true; //$parentRecord =& $record->getParentRecord(); $app =& Dataface_Application::getInstance(); //$parentIO =& $this->getParentIO(); if (!is_a($record, "Dataface_Record")) { throw new Exception(df_translate('scripts.Dataface.IO.write.ERROR_PARAMETER_1', "Dataface_IO::write() requires first parameter to be of type 'Dataface_Record' but received '" . get_class($record) . "\n<br>", array('class' => get_class($record))), E_USER_ERROR); } if ($tablename === null and $this->_altTablename !== null) { $tablename = $this->_altTablename; } if ($this->fireTriggers) { $res = $this->fireBeforeSave($record); if (PEAR::isError($res)) { //$record->vetoSecurity = $oldVeto; return $res; } } if (!$forceNew and $this->recordExists($record, $keys, $this->tablename($tablename))) { $res = $this->_update($record, $keys, $this->tablename($tablename), $secure); } else { $res = $this->_insert($record, $this->tablename($tablename), $secure); } if (PEAR::isError($res)) { if (Dataface_Error::isDuplicateEntry($res)) { /* * Duplicate entries we will propogate up so that the application can decide what to do. */ //$record->vetoSecurity = $oldVeto; return $res; } $res->addUserInfo(df_translate('scripts.Dataface.IO.write.ERROR_SAVING', "Error while saving record of table '" . $this->_table->tablename . "' in Dataface_IO::write() ", array('tablename' => $this->_table->tablename, 'line' => 0, 'file' => '_'))); //$record->vetoSecurity = $oldVeto; return $res; } $res = $this->saveTransients($record, $keys, $tablename, $secure); if (PEAR::isError($res)) { return $res; } if ($this->fireTriggers) { $res2 = $this->fireAfterSave($record); if (PEAR::isError($res2)) { //$record->vetoSecurity = $oldVeto; return $res2; } } if (isset($app->_conf['history']) and @$app->_conf['history']['enabled'] || !isset($app->_conf['history']['enabled'])) { // History is enabled ... let's save this record in our history. import('Dataface/HistoryTool.php'); $historyTool = new Dataface_HistoryTool(); $historyTool->logRecord($record, $this->getHistoryComments($record), $this->lang); } if (isset($app->_conf['_index']) and @$app->_conf['_index'][$record->table()->tablename]) { // If indexing is enabled, we index the record so that it is // searchable by natural language searching. // The Dataface_Index class takes care of whether or not this // record should be indexed. import('Dataface/Index.php'); $index = new Dataface_Index(); $index->indexRecord($record); } // It seems to me that we should be setting a new snapshot at this point. //$record->clearSnapshot(); $record->setSnapshot(); self::touchTable($this->_table->tablename); self::touchRecord($record); //$record->vetoSecurity = $oldVeto; return $res; }
function test_restore_to_date() { $app =& Dataface_Application::getInstance(); $record = df_get_record('HistoryToolTest', array('name' => 'Johnny')); $this->assertEquals('john.gif', $record->val('container_field')); $record->setValue('container_field', 'john2.gif'); $record->save(); $ht = new Dataface_HistoryTool(); $hid = $ht->logRecord($record); $history1 = $ht->getRecordById('HistoryToolTest', $hid); $this->assertEquals(array('name' => 'Johnny', 'container_field' => 'john2.gif'), $history1->strvals(array('name', 'container_field'))); $record->setValue('container_field', 'john3.gif'); $record->save(); $hid2 = $ht->logRecord($record); $history2 = $ht->getRecordById('HistoryToolTest', $hid2); $this->assertEquals(array('name' => 'Johnny', 'container_field' => 'john3.gif'), $history2->strvals(array('name', 'container_field'))); $record2 = df_get_record('HistoryToolTest', array('name' => 'Johnny')); $this->assertEquals($record2->strvals(array('name', 'container_field')), $history2->strvals(array('name', 'container_field'))); $sql = array(); $sql[] = "update `HistoryToolTest__history` set `history__modified` = '2004-01-02' where `history__id` = '{$hid}'"; foreach ($sql as $q) { $res = xf_db_query($q, $app->db()); if (!$res) { trigger_error(xf_db_error($app->db()), E_USER_ERROR); } } $ht->restoreToDate($record, '2004-02-02'); $record3 = df_get_record('HistoryToolTest', array('name' => 'Johnny')); $this->assertEquals(array('name' => 'Johnny', 'container_field' => 'john2.gif'), $record3->strvals(array('name', 'container_field'))); }
function handle(&$params) { $app =& Dataface_Application::getInstance(); if (!@$_GET['history__id']) { return PEAR::raiseError('No history id supplied', DATAFACE_E_ERROR); } $historyid = $_GET['history__id']; $query =& $app->getQuery(); $table = $query['-table']; $r = $app->getRecord(); import('Dataface/HistoryTool.php'); $ht = new Dataface_HistoryTool(); if (@$_GET['-fromcurrent']) { $record = $ht->getDiffs($table, $historyid); $record->escapeOutput = false; } else { if (@$_GET['-show_changes']) { $thisVersion = $ht->getRecordById($table, $historyid); if (PEAR::isError($thisVersion)) { return $thisVersion; } else { if (!$thisVersion) { return PEAR::raiseError('No history record found', DATAFACE_E_ERROR); } } $mdate = $thisVersion->strval("history__modified"); //echo "mdate: ".$mdate; $prevDate = date('Y-m-d H:i:s', strtotime('-1 second', strtotime($mdate))); //echo " prevdate: ".$prevDate.' '; $prevVersionId = $ht->getPreviousVersion($r, $prevDate, $thisVersion->val('history__language'), null, true); //echo "Prev: $prevVersionId"; if (!$prevVersionId) { $record = new Dataface_Record($table . '__history', array()); } else { $record = $ht->getDiffs($table, $prevVersionId, $historyid); } $record->escapeOutput = false; } else { $record = $ht->getRecordById($table, $historyid); } } if (!$record) { return PEAR::raiseError("No history record for table {$table} with history id {$historyid} could be found", DATAFACE_E_ERROR); } if (PEAR::isError($record)) { return $record; } $record->secureDisplay = false; $context = array('history_record' => &$record); $context['source_record'] = $app->getRecord(); $t =& Dataface_Table::loadTable($table); $numfields = count($t->fields()); $pts = 0; $ppf = array(); $fields = $t->fields(); $tmp = array(); foreach ($fields as $k => $f) { if ($r->checkPermission('view', array('field' => $k))) { $tmp[$k] = $fields[$k]; } } $fields = $tmp; $context['fields'] = $fields; foreach ($fields as $field) { if ($t->isText($field['name'])) { $pts += 5; $ppf[$field['name']] = $pts; } else { $pts++; $ppf[$field['name']] = $pts; } } $firstField = null; $threshold = floatval(floatval($pts) / floatval(2)); foreach ($fields as $field) { if ($ppf[$field['name']] >= $threshold) { $firstField = $field['name']; break; } } $context['first_field_second_col'] = $firstField; $context['changes'] = @$_GET['-show_changes']; $context['table'] =& $t; df_display($context, 'Dataface_HistoryRecordDetails.html'); }