Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F773107
in-portal
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Feb 2, 1:46 AM
Size
22 KB
Mime Type
text/x-diff
Expires
Tue, Feb 4, 1:46 AM (1 d, 15 h)
Engine
blob
Format
Raw Data
Handle
556366
Attached To
rINP In-Portal
in-portal
View Options
Index: trunk/core/kernel/utility/temp_handler.php
===================================================================
--- trunk/core/kernel/utility/temp_handler.php (revision 2790)
+++ trunk/core/kernel/utility/temp_handler.php (revision 2791)
@@ -1,581 +1,585 @@
<?php
class kTempTablesHandler extends kBase {
var $Tables = Array();
-
+
/**
* Master table name for temp handler
*
* @var string
* @access private
*/
var $MasterTable = '';
/**
* IDs from master table
*
* @var Array
* @access private
*/
var $MasterIDs = Array();
-
+
var $AlreadyProcessed = Array();
-
+
+ var $DroppedTables = Array();
+
/**
* Description
*
* @var kDBConnection
* @access public
*/
var $Conn;
-
+
function kTempTablesHandler()
{
parent::kBase();
$this->Conn =& $this->Application->GetADODBConnection();
}
-
+
function SetTables($tables)
{
// set tablename as key for tables array
$ret = Array();
$this->Tables = $tables;
$this->MasterTable = $tables['TableName'];
}
-
+
/**
* Get temp table name
*
* @param string $table
* @return string
*/
function GetTempName($table)
{
// function is sometimes called as static, so we CAN'T use $this->GetTempTablePrefix() here
return TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_'.$table;
}
-
+
function GetTempTablePrefix()
{
return TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_';
}
-
+
/**
* Return live table name based on temp table name
*
* @param string $temp_table
* @return string
*/
function GetLiveName($temp_table)
{
if( preg_match('/'.TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_(.*)/',$temp_table,$rets) )
{
return $rets[1];
}
else
{
return $temp_table;
}
}
-
+
function IsTempTable($table)
{
return strpos($table, TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_') !== false;
}
-
+
/**
* Return temporary table name for master table
*
* @return string
* @access public
*/
function GetMasterTempName()
{
return $this->GetTempName($this->MasterTable);
}
-
+
function CreateTempTable($table)
{
$query = sprintf("CREATE TABLE %s SELECT * FROM %s WHERE 0",
$this->GetTempName($table),
$table);
$this->Conn->Query($query);
}
-
+
function BuildTables($prefix, $ids)
{
$tables = Array(
'TableName' => $this->Application->getUnitOption($prefix,'TableName'),
'IdField' => $this->Application->getUnitOption($prefix,'IDField'),
'IDs' => $ids,
'Prefix' => $prefix,
);
-
+
$SubItems = $this->Application->getUnitOption($prefix,'SubItems');
if (is_array($SubItems)) {
foreach ($SubItems as $prefix) {
- $this->AddTables($prefix, $tables);
+ $this->AddTables($prefix, $tables);
}
}
$this->SetTables($tables);
}
-
+
function AddTables($prefix, &$tables)
{
$tmp = Array(
'TableName' => $this->Application->getUnitOption($prefix,'TableName'),
'IdField' => $this->Application->getUnitOption($prefix,'IDField'),
'ForeignKey' => $this->Application->getUnitOption($prefix,'ForeignKey'),
'ParentTableKey' => $this->Application->getUnitOption($prefix,'ParentTableKey'),
'Prefix' => $prefix,
'AutoClone' => $this->Application->getUnitOption($prefix,'AutoClone'),
'AutoDelete' => $this->Application->getUnitOption($prefix,'AutoDelete'),
);
-
+
$constrain = $this->Application->getUnitOption($prefix,'Constrain');
if ($constrain) $tmp['Constrain'] = $constrain;
-
+
$SubItems = $this->Application->getUnitOption($prefix,'SubItems');
$same_sub_counter = 1;
if (is_array($SubItems)) {
foreach ($SubItems as $prefix) {
if (preg_match("/^SAME:(.*)/", $prefix, $regs)) {
$same_sub = $tmp;
$same_sub['Prefix'] = $tmp['Prefix'].'.'.$same_sub_counter;
$same_sub['Constrain'] = $regs[1];
$same_sub['ParentTableKey'] = $tmp['IdField'];
$same_sub['ForeignKey'] = $this->Application->getUnitOption($tmp['Prefix'],'ForeignKey'.$same_sub_counter);
$tmp['SubTables'][] = $same_sub;
$same_sub_counter++;
}
else {
$this->AddTables($prefix, $tmp);
}
}
}
-
+
if ( !is_array(getArrayValue($tables, 'SubTables')) ) {
$tables['SubTables'] = array();
}
-
+
$tables['SubTables'][] = $tmp;
}
-
+
function CloneItems($prefix, $special, $ids, $master=null, $foreign_key=null, $parent_prefix=null)
{
if (!isset($master)) $master = $this->Tables;
if( strpos($prefix,'.') !== false ) list($prefix,$special) = explode('.', $prefix, 2);
-
+
$prefix_special = rtrim($prefix.'.'.$special, '.');
-
+
//recalling by different name, because we may get kDBList, if we recall just by prefix
$recall_prefix = $prefix_special.($special ? '' : '.').'-item';
$this->Application->setUnitOption($prefix, 'AutoLoad', false);
-
+
$object =& $this->Application->recallObject($recall_prefix, $prefix);
foreach ($ids as $id)
{
$mode = 'create';
if ( $cloned_ids = getArrayValue($this->AlreadyProcessed, $master['TableName']) ) {
// if we have already cloned the id, replace it with cloned id and set mode to update
// update mode is needed to update second ForeignKey for items cloned by first ForeignKey
if ( getArrayValue($cloned_ids, $id) ) {
$id = $cloned_ids[$id];
$mode = 'update';
}
}
-
+
$object->Load($id);
$original_values = $object->FieldValues;
-
+
$object->NameCopy($master, $foreign_key);
-
+
if (isset($foreign_key)) {
$master_foreign_key_field = is_array($master['ForeignKey']) ? $master['ForeignKey'][$parent_prefix] : $master['ForeignKey'];
$object->SetDBField($master_foreign_key_field, $foreign_key);
}
-
+
if ($mode == 'create') {
$this->RaiseEvent('OnBeforeClone', $master['Prefix'], Array($object->GetId()) );
}
-
+
$res = $mode == 'update' ? $object->Update() : $object->Create();
-
+
if( $res )
{
if ( $mode == 'create' && is_array( getArrayValue($master, 'ForeignKey')) ) {
- // remember original => clone mapping for dual ForeignKey updating
+ // remember original => clone mapping for dual ForeignKey updating
$this->AlreadyProcessed[$master['TableName']][$id] = $object->GetId();
}
if($object->mode == 't') $object->setTempID();
if ($mode == 'create') {
$this->RaiseEvent('OnAfterClone', $master['Prefix'], Array($object->GetId()) );
}
-
+
if ( is_array(getArrayValue($master, 'SubTables')) ) {
foreach($master['SubTables'] as $sub_table) {
if (!getArrayValue($sub_table, 'AutoClone')) continue;
$sub_TableName = ($object->mode == 't') ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
-
+
$foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
$parent_key_field = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
-
- $query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
+
+ $query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
WHERE '.$foreign_key_field.' = '.$original_values[$parent_key_field];
-
+
$sub_ids = $this->Conn->GetCol($query);
-
+
if ( is_array(getArrayValue($sub_table, 'ForeignKey')) ) {
// $sub_ids could containt newly cloned items, we need to remove it here
// to escape double cloning
-
+
$cloned_ids = getArrayValue($this->AlreadyProcessed, $sub_table['TableName']);
if ( !$cloned_ids ) $cloned_ids = Array();
$new_ids = array_values($cloned_ids);
$sub_ids = array_diff($sub_ids, $new_ids);
}
-
+
$parent_key = $object->GetDBField($parent_key_field);
-
+
$this->CloneItems($sub_table['Prefix'], '', $sub_ids, $sub_table, $parent_key, $master['Prefix']);
}
}
}
}
}
-
+
function DeleteItems($prefix, $special, $ids, $master=null, $foreign_key=null)
{
if (!isset($master)) $master = $this->Tables;
if( strpos($prefix,'.') !== false ) list($prefix,$special) = explode('.', $prefix, 2);
-
+
$prefix_special = rtrim($prefix.'.'.$special, '.');
-
+
//recalling by different name, because we may get kDBList, if we recall just by prefix
$recall_prefix = $prefix_special.($special ? '' : '.').'-item';
$this->Application->setUnitOption($prefix,'AutoLoad',false);
$object =& $this->Application->recallObject($recall_prefix, $prefix);
-
+
foreach ($ids as $id)
{
$object->Load($id);
$original_values = $object->FieldValues;
if( !$object->Delete($id) ) continue;
-
+
if ( is_array(getArrayValue($master, 'SubTables')) ) {
foreach($master['SubTables'] as $sub_table) {
if (!getArrayValue($sub_table, 'AutoDelete')) continue;
$sub_TableName = ($object->mode == 't') ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
-
+
$foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
$parent_key_field = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
-
- $query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
+
+ $query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
WHERE '.$foreign_key_field.' = '.$original_values[$parent_key_field];
-
+
$sub_ids = $this->Conn->GetCol($query);
-
+
$parent_key = $object->GetDBField($sub_table['ParentTableKey']);
-
+
$this->DeleteItems($sub_table['Prefix'], '', $sub_ids, $sub_table, $parent_key);
}
}
-
- }
+
+ }
}
-
+
function DoCopyLiveToTemp($master, $ids, $parent_prefix=null)
{
// when two tables refers the same table as sub-sub-table, and ForeignKey and ParentTableKey are arrays
// the table will be first copied by first sub-table, then dropped and copied over by last ForeignKey in the array
// this should not do any problems :)
if ( !preg_match("/.*\.[0-9]+/", $master['Prefix']) ) {
$this->DropTempTable($master['TableName']);
$this->CreateTempTable($master['TableName']);
}
-
+
if (is_array($ids)) {
$ids = join(',', $ids);
}
-
+
if ($ids != '') {
if ( getArrayValue($master, 'ForeignKey') ) {
if ( is_array($master['ForeignKey']) ) {
$key_field = $master['ForeignKey'][$parent_prefix];
}
else {
$key_field = $master['ForeignKey'];
}
}
else {
$key_field = $master['IdField'];
}
-
+
$query = 'INSERT INTO '.$this->GetTempName($master['TableName']).'
SELECT * FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
-
+
$query = 'SELECT '.$master['IdField'].' FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->RaiseEvent( 'OnAfterCopyToTemp', $master['Prefix'], $this->Conn->GetCol($query) );
}
-
+
if ( getArrayValue($master, 'SubTables') ) {
foreach ($master['SubTables'] as $sub_table) {
-
+
$parent_key = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
-
+
if ( $ids != '' && $parent_key != $key_field ) {
- $query = 'SELECT '.$parent_key.' FROM '.$master['TableName'].'
+ $query = 'SELECT '.$parent_key.' FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
$sub_foreign_keys = join(',', $this->Conn->GetCol($query));
}
else {
$sub_foreign_keys = $ids;
}
$this->DoCopyLiveToTemp($sub_table, $sub_foreign_keys, $master['Prefix']);
}
}
}
-
- function GetForeignKeys($master, $sub_table, $live_id, $temp_id=null)
+
+ function GetForeignKeys($master, $sub_table, $live_id, $temp_id=null)
{
$mode = 1; //multi
if (!is_array($live_id)) {
$live_id = Array($live_id);
$mode = 2; //single
}
if (isset($temp_id) && !is_array($temp_id)) $temp_id = Array($temp_id);
-
+
if ( isset($sub_table['ParentTableKey']) ) {
if ( is_array($sub_table['ParentTableKey']) ) {
$parent_key_field = $sub_table['ParentTableKey'][$master['Prefix']];
}
else {
$parent_key_field = $sub_table['ParentTableKey'];
}
}
else {
$parent_key_field = $master['IdField'];
}
-
+
if ( $cached = getArrayValue($this->FKeysCache, $master['TableName'].'.'.$parent_key_field) ) {
if ( array_key_exists(serialize($live_id), $cached) ) {
list($live_foreign_key, $temp_foreign_key) = $cached[serialize($live_id)];
if ($mode == 1) {
return $live_foreign_key;
}
else {
return Array($live_foreign_key[0], $temp_foreign_key[0]);
}
}
}
if ($parent_key_field != $master['IdField']) {
- $query = 'SELECT '.$parent_key_field.' FROM '.$master['TableName'].'
+ $query = 'SELECT '.$parent_key_field.' FROM '.$master['TableName'].'
WHERE '.$master['IdField'].' IN ('.join(',', $live_id).')';
$live_foreign_key = $this->Conn->GetCol($query);
-
+
if (isset($temp_id)) {
- $query = 'SELECT '.$parent_key_field.' FROM '.$this->GetTempName($master['TableName']).'
+ $query = 'SELECT '.$parent_key_field.' FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' IN ('.join(',', $temp_id).')';
$temp_foreign_key = $this->Conn->GetCol($query);
}
else {
$temp_foreign_key = Array();
}
}
else {
$live_foreign_key = $live_id;
$temp_foreign_key = $temp_id;
}
-
+
$this->FKeysCache[$master['TableName'].'.'.$parent_key_field][serialize($live_id)] = Array($live_foreign_key, $temp_foreign_key);
-
+
if ($mode == 1) {
return $live_foreign_key;
}
else {
return Array($live_foreign_key[0], $temp_foreign_key[0]);
}
}
-
- function DoCopyTempToOriginal($master, $parent_prefix=null)
+
+ function DoCopyTempToOriginal($master, $parent_prefix=null)
{
$query = 'SELECT '.$master['IdField'].' FROM '.$this->GetTempName($master['TableName']);
if (isset($master['Constrain'])) $query .= ' WHERE '.$master['Constrain'];
$current_ids = $this->Conn->GetCol($query);
-
+
if ($current_ids) {
// delete all ids from live table - for MasterTable ONLY!
// because items from Sub Tables get deteleted in CopySubTablesToLive !BY ForeignKey!
if ($master['TableName'] == $this->MasterTable) {
$this->RaiseEvent( 'OnBeforeDeleteFromLive', $master['Prefix'], $current_ids );
-
+
$query = 'DELETE FROM '.$master['TableName'].' WHERE '.$master['IdField'].' IN ('.join(',', $current_ids).')';
$this->Conn->Query($query);
}
-
+
if ( getArrayValue($master, 'SubTables') ) {
foreach ($current_ids AS $id) {
$this->RaiseEvent( 'OnBeforeCopyToLive', $master['Prefix'], Array($id) );
-
+
//reset negative ids to 0, so autoincrement in live table works fine
if ($id < 0) {
- $query = 'UPDATE '.$this->GetTempName($master['TableName']).'
- SET '.$master['IdField'].' = 0
+ $query = 'UPDATE '.$this->GetTempName($master['TableName']).'
+ SET '.$master['IdField'].' = 0
WHERE '.$master['IdField'].' = '.$id;
$this->Conn->Query($query);
$id_to_copy = 0;
}
else {
$id_to_copy = $id;
}
-
+
//copy current id_to_copy (0 for new or real id) to live table
- $query = 'INSERT INTO '.$master['TableName'].'
- SELECT * FROM '.$this->GetTempName($master['TableName']).'
+ $query = 'INSERT INTO '.$master['TableName'].'
+ SELECT * FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' = '.$id_to_copy;
$this->Conn->Query($query);
$insert_id = $id_to_copy == 0 ? $this->Conn->getInsertID() : $id_to_copy;
-
+
$this->RaiseEvent( 'OnAfterCopyToLive', $master['Prefix'], Array($insert_id) );
-
- $this->UpdateForeignKeys($master, $insert_id, $id);
-
+
+ $this->UpdateForeignKeys($master, $insert_id, $id);
+
//delete already copied record from master temp table
- $query = 'DELETE FROM '.$this->GetTempName($master['TableName']).'
+ $query = 'DELETE FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' = '.$id_to_copy;
$this->Conn->Query($query);
}
// when all of ids in current master has been processed, copy all sub-tables data
$this->CopySubTablesToLive($master, $current_ids);
}
else { //If current master doesn't have sub-tables - we could use mass operations
// We don't need to delete items from live here, as it get deleted in the beggining of the method for MasterTable
- // or in parent table processing for sub-tables
-
+ // or in parent table processing for sub-tables
+
$this->RaiseEvent('OnBeforeCopyToLive', $master['Prefix'], $current_ids);
-
+
// reset ALL negative IDs to 0 so it get inserted into live table with autoincrement
- $query = 'UPDATE '.$this->GetTempName($master['TableName']).'
- SET '.$master['IdField'].' = 0
+ $query = 'UPDATE '.$this->GetTempName($master['TableName']).'
+ SET '.$master['IdField'].' = 0
WHERE '.$master['IdField'].' < 0';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
-
+
// copy ALL records to live table
- $query = 'INSERT INTO '.$master['TableName'].'
+ $query = 'INSERT INTO '.$master['TableName'].'
SELECT * FROM '.$this->GetTempName($master['TableName']);
if (isset($master['Constrain'])) $query .= ' WHERE '.$master['Constrain'];
$this->Conn->Query($query);
-
+
/*
-
+
!!! WE NEED TO FIND A WAY TO DETERMINE IF OnAfterCopyToLive is not an empty method, and do on-by-one insert
and pass Ids to OnAfterCopyToLive, otherwise it's not smart to do on-by-one insert for any object
OR WE COULD FIND A WAY TO GET ALL INSERTED IDS as an array and iterate them !!!
-
+
$this->RaiseEvent('OnAfterCopyToLive', IDS ??? );
-
+
*/
-
+
// no need to clear temp table - it will be dropped by next statement
}
}
if ( is_array(getArrayValue($master, 'ForeignKey')) ) { //if multiple ForeignKeys
if ( $master['ForeignKey'][$parent_prefix] != end($master['ForeignKey']) ) {
return; // Do not delete temp table if not all ForeignKeys have been processed (current is not the last)
}
}
$this->DropTempTable($master['TableName']);
}
-
- function UpdateForeignKeys($master, $live_id, $temp_id) {
+
+ function UpdateForeignKeys($master, $live_id, $temp_id) {
foreach ($master['SubTables'] as $sub_table) {
list ($live_foreign_key, $temp_foreign_key) = $this->GetForeignKeys($master, $sub_table, $live_id, $temp_id);
-
+
$foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
-
+
//Update ForeignKey in sub TEMP table
- if ($live_foreign_key != $temp_foreign_key) {
- $query = 'UPDATE '.$this->GetTempName($sub_table['TableName']).'
- SET '.$foreign_key_field.' = '.$live_foreign_key.'
+ if ($live_foreign_key != $temp_foreign_key) {
+ $query = 'UPDATE '.$this->GetTempName($sub_table['TableName']).'
+ SET '.$foreign_key_field.' = '.$live_foreign_key.'
WHERE '.$foreign_key_field.' = '.$temp_foreign_key;
$this->Conn->Query($query);
}
}
}
-
+
function CopySubTablesToLive($master, $current_ids) {
foreach ($master['SubTables'] as $sub_table) {
-
+
// delete records from live table by foreign key, so that records deleted from temp table
// get deleted from live
if (count($current_ids) > 0) {
$foreign_keys = $this->GetForeignKeys($master, $sub_table, $current_ids);
$foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
if (count($foreign_keys) > 0) {
$query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_table['TableName'].'
WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
-
+
$this->RaiseEvent( 'OnBeforeDeleteFromLive', $sub_table['Prefix'], $this->Conn->GetCol($query) );
-
- $query = 'DELETE FROM '.$sub_table['TableName'].'
+
+ $query = 'DELETE FROM '.$sub_table['TableName'].'
WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$this->Conn->Query($query);
}
}
-
+
//sub_table passed here becomes master in the method, and recursively updated and copy its sub tables
$this->DoCopyTempToOriginal($sub_table, $master['Prefix']);
}
}
-
+
function RaiseEvent($name, $prefix, $ids)
{
if ( !is_array($ids) ) return;
foreach ($ids as $id) {
$event = new kEvent( Array('name'=>$name, 'prefix'=>$prefix, 'special'=>'') );
$event->setEventParam('id', $id);
$this->Application->HandleEvent($event);
}
}
-
+
function DropTempTable($table)
{
+ if (in_array($table, $this->DroppedTables)) return;
$query = sprintf("DROP TABLE IF EXISTS %s",
$this->GetTempName($table)
);
+ $this->DroppedTables = array_unique(array_push($this->DroppedTables, $table));
$this->Conn->Query($query);
}
-
+
function PrepareEdit()
{
$this->DoCopyLiveToTemp($this->Tables, $this->Tables['IDs']);
}
-
+
function SaveEdit($skip_master=0)
{
$this->DoCopyTempToOriginal($this->Tables);
}
-
+
function CancelEdit($master=null)
{
if (!isset($master)) $master = $this->Tables;
$this->DropTempTable($master['TableName']);
if ( getArrayValue($master, 'SubTables') ) {
foreach ($master['SubTables'] as $sub_table) {
$this->CancelEdit($sub_table);
}
}
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/temp_handler.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.6
\ No newline at end of property
+1.7
\ No newline at end of property
Event Timeline
Log In to Comment