Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Thu, Jul 17, 5:29 PM

in-portal

Index: trunk/core/kernel/utility/temp_handler.php
===================================================================
--- trunk/core/kernel/utility/temp_handler.php (revision 3702)
+++ trunk/core/kernel/utility/temp_handler.php (revision 3703)
@@ -1,624 +1,629 @@
<?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();
var $FinalRefs = Array();
var $CopiedTables = 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)
{
$this->TableIdCounter = 0;
$tables = Array(
'TableName' => $this->Application->getUnitOption($prefix,'TableName'),
'IdField' => $this->Application->getUnitOption($prefix,'IDField'),
'IDs' => $ids,
'Prefix' => $prefix,
'TableId' => $this->TableIdCounter++,
);
$SubItems = $this->Application->getUnitOption($prefix,'SubItems');
if (is_array($SubItems)) {
foreach ($SubItems as $prefix) {
$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'),
'ParentPrefix' => $this->Application->getUnitOption($prefix, 'ParentPrefix'),
'ParentTableKey' => $this->Application->getUnitOption($prefix,'ParentTableKey'),
'Prefix' => $prefix,
'AutoClone' => $this->Application->getUnitOption($prefix,'AutoClone'),
'AutoDelete' => $this->Application->getUnitOption($prefix,'AutoDelete'),
'TableId' => $this->TableIdCounter++,
);
$this->FinalRefs[ $tmp['TableName'] ] = $tmp['TableId'];
$constrain = $this->Application->getUnitOption($prefix,'Constrain');
if ($constrain)
{
$tmp['Constrain'] = $constrain;
$this->FinalRefs[ $tmp['TableName'].$tmp['Constrain'] ] = $tmp['TableId'];
}
$SubItems = $this->Application->getUnitOption($prefix,'SubItems');
$same_sub_counter = 1;
if( is_array($SubItems) )
{
foreach($SubItems as $prefix)
{
$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()), $foreign_key);
}
$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
$this->AlreadyProcessed[$master['TableName']][$id] = $object->GetId();
}
if($object->mode == 't') $object->setTempID();
if ($mode == 'create') {
$this->RaiseEvent('OnAfterClone', $master['Prefix'], Array($object->GetId()), $foreign_key, array('original_id' => $id) );
}
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.'
WHERE '.$foreign_key_field.' = '.$original_values[$parent_key_field];
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$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'];
+ $foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
+ $parent_key_field = is_array($sub_table['ParentTableKey']) ? getArrayValue($sub_table, 'ParentTableKey', $master['Prefix']) : $sub_table['ParentTableKey'];
+
+ if (!$foreign_key_field || !$parent_key_field) continue;
$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']) ) {
if( $this->DropTempTable($master['TableName']) )
{
$this->CreateTempTable($master['TableName']);
}
}
if (is_array($ids)) {
$ids = join(',', $ids);
}
$table_sig = $master['TableName'].(isset($master['Constrain']) ? $master['Constrain'] : '');
if ($ids != '' && !in_array($table_sig, $this->CopiedTables)) {
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);
$this->CopiedTables[] = $table_sig;
$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 (!$parent_key) continue;
if ( $ids != '' && $parent_key != $key_field ) {
$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)
{
$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'].'
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']).'
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)
{
$query = 'SELECT '.$master['IdField'].' FROM '.$this->GetTempName($master['TableName']);
if (isset($master['Constrain'])) $query .= ' WHERE '.$master['Constrain'];
$current_ids = $this->Conn->GetCol($query);
$table_sig = $master['TableName'].(isset($master['Constrain']) ? $master['Constrain'] : '');
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') ) {
if( in_array($table_sig, $this->CopiedTables) || $this->FinalRefs[$table_sig] != $master['TableId'] ) return;
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
WHERE '.$master['IdField'].' = '.$id;
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$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']).'
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), null, array('temp_id' => $id) );
$this->UpdateForeignKeys($master, $insert_id, $id);
//delete already copied record from master temp table
$query = 'DELETE FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' = '.$id_to_copy;
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
}
$this->CopiedTables[] = $table_sig;
// when all of ids in current master has been processed, copy all sub-tables data
$this->CopySubTablesToLive($master, $current_ids);
}
elseif( !in_array($table_sig, $this->CopiedTables) && ($this->FinalRefs[$table_sig] == $master['TableId']) ) { //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
$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
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'].'
SELECT * FROM '.$this->GetTempName($master['TableName']);
if (isset($master['Constrain'])) $query .= ' WHERE '.$master['Constrain'];
$this->Conn->Query($query);
$this->CopiedTables[] = $table_sig;
/*
!!! 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 ($this->FinalRefs[ $master['TableName'] ] != $master['TableId']) return;
/*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) {
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']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
+ if (!$foreign_key_field) return;
- $foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
+ list ($live_foreign_key, $temp_foreign_key) = $this->GetForeignKeys($master, $sub_table, $live_id, $temp_id);
//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.'
WHERE '.$foreign_key_field.' = '.$temp_foreign_key;
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$this->Conn->Query($query);
}
}
}
function CopySubTablesToLive($master, $current_ids) {
foreach ($master['SubTables'] as $sub_table) {
$table_sig = $sub_table['TableName'].(isset($sub_table['Constrain']) ? $sub_table['Constrain'] : '');
// delete records from live table by foreign key, so that records deleted from temp table
// get deleted from live
if (count($current_ids) > 0 && !in_array($table_sig, $this->CopiedTables) ) {
+ $foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
+ if (!$foreign_key_field) continue;
$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'].'
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, $foreign_key = null, $add_params = null)
{
if ( !is_array($ids) ) return;
$event = new kEvent( Array('name'=>$name, 'prefix'=>$prefix, 'special'=>'') );
if( isset($foreign_key) ) $event->setEventParam('foreign_key', $foreign_key);
foreach($ids as $id)
{
$event->setEventParam('id', $id);
if (is_array($add_params)) {
foreach ($add_params as $name => $val) {
$event->setEventParam($name, $val);
}
}
$this->Application->HandleEvent($event);
}
}
function DropTempTable($table)
{
if( in_array($table, $this->DroppedTables) ) return false;
$query = sprintf("DROP TABLE IF EXISTS %s",
$this->GetTempName($table)
);
array_push($this->DroppedTables, $table);
$this->DroppedTables = array_unique($this->DroppedTables);
$this->Conn->Query($query);
return true;
}
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.16
\ No newline at end of property
+1.17
\ No newline at end of property
Index: trunk/core/kernel/db/dblist.php
===================================================================
--- trunk/core/kernel/db/dblist.php (revision 3702)
+++ trunk/core/kernel/db/dblist.php (revision 3703)
@@ -1,765 +1,769 @@
<?php
/**
* System Having/Where filter
*
*/
define('FLT_SYSTEM', 1);
/**
* User Having/Where filter
*
*/
define('FLT_NORMAL', 2);
/**
* User "Search" Having/Where filter
*
*/
define('FLT_SEARCH', 3);
/**
* User "View Menu" Having/Where filter
*
*/
define('FLT_VIEW', 4);
/**
* DBList
*
* Desciption
* @package kernel4
*/
class kDBList extends kDBBase {
-
+
/**
* Holds totals for fields specified in config
*
* @var Array
*/
var $Totals = Array();
-
+
/**
* Description
*
* @var array
* @access public
*/
var $OrderFields;
/**
* Holds counted total number of records in the query - without pagination (system+user filters)
*
* @var int
* @access public
*/
var $RecordsCount;
/**
* Records count with system filters only applied
*
* @var int
* @access private
*/
var $NoFilterCount = 0;
/**
* Record count selected to be
* showed on current page
*
* @var int
*/
var $SelectedCount=0;
/**
* Array of records selected
*
* @var Array
* @access private
*/
var $Records;
var $CurrentIndex = 0;
/**
* List items per-page
*
* @var int
* @access public
*/
var $PerPage;
/**
* Pages count in list based on PerPage & RecordsCount attributes
*
* @var int
* @access public
*/
var $TotalPages;
/**
* Description
*
* @var int
* @access public
*/
var $Direction;
/**
* Holds current page number - used when forming LIMIT clause of SELECT statement
*
* @var int
* @access public
*/
var $Page;
/**
* Holds offset for LIMIT clause, calculated in {@link kDBList::PerPage()}
*
* @var int
* @access private
*/
var $Offset;
/**
* Count SQL was already issued on query
*
* @var bool
* @access private
*/
var $hasCounted = false;
/**
* Holds list WHERE filter object
*
* @var kMultipleFilter
* @access private
*/
var $WhereFilter = Array(FLT_SYSTEM => null, FLT_NORMAL => null, FLT_SEARCH => null, FLT_VIEW => null);
/**
* Holds list HAVING filter object
*
* @var kMultipleFilter
* @access private
*/
var $HavingFilter = Array(FLT_SYSTEM => null, FLT_NORMAL => null, FLT_SEARCH => null, FLT_VIEW => null);
var $GroupByFields = Array();
var $Queried = false;
var $Counted = false;
/**
* Creates kDBList
*
* @return kDBList
*/
function kDBList()
{
parent::kDBBase();
$this->OrderFields = Array();
$this->WhereFilter[FLT_SYSTEM] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
$this->WhereFilter[FLT_NORMAL] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
$this->WhereFilter[FLT_SEARCH] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
$this->WhereFilter[FLT_SEARCH]->setType(FLT_TYPE_OR);
$this->WhereFilter[FLT_VIEW] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
$this->HavingFilter[FLT_SYSTEM] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
$this->HavingFilter[FLT_NORMAL] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
$this->HavingFilter[FLT_SEARCH] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
$this->HavingFilter[FLT_SEARCH]->setType(FLT_TYPE_OR);
$this->HavingFilter[FLT_VIEW] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
$this->PerPage = -1;
}
/**
* Adds new or replaces old filter with same name
*
* @param string $name filter name (for internal use)
* @param string $clause where/having clause part (no OR/AND allowed)
* @param int $filter_type is filter having filter or where filter
* @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW
* @access public
*/
function addFilter($name, $clause, $filter_type = WHERE_FILTER, $filter_scope = FLT_SYSTEM)
{
$filter_name = ($filter_type == WHERE_FILTER) ? 'WhereFilter' : 'HavingFilter';
$filter =& $this->$filter_name;
$filter =& $filter[$filter_scope];
$filter->addFilter($name,$clause);
}
/**
* Removes specified filter from filters list
*
* @param string $name filter name (for internal use)
* @param int $filter_type is filter having filter or where filter
* @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW
* @access public
*/
function removeFilter($name, $filter_type = WHERE_FILTER, $filter_scope = FLT_SYSTEM)
{
$filter_name = ($filter_type == WHERE_FILTER) ? 'WhereFilter' : 'HavingFilter';
$filter =& $this->$filter_name;
$filter =& $filter[$filter_scope];
$filter->removeFilter($name);
}
/**
* Clear list filters
*
* @param bool $user clear user filters
* @param bool $system clear system filters
*/
function clearFilters($user=true,$system=true,$search=true,$view=true)
{
if($system)
{
$this->WhereFilter[FLT_SYSTEM]->clearFilters();
$this->HavingFilter[FLT_SYSTEM]->clearFilters();
}
if($user)
{
$this->WhereFilter[FLT_NORMAL]->clearFilters();
$this->HavingFilter[FLT_NORMAL]->clearFilters();
}
if($search)
{
$this->WhereFilter[FLT_SEARCH]->clearFilters();
$this->HavingFilter[FLT_SEARCH]->clearFilters();
}
if($view)
{
$this->WhereFilter[FLT_VIEW]->clearFilters();
$this->HavingFilter[FLT_VIEW]->clearFilters();
}
}
/**
* Counts the total number of records base on the query resulted from {@link kDBList::GetSelectSQL()}
*
* The method modifies the query to substitude SELECT part (fields listing) with COUNT(*).
* Special care should be applied when working with lists based on grouped queries, all aggregate function fields
* like SUM(), AVERAGE() etc. should be added to CountedSQL by using {@link kDBList::SetCountedSQL()}
*
* @access public
* @param string
* @return void
*/
function CountRecs()
{
$all_sql = $this->GetSelectSQL(true,false);
$sql = $this->getCountSQL($all_sql);
if( $this->GetGroupClause() )
{
$this->RecordsCount = count( $this->Conn->GetCol($sql) );
}
else
{
$this->RecordsCount = (int)$this->Conn->GetOne($sql);
}
$system_sql = $this->GetSelectSQL(true,true);
if($system_sql == $all_sql) //no need to query the same again
{
$this->NoFilterCount = $this->RecordsCount;
return;
}
-
+
$sql = $this->getCountSQL($system_sql);
if( $this->GetGroupClause() )
{
$this->NoFilterCount = count( $this->Conn->GetCol($sql) );
}
else
{
$this->NoFilterCount = (int)$this->Conn->GetOne($sql);
}
-
+
$this->Counted = true;
}
function getCountSQL($sql)
{
if ( preg_match("/DISTINCT(.*?)FROM(?!_)/is",$sql,$regs ) )
{
return preg_replace("/^.*SELECT DISTINCT(.*?)FROM(?!_)/is", "SELECT COUNT(DISTINCT ".$regs[1].") AS count FROM", $sql);
}
else
{
return preg_replace("/^.*SELECT(.*?)FROM(?!_)/is", "SELECT COUNT(*) AS count FROM ", $sql);
}
}
/**
* Queries the database with SQL resulted from {@link kDBList::GetSelectSQL()} and stores result in {@link kDBList::SelectRS}
*
* All the sorting, pagination, filtration of the list should be set prior to calling Query().
*
* @access public
* @param string
* @return void
*/
function Query($force=false)
{
if (!$force && $this->Queried) return true;
$q = $this->GetSelectSQL();
-
+
//$rs = $this->Conn->SelectLimit($q, $this->PerPage, $this->Offset);
//in case we have not counted records try to select one more item to find out if we have something more than perpage
$limit = $this->Counted ? $this->PerPage : $this->PerPage+1;
$sql = $q.' '.$this->Conn->getLimitClause($this->Offset,$limit);
$this->Records = $this->Conn->Query($sql);
$this->SelectedCount = count($this->Records);
if (!$this->Counted) $this->RecordsCount = $this->SelectedCount;
if (!$this->Counted && $this->SelectedCount > $this->PerPage && $this->PerPage != -1) $this->SelectedCount--;
if ($this->Records === false) {
//handle errors here
return false;
}
$this->Queried = true;
return true;
}
function CalculateTotals()
{
$this->Totals = Array();
-
+
$fields = Array();
foreach($this->Fields as $field_name => $field_options)
{
$totals = getArrayValue($field_options, 'totals');
if(!$totals) continue;
-
+
$calculated_field = isset($this->CalculatedFields[$field_name]) && isset($this->VirtualFields[$field_name]);
$db_field = !isset($this->VirtualFields[$field_name]);
-
+
if($calculated_field || $db_field)
{
$field_expression = $calculated_field ? $this->CalculatedFields[$field_name] : '`'.$this->TableName.'`.`'.$field_name.'`';
$fields[$field_name] = $totals.'('.$field_expression.') AS '.$field_name.'_'.$totals;
}
}
-
+
if(!$fields) return false;
-
+
$sql = $this->GetSelectSQL(true, false);
$fields = implode(', ', $fields);
-
+
if ( preg_match("/DISTINCT(.*?)FROM(?!_)/is",$sql,$regs ) )
{
$sql = preg_replace("/^.*SELECT DISTINCT(.*?)FROM(?!_)/is", 'SELECT '.$fields.' FROM', $sql);
}
else
{
$sql = preg_replace("/^.*SELECT(.*?)FROM(?!_)/is", 'SELECT '.$fields.' FROM ', $sql);
}
-
+
$totals = $this->Conn->Query($sql);
-
+
foreach($totals as $totals_row)
{
foreach($totals_row as $total_field => $field_value)
{
if(!isset($this->Totals[$total_field])) $this->Totals[$total_field] = 0;
$this->Totals[$total_field] += $field_value;
}
}
}
-
+
function getTotal($field, $total_function)
{
return $this->Totals[$field.'_'.$total_function];
}
-
+
/**
* Builds full select query except for LIMIT clause
*
* @access public
* @return string
*/
function GetSelectSQL($for_counting=false,$system_filters_only=false)
{
$q = parent::GetSelectSQL($this->SelectClause);
if(!$for_counting) $q = $this->addCalculatedFields($q);
$where = $this->GetWhereClause($for_counting,$system_filters_only);
$having = $this->GetHavingClause($for_counting,$system_filters_only);
$order = $this->GetOrderClause();
$group = $this->GetGroupClause();
if (!empty($where)) $q .= ' WHERE ' . $where;
if (!empty($group)) $q .= ' GROUP BY ' . $group;
if (!empty($having)) $q .= ' HAVING ' . $having;
if ( !$for_counting && !empty($order) ) $q .= ' ORDER BY ' . $order;
return str_replace('%1$s',$this->TableName,$q);
}
function extractCalculatedFields($clause)
{
if ( is_array($this->CalculatedFields) ) {
foreach($this->CalculatedFields as $field_name => $field_expression)
{
$clause = preg_replace('/`'.$field_name.'`/', $field_expression, $clause);
}
}
return $clause;
}
/**
* Returns WHERE clause of the query
*
* @access public
* @param bool $for_counting merge where filters with having filters + replace field names for having fields with their values
* @return string
*/
function GetWhereClause($for_counting=false,$system_filters_only=false)
{
$where =& $this->Application->makeClass('kMultipleFilter');
$where->addFilter('system_where', $this->WhereFilter[FLT_SYSTEM] );
if (!$system_filters_only) {
$where->addFilter('view_where', $this->WhereFilter[FLT_VIEW] );
$search_w = $this->WhereFilter[FLT_SEARCH]->getSQL();
if( $search_w || $for_counting ) // move search_having to search_where in case search_where isset or we are counting
{
$search_h = $this->extractCalculatedFields( $this->HavingFilter[FLT_SEARCH]->getSQL() );
$search_w = ($search_w && $search_h) ? $search_w.' OR '.$search_h : $search_w.$search_h;
$where->addFilter('search_where', $search_w );
}
}
if( $for_counting ) // add system_having and view_having to where
{
$where->addFilter('system_having', $this->extractCalculatedFields( $this->HavingFilter[FLT_SYSTEM]->getSQL() ) );
if (!$system_filters_only) $where->addFilter('view_having', $this->extractCalculatedFields( $this->HavingFilter[FLT_VIEW]->getSQL() ) );
}
return $where->getSQL();
}
/**
* Depricated method
*
* @param string $clause
* @todo REMOVE
*/
function SetWhereClause($clause)
{
if( $this->Application->isDebugMode() )
{
global $debugger;
$debugger->appendTrace();
}
trigger_error('Depricated method <b>kDBList->SetWhereClause</b>. Use <b>kDBList->addFilter</b> instead.', E_USER_ERROR);
}
/**
* Returns HAVING clause of the query
*
* @param bool $for_counting don't return having filter in case if this is counting sql
* @return string
* @access public
*/
function GetHavingClause($for_counting=false, $system_filters_only=false)
{
if( $for_counting ) return '';
$having =& $this->Application->makeClass('kMultipleFilter');
$having->addFilter('system_having', $this->HavingFilter[FLT_SYSTEM] );
if (!$system_filters_only) {
$having->addFilter('view_having', $this->HavingFilter[FLT_VIEW] );
$search_w = $this->WhereFilter[FLT_SEARCH]->getSQL();
if (!$search_w) {
$having->addFilter('search_having', $this->HavingFilter[FLT_SEARCH] );
}
}
return $having->getSQL();
}
/**
* Returns GROUP BY clause of the query
*
* @access public
* @return string
*/
function GetGroupClause()
{
return $this->GroupByFields ? implode(',', $this->GroupByFields) : '';
}
function AddGroupByField($field)
{
$this->GroupByFields[$field] = $field;
}
function RemoveGroupByField($field)
{
unset($this->GroupByFields[$field]);
}
/**
* Adds order field to ORDER BY clause
*
* @access public
* @param string $field Field name
* @param string $direction Direction of ordering (asc|desc)
* @return void
*/
function AddOrderField($field, $direction)
{
// original multilanguage field - convert to current lang field
if (getArrayValue($this->Fields, $field, 'formatter') == 'kMultiLanguage' && !getArrayValue($this->Fields, $field, 'master_field')) {
$lang = $this->Application->GetVar('m_lang');
$field = 'l'.$lang.'_'.$field;
}
-
+
if( !isset($this->Fields[$field]) )
{
trigger_error('<span class="debug_error">Incorrect sorting</span> defined (field = <b>'.$field.'</b>; direction = <b>'.$direction.'</b>) in config for prefix <b>'.$this->Prefix.'</b>', E_USER_WARNING);
}
-
+
$this->OrderFields[] = Array($field, $direction);
}
/**
* Removes all order fields
*
* @access public
* @return void
*/
function ClearOrderFields()
{
$this->OrderFields = Array();
}
/**
* Returns ORDER BY Clause of the query
*
* The method builds order by clause by iterating {@link kDBList::OrderFields} array and concatenating it.
*
* @access public
* @return string
*/
function GetOrderClause()
{
$ret = '';
foreach ($this->OrderFields as $field) {
$name = $field[0];
$ret .= isset($this->Fields[$name]) && !isset($this->VirtualFields[$name]) ? '`'.$this->TableName.'`.' : '';
if ($field[0] == 'RAND()') {
$ret .= $field[0].' '.$field[1].',';
}
else {
$ret .= '`'.$field[0] . '` ' . $field[1] . ',';
}
}
$ret = rtrim($ret, ',');
return $ret;
}
function GetOrderField($pos=NULL)
{
if(!(isset($this->OrderFields[$pos]) && $this->OrderFields[$pos]) )
{
$pos = 0;
}
return isset($this->OrderFields[$pos][0]) ? $this->OrderFields[$pos][0] : '';
}
function GetOrderDirection($pos=NULL)
{
if( !getArrayValue($this->OrderFields, $pos) ) $pos = 0;
return getArrayValue($this->OrderFields, $pos, 1);
}
/**
* Return unformatted field value
*
* @param string
* @return mixed
* @access public
*/
function GetDBField($name)
{
$row =& $this->getCurrentRecord();
return $row[$name];
}
function HasField($name)
{
$row =& $this->getCurrentRecord();
return isset($row[$name]);
}
function GetFieldValues()
{
return $this->getCurrentRecord();
}
function &getCurrentRecord()
{
return $this->Records[$this->CurrentIndex];
}
/**
* Description
*
* @access public
* @param string
* @return void
*/
function GoFirst()
{
$this->CurrentIndex = 0;
}
/**
* Description
*
* @access public
* @return void
*/
function GoNext()
{
$this->CurrentIndex++;
}
/**
* Description
*
* @access public
* @return void
*/
function GoPrev()
{
if ($this->CurrentIndex>0)
$this->CurrentIndex--;
}
/**
* Description
*
* @access public
* @return bool
*/
function EOL()
{
return ($this->CurrentIndex >= $this->SelectedCount);
}
/**
* Description
*
* @access public
* @param string
* @return void
*/
function GetTotalPages()
{
if (!$this->Counted) $this->CountRecs();
if ($this->PerPage == -1) return 1;
$this->TotalPages = (($this->RecordsCount - ($this->RecordsCount % $this->PerPage)) / $this->PerPage) // integer part of division
+ (($this->RecordsCount % $this->PerPage) != 0); // adds 1 if there is a reminder
return $this->TotalPages;
}
/**
* Sets number of records to query per page
*
* @access public
* @param int $per_page Number of records to display per page
* @return void
*/
function SetPerPage($per_page)
{
$this->PerPage = $per_page;
}
function GetPerPage()
{
return $this->PerPage == -1 ? $this->RecordsCount : $this->PerPage;
}
/**
* Description
*
* @access public
* @param int $page
* @return void
*/
function SetPage($page)
{
if ($this->PerPage == -1) {
$this->Page = 1;
return;
}
if ($page < 1) $page = 1;
$this->Offset = ($page-1)*$this->PerPage;
if ($this->Counted && $this->Offset > $this->RecordsCount) {
$this->SetPage(1);
}
else {
$this->Page = $page;
}
//$this->GoFirst();
}
/**
* Sets current item field value
* (doesn't apply formatting)
*
* @access public
* @param string $name Name of the field
* @param mixed $value Value to set the field to
* @return void
*/
function SetDBField($name,$value)
{
$this->Records[$this->CurrentIndex][$name] = $value;
}
/**
* Apply where clause, that links this object to it's parent item
*
* @param string $special
* @access public
*/
function linkToParent($special)
{
$parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix');
if($parent_prefix)
{
$parent_table_key = $this->Application->getUnitOption($this->Prefix, 'ParentTableKey');
+ if (is_array($parent_table_key)) $parent_table_key = getArrayValue($parent_table_key, $parent_prefix);
$foreign_key_field = $this->Application->getUnitOption($this->Prefix, 'ForeignKey');
+ if (is_array($foreign_key_field)) $foreign_key_field = getArrayValue($foreign_key_field, $parent_prefix);
+
+ if (!$parent_table_key || !$foreign_key_field) return ;
$parent_object =& $this->Application->recallObject($parent_prefix.'.'.$special);
$parent_id = $parent_object->GetDBField($parent_table_key);
$this->addFilter('parent_filter', '`'.$this->TableName.'`.`'.$foreign_key_field.'` = '.$parent_id); // only for list in this case
}
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/db/dblist.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.14
\ No newline at end of property
+1.15
\ No newline at end of property
Index: trunk/core/kernel/kbase.php
===================================================================
--- trunk/core/kernel/kbase.php (revision 3702)
+++ trunk/core/kernel/kbase.php (revision 3703)
@@ -1,530 +1,536 @@
<?php
/**
* Base
*
* Desciption
* @package kernel4
*/
class kBase {
/**
* Holds reference to global KernelApplication instance
* @access public
* @var kApplication
*/
var $Application;
/**
* Prefix, that was used
* to create an object
*
* @var string
* @access public
*/
var $Prefix='';
-
+
/**
* Special, that was used
* to create an object
*
* @var string
* @access public
*/
var $Special='';
-
+
var $OriginalParams;
-
+
/**
* Set's application
*
* @return kBase
* @access public
*/
function kBase()
{
$this->Application =& kApplication::Instance();
}
-
+
/**
* Create new instance of object
*
* @return kBase
*/
function &makeClass()
{
return new kBase();
}
-
+
/**
* Set's prefix and special
*
* @param string $prefix
* @param string $special
* @access public
*/
function Init($prefix,$special,$event_params=null)
{
$prefix=explode('_',$prefix,2);
$this->Prefix=$prefix[0];
$this->Special=$special;
$this->OriginalParams = $event_params;
}
-
+
/**
* Returns joined prefix
* and special if any
*
* @param bool $from_submit if true, then joins prefix & special by "_", uses "." otherwise
* @return string
* @access protected
*/
function getPrefixSpecial($from_submit = false)
{
$separator = !$from_submit ? '.' : '_';
$ret = $this->Prefix.$separator.$this->Special;
return rtrim($ret, $separator);
}
-
+
function &getProperty($property_name)
{
return $this->$property_name;
}
-
+
function setProperty($property_name, &$property_value)
{
$this->$property_name =& $property_value;
}
}
class kHelper extends kBase {
-
+
/**
* Connection to database
*
* @var kDBConnection
* @access public
*/
var $Conn;
-
+
function kHelper()
{
parent::kBase();
$this->Conn =& $this->Application->GetADODBConnection();
}
-
+
function InitHelper()
{
-
+
}
-
+
}
class kDBBase extends kBase {
/**
* Connection to database
*
* @var kDBConnection
* @access public
*/
var $Conn;
-
+
/**
* Description
*
* @var string Name of primary key field for the item
* @access public
*/
var $IDField;
-
+
/**
* Holds SELECT, FROM, JOIN parts of SELECT query
*
* @var string
* @access public
*/
var $SelectClause;
-
+
/**
* Fields allowed to be set (from table + virtual)
*
* @var Array
* @access private
*/
var $Fields=Array();
-
+
/**
* All virtual field names
*
* @var Array
* @access private
*/
var $VirtualFields=Array();
-
+
/**
* Fields that need to be queried using custom expression, e.g. IF(...) AS value
*
* @var Array
* @access private
*/
var $CalculatedFields = Array();
-
+
/**
* Description
*
* @var string Item' database table name, without prefix
* @access public
*/
var $TableName;
-
+
/**
* Allows to determine object's table status ('temp' - temp table, '' - live table)
*
* @var string
* @access public
*/
var $mode='';
-
+
function kDBBase()
{
parent::kBase();
$this->Conn =& $this->Application->GetADODBConnection();
}
-
+
/**
* Set current item' database table name
*
* @access public
* @param string $table_name
* @return void
*/
function setTableName($table_name)
{
$this->TableName = $table_name;
}
-
+
/**
* Set object' TableName to Live table from config
*
* @access public
*/
function SwitchToLive()
{
$this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName');
}
-
+
/**
* Set object' TableName to Temp table from config
*
* @access public
*/
function SwitchToTemp()
{
$this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName');
$this->SetTableName( kTempTablesHandler::GetTempName($this->TableName) );
$this->mode = 't';
}
-
+
/**
* Checks if object uses temp table
*
* @return bool
*/
function IsTempTable()
{
return kTempTablesHandler::IsTempTable($this->TableName);
}
-
+
/**
* Sets SELECT part of list' query
*
* @access public
* @param string $sql SELECT and FROM [JOIN] part of the query up to WHERE
* @return void
*/
function SetSelectSQL($sql)
{
$this->SelectClause = $sql;
}
-
+
function GetSelectSQL($base_query=null)
{
if( !isset($base_query) ) $base_query = $this->SelectClause;
return $q = str_replace( Array('%1$s','%s'), $this->TableName, $base_query);
}
-
+
/**
* Insert calculated fields sql into query in place of %2$s,
* return processed query.
*
* @param string $query
* @return string
*/
function addCalculatedFields($query)
{
if($this->CalculatedFields)
{
$sql = Array();
foreach($this->CalculatedFields as $field_name => $field_expression)
{
$sql[] = '('.$field_expression.') AS '.$field_name;
}
$sql = implode(',',$sql);
return $this->Application->ReplaceLanguageTags( str_replace('%2$s', ','.$sql, $query) );
}
else
{
return str_replace('%2$s', '', $query);
}
}
-
+
/**
* Adds calculated field declaration to object.
*
* @param string $name
* @param string $sql_clause
*/
function addCalculatedField($name, $sql_clause)
{
$this->CalculatedFields[$name] = $sql_clause;
}
-
+
/**
* Sets ID Field name used as primary key for loading items
*
* @access public
* @param string $field_name
* @return void
* @see kDBBase::IDField
*/
function setIDField($field_name)
{
$this->IDField = $field_name;
}
-
+
function Configure()
{
$this->setTableName( $this->Application->getUnitOption($this->Prefix, 'TableName') );
$this->setIDField( $this->Application->getUnitOption($this->Prefix, 'IDField') );
-
+
$this->defineFields();
-
+
$this->ApplyFieldModifiers(); // should be called only after all fields definitions been set
$this->prepareConfigOptions(); // this should go last, but before setDefaultValues, order is significant!
$this->SetDefaultValues();
}
-
+
/**
* Add field definitions from all possible sources (DB Fields, Virtual Fields, Calcualted Fields, e.t.c.)
*
*/
function defineFields()
{
$this->setConfigFields( $this->Application->getUnitOption($this->Prefix, 'Fields') );
$this->setVirtualFields( $this->Application->getUnitOption($this->Prefix, 'VirtualFields') );
$this->setCalculatedFields( $this->Application->getUnitOption($this->Prefix, 'CalculatedFields') );
}
-
+
function setCalculatedFields($fields)
{
$this->CalculatedFields = isset($fields[$this->Special]) ? $fields[$this->Special] : (isset($fields['']) ? $fields[''] : false);
}
-
+
/**
* Set's field names from table
* from config
*
* @param Array $fields
* @access public
*/
function setConfigFields($fields)
{
$this->Fields = $fields;
}
-
+
/**
* Override field options with ones defined in submit via "field_modfiers" array (common for all prefixes)
*
* @access private
* @author Alex
*/
function ApplyFieldModifiers()
{
// $this->Application->APCalled[] = $this->getPrefixSpecial();
$allowed_modifiers = Array('required');
-
+
$field_modifiers = $this->Application->GetVar('field_modifiers');
if(!$field_modifiers) return false;
-
+
$field_modifiers = getArrayValue($field_modifiers, $this->getPrefixSpecial());
if(!$field_modifiers) return false;
-
+
foreach ($field_modifiers as $field => $field_options)
{
foreach ($field_options as $option_name => $option_value)
{
if ( !in_array(strtolower($option_name), $allowed_modifiers) ) continue;
$this->Fields[$field][$option_name] = $option_value;
}
}
}
-
+
/**
- * Set fields (+options) for fields that physically doesn't exist in database
+ * Set fields (+options) for fields that physically doesn't exist in database
*
* @param Array $fields
* @access public
*/
function setVirtualFields($fields)
{
if($fields)
{
$this->VirtualFields = $fields;
$this->Fields = array_merge_recursive2($this->VirtualFields, $this->Fields);
}
}
-
+
function SetDefaultValues()
{
foreach($this->Fields as $field => $options)
{
if( getArrayValue($options, 'default') === '#NOW#')
{
$this->Fields[$field]['default'] = adodb_mktime();
}
}
}
-
+
function SetFieldOptions($field, $options)
{
$this->Fields[$field] = $options;
}
-
+
function GetFieldOptions($field)
{
return isset($this->Fields[$field]) ? $this->Fields[$field] : Array();
}
-
+
/**
* Returns formatted field value
*
* @param string $field
* @return string
* @access public
*/
function GetField($name, $format=null)
{
$options = $this->GetFieldOptions($name);
$val = $this->GetDBField($name);
$res = $val;
if (isset($options['formatter'])) {
$formatter =& $this->Application->recallObject($options['formatter']);
$res = $formatter->Format($val, $name, $this, $format );
}
return $res;
}
-
+
function HasField($name)
{
-
+
}
-
+
function GetFieldValues()
{
-
+
}
-
+
function UpdateFormattersSubFields()
{
foreach ($this->Fields as $field => $options) {
if (isset($options['formatter'])) {
$formatter =& $this->Application->recallObject($options['formatter']);
$formatter->UpdateSubFields($field, $this->GetDBField($field), $options, $this);
}
}
}
-
+
function prepareConfigOptions()
{
foreach (array_keys($this->Fields) as $field_name)
{
$field_options =& $this->Fields[$field_name];
if( isset($field_options['options_sql']) )
{
// replace with query result
$select_clause = $field_options['option_title_field'].','.$field_options['option_key_field'];
$sql = sprintf($field_options['options_sql'], $select_clause);
-
+
$options_hash = getArrayValue($field_options,'options');
if($options_hash === false) $options_hash = Array();
-
+
$dynamic_options = $this->Conn->GetCol($sql, $field_options['option_key_field']);
$field_options['options'] = array_merge_recursive2($options_hash, $dynamic_options);
-
+
unset($field_options['options_sql']);
}
$this->PrepareOptions($field_name);
}
}
-
+
function PrepareOptions($field_name)
{
if( $formatter_class = getArrayValue($this->Fields[$field_name], 'formatter') )
{
$formatter =& $this->Application->recallObject($formatter_class);
$formatter->PrepareOptions($field_name, $this->Fields[$field_name], $this);
}
}
-
+
/**
* Returns unformatted field value
*
* @param string $field
* @return string
* @access public
*/
function GetDBField($field)
{
-
+
}
-
+
/**
* Returns ID of currently processed record
*
* @return int
* @access public
*/
function GetID()
{
return $this->GetDBField($this->IDField);
}
-
+
/**
* Returns parent table information
*
* @param bool $from_temp load parent item from temp table
* @param string $special special of main item
* @return Array
*/
function getLinkedInfo($special = '')
{
$parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix');
if($parent_prefix)
{
// if this is linked table, then set id from main table
$table_info = Array(
'TableName' => $this->Application->getUnitOption($this->Prefix,'TableName'),
'IdField' => $this->Application->getUnitOption($this->Prefix,'IDField'),
'ForeignKey' => $this->Application->getUnitOption($this->Prefix,'ForeignKey'),
'ParentTableKey' => $this->Application->getUnitOption($this->Prefix,'ParentTableKey'),
'ParentPrefix' => $parent_prefix
);
-
+ if (is_array($table_info['ForeignKey'])) {
+ $table_info['ForeignKey'] = getArrayValue($table_info, 'ForeignKey', $parent_prefix);
+ }
+ if (is_array($table_info['ParentTableKey'])) {
+ $table_info['ParentTableKey'] = getArrayValue($table_info, 'ParentTableKey', $parent_prefix);
+ }
+
$main_object =& $this->Application->recallObject($parent_prefix.'.'.$special);
return array_merge($table_info, Array('ParentId'=> $main_object->GetDBField( $table_info['ParentTableKey'] ) ) );
}
return false;
}
-
+
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/kbase.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.17
\ No newline at end of property
+1.18
\ No newline at end of property

Event Timeline