Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sun, Feb 2, 12:54 PM

in-portal

This file is larger than 256 KB, so syntax highlighting was skipped.
Index: trunk/core/kernel/event_manager.php
===================================================================
--- trunk/core/kernel/event_manager.php (revision 1338)
+++ trunk/core/kernel/event_manager.php (revision 1339)
@@ -1,164 +1,241 @@
<?php
define('hBEFORE',1);
define('hAFTER',2);
class kEventManager extends kDBBase {
/**
* Cache of QueryString parameters
* from config, that are represented
* in enviroment variable
*
* @var Array
*/
var $queryMaps=Array();
/**
* Build events registred for
* pseudo classes. key - pseudo class
* value - event name
*
* @var Array
* @access private
*/
var $buildEvents=Array();
/**
* Holds before hooks
* key - prefix.event (to link to)
* value - hooked event info
*
* @var Array
* @access private
*/
var $beforeHooks=Array();
/**
* Holds after hooks
* key - prefix.event (to link to)
* value - hooked event info
*
* @var Array
* @access private
*/
var $afterHooks=Array();
/**
* Set's new enviroment parameter mappings
* between their names as application vars
*
* @param Array $new_query_maps
* @access public
*/
function setQueryMaps($new_query_maps)
{
$this->queryMaps=$new_query_maps;
}
function registerBuildEvent($pseudo_class,$build_event_name)
{
$this->buildEvents[$pseudo_class]=$build_event_name;
}
/**
* Returns build event by pseudo class
* name if any defined in config
*
* @param string $pseudo_class
* @return kEvent
* @access public
*/
function &getBuildEvent($pseudo_class)
{
if( !isset($this->buildEvents[$pseudo_class]) ) return false;
$event = new kEvent();
$event->Name=$this->buildEvents[$pseudo_class];
$event->MasterEvent=null;
return $event;
}
/**
* Allows to process any type of event
*
* @param kEvent $event
* @access public
*/
function HandleEvent(&$event)
{
+ if (!$event->SkipBeforeHooks) {
+ $this->processHooks($event, hBEFORE);
+ if ($event->status == erFATAL) return;
+ }
+
$event_handler =& $this->Application->recallObject($event->Prefix.'_EventHandler');
- $event_handler->processEvent(&$event);
+ $event_handler->processEvent($event);
+ if ($event->status == erFATAL) return;
+ if (!$event->SkipAfterHooks) {
+ $this->processHooks($event, hAFTER);
+ }
}
function ProcessRequest()
{
+ $this->processOpener();
+
// 1. get events from $_POST
$events=$this->Application->GetVar('events');
if($events===false) $events=Array();
// 2. if nothing there, then try to find them in $_GET
if($this->queryMaps && !$events)
{
// if we got $_GET type submit (links, not javascript)
foreach($this->queryMaps as $prefix_special => $query_map)
{
$query_map=array_flip($query_map);
if(isset($query_map['event']))
{
$events[$prefix_special]=$this->Application->GetVar($prefix_special.'_event');
}
}
}
- //print_pre($events);
+ $passed = explode(',', $this->Application->GetVar('passed'));
foreach($events as $prefix_special => $event_name)
{
if(!$event_name) continue;
$event = new kEvent();
$event->Name=$event_name;
$event->Prefix_Special=$prefix_special;
$prefix_special=explode('.',$prefix_special);
$event->Prefix=$prefix_special[0];
+ array_push($passed, $prefix_special[0]);
$event->Special=isset($prefix_special[1])?$prefix_special[1]:'';
- $event->redirect=$this->Application->RecallVar('redirect_to');
- $this->HandleEvent(&$event);
+ $event->redirect_params = Array('opener'=>'s', 'pass'=>'all');
+ $event->redirect = true;
+ $this->HandleEvent($event);
+
+ if($event->status==erSUCCESS && ($event->redirect === true || strlen($event->redirect) > 0) )
+ {
+ $this->Application->Redirect($event->redirect, $event->redirect_params, null, $event->redirect_script);
+ }
}
+ $this->Application->SetVar('passed', implode(',', $passed));
}
- function registerHook($hookto_unit, $hookto_event_name, $mode, $do_unit, $do_event_name)
+ function processOpener()
{
-
-
-
-
+ $opener_action=$this->Application->GetVar('m_opener');
+ $opener_stack=$this->Application->RecallVar('opener_stack');
+ $opener_stack=$opener_stack?unserialize($opener_stack):Array();
+ switch($opener_action)
+ {
+ case 'r': // "reset" opener stack
+ $opener_stack=Array();
+ break;
+
+ case 'd': // "down/push" new template to opener stack, deeplevel++
+ array_push($opener_stack, $this->Application->RecallVar('last_template') );
+ break;
+
+ case 'u': // "up/pop" last template from opener stack, deeplevel--
+ array_pop($opener_stack);
+ break;
+
+ default: // "s/0," stay on same deep level
+ break;
+ }
+ $this->Application->SetVar('m_opener','s');
+ $this->Application->StoreVar('opener_stack',serialize($opener_stack));
+ }
+
+ function registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional)
+ {
+ $hookto_prefix_special = rtrim($hookto_prefix.'.'.$hookto_special, '.');
+ if ($mode == hBEFORE) {
+ $this->beforeHooks[strtolower($hookto_prefix_special.'.'.$hookto_event)][] = Array(
+ 'DoPrefix' => $do_prefix,
+ 'DoSpecial' => $do_special,
+ 'DoEvent' => $do_event,
+ 'Conditional' => $conditional,
+ );
+ }
+ elseif ($mode == hAFTER) {
+ $this->afterHooks[strtolower($hookto_prefix_special.'.'.$hookto_event)][] = Array(
+ 'DoPrefix' => $do_prefix,
+ 'DoSpecial' => $do_special,
+ 'DoEvent' => $do_event,
+ 'Conditional' => $conditional,
+ );
+ }
}
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ * @param int $mode hBEFORE or hAFTER
+ */
function processHooks(&$event, $mode)
{
-
-
-
-
+ if ($mode == hBEFORE) {
+ $mode_hooks =& $this->beforeHooks;
+ }
+ else {
+ $mode_hooks =& $this->afterHooks;
+ }
+ if ( $hooks = getArrayValue($mode_hooks, strtolower($event->Prefix_Special.'.'.$event->Name)) ) {
+ foreach($hooks as $hook)
+ {
+ $prefix_special = rtrim($hook['DoPrefix'].'_'.$hook['DoSpecial'],'_');
+ if( $hook['Conditional'] && !$this->Application->GetVar($prefix_special) ) continue;
+ $hook_event = new kEvent( Array('name'=>$hook['DoEvent'],'prefix'=>$hook['DoPrefix'],'special'=>$hook['DoSpecial']) );
+ $hook_event->MasterEvent =& $event;
+
+ $this->HandleEvent($hook_event);
+ }
+ }
}
/**
* Set's new event for $prefix_special
* passed
*
* @param string $prefix_special
* @param string $event_name
* @access public
*/
function setEvent($prefix_special,$event_name)
{
$actions =& $this->Application->recallObject('kActions');
$actions->Set('events['.$prefix_special.']',$event_name);
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/event_manager.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
\ No newline at end of property
+1.4
\ No newline at end of property
Index: trunk/core/kernel/processors/tag_processor.php
===================================================================
--- trunk/core/kernel/processors/tag_processor.php (revision 1338)
+++ trunk/core/kernel/processors/tag_processor.php (revision 1339)
@@ -1,74 +1,109 @@
<?php
class TagProcessor extends kBase {
/**
* Processes tag
*
* @param Tag $tag
* @return string
* @access public
*/
function ProcessTag(&$tag)
{
$Method=$tag->Tag;
if(method_exists($this, $Method))
{
//echo htmlspecialchars($tag->GetFullTag()).'<br>';
return $this->$Method($tag->NP);
}
else
{
+ if ($this->Application->hasObject('TagsAggregator')) {
+ $aggregator = $this->Application->recallObject('TagsAggregator');
+ $tag_mapping = $aggregator->GetArrayValue($tag->Prefix, $Method);
+ if ($tag_mapping) {
+
+ $mapped_tag =& new MyTag('', $this->Application->Parser);
+ $mapped_tag->CopyFrom($tag);
+ $mapped_tag->Processor = $tag_mapping[0];
+ $mapped_tag->Tag = $tag_mapping[1];
+ $mapped_tag->NP['PrefixSpecial'] = $tag->getPrefixSpecial();
+ $mapped_tag->RebuildTagData();
+ return $mapped_tag->DoProcessTag();
+ }
+ }
$this->Application->trigerError('Tag Undefined:<br><b>'.$tag->RebuildTagData().'</b>');
return false;
}
}
+
+ function ProcessParsedTag($tag, $params)
+ {
+ $Method=$tag;
+ if(method_exists($this, $Method))
+ {
+ if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_SHOW_TAGS') )
+ {
+ global $debugger;
+ $debugger->appendHTML('Processing PreParsed Tag '.$Method.' in '.$this->Prefix);
+ }
+
+ //echo htmlspecialchars($tag->GetFullTag()).'<br>';
+ return $this->$Method($params);
+ }
+ else
+ {
+ $this->Application->trigerError('Tag Undefined:<br><b>'.$tag.'</b>');
+ return false;
+ }
+ }
}
/*class ProcessorsPool {
var $Processors = Array();
var $Application;
var $Prefixes = Array();
var $S;
function ProcessorsPool()
{
$this->Application =& KernelApplication::Instance();
$this->S =& $this->Application->Session;
}
function RegisterPrefix($prefix, $path, $class)
{
// echo " RegisterPrefix $prefix, $path, $class <br>";
$prefix_item = Array(
'path' => $path,
'class' => $class
);
$this->Prefixes[$prefix] = $prefix_item;
}
function CreateProcessor($prefix, &$tag)
{
// echo " prefix : $prefix <br>";
if (!isset($this->Prefixes[$prefix]))
die ("<b>Filepath and ClassName for prefix $prefix not defined while processing ".htmlspecialchars($tag->GetFullTag())."!</b>");
include_once($this->Prefixes[$prefix]['path']);
$ClassName = $this->Prefixes[$prefix]['class'];
$a_processor =& new $ClassName($prefix);
$this->SetProcessor($prefix, $a_processor);
}
function SetProcessor($prefix, &$a_processor)
{
$this->Processors[$prefix] =& $a_processor;
}
function &GetProcessor($prefix, &$tag)
{
if (!isset($this->Processors[$prefix]))
$this->CreateProcessor($prefix, $tag);
return $this->Processors[$prefix];
}
}*/
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/processors/tag_processor.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
\ No newline at end of property
+1.2
\ No newline at end of property
Index: trunk/core/kernel/processors/main_processor.php
===================================================================
--- trunk/core/kernel/processors/main_processor.php (revision 1338)
+++ trunk/core/kernel/processors/main_processor.php (revision 1339)
@@ -1,575 +1,660 @@
<?php
class MainProcessor extends TagProcessor {
function Init($prefix,$special)
{
parent::Init($prefix,$special);
$actions =& $this->Application->recallObject('kActions');
$actions->Set('t', $this->Application->GetVar('t'));
$actions->Set('sid', $this->Application->GetSID());
+ $actions->Set('m_opener', $this->Application->GetVar('m_opener') );
+
}
/**
* Used to handle calls where tag name
* match with existing php function name
*
* @param Tag $tag
* @return string
*/
function ProcessTag(&$tag)
{
if ($tag->Tag=='include') $tag->Tag='MyInclude';
return parent::ProcessTag($tag);
}
/**
* Creates <base href ..> HTML tag for all templates
* affects future css, js files and href params of links
*
* @param Array $params
* @return string
* @access public
*/
function Base_Ref($params)
{
- $templates_path = substr(THEMES_PATH,1);
- return "<base href='".$this->Application->BaseURL().$templates_path."/'>";
+ $url = $this->Application->BaseURL().substr(THEMES_PATH,1).'/';
+ return '<base href="'.$url.'" />';
}
- /*function Base_URL($params)
+ /**
+ * Returns base url for web-site
+ *
+ * @return string
+ * @access public
+ */
+ function BaseURL()
{
- $templates_path = substr(THEMES_PATH,1);
- return $this->Application->BaseURL().$templates_path;
+ return $this->Application->BaseURL();
}
- function Base($params)
+ function TemplatesBase($params)
+ {
+ return $this->Application->BaseURL().THEMES_PATH;
+ }
+
+ function ProjectBase($params)
+ {
+ return $this->Application->BaseURL();
+ }
+
+ /*function Base($params)
{
return $this->Application->BaseURL().$params['add'];
}*/
/**
* Used to create link to any template.
* use "pass" paramter if "t" tag to specify
* prefix & special of object to be represented
* in resulting url
*
* @param Array $params
* @return string
* @access public
*/
function T($params)
{
- $t=isset($params['t'])&&$params['t']?$params['t']:$this->Application->GetVar('t'); unset($params['t']);
- $prefix=isset($params['prefix'])?$params['prefix']:''; unset($params['prefix']);
-
- $pass=isset($params['pass'])?$params['pass']:$this->Application->GetVar('t_pass'); unset($params['pass']);
- $this->Application->SetVar('t_pass',$pass);
-
- $pass_events=isset($params['pass_events'])&&$params['pass_events']?1:0; unset($params['pass_events']);
- $this->Application->SetVar('t_pass_events',$pass_events);
-
- $this->Set($params); // set other params as application vars
- return $this->Application->HREF($t,$prefix);
+ //by default link to current template
+ $t=isset($params['t'])&&$params['t'] ? $params['t'] : $this->Application->GetVar('t'); unset($params['t']);
+ $prefix=isset($params['prefix']) ? $params['prefix'] : ''; unset($params['prefix']);
+ $index_file = isset($params['index_file']) ? $params['index_file'] : null; unset($params['index_file']);
+
+ /*$pass=isset($params['pass']) ? $params['pass'] : $this->Application->GetVar('t_pass'); unset($params['pass']);
+ $this->Application->SetVar('t_pass', $pass);
+
+ $pass_events = isset($params['pass_events']) && $params['pass_events'] ? 1 : 0; unset($params['pass_events']);
+ $this->Application->SetVar('t_pass_events', $pass_events);*/
+
+ //Use only implicit params passing, do not set into APP
+// $this->Set($params); // set other params as application vars
+ return $this->Application->HREF($t,$prefix,$params,$index_file);
}
/*// NEEDS TEST
function Config($params)
{
return $this->Application->ConfigOption($params['var']);
}
function Object($params)
{
$name = $params['name'];
$method = $params['method'];
$tmp =& $this->Application->recallObject($name);
if ($tmp != null) {
if (method_exists($tmp, $method))
return $tmp->$method($params);
else
echo "Method $method does not exist in object ".get_class($tmp)." named $name<br>";
}
else
echo "Object $name does not exist in the appliaction<br>";
}*/
/**
* Tag, that always returns true.
* For parser testing purposes
*
* @param Array $params
* @return bool
* @access public
*/
function True($params)
{
return true;
}
/**
* Tag, that always returns false.
* For parser testing purposes
*
* @param Array $params
* @return bool
* @access public
*/
function False($params)
{
return false;
}
/**
* Returns block parameter by name
*
* @param Array $params
* @return stirng
* @access public
*/
function Param($params)
{
//$parser =& $this->Application->recallObject('TemplateParser');
$res = $this->Application->Parser->GetParam($params['name']);
if ($res === false) $res = '';
if (isset($params['plus']))
$res += $params['plus'];
return $res;
}
/**
* Compares block parameter with value specified
*
* @param Array $params
* @return bool
* @access public
*/
- function Param_Equals($params)
+ function ParamEquals($params)
{
//$parser =& $this->Application->recallObject('TemplateParser');
$name = $this->SelectParam($params, 'name,var,param');
$value = $params['value'];
return ($this->Application->Parser->GetParam($name) == $value);
}
/*function PHP_Self($params)
{
return $HTTP_SERVER_VARS['PHP_SELF'];
}
*/
/**
* Not tag, method for parameter
* selection from list in this TagProcessor
*
* @param Array $params
* @param string $possible_names
* @return string
* @access public
*/
function SelectParam($params, $possible_names)
{
if (!is_array($params)) return;
if (!is_array($possible_names))
$possible_names = explode(',', $possible_names);
foreach ($possible_names as $name)
{
if( isset($params[$name]) ) return $params[$name];
}
return false;
}
/**
* Returns session variable value by name
*
* @param Array $params
* @return string
* @access public
*/
function Recall($params)
{
$res = $this->Application->RecallVar( $this->SelectParam($params,'name,var,param') );
return ($res === false && isset($params['no_null']))?'':$res;
}
// bad style to store something from template to session !!! (by Alex)
// Used here only to test how session works, nothing more
function Store($params)
{
//echo"Store $params[name]<br>";
$name = $params['name'];
$value = $params['value'];
$this->Application->StoreVar($name,$value);
}
/**
* Sets application variable value(-s)
*
* @param Array $params
* @access public
*/
function Set($params)
{
foreach ($params as $param => $value) {
$this->Application->SetVar($param, $value);
}
}
/**
* Increment application variable
* specified by number specified
*
* @param Array $params
* @access public
*/
function Inc($params)
{
$this->Application->SetVar($params['param'], $this->Application->GetVar($params['param']) + $params['by']);
}
/**
* Retrieves application variable
* value by name
*
* @param Array $params
* @return string
* @access public
*/
function Get($params)
{
return $this->Application->GetVar($this->SelectParam($params, 'name,var,param'), EMPTY_ON_NULL);
}
+ /**
+ * Retrieves application constant
+ * value by name
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function GetConst($params)
+ {
+ return defined($this->SelectParam($params, 'name,const')) ? constant($this->SelectParam($params, 'name,const,param')) : '';
+ }
+
/*function Config_Equals($params)
{
foreach ($params as $name => $val) {
if (in_array($name, Array( 'prefix', 'function'))) continue;
return $this->Application->ConfigOption($name) == $val;
}
return false;
}*/
/**
* Creates all hidden fields
* needed for kernel_form
*
* @param Array $params
* @return string
* @access public
*/
function DumpSystemInfo($params)
{
$actions =& $this->Application->recallObject('kActions');
$actions->Set('t', $this->Application->GetVar('t') );
$params = $actions->GetParams();
$o='';
foreach ($params AS $name => $val)
{
$o .= "<input type='hidden' name='$name' id='$name' value='$val'>\n";
}
return $o;
}
- /*function Odd_Even($params)
+ function Odd_Even($params)
{
$odd = $params['odd'];
$even = $params['even'];
- if ($this->Session->GetProperty('odd_even') == 'even') {
- $this->Session->SetProperty('odd_even', 'odd');
+ if ($this->Application->GetVar('odd_even') == 'even') {
+ $this->Application->SetVar('odd_even', 'odd');
return $even;
}
else {
- $this->Session->SetProperty('odd_even', 'even');
+ $this->Application->SetVar('odd_even', 'even');
return $odd;
}
- }*/
+ }
/**
* Returns phrase translation by name
*
* @param Array $params
* @return string
* @access public
*/
function Phrase($params)
{
// m:phrase name="phrase_name" default="Tr-alala" updated="2004-01-29 12:49"
if (array_key_exists('default', $params)) return $params['default']; //backward compatibility
return $this->Application->Phrase($this->SelectParam($params, 'label,name,title'));
}
// for tabs
function is_active($params)
{
$test_templ = $params["templ"];
- if (!$params['allow_empty']) {
- $if_true = $params["true"] != '' ? $params["true"] : 1;
- $if_false = $params["false"] != '' ? $params["false"] : 0;
+ if ( !getArrayValue($params,'allow_empty') )
+ {
+ $if_true=getArrayValue($params,'true')?$params['true']:1;
+ $if_false=getArrayValue($params,'false')?$params['false']:0;
}
- else {
- $if_true = $params["true"];
- $if_false = $params["false"];
+ else
+ {
+ $if_true=$params['true'];
+ $if_false=$params['false'];
}
if ( eregi("^$test_templ", $this->Application->GetVar('t')))
return $if_true;
else
return $if_false;
}
function is_t_active($params)
{
return $this->is_active($params);
}
/**
* Checks if session variable
* specified by name value match
* value passed as parameter
*
* @param Array $params
* @return string
* @access public
*/
- function Recall_Equals($params)
+ function RecallEquals($params)
{
$name = $params['var'];
$value = $params['value'];
return ($this->Application->RecallVar($name) == $value);
}
/**
* Checks if application variable
* specified by name value match
* value passed as parameter
*
* @param Array $params
* @return bool
* @access public
*/
- function Get_Equals($params)
+ function GetEquals($params)
{
$name = $this->SelectParam($params, 'var,name,param');
$value = $params['value'];
if ($this->Application->GetVar($name) == $value) {
return 1;
}
}
/**
* Includes template
* and returns it's
* parsed version
*
* @param Array $params
* @return string
* @access public
*/
function MyInclude($params)
{
- $BlockParser =& $this->Application->Factory->makeClass('TemplateParser');
+ $BlockParser =& $this->Application->makeClass('TemplateParser');
$BlockParser->SetParams($params);
$parser =& $this->Application->Parser;
$t = $params['t'];
$t = eregi_replace("\.tpl$", '', $t);
$templates_cache =& $this->Application->recallObject('TemplatesCache');
- $res = $BlockParser->Parse( $templates_cache->GetTemplateBody($t) );
+ $res = $BlockParser->Parse( $templates_cache->GetTemplateBody($t), $t );
$this->Application->Parser =& $parser;
return $res;
}
/*function Kernel_Scripts($params)
{
return '<script type="text/javascript" src="'.PROTOCOL.SERVER_NAME.BASE_PATH.'/kernel3/js/grid.js"></script>';
}*/
/*function GetUserPermission($params)
{
// echo"GetUserPermission $params[name]";
if ($this->Application->RecallVar('user_type') == 1)
return 1;
else {
$perm_name = $params[name];
$aPermissions = unserialize($this->Application->RecallVar('user_permissions'));
if ($aPermissions)
return $aPermissions[$perm_name];
}
}*/
/**
* Set's parser block param value
*
* @param Array $params
* @access public
*/
function AddParam($params)
{
$parser =& $this->Application->Parser; // recallObject('TemplateParser');
foreach ($params as $param => $value) {
$this->Application->SetVar($param, $value);
$parser->SetParam($param, $value);
$parser->AddParam('/\$'.$param.'/', $value);
}
}
/*function ParseToVar($params)
{
$var = $params['var'];
$tagdata = $params['tag'];
$parser =& $this->Application->Parser; //recallObject('TemplateParser');
$res = $this->Application->ProcessTag($tagdata);
$parser->SetParam($var, $res);
$parser->AddParam('/\$'.$var.'/', $res);
return '';
}*/
/*function TagNotEmpty($params)
{
$tagdata = $params['tag'];
$res = $this->Application->ProcessTag($tagdata);
return $res != '';
}*/
/*function TagEmpty($params)
{
return !$this->TagNotEmpty($params);
}*/
/**
* Parses block and returns result
*
* @param Array $params
* @return string
* @access public
*/
function ParseBlock($params)
{
$parser =& $this->Application->Parser; // recallObject('TemplateParser');
return $parser->ParseBlock($params);
}
/**
- * Find out what object were in link
- * used to move here and copy them to
- * form submit url
+ * Checks if debug mode is on
*
- * @param unknown_type $params
+ * @return bool
+ * @access public
*/
- function PrepareSubmitURL($params)
+ function IsDebugMode()
{
- $this->Application->ReBuildENV();
+ return $this->Application->isDebugMode();
+ }
+
+ function MassParse($params)
+ {
+ $qty = $params['qty'];
+ $block = $params['block'];
+ $mode = $params['mode'];
+
+ $o = '';
+ if ($mode == 'func') {
+ $func = create_function('$params', '
+ $o = \'<tr>\';
+ $o.= \'<td>a\'.$params[\'param1\'].\'</td>\';
+ $o.= \'<td>a\'.$params[\'param2\'].\'</td>\';
+ $o.= \'<td>a\'.$params[\'param3\'].\'</td>\';
+ $o.= \'<td>a\'.$params[\'param4\'].\'</td>\';
+ $o.= \'</tr>\';
+ return $o;
+ ');
+ for ($i=1; $i<$qty; $i++) {
+ $block_params['param1'] = rand(1, 10000);
+ $block_params['param2'] = rand(1, 10000);
+ $block_params['param3'] = rand(1, 10000);
+ $block_params['param4'] = rand(1, 10000);
+ $o .= $func($block_params);
+ }
+ return $o;
+ }
+
+ $block_params['name'] = $block;
+
+ for ($i=0; $i<$qty; $i++) {
+ $block_params['param1'] = rand(1, 10000);
+ $block_params['param2'] = rand(1, 10000);
+ $block_params['param3'] = rand(1, 10000);
+ $block_params['param4'] = rand(1, 10000);
+ $block_params['passed'] = $params['passed'];
+ $block_params['prefix'] = 'm';
+
+ $o.= $this->Application->ParseBlock($block_params, 1);
+ }
+ return $o;
+ }
+
+ function AfterScript($params)
+ {
+ $after_script = $this->Application->GetVar('after_script');
+ if ( $after_script ) {
+ return '<script type="text/javascript">'.$after_script.'</script>';
+ }
+ return '';
}
/*
function Login($params)
{
$user_prefix = 'users';
$this->parser->registerprefix($user_prefix);
$user_class = $this->parser->processors[$user_prefix]->item_class;
$candidate = new $user_class(NULL, $this->parser->processors[$user_prefix]);
//print_pre($this->Session->Property);
$special = array_shift($params);
//echo"$special<br>";
$candidate_id = $candidate->Login($this->Session->GetProperty('username'), $this->Session->GetProperty('password'), $special);
if ($candidate_id !== false) {
$this->Session->SetField('user_id', $candidate_id);
$this->Session->Update();
$this->Session->AfterLogin();
$this->parser->register_prefix('m');
$template = array_shift($params);
if ($template == '') $template = 'index';
$location = $this->parser->do_process_tag('m', 't', Array($template));
header("Location: $location");
exit;
}
elseif ($this->Session->GetProperty('username') != '') {
$this->Session->SetProperty('login_error', 'Incorrect username or password');
}
}
*/
}
global $suite;
if (isset($suite)) {
class TestMainProcessor extends TestCase {
function testParam_Equals()
{
global $application;
$mp =& new MainProcessor($application, 'm');
$mp->Application->Parser->SetParams( Array('test' => 1));
$this->assertTrue($mp->Param_Equals( Array('param' => 'test', 'value' => 1 )));
$this->assertFalse($mp->Param_Equals( Array('param' => 'test', 'value' => 2 )));
$this->assertFalse($mp->Param_Equals( Array('param' => 'test1', 'value' => 2 )));
}
function testParam()
{
global $application;
$mp =& new MainProcessor($application, 'm');
$mp->Application->Parser->SetParams( Array('test' => 2));
$this->assertEquals(2, $mp->Param( Array('name' => 'test')));
$this->assertEquals(5, $mp->Param( Array('name' => 'test', 'plus' => 3 )));
$this->assertEquals(1, $mp->Param( Array('name' => 'test', 'plus' => -1 )));
}
function testSetGet()
{
global $application;
$mp =& new MainProcessor($application, 'm');
$mp->Set( Array('test_var' => 7, 'another_var' => 'abc') );
$this->assertEquals(7, $mp->Get( Array('param' => 'test_var')));
$this->assertEquals('abc', $mp->Get( Array('param' => 'another_var')));
}
function testConfig()
{
global $application;
$mp =& new MainProcessor($application, 'm');
$application->Session->Config->SetOption('test_config_var', '1');
$this->assertEquals(true, $mp->Config_Equals( Array('test_config_var' => '1')));
}
function testOddEven()
{
global $application;
$mp =& new MainProcessor($application, 'm');;
$this->assertEquals('odd_value', $mp->Odd_Even(Array('odd' => 'odd_value', 'even' => 'even_value')));
$this->assertEquals('even_value', $mp->Odd_Even(Array('odd' => 'odd_value', 'even' => 'even_value')));
$this->assertEquals('odd_value', $mp->Odd_Even(Array('odd' => 'odd_value', 'even' => 'even_value')));
}
function testApplicationProcessTag()
{
global $application;
$this->assertEquals($application->GetSID(), $application->ProcessTag('m:sid'));
}
}
$suite->addTest(new TestSuite("TestMainProcessor"));
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/processors/main_processor.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.4
\ No newline at end of property
+1.5
\ No newline at end of property
Index: trunk/core/kernel/session/session.php
===================================================================
--- trunk/core/kernel/session/session.php (revision 1338)
+++ trunk/core/kernel/session/session.php (revision 1339)
@@ -1,513 +1,614 @@
<?php
/*
The session works the following way:
1. When a visitor loads a page from the site the script checks if cookies_on varibale has been passed to it as a cookie.
2. If it has been passed, the script tries to get Session ID (SID) from the request:
3. Depending on session mode the script is getting SID differently.
The following modes are available:
smAUTO - Automatic mode: if cookies are on at the client side, the script relays only on cookies and
ignore all other methods of passing SID.
If cookies are off at the client side, the script relays on SID passed through query string
and referal passed by the client. THIS METHOD IS NOT 100% SECURE, as long as attacker may
get SID and substitude referal to gain access to user' session. One of the faults of this method
is that the session is only created when the visitor clicks the first link on the site, so
there is NO session at the first load of the page. (Actually there is a session, but it gets lost
after the first click because we do not use SID in query string while we are not sure if we need it)
smCOOKIES_ONLY - Cookies only: in this mode the script relays solely on cookies passed from the browser
and ignores all other methods. In this mode there is no way to use sessions for clients
without cookies support or cookies support disabled. The cookies are stored with the
full domain name and path to base-directory of script installation.
smGET_ONLY - GET only: the script will not set any cookies and will use only SID passed in
query string using GET, it will also check referal. The script will set SID at the
first load of the page
smCOOKIES_AND_GET - Combined mode: the script will use both cookies and GET right from the start. If client has
cookies enabled, the script will check SID stored in cookie and passed in query string, and will
use this SID only if both cookie and query string matches. However if cookies are disabled on the
client side, the script will work the same way as in GET_ONLY mode.
4. After the script has the SID it tries to load it from the Storage (default is database)
5. If such SID is found in the database, the script checks its expiration time. If session is not expired, it updates
its expiration, and resend the cookie (if applicable to session mode)
6. Then the script loads all the data (session variables) pertaining to the SID.
Usage:
$session =& new Session(smAUTO); //smAUTO is default, you could just leave the brackets empty, or provide another mode
$session->SetCookieDomain('my.domain.com');
$session->SetCookiePath('/myscript');
$session->SetCookieName('my_sid_cookie');
$session->SetGETName('sid');
$session->InitSession();
...
//link output:
echo "<a href='index.php?'". ( $session->NeedQueryString() ? 'sid='.$session->SID : '' ) .">My Link</a>";
*/
//Implements session storage in the database
class SessionStorage extends kDBBase {
var $Expiration;
+ var $SessionTimeout=0;
var $OriginalData=Array();
+ var $TimestampField;
+ var $SessionDataTable;
+ var $DataValueField;
+ var $DataVarField;
+
+ function Init($prefix,$special)
+ {
+ parent::Init($prefix,$special);
+ $this->setTableName('sessions');
+ $this->setIDField('sid');
+ $this->TimestampField = 'expire';
+ $this->SessionDataTable = 'SessionData';
+ $this->DataValueField = 'value';
+ $this->DataVarField = 'var';
+ }
+
+ function setSessionTimeout($new_timeout)
+ {
+ $this->SessionTimeout = $new_timeout;
+ }
+
function StoreSession(&$session)
{
- $query = sprintf( "INSERT INTO %sSessions (sid, expire) VALUES (%s, %s)",
- TABLE_PREFIX,
- $session->SID,
- $session->Expiration);
+ $query = ' INSERT INTO '.$this->TableName.' ('.$this->IDField.', '.$this->TimestampField.')'.
+ ' VALUES ('.$this->Conn->qstr($session->SID).', '.$session->Expiration.')';
$this->Conn->Query($query);
}
function DeleteSession(&$session)
{
- $query = sprintf( "DELETE FROM %sSessions WHERE %s = %s",
- TABLE_PREFIX,
- 'sid',
- $session->SID);
+ $query = ' DELETE FROM '.$this->TableName.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
- $query = sprintf( "DELETE FROM %sSessionData WHERE %s = %s",
- TABLE_PREFIX,
- 'sid',
- $session->SID);
+ $query = ' DELETE FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
$this->OriginalData = Array();
}
- function UpdateSession(&$session)
+ function UpdateSession(&$session, $timeout=0)
{
- $query = sprintf( "UPDATE %sSessions SET expire = %s WHERE %s = %s",
- TABLE_PREFIX,
- $session->Expiration,
- 'sid',
- $session->SID);
+ $query = ' UPDATE '.$this->TableName.' SET '.$this->TimestampField.' = '.$session->Expiration.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
}
function LocateSession($sid)
{
- $query = sprintf( "SELECT expire FROM %sSessions WHERE %s = %s",
- TABLE_PREFIX,
- 'sid',
- $sid);
+ $query = ' SELECT '.$this->TimestampField.' FROM '.$this->TableName.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($sid);
$result = $this->Conn->GetOne($query);
+
if($result===false) return false;
$this->Expiration = $result;
return true;
}
function GetExpiration()
{
return $this->Expiration;
}
function LoadData(&$session)
{
- $query = sprintf( "SELECT value,name FROM %sSessionData WHERE %s = %s",
- TABLE_PREFIX,
- 'sid',
- $session->SID);
- $this->OriginalData = $this->Conn->GetCol($query,'name');
+ $query = 'SELECT '.$this->DataValueField.','.$this->DataVarField.' FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
+
+ $this->OriginalData = $this->Conn->GetCol($query, $this->DataVarField);
return $this->OriginalData;
}
+ /**
+ * Enter description here...
+ *
+ * @param Session $session
+ * @param string $var_name
+ */
+ function GetField(&$session, $var_name)
+ {
+ return $this->Conn->GetOne('SELECT '.$var_name.' FROM '.$this->TableName.' WHERE `'.$this->IDField.'` = '.$this->Conn->qstr($session->GetID()) );
+ }
+
function SaveData(&$session)
{
+ if(!$session->SID) return false; // can't save without sid
+
$ses_data = $session->Data->GetParams();
$replace = '';
foreach ($ses_data as $key => $value)
{
if ( isset($this->OriginalData[$key]) && $this->OriginalData[$key] == $value)
{
continue; //skip unchanged session data
}
else
{
$replace .= sprintf("(%s, %s, %s),",
- $session->SID,
+ $this->Conn->qstr($session->SID),
$this->Conn->qstr($key),
$this->Conn->qstr($value));
}
}
$replace = rtrim($replace, ',');
if ($replace != '') {
- $query = sprintf( 'REPLACE INTO %sSessionData (sid, name, value) VALUES %s',
- TABLE_PREFIX,
- $replace);
+ $query = ' REPLACE INTO '.$this->SessionDataTable. ' ('.$this->IDField.', '.$this->DataVarField.', '.$this->DataValueField.') VALUES '.$replace;
$this->Conn->Query($query);
}
}
function RemoveFromData(&$session, $var)
{
- $query = sprintf( "DELETE FROM %sSessionData WHERE %s = %s AND %s = %s",
- TABLE_PREFIX,
- 'sid',
- $session->SID,
- 'name',
- $this->Conn->qstr($var));
+ $query = 'DELETE FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID).
+ ' AND '.$this->DataVarField.' = '.$this->Conn->qstr($var);
$this->Conn->Query($query);
unset($this->OriginalData[$var]);
}
+
+ function GetExpiredSIDs()
+ {
+ $query = ' SELECT '.$this->IDField.' FROM '.$this->TableName.' WHERE '.$this->TimestampField.' > '.time();
+ return $this->Conn->GetCol($query);
+ }
+
+ function DeleteExpired()
+ {
+ $expired_sids = $this->GetExpiredSIDs();
+ if($expired_sids)
+ {
+ $where_clause=' WHERE '.$this->IDField.' IN ("'.implode('","',$expired_sids).'")';
+ $sql = 'DELETE FROM '.$this->SessionDataTable.$where_clause;
+ $this->Conn->Query($sql);
+
+ $sql = 'DELETE FROM '.$this->TableName.$where_clause;
+ $this->Conn->Query($sql);
+ }
+ return $expired_sids;
+ }
}
define('smAUTO', 1);
define('smCOOKIES_ONLY', 2);
define('smGET_ONLY', 3);
define('smCOOKIES_AND_GET', 4);
class Session extends kBase {
var $Checkers;
var $Mode;
var $GETName = 'sid';
var $CookiesEnabled = true;
var $CookieName = 'sid';
var $CookieDomain;
var $CookiePath;
var $CookieSecure = 0;
var $SessionTimeout = 3600;
var $Expiration;
var $SID;
var $Storage;
var $CachedNeedQueryString = null;
var $Data;
function Session($mode=smAUTO)
{
parent::kBase();
$this->SetMode($mode);
}
function SetMode($mode)
{
$this->Mode = $mode;
}
function SetCookiePath($path)
{
$this->CookiePath = $path;
}
function SetCookieDomain($domain)
{
$this->CookieDomain = $domain;
}
function SetGETName($get_name)
{
$this->GETName = $get_name;
}
function SetCookieName($cookie_name)
{
$this->CookieName = $cookie_name;
}
function InitStorage()
{
- $this->Storage =& new SessionStorage();
+ $this->Storage =& $this->Application->recallObject('SessionStorage');
+ $this->Storage->setSessionTimeout($this->SessionTimeout);
}
function Init($prefix,$special)
{
parent::Init($prefix,$special);
$this->CheckIfCookiesAreOn();
$this->Checkers = Array();
$this->InitStorage();
$this->Data =& new Params();
+
+ $tmp_sid = $this->GetPassedSIDValue();
+ $expired_sids = $this->DeleteExpired();
+ if( ( $expired_sids && in_array($tmp_sid,$expired_sids) ) || ( $tmp_sid && !$this->Check() ) )
+ {
+ $event = new kEvent();
+ $event->Init('login','');
+ $event->Name = 'OnSessionExpire';
+ $this->SID='';
+ $this->SetSessionCookie();
+ $this->Application->HandleEvent($event);
+ }
+
if ($this->Check()) {
$this->SID = $this->GetPassedSIDValue();
$this->Refresh();
$this->LoadData();
}
else {
$this->SetSession();
}
}
function CheckReferer()
{
$reg = '#^'.preg_quote(PROTOCOL.$this->CookieDomain.$this->CookiePath).'#';
return preg_match($reg, $_SERVER['HTTP_REFERER']);
}
function CheckIfCookiesAreOn()
{
- if ($this->Mode == smGET_ONLY) {
+ if ($this->Mode == smGET_ONLY || (defined('INPORTAL_ENV')&&INPORTAL_ENV && defined('ADMIN')&&ADMIN) )
+ {
//we don't need to bother checking if we would not use it
$this->CookiesEnabled = false;
return;
}
$http_query =& $this->Application->recallObject('HTTPQuery');
- $cookies_on = $http_query->Cookie['cookies_on']; // not good here
+ $cookies_on = isset($http_query->Cookie['cookies_on']); // not good here
if (!$cookies_on) {
//If referer is our server, but we don't have our cookies_on, it's definetly off
if ($this->CheckReferer()) {
$this->CookiesEnabled = false;
}
else {
//Otherwise we still suppose cookies are on, because may be it's the first time user visits the site
//So we send cookies on to get it next time (when referal will tell us if they are realy off
setcookie(
'cookies_on',
1,
time()+31104000, //one year should be enough
$this->CookiePath,
$this->CookieDomain,
$this->CookieSecure
);
}
}
else
$this->CookiesEnabled = true;
return $this->CookiesEnabled;
}
function Check()
{
// we should check referer if cookies are disabled, and in combined mode
// auto mode would detect cookies, get only mode would turn it off - so we would get here
// and we don't care about referal in cookies only mode
if ( $this->Mode != smCOOKIES_ONLY && (!$this->CookiesEnabled || $this->Mode == smCOOKIES_AND_GET) ) {
if (!$this->CheckReferer())
return false;
}
$sid = $this->GetPassedSIDValue();
if (empty($sid)) return false;
//try to load session by sid, if everything is fine
$result = $this->LoadSession($sid);
return $result;
}
function LoadSession($sid)
{
- if ($this->Storage->LocateSession($sid)) {
+ if( $this->Storage->LocateSession($sid) ) {
//if we have session with such SID - get its expiration
$this->Expiration = $this->Storage->GetExpiration();
//If session has expired
if ($this->Expiration < time()) return false;
//Otherwise it's ok
return true;
}
else //fake or deleted due to expiration SID
return false;
}
function GetPassedSIDValue($use_cache = 1)
{
if (!empty($this->CachedSID) && $use_cache) return $this->CachedSID;
$http_query =& $this->Application->recallObject('HTTPQuery');
$get_sid=$this->Application->GetVar($this->GETName);
switch ($this->Mode) {
case smAUTO:
//Cookies has the priority - we ignore everything else
- $sid=$this->CookiesEnabled?$http_query->Cookie[$this->CookieName]:$get_sid;
+ $sid=$this->CookiesEnabled ? getArrayValue($http_query->Cookie,$this->CookieName) : $get_sid;
break;
case smCOOKIES_ONLY:
$sid = $http_query->Cookie[$this->CookieName];
break;
case smGET_ONLY:
$sid = $get_sid;
break;
case smCOOKIES_AND_GET:
$cookie_sid = $http_query->Cookie[$this->CookieName];
//both sids should match if cookies are enabled
if (!$this->CookiesEnabled || ($cookie_sid == $get_sid))
{
$sid = $get_sid; //we use get here just in case cookies are disabled
}
else
{
$sid = '';
}
break;
}
$this->CachedSID = $sid;
return $this->CachedSID;
}
/**
* Returns session id
*
* @return int
* @access public
*/
function GetID()
{
return $this->SID;
}
/**
* Generates new session id
*
* @return int
* @access private
*/
function GenerateSID()
{
list($usec, $sec) = explode(" ",microtime());
$sid_part_1 = substr($usec, 4, 4);
$sid_part_2 = mt_rand(1,9);
$sid_part_3 = substr($sec, 6, 4);
$digit_one = substr($sid_part_1, 0, 1);
if ($digit_one == 0) {
$digit_one = mt_rand(1,9);
$sid_part_1 = ereg_replace("^0","",$sid_part_1);
$sid_part_1=$digit_one.$sid_part_1;
}
$this->setSID($sid_part_1.$sid_part_2.$sid_part_3);
return $this->SID;
}
/**
* Set's new session id
*
* @param int $new_sid
* @access private
*/
function setSID($new_sid)
{
$this->SID=$new_sid;
$this->Application->SetVar($this->GETName,$new_sid);
}
function SetSession()
{
$this->GenerateSID();
$this->Expiration = time() + $this->SessionTimeout;
switch ($this->Mode) {
case smAUTO:
if ($this->CookiesEnabled) {
$this->SetSessionCookie();
}
break;
case smGET_ONLY:
break;
case smCOOKIES_ONLY:
case smCOOKIES_AND_GET:
$this->SetSessionCookie();
break;
}
$this->Storage->StoreSession($this);
}
function SetSessionCookie()
{
setcookie(
$this->CookieName,
$this->SID,
$this->Expiration,
$this->CookiePath,
$this->CookieDomain,
$this->CookieSecure
);
}
/**
* Refreshes session expiration time
*
* @access private
*/
function Refresh()
{
if ($this->CookiesEnabled) $this->SetSessionCookie(); //we need to refresh the cookie
$this->Storage->UpdateSession($this);
}
function Destroy()
{
$this->Storage->DeleteSession($this);
$this->Data =& new Params();
$this->SID = '';
if ($this->CookiesEnabled) $this->SetSessionCookie(); //will remove the cookie due to value (sid) is empty
$this->SetSession(); //will create a new session
}
function NeedQueryString($use_cache = 1)
{
if ($this->CachedNeedQueryString != null && $use_cache) return $this->CachedNeedQueryString;
switch ($this->Mode) {
case smAUTO:
if ($this->CookiesEnabled) {
$res = 0;
}
else {
$res = 1;
}
break;
case smCOOKIES_ONLY:
break;
case smGET_ONLY:
case smCOOKIES_AND_GET:
$res = 1;
break;
}
$this->CachedNeedQueryString = $res;
return $res;
}
function LoadData()
{
$this->Data->AddParams($this->Storage->LoadData($this));
}
+ function PrintSession($comment='')
+ {
+ if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_SHOW_SESSIONDATA') )
+ {
+ global $debugger;
+ $debugger->appendHTML('SessionStorage ('.$comment.'):');
+ $session_data = $this->Data->GetParams();
+ ksort($session_data);
+ foreach($session_data as $session_key => $session_value)
+ {
+ if( preg_match('/a:([\d]+):{/',$session_value) )
+ {
+ $session_data[$session_key] = unserialize($session_value);
+ }
+ }
+ $debugger->dumpVars($session_data);
+
+ // to insert after HTTPQuery if it's visible
+ $new_row = dbg_ConstOn('DBG_SHOW_HTTPQUERY') ? 4 : 2;
+
+ //$debugger->moveAfterRow($new_row,2);
+ }
+ }
+
function SaveData()
{
+ $this->StoreVar('last_template', basename($_SERVER['PHP_SELF']).'|'.substr($this->Application->BuildEnv($this->Application->GetVar('t'), Array('m_opener' => 'u'), 'all', true), strlen(ENV_VAR_NAME)+1 ));
+ $this->PrintSession('after save');
$this->Storage->SaveData($this);
}
function StoreVar($name, $value)
{
$this->Data->Set($name, $value);
}
+ function StoreVarDefault($name, $value)
+ {
+ $tmp = $this->RecallVar($name);
+ if($tmp === false || $tmp == '')
+ {
+ $this->StoreVar($name, $value);
+ }
+ }
+
function RecallVar($name,$default=false)
{
- $ret=$this->Data->Get($name);
- return ($ret===false)?$default:$ret;
+ $ret = $this->Data->Get($name);
+ return ($ret===false) ? $default : $ret;
}
function RemoveVar($name)
{
$this->Storage->RemoveFromData($this, $name);
$this->Data->Remove($name);
}
+
+ function GetField($var_name)
+ {
+ return $this->Storage->GetField($this, $var_name);
+ }
+
+ /**
+ * Deletes expired sessions
+ *
+ * @return Array expired sids if any
+ * @access private
+ */
+ function DeleteExpired()
+ {
+ return $this->Storage->DeleteExpired();
+ }
+
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/session/session.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.3
\ No newline at end of property
+1.4
\ No newline at end of property
Index: trunk/core/kernel/session/login_event_handler.php
===================================================================
--- trunk/core/kernel/session/login_event_handler.php (nonexistent)
+++ trunk/core/kernel/session/login_event_handler.php (revision 1339)
@@ -0,0 +1,12 @@
+<?php
+
+ class LoginEventHandler extends kEventHandler
+ {
+ function OnSessionExpire()
+ {
+ $this->Application->Redirect('logout');
+ }
+ }
+
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/session/login_event_handler.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.2
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/utility/event.php
===================================================================
--- trunk/core/kernel/utility/event.php (revision 1338)
+++ trunk/core/kernel/utility/event.php (revision 1339)
@@ -1,146 +1,237 @@
<?php
- define('erFATAL',-1);
- define('erFAIL',-2);
+/**
+ * Event finished working succsessfully
+ *
+ */
define('erSUCCESS',0);
+
+/**
+ * Event finished working, but result is unsuccsessfull
+ *
+ */
+ define('erFAIL',-1);
+/**
+ * Event experienced FATAL error - no hooks should continue!
+ *
+ */
+ define('erFATAL',-2);
class kEvent extends kBase {
/**
* Event reference, that
* created this event
*
* @var kEvent
* @access public
*/
var $MasterEvent;
/**
* Event name
*
* @var string
* @access public
*/
var $Name;
/**
* Pseudo class name
*
* @var string
* @access public
*/
//var $Prefix;
/**
* Special, that is recognized
* by class with pseudo class
* equals to $Prefix attrbute.
*
* @var string
* @access public
*/
//var $Special;
/**
* Joined prefix and special,
* usually taken directly from
* tag beeing processes, to use
* in recallObject method
*
* @var string
*/
var $Prefix_Special;
/**
- * Stop event queue processing
- * after this event
+ * Do not execute Before hooks
+ * while processing main event
*
* @var bool
* @access public
*/
- var $cancelBubble=false;
+ var $SkipBeforeHooks=false;
+
+ /**
+ * Do not execute After hooks
+ * while processing main event
+ *
+ * @var bool
+ * @access public
+ */
+ var $SkipAfterHooks=false;
/**
* Redirect is allowed after
* this event
*
* @var bool
* @access public
*/
var $redirect=false;
+
+
+ /**
+ * Params passed to redirect on succsessfull event
+ *
+ * @var bool
+ * @access public
+ */
+ var $redirect_params=null;
/**
+ * php file to redirect to
+ *
+ * @var string
+ * @access public
+ */
+ var $redirect_script=null;
+
+ /**
* Event processing result
*
* @var int
* @access public
*/
var $status=erSUCCESS;
/**
* Each event specific only params,
* that they use for communication
*
* @var Array
* @access public
*/
var $specificParams=Array();
/**
* Pseudo class used to create object,
* in case if one is not already created
*
* @var string
* @access public
*/
var $pseudoClass='';
+ /**
+ * Create event based on params passed
+ *
+ * @param Array $params
+ * @return kEvent
+ * @access public
+ */
+ function kEvent($params=Array())
+ {
+ parent::kBase();
+ if($params)
+ {
+ $prefix = getArrayValue($params,'prefix');
+ $special = getArrayValue($params,'special');
+ if($prefix) $this->Init($prefix,$special);
+ $this->Name = getArrayValue($params,'name');
+ }
+ }
+
function setEventParam($name,$value)
{
$this->specificParams[$name]=$value;
}
function getEventParam($name)
{
- return isset($this->specificParams[$name])?$this->specificParams[$name]:false;
+ return getArrayValue($this->specificParams, $name);
}
function getPrefixSpecial($from_submit=false)
{
$separator=!$from_submit?'.':'_';
$ret=$this->Prefix.$separator.$this->Special;
return rtrim($ret,$separator);
}
/**
* Set's pseudo class that differs from
* the one specified in $Prefix
*
* @param string $appendix
* @access public
*/
function setPseudoClass($appendix)
{
$this->pseudoClass=$this->Prefix.$appendix;
}
- function Init($prefix,$special)
+ function Init($prefix,$special='')
{
$this->Prefix=$prefix;
$this->pseudoClass=$prefix; // default value
$this->Special=$special;
$this->Prefix_Special = rtrim($this->Prefix.'.'.$this->Special,'.');
}
/**
* Returns object used in event
*
* @access public
+ * @return kDBBase
*/
- function &createObject()
+ function &getObject()
+ {
+ return $this->Application->recallObject($this->Prefix_Special,$this->pseudoClass);
+ }
+
+ /**
+ * Calls passed event by name in current prefix/special environment
+ * Called event gets this event as MasterEvent,
+ * but its results (status and redirect* properties are copied back to current event)
+ *
+ * @param string $name EventName to call
+ */
+ function CallSubEvent($name)
+ {
+ $child_event = new kEvent();
+ $child_event->MasterEvent =& $this;
+ $child_event->Prefix = $this->Prefix;
+ $child_event->Special = $this->Special;
+ $child_event->Prefix_Special = $this->Prefix_Special;
+ $child_event->redirect = $this->redirect;
+ $child_event->redirect_params = $this->redirect_params;
+ $child_event->redirect_script = $this->redirect_script;
+ $child_event->Name = $name;
+
+ $this->Application->HandleEvent( $child_event );
+
+ $this->status = $child_event->status;
+ $this->redirect = $child_event->redirect;
+ $this->redirect_params = $child_event->redirect_params;
+ $this->redirect_script = $child_event->redirect_script;
+ }
+
+ function SetRedirectParam($name, $value)
{
- return $this->Application->recallObject($this->Prefix_Special,$this->pseudoClass);
+ $this->redirect_params = array_merge_recursive2( $this->redirect_params, Array($name => $value) );
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/event.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
\ No newline at end of property
+1.3
\ No newline at end of property
Index: trunk/core/kernel/utility/temp_handler.php
===================================================================
--- trunk/core/kernel/utility/temp_handler.php (nonexistent)
+++ trunk/core/kernel/utility/temp_handler.php (revision 1339)
@@ -0,0 +1,546 @@
+<?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();
+
+ /**
+ * Description
+ *
+ * @var DBConnection
+ * @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)
+ {
+ return TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_'.$table;
+ }
+
+ /**
+ * 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->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'),
+ );
+
+ $SubItems = $this->Application->getUnitOption($prefix,'SubItems');
+ 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;
+ $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';
+ $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
+ $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.'
+ 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;
+ $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;
+ $object->Delete($id);
+
+ 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.'
+ 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 :)
+ $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.')';
+ $this->Conn->Query($query);
+
+ $query = 'SELECT '.$master['IdField'].' FROM '.$master['TableName'].'
+ WHERE '.$key_field.' IN ('.$ids.')';
+
+ $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'].'
+ 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']);
+ $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
+ 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']).'
+ 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);
+
+ //delete already copied record from master temp table
+ $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
+
+ $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';
+ $this->Conn->Query($query);
+
+ // copy ALL records to live table
+ $query = 'INSERT INTO '.$master['TableName'].'
+ SELECT * FROM '.$this->GetTempName($master['TableName']);
+ $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) {
+ 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.'
+ 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).')';
+
+ $this->RaiseEvent( 'OnBeforeDeleteFromLive', $sub_table['Prefix'], $this->Conn->GetCol($query) );
+
+ $query = 'DELETE FROM '.$sub_table['TableName'].'
+ WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
+ $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)
+ {
+ $query = sprintf("DROP TABLE IF EXISTS %s",
+ $this->GetTempName($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
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.2
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/utility/params.php
===================================================================
--- trunk/core/kernel/utility/params.php (revision 1338)
+++ trunk/core/kernel/utility/params.php (revision 1339)
@@ -1,171 +1,206 @@
<?php
define ('FALSE_ON_NULL', 1);
define ('EMPTY_ON_NULL', 2);
class Params extends kBase {
var $_Params = Array();
function Params($params_str=null)
{
parent::kBase();
if($params_str != '') $this->SplitParamsStr($params_str);
}
/**
* Splits tag params into associative array
*
* @param string $params_str
* @access private
*/
function SplitParamsStr($params_str)
{
preg_match_all("/([a-zA-Z0-9_.]+)=([\"']{1,1})(.*?)(?<!\\\)\\2/", $params_str, $rets, PREG_SET_ORDER);
$values = Array();
foreach ($rets AS $key => $val){
$values[$val[1]] = str_replace('\\' . $val[2], $val[2], $val[3]);
}
$this->AddParams($values);
}
/**
* Sets new parameter value
*
* @param string $name
* @param string $val
* @access public
*/
function Set($name, $val)
{
//echo "sessing params: [$name] = [$val] (class: <b>".get_class($this)."</b>)<br>";
- $this->_Params[strtolower($name)] = $val;
+// $this->_Params[strtolower($name)] = $val;
+ $this->_Params[$name] = $val;
}
/**
* Removes parameter
*
* @param string $name
* @access public
*/
function Remove($name)
{
unset($this->_Params[$name]);
}
/**
* Gets parameter value by parameter name
*
* @param string $name
* @param int $mode
* @return string
* @access public
*/
function Get($name, $mode=FALSE_ON_NULL)
{
// echo " name : '$name' || mode : $mode <br> ";
- $name = strtolower($name);
+ //$name = strtolower($name);
if (array_key_exists($name, $this->_Params))
return $this->_Params[$name];
else
return $mode == FALSE_ON_NULL ? false : '';
}
/**
* Mass parameter setting from hash
*
* @param Array $params
* @access public
*/
function AddParams($params)
{
if (!is_array($params)) return;
/*if (count($this->_Params) == 0) {
$this->_Params = $params;
}
else {*/
foreach ($params as $name => $val)
- $this->Set(strtolower($name), $val);
+// $this->Set(strtolower($name), $val);
+ $this->Set($name, $val);
//}
}
/**
* Return all paramters as hash
*
* @return Array
* @access public
*/
function GetParams()
{
return $this->_Params;
}
}
+class kArray extends kBase {
+ var $_Array;
+
+ /**
+ * Returns array value with any deep key
+ *
+ * @return mixed
+ * @todo array_unshift doesn't accept parameters by reference, fix it's usage in this method
+ */
+ function GetArrayValue()
+ {
+ $args = func_get_args();
+ array_unshift($args, &$this->_Array);
+ return call_user_func_array('getArrayValue', $args);
+ }
+
+ function SetArrayValue()
+ {
+ $args = func_get_args();
+ $value = array_pop($args);
+
+ $arr =& $this->_Array;
+ for ($i=0; $i<count($args); $i++) {
+ $key = $args[$i];
+ if ( !isset($arr[$key]) || !is_array($arr[$key]) ) {
+ $arr[$key] = Array();
+ }
+ $arr =& $arr[$key];
+ }
+ $arr = $value;
+ }
+}
+
/*class RefParams extends Params {
function Set($name, &$val)
{
$this->_Params[$name] =& $val;
}
function &Get($name)
{
if (isset($this->_Params[$name]))
return $this->_Params[$name];
else
return false;
}
}*/
// ################### TESTS ############################
global $suite;
if (isset($suite)) {
class TestParams extends TestCase {
function testParamsOperations()
{
$params =& new Params();
$params->Set('test_var', 24);
$this->AssertEquals(24, $params->Get('test_var'));
$this->AssertFalse($params->Get('none_existant_param'));
$res = $params->GetParams();
$this->AssertEquals(24, $res['test_var']);
}
function testSplitParams()
{
$params =& new Params('test_param="abc" another_param="7"');
$this->AssertEquals('abc', $params->Get('test_param'));
$this->AssertEquals('7', $params->Get('another_param'));
}
}
$suite->addTest(new TestSuite("TestParams"));
}
/*
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
//echo "Usec: $usec, sec: $sec<br>";
return ((float)$usec + (float)$sec);
}
$total = 0;
$params =& new MyParams();
$param_str = "param1=\"1\" param2='atessafa \'sdf'
params3=\"asd ' \\\"f\"";
$param_str = "m:test escape1='-\"-' \t\t \n \t\n escape2=\"+\\\"+\" \n escape3='*\'*' escape4='=\='";
//3852
for ($i=0; $i<1; $i++)
{
$start = getmicrotime();
$params->SplitParamsStr($param_str);
$end = getmicrotime();
$total += $end-$start;
}
printf ("total: %.8f; average: %.8f <br>", $total, $total/100);
*/
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/params.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
\ No newline at end of property
+1.3
\ No newline at end of property
Index: trunk/core/kernel/utility/debugger.php
===================================================================
--- trunk/core/kernel/utility/debugger.php (revision 1338)
+++ trunk/core/kernel/utility/debugger.php (revision 1339)
@@ -1,798 +1,893 @@
<?php
-
- if(!defined('DBG_OPTIONS')) define('DBG_OPTIONS',0);
-
- if(!defined('DBG_USE_HIGHLIGHT')) define('DBG_USE_HIGHLIGHT',1);
-
- if(!defined('DBG_USE_SHUTDOWN_FUNC')) define('DBG_USE_SHUTDOWN_FUNC',1);
- if(!defined('DBG_HANDLE_ERRORS')) define('DBG_HANDLE_ERRORS', isset($_REQUEST['debug_host']) ? 0 : 1);
-
- if(!defined('DBG_RAISE_ON_WARNINGS')) define('DBG_RAISE_ON_WARNINGS',0);
- if(!defined('DBG_SHOW_MEMORY_USAGE')) define('DBG_SHOW_MEMORY_USAGE',1);
-
- if(!defined('DOC_ROOT')) define('DOC_ROOT',$_SERVER['DOCUMENT_ROOT']);
- if(!defined('WINDOWS_ROOT')) define('WINDOWS_ROOT','w:');
-
- if(!defined('WINDOWS_EDITOR'))
- {
- $dbg_editor = 0;
- $dbg_editors[0] = Array('editor' => 'c:\Program Files\UltraEdit\uedit32.exe', 'params' => '%F/%L');
- $dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-4.0Beta\bin\ZDE.exe', 'params' => '%F');
- define('WINDOWS_EDITOR',$dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']);
- unset($dbg_editors,$dbg_editor);
- }
-
- class Debugger
+
+ if(!class_exists('Debugger'))
{
- /**
- * Debugger data for building report
- *
- * @var Array
- */
- var $Data = Array();
- var $ProfilerData = Array();
- var $RecursionStack = Array(); // prevent recursion when processing debug_backtrace() function results
-
- var $TraceNextError=false;
-
- var $Options = 0;
- var $OptionsMap = Array('shutdown_func' => 1, 'error_handler' => 2,
- 'output_buffer' => 4, 'highlight_output' => 8);
-
-
- var $longErrors=Array();
-
- /**
- * Amount of memory used by debugger itself
- *
- * @var Array
- * @access private
- */
- var $memoryUsage=Array();
-
- function Debugger()
+ function dbg_ConstOn($const_name)
{
- $this->memoryUsage['error_handling']=0; // memory amount used by error handler
- $this->appendRequest();
+ return defined($const_name)&&constant($const_name);
}
- function initOptions()
+ function dbg_safeDefine($const_name,$const_value)
{
-
+ if(!defined($const_name)) define($const_name,$const_value);
}
- function mapLongError($msg)
- {
- $key=$this->generateID();
- $this->longErrors[$key]=$msg;
- return $key;
- }
+ unset($_REQUEST['debug_host']); // this var messed up whole detection stuff :(
- function setOption($name,$value)
+ // Detect fact, that this session beeing debugged by Zend Studio
+ foreach($_REQUEST as $rq_name=>$rq_value)
{
- if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>');
- if($value)
+ if( substr($rq_name,0,6)=='debug_' )
{
- $this->Options|=$this->OptionsMap[$name];
- }
- else
- {
- $this->Options=$this->Options&~$this->OptionsMap[$name];
- }
+ define('DBG_ZEND_PRESENT',1);
+ break;
+ }
}
- function getOption($name)
- {
- if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>');
- return ($this->Options & $this->OptionsMap[$name]) == $this->OptionsMap[$name];
- }
+ dbg_safeDefine('DBG_ZEND_PRESENT',0);
+
+ // set default values for debugger constants
+ $dbg_constMap=Array('DBG_OPTIONS'=>0,
+ 'DBG_USE_HIGHLIGHT'=>1,
+ 'DBG_USE_SHUTDOWN_FUNC'=>DBG_ZEND_PRESENT?0:1,
+ 'DBG_HANDLE_ERRORS'=>DBG_ZEND_PRESENT?0:1,
+ 'DBG_SHOW_MEMORY_USAGE'=>1,
+ 'DBG_IGNORE_STRICT_ERRORS'=>1,
+ 'DOC_ROOT'=>$_SERVER['DOCUMENT_ROOT'],
+ 'DBG_LOCAL_BASE_PATH'=>'w:');
- /**
- * Set's flag, that next error that occurs will
- * be prepended by backtrace results
- *
- */
- function traceNext()
+ foreach($dbg_constMap as $dbg_constName=>$dbg_constValue)
{
- $this->TraceNextError=true;
+ dbg_safeDefine($dbg_constName,$dbg_constValue);
}
- function dumpVars()
+ // only for IE, in case if no windows php script editor defined
+ /*if(!defined('WINDOWS_EDITOR'))
{
- $dumpVars = func_get_args();
- foreach($dumpVars as $varValue)
+ $dbg_editor = 0;
+ $dbg_editors[0] = Array('editor' => 'c:\Program Files\UltraEdit\uedit32.exe', 'params' => '%F/%L');
+ $dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-4.0Beta\bin\ZDE.exe', 'params' => '%F');
+ define('WINDOWS_EDITOR',$dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']);
+ unset($dbg_editors,$dbg_editor);
+ }*/
+
+ class Debugger
+ {
+ /**
+ * Debugger data for building report
+ *
+ * @var Array
+ */
+ var $Data = Array();
+ var $ProfilerData = Array();
+ var $RecursionStack = Array(); // prevent recursion when processing debug_backtrace() function results
+
+ var $TraceNextError=false;
+
+ var $Options = 0;
+ var $OptionsMap = Array('shutdown_func' => 1, 'error_handler' => 2,
+ 'output_buffer' => 4, 'highlight_output' => 8);
+
+
+ var $longErrors=Array();
+
+ /**
+ * Amount of memory used by debugger itself
+ *
+ * @var Array
+ * @access private
+ */
+ var $memoryUsage=Array();
+
+ var $IncludesData=Array();
+ var $IncludeLevel=0;
+
+ function Debugger()
{
- $this->Data[] = Array('value' => $varValue, 'debug_type' => 'var_dump');
+ $this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4');
+ ini_set('display_errors',dbg_ConstOn('DBG_ZEND_PRESENT')?0:1);
+ $this->memoryUsage['error_handling']=0; // memory amount used by error handler
+ $this->appendRequest();
}
- }
-
- function prepareHTML($dataIndex)
- {
- $Data =& $this->Data[$dataIndex];
- if($Data['debug_type'] == 'html') return $Data['html'];
- switch($Data['debug_type'])
+ function initOptions()
{
- case 'error':
- $fileLink = $this->getFileLink($Data['file'],$Data['line']);
- $ret = '<b class="debug_error">'.$this->getErrorNameByCode($Data['no']).'</b>: '.$Data['str'];
- $ret .= ' in <b>'.$fileLink.'</b> on line <b>'.$Data['line'].'</b>';
- return $ret;
- break;
-
- case 'var_dump':
- $ret = $this->highlightString( print_r($Data['value'], true) );
- return addslashes($ret);
- break;
-
- case 'trace':
- ini_set('memory_limit','500M');
- $trace =& $Data['trace'];
-
- //return 'sorry';
- //return $this->highlightString(print_r($trace,true));
-
-
- $i = 0; $traceCount = count($trace);
- $ret = '';
- while($i < $traceCount)
- {
- $traceRec =& $trace[$i];
- $argsID = 'trace_args_'.$dataIndex.'_'.$i;
- if(isset($traceRec['file']))
- {
- $func_name=isset($traceRec['class'])?$traceRec['class'].$traceRec['type'].$traceRec['function']:$traceRec['function'];
- $ret .= '<a href="javascript:toggleTraceArgs(\''.$argsID.'\');" title="Show/Hide Function Arguments"><b>Function</b></a>: '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name);
- $ret .= ' in <b>'.basename($traceRec['file']).'</b> on line <b>'.$traceRec['line'].'</b><br>';
- }
- else
- {
- $ret .= 'no file information available';
- }
-
- // ensure parameter value is not longer then 200 symbols
- $this->processTraceArguments($traceRec['args']);
- $args = $this->highlightString(print_r($traceRec['args'], true));
- $ret .= '<div id="'.$argsID.'" style="display: none;">'.$args.'</div>';
- $i++;
- }
- return $ret;
- break;
- case 'profiler':
- $profileKey = $Data['profile_key'];
- $Data =& $this->ProfilerData[$profileKey];
- $runtime = ($Data['ends'] - $Data['begins']); // in seconds
- return '<b>Name</b>: '.$Data['description'].'<br><b>Runtime</b>: '.$runtime.'s';
- break;
-
- default:
- return 'incorrect debug data';
- break;
}
- }
-
- function processTraceArguments(&$traceArgs)
- {
- if(!$traceArgs) return '';
- foreach ($traceArgs as $argID => $argValue)
+
+ function mapLongError($msg)
{
- if( is_array($argValue) || is_object($argValue) )
+ $key=$this->generateID();
+ $this->longErrors[$key]=$msg;
+ return $key;
+ }
+
+ function setOption($name,$value)
+ {
+ if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>');
+ if($value)
{
- if(is_object($argValue) && !in_array(get_class($argValue),$this->RecursionStack) )
- {
- // object & not in stack - ok
- array_push($this->RecursionStack, get_class($argValue));
- settype($argValue,'array');
- $this->processTraceArguments($argValue);
- array_pop($this->RecursionStack);
- }
- elseif(is_object($argValue) && in_array(get_class($argValue),$this->RecursionStack) )
- {
- // object & in stack - recursion
- $traceArgs[$argID] = '**** RECURSION ***';
- }
- else
- {
- // normal array here
- $this->processTraceArguments($argValue);
- }
+ $this->Options|=$this->OptionsMap[$name];
}
else
{
- $traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]);
+ $this->Options=$this->Options&~$this->OptionsMap[$name];
}
}
- }
-
- function cutStringForHTML($string)
- {
- if( strlen($string) > 200 ) $string = substr($string,0,50).' ...';
- return $string;
- }
-
- /**
- * Format SQL Query using predefined formatting
- * and highlighting techniques
- *
- * @param string $sql
- * @return string
- */
- function formatSQL($sql)
- {
- $sql = preg_replace('/(\n|\t| )+/is',' ',$sql);
- $sql = preg_replace('/(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY) /is', "\n\t$1 ",$sql);
- return $this->highlightString($sql);
- }
-
- function highlightString($string)
- {
- if( defined('DBG_USE_HIGHLIGHT')&&DBG_USE_HIGHLIGHT )
- {
- $string = highlight_string('<?php '.$string.'?>', true);
- return preg_replace('/&lt;\?(.*)php (.*)\?&gt;/s','$2',$string);
- }
- else
+
+ function getOption($name)
{
- return $string;
+ if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>');
+ return ($this->Options & $this->OptionsMap[$name]) == $this->OptionsMap[$name];
}
- }
-
- function getFileLink($file, $lineno = 1, $title = '')
- {
- if(!$title) $title = $file;
- $is_mozilla=strpos(strtolower($_SERVER['HTTP_USER_AGENT']),'firefox')!==false?true:false;
- if($is_mozilla)
+
+ /**
+ * Set's flag, that next error that occurs will
+ * be prepended by backtrace results
+ *
+ */
+ function traceNext()
{
- return '<a href="file://'.$this->getLocalFile($file).'">'.$title.'</a>';
+ $this->TraceNextError=true;
}
- else
+
+ function dumpVars()
{
- return '<a href="javascript:editFile(\''.$this->getLocalFile($file).'\','.$lineno.');" title="'.$file.'">'.$title.'</a>';
+ $dumpVars = func_get_args();
+ foreach($dumpVars as $varValue)
+ {
+ $this->Data[] = Array('value' => $varValue, 'debug_type' => 'var_dump');
+ }
}
- }
-
- function getLocalFile($remoteFile)
- {
- return str_replace(DOC_ROOT, WINDOWS_ROOT, $remoteFile);
- }
-
- function appendTrace()
- {
- $trace = debug_backtrace();
- array_shift($trace);
- $this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace');
- }
-
- function appendHTML($html)
- {
- $this->Data[] = Array('html' => $html,'debug_type' => 'html');
- }
-
- /**
- * Change debugger info that was already generated before.
- * Returns true if html was set.
- *
- * @param int $index
- * @param string $html
- * @param string $type = {'append','prepend','replace'}
- * @return bool
- */
- function setHTMLByIndex($index,$html,$type='append')
- {
- if( !isset($this->Data[$index]) || $this->Data[$index]['debug_type'] != 'html' )
+ function prepareHTML($dataIndex)
{
- return false;
+ $Data =& $this->Data[$dataIndex];
+ if($Data['debug_type'] == 'html') return $Data['html'];
+
+ switch($Data['debug_type'])
+ {
+ case 'error':
+ $fileLink = $this->getFileLink($Data['file'],$Data['line']);
+ $ret = '<b class="debug_error">'.$this->getErrorNameByCode($Data['no']).'</b>: '.$Data['str'];
+ $ret .= ' in <b>'.$fileLink.'</b> on line <b>'.$Data['line'].'</b>';
+ return $ret;
+ break;
+
+ case 'var_dump':
+ return $this->highlightString( print_r($Data['value'], true) );
+ break;
+
+ case 'trace':
+ ini_set('memory_limit','500M');
+ $trace =& $Data['trace'];
+
+ //return 'sorry';
+ //return $this->highlightString(print_r($trace,true));
+
+
+ $i = 0; $traceCount = count($trace);
+ $ret = '';
+ while($i < $traceCount)
+ {
+ $traceRec =& $trace[$i];
+ $argsID = 'trace_args_'.$dataIndex.'_'.$i;
+ if(isset($traceRec['file']))
+ {
+ $func_name=isset($traceRec['class'])?$traceRec['class'].$traceRec['type'].$traceRec['function']:$traceRec['function'];
+ $ret .= '<a href="javascript:toggleTraceArgs(\''.$argsID.'\');" title="Show/Hide Function Arguments"><b>Function</b></a>: '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name);
+ $ret .= ' in <b>'.basename($traceRec['file']).'</b> on line <b>'.$traceRec['line'].'</b><br>';
+ }
+ else
+ {
+ $ret .= 'no file information available';
+ }
+
+ // ensure parameter value is not longer then 200 symbols
+ $this->processTraceArguments($traceRec['args']);
+ $args = $this->highlightString(print_r($traceRec['args'], true));
+ $ret .= '<div id="'.$argsID.'" style="display: none;">'.$args.'</div>';
+ $i++;
+ }
+ return $ret;
+ break;
+
+ case 'profiler':
+ $profileKey = $Data['profile_key'];
+ $Data =& $this->ProfilerData[$profileKey];
+ $runtime = ($Data['ends'] - $Data['begins']); // in seconds
+ return '<b>Name</b>: '.$Data['description'].'<br><b>Runtime</b>: '.$runtime.'s';
+ break;
+
+ default:
+ return 'incorrect debug data';
+ break;
+ }
}
- switch ($type)
+ function processTraceArguments(&$traceArgs)
{
- case 'append':
- $this->Data[$index]['html'] .= '<br>'.$html;
- break;
- case 'prepend':
- $this->Data[$index]['html'] = $this->Data[$index]['html'].'<br>'.$html;
- break;
- case 'replace':
- $this->Data[$index]['html'] = $html;
- break;
- }
- return true;
- }
-
- /**
- * Move $debugLineCount lines of input from debug output
- * end to beginning.
- *
- * @param int $debugLineCount
- */
- function moveToBegin($debugLineCount)
- {
- $lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
- $this->Data = array_merge($lines,$this->Data);
- }
-
- function appendRequest()
- {
- $script = $_SERVER['PATH_TRANSLATED'];
- $this->appendHTML('ScriptName: <b>'.$this->getFileLink($script,1,basename($script)).'</b> (<b>'.dirname($script).'</b>)');
- ob_start();
- ?>
- <table width="100%" border="0" cellspacing="0" cellpadding="4" class="flat_table">
- <thead style="font-weight: bold;">
- <td width="20">Src</td><td>Name</td><td>Value</td>
- </thead>
- <?php
- foreach($_REQUEST as $key => $value)
+ if(!$traceArgs) return '';
+ foreach ($traceArgs as $argID => $argValue)
{
- if( !is_array($value) && trim($value) == '' )
+ if( is_array($argValue) || is_object($argValue) )
{
- $value = '<b class="debug_error">no value</b>';
+ if(is_object($argValue) && !in_array(get_class($argValue),$this->RecursionStack) )
+ {
+ // object & not in stack - ok
+ array_push($this->RecursionStack, get_class($argValue));
+ settype($argValue,'array');
+ $this->processTraceArguments($argValue);
+ array_pop($this->RecursionStack);
+ }
+ elseif(is_object($argValue) && in_array(get_class($argValue),$this->RecursionStack) )
+ {
+ // object & in stack - recursion
+ $traceArgs[$argID] = '**** RECURSION ***';
+ }
+ else
+ {
+ // normal array here
+ $this->processTraceArguments($argValue);
+ }
}
else
{
- $value = htmlspecialchars(print_r($value, true));
+ $traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]);
}
- $src = isset($_GET[$key]) ? 'GE' : (isset($_POST[$key]) ? 'PO' : (isset($_COOKIE[$key]) ? 'CO' : '?') );
- echo '<tr><td>'.$src.'</td><td>'.$key.'</td><td>'.$value.'</td></tr>';
}
- ?>
- </table>
- <?php
- $this->appendHTML( ob_get_contents() );
- ob_end_clean();
- }
-
- function appendSession()
- {
- if( isset($_SESSION)&&$_SESSION )
+ }
+
+ function cutStringForHTML($string)
{
- $this->appendHTML('PHP Session: [<b>'.ini_get('session.name').'</b>]');
- $this->dumpVars($_SESSION);
- $this->moveToBegin(2);
- }
- }
-
- function profileStart($key, $description)
- {
- $timeStamp = $this->getMoment();
- $this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data), 'description' => $description);
- $this->Data[] = array('profile_key' => $key, 'debug_type' => 'profiler');
- }
-
- function profileFinish($key)
- {
- $this->ProfilerData[$key]['ends'] = $this->getMoment();
- }
-
- function getMoment()
- {
- list($usec, $sec) = explode(' ', microtime());
- return ((float)$usec + (float)$sec);
- }
-
- function generateID()
- {
- list($usec, $sec) = explode(" ",microtime());
-
- $id_part_1 = substr($usec, 4, 4);
- $id_part_2 = mt_rand(1,9);
- $id_part_3 = substr($sec, 6, 4);
- $digit_one = substr($id_part_1, 0, 1);
- if ($digit_one == 0) {
- $digit_one = mt_rand(1,9);
- $id_part_1 = ereg_replace("^0","",$id_part_1);
- $id_part_1=$digit_one.$id_part_1;
+ if( strlen($string) > 200 ) $string = substr($string,0,50).' ...';
+ return $string;
}
- return $id_part_1.$id_part_2.$id_part_3;
- }
-
-
- function getErrorNameByCode($errorCode)
- {
- switch($errorCode)
+
+ /**
+ * Format SQL Query using predefined formatting
+ * and highlighting techniques
+ *
+ * @param string $sql
+ * @return string
+ */
+ function formatSQL($sql)
+ {
+ $sql = preg_replace('/(\n|\t| )+/is',' ',$sql);
+ $sql = preg_replace('/(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY) /is', "\n\t$1 ",$sql);
+ return $this->highlightString($sql);
+ }
+
+ function highlightString($string)
{
- case E_USER_ERROR:
- return 'Fatal Error';
- break;
-
- case E_WARNING:
- case E_USER_WARNING:
- return 'Warning';
- break;
-
- case E_NOTICE:
- case E_USER_NOTICE:
- return 'Notice';
- break;
+ if( dbg_ConstOn('DBG_USE_HIGHLIGHT') )
+ {
+ $string = str_replace('\\','_no_match_string_',$string);
+ $string = highlight_string('<?php '.$string.'?>', true);
+ $string = str_replace('_no_match_string_','\\',$string);
+ return preg_replace('/&lt;\?(.*)php (.*)\?&gt;/s','$2',$string);
+ }
+ else
+ {
+ return $string;
+ }
+ }
+
+ function getFileLink($file, $lineno = 1, $title = '')
+ {
+ if(!$title) $title = $file;
+ $is_mozilla=strpos(strtolower($_SERVER['HTTP_USER_AGENT']),'firefox')!==false?true:false;
+ if($is_mozilla)
+ {
+ return '<a href="file://'.$this->getLocalFile($file).'">'.$title.'</a>';
+ }
+ else
+ {
+ return '<a href="javascript:editFile(\''.$this->getLocalFile($file).'\','.$lineno.');" title="'.$file.'">'.$title.'</a>';
+ }
- default:
- return '';
- break;
}
- }
-
- /**
- * Generates report
- *
- */
- function printReport($returnResult = false)
- {
- $this->memoryUsage['debugger_start']=memory_get_usage();
- // show php session if any
- $this->appendSession();
+ function getLocalFile($remoteFile)
+ {
+ return str_replace(DOC_ROOT, DBG_LOCAL_BASE_PATH, $remoteFile);
+ }
- // ensure, that 1st line of debug output always is this one:
- $this->appendHTML('<a href="javascript:toggleDebugLayer(27);">Hide Debugger</a>');
- $this->moveToBegin(1);
-
- $i = 0; $lineCount = count($this->Data);
- ob_start();
- ?>
- <style type="text/css">
- .flat_table TD {
- border: 1px solid buttonface;
- border-width: 1 1 0 0;
-
- }
-
- .debug_layer_table {
- border-collapse: collapse;
- width: 480px;
- }
-
- .debug_text, .debug_row_even TD, .debug_row_odd TD {
- color: #000000;
- font-family: Verdana;
- font-size: 11px;
- word-wrap: break-word;
- }
-
- .debug_cell {
- border: 1px solid #FF0000;
- padding: 2px;
- word-wrap: break-word;
- }
-
- .debug_row_even {
- background-color: #CCCCFF;
- }
-
- .debug_row_odd {
- background-color: #FFFFCC;
- }
-
- .debug_layer_container {
- left: 2px;
- top: 1px;
- width: 500px;
- z-index: +1000;
- position: absolute;
- overflow: auto;
- border: 2px solid;
- padding: 3px;
- border-top-color: threedlightshadow;
- border-left-color: threedlightshadow;
- border-right-color: threeddarkshadow;
- border-bottom-color: threeddarkshadow;
- background-color: buttonface;
- }
-
- .debug_layer {
- padding: 0px;
- width: 480px;
- }
-
- .debug_error {
- color: #FF0000;
- }
- </style>
- <div id="debug_layer" class="debug_layer_container" style="display: none;">
- <div class="debug_layer">
- <table width="100%" cellpadding="0" cellspacing="1" border="0" class="debug_layer_table">
- <?php
- while ($i < $lineCount)
+ function appendTrace()
{
- echo '<tr class="debug_row_'.(($i % 2) ? 'odd' : 'even').'"><td class="debug_cell">'.$this->prepareHTML($i).'</td></tr>';
- $i++;
+ $trace = debug_backtrace();
+ array_shift($trace);
+ $this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace');
}
- ?>
- </table>
- </div>
- </div>
- <script language="javascript">
- function getEventKeyCode($e)
- {
- var $KeyCode = 0;
- if($e.keyCode) $KeyCode = $e.keyCode;
- else if($e.which) $KeyCode = $e.which;
- return $KeyCode;
- }
+
+ function appendHTML($html)
+ {
+ $this->Data[] = Array('html' => $html,'debug_type' => 'html');
+ }
+
+ /**
+ * Change debugger info that was already generated before.
+ * Returns true if html was set.
+ *
+ * @param int $index
+ * @param string $html
+ * @param string $type = {'append','prepend','replace'}
+ * @return bool
+ */
+ function setHTMLByIndex($index,$html,$type='append')
+ {
+ if( !isset($this->Data[$index]) || $this->Data[$index]['debug_type'] != 'html' )
+ {
+ return false;
+ }
- function keyProcessor($e)
+ switch ($type)
+ {
+ case 'append':
+ $this->Data[$index]['html'] .= '<br>'.$html;
+ break;
+ case 'prepend':
+ $this->Data[$index]['html'] = $this->Data[$index]['html'].'<br>'.$html;
+ break;
+ case 'replace':
+ $this->Data[$index]['html'] = $html;
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Move $debugLineCount lines of input from debug output
+ * end to beginning.
+ *
+ * @param int $debugLineCount
+ */
+ function moveToBegin($debugLineCount)
+ {
+ $lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
+ $this->Data = array_merge($lines,$this->Data);
+ }
+
+ function moveAfterRow($new_row, $debugLineCount)
+ {
+ $lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
+ $rows_before = array_splice($this->Data,0,$new_row,$lines);
+ $this->Data = array_merge($rows_before,$this->Data);
+ }
+
+ function appendRequest()
+ {
+ $script = $_SERVER['PATH_TRANSLATED'];
+ $this->appendHTML('ScriptName: <b>'.$this->getFileLink($script,1,basename($script)).'</b> (<b>'.dirname($script).'</b>)');
+ ob_start();
+ ?>
+ <table width="100%" border="0" cellspacing="0" cellpadding="4" class="dbg_flat_table">
+ <thead style="font-weight: bold;">
+ <td width="20">Src</td><td>Name</td><td>Value</td>
+ </thead>
+ <?php
+ foreach($_REQUEST as $key => $value)
{
- if(!$e) $e = window.event;
- var $KeyCode = getEventKeyCode($e);
- if($KeyCode==123||$KeyCode==27) // F12 or ESC
- {
- toggleDebugLayer($KeyCode);
- $e.cancelBubble = true;
- if($e.stopPropagation) $e.stopPropagation();
+ if( !is_array($value) && trim($value) == '' )
+ {
+ $value = '<b class="debug_error">no value</b>';
}
- }
-
- function toggleDebugLayer($KeyCode)
- {
- var $isVisible=false;
- var $DebugLayer = document.getElementById('debug_layer');
- if( typeof($DebugLayer) != 'undefined' )
+ else
{
- $isVisible = ($DebugLayer.style.display == 'none')?false:true;
- if(!$isVisible&&$KeyCode==27) return false;
-
- resizeDebugLayer(null);
- $DebugLayer.style.display = $isVisible?'none':'block';
+ $value = htmlspecialchars(print_r($value, true));
}
+ $src = isset($_GET[$key]) ? 'GE' : (isset($_POST[$key]) ? 'PO' : (isset($_COOKIE[$key]) ? 'CO' : '?') );
+ echo '<tr><td>'.$src.'</td><td>'.$key.'</td><td>'.$value.'</td></tr>';
}
+ ?>
+ </table>
+ <?php
+ $this->appendHTML( ob_get_contents() );
+ ob_end_clean();
+ }
+
+ function appendSession()
+ {
+ if( isset($_SESSION)&&$_SESSION )
+ {
+ $this->appendHTML('PHP Session: [<b>'.ini_get('session.name').'</b>]');
+ $this->dumpVars($_SESSION);
+ $this->moveToBegin(2);
+ }
+ }
+
+ function profileStart($key, $description)
+ {
+ $timeStamp = $this->getMoment();
+ $this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data), 'description' => $description);
+ $this->Data[] = array('profile_key' => $key, 'debug_type' => 'profiler');
+ }
+
+ function profileFinish($key)
+ {
+ $this->ProfilerData[$key]['ends'] = $this->getMoment();
+ }
+
+ function getMoment()
+ {
+ list($usec, $sec) = explode(' ', microtime());
+ return ((float)$usec + (float)$sec);
+ }
+
+ function generateID()
+ {
+ list($usec, $sec) = explode(" ",microtime());
+
+ $id_part_1 = substr($usec, 4, 4);
+ $id_part_2 = mt_rand(1,9);
+ $id_part_3 = substr($sec, 6, 4);
+ $digit_one = substr($id_part_1, 0, 1);
+ if ($digit_one == 0) {
+ $digit_one = mt_rand(1,9);
+ $id_part_1 = ereg_replace("^0","",$id_part_1);
+ $id_part_1=$digit_one.$id_part_1;
+ }
+ return $id_part_1.$id_part_2.$id_part_3;
+ }
+
+
+ function getErrorNameByCode($errorCode)
+ {
+ switch($errorCode)
+ {
+ case E_USER_ERROR:
+ return 'Fatal Error';
+ break;
+
+ case E_WARNING:
+ case E_USER_WARNING:
+ return 'Warning';
+ break;
+
+ case E_NOTICE:
+ case E_USER_NOTICE:
+ return 'Notice';
+ break;
+
+ case E_STRICT:
+ return 'PHP5 Strict';
+ break;
- function prepareSizes($Prefix)
+ default:
+ return '';
+ break;
+ }
+ }
+
+ /**
+ * Generates report
+ *
+ */
+ function printReport($returnResult = false)
+ {
+ if( dbg_ConstOn('DBG_ZEND_PRESENT') ) return;
+ dbg_safeDefine('DBG_RAISE_ON_WARNINGS',0);
+ dbg_safeDefine('DBG_WINDOW_WIDTH', 700);
+
+ $this->memoryUsage['debugger_start']=memory_get_usage();
+
+ // show php session if any
+ $this->appendSession();
+
+ // ensure, that 1st line of debug output always is this one:
+ $this->appendHTML('<a href="javascript:toggleDebugLayer(27);">Hide Debugger</a>');
+ $this->moveToBegin(1);
+
+ if ( dbg_ConstOn('DBG_INCLUDED_FILES') ) {
+ $files = get_included_files();
+ $this->appendHTML('<b>Included files:</b>');
+ foreach ($files as $file)
{
- var $ret = '';
- $ret = eval('document.body.'+$Prefix+'Top')+'; ';
- $ret += eval('document.body.'+$Prefix+'Left')+'; ';
- $ret += eval('document.body.'+$Prefix+'Height')+'; ';
- $ret += eval('document.body.'+$Prefix+'Width')+'; ';
- return $ret;
+ $this->appendHTML($this->getFileLink($this->getLocalFile($file)).' ('.round(filesize($file)/1024, 2).'Kb)');
}
+ }
+
+ $this->appendHTML('<b>Included files statistics:</b>'.( dbg_ConstOn('DBG_PROFILE_INCLUDES') ? ' (sorted by memory usage)':''));
+ $totals = Array( 'mem' => 0, 'time' => 0);
+ $totals_configs = Array( 'mem' => 0, 'time' => 0);
+ if ( dbg_ConstOn('DBG_PROFILE_INCLUDES') ) {
+ if ( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ) {
+ array_multisort($this->IncludesData['mem'], SORT_DESC, $this->IncludesData['file'], $this->IncludesData['time'], $this->IncludesData['level']);
+ }
+ foreach ($this->IncludesData['file'] as $key => $file_name) {
+ $this->appendHTML( str_repeat('&nbsp;->&nbsp;', ($this->IncludesData['level'][$key] >= 0 ? $this->IncludesData['level'][$key] : 0)).$file_name.' Mem: '.sprintf("%.4f Kb", $this->IncludesData['mem'][$key]/1024).' Time: '.sprintf("%.4f", $this->IncludesData['time'][$key]));
+ if ($this->IncludesData['level'][$key] == 0) {
+ $totals['mem'] += $this->IncludesData['mem'][$key];
+ $totals['time'] += $this->IncludesData['time'][$key];
+ }
+ else if ($this->IncludesData['level'][$key] == -1) {
+ $totals_configs['mem'] += $this->IncludesData['mem'][$key];
+ $totals_configs['time'] += $this->IncludesData['time'][$key];
+ }
+ }
+ $this->appendHTML('<b>Sub-Total classes:</b> '.' Mem: '.sprintf("%.4f Kb", $totals['mem']/1024).' Time: '.sprintf("%.4f", $totals['time']));
+ $this->appendHTML('<b>Sub-Total configs:</b> '.' Mem: '.sprintf("%.4f Kb", $totals_configs['mem']/1024).' Time: '.sprintf("%.4f", $totals_configs['time']));
+ $this->appendHTML('<span class="error"><b>Grand Total:</b></span> '.' Mem: '.sprintf("%.4f Kb", ($totals['mem']+$totals_configs['mem'])/1024).' Time: '.sprintf("%.4f", $totals['time']+$totals_configs['time']));
- function resizeDebugLayer($e)
- {
- if(!$e) $e = window.event;
- var $DebugLayer = document.getElementById('debug_layer');
- var $TopMargin = 1;
- if( typeof($DebugLayer) != 'undefined' )
- {
- $DebugLayer.style.top = parseInt(document.body.offsetTop + document.body.scrollTop) + $TopMargin;
- $DebugLayer.style.height = document.body.clientHeight - $TopMargin - 5;
- }
- //window.parent.status = 'OFFSET: '+prepareSizes('offset')+' | SCROLL: '+prepareSizes('scroll')+' | CLIENT: '+prepareSizes('client');
- //window.parent.status += 'DL Info: '+$DebugLayer.style.top+'; S.AH: '+screen.availHeight;
- return true;
- }
- function SetClipboard(copyText)
- {
- if(window.clipboardData)
- {
- // IE send-to-clipboard method.
- window.clipboardData.setData('Text', copyText);
+ }
+
+
+ $i = 0; $lineCount = count($this->Data);
+ ob_start();
+ ?>
+ <style type="text/css">
+
+ .dbg_flat_table {
+ border-collapse: collapse;
+ }
+
+ .dbg_flat_table TD {
+ border: 1px solid buttonface;
+ }
+
+ .debug_layer_table {
+ border-collapse: collapse;
+ width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px;
}
- else if (window.netscape)
+
+ .debug_text, .debug_row_even TD, .debug_row_odd TD {
+ color: #000000;
+ font-family: Verdana;
+ font-size: 11px;
+ word-wrap: break-word;
+ }
+
+ .debug_cell {
+ border: 1px solid #FF0000;
+ padding: 2px;
+ word-wrap: break-word;
+ }
+
+ .debug_row_even {
+ background-color: #CCCCFF;
+ }
+
+ .debug_row_odd {
+ background-color: #FFFFCC;
+ }
+
+ .debug_layer_container {
+ left: 2px;
+ top: 1px;
+ width: <?php echo DBG_WINDOW_WIDTH; ?>px;
+ z-index: +1000;
+ position: absolute;
+ overflow: auto;
+ border: 2px solid;
+ padding: 3px;
+ border-top-color: threedlightshadow;
+ border-left-color: threedlightshadow;
+ border-right-color: threeddarkshadow;
+ border-bottom-color: threeddarkshadow;
+ background-color: buttonface;
+ }
+
+ .debug_layer {
+ padding: 0px;
+ width: <?php echo DBG_WINDOW_WIDTH - 20; ?>px;
+ }
+
+ .debug_error {
+ color: #FF0000;
+ }
+ </style>
+ <div id="debug_layer" class="debug_layer_container" style="display: none;">
+ <div class="debug_layer">
+ <table width="100%" cellpadding="0" cellspacing="1" border="0" class="debug_layer_table">
+ <?php
+ while ($i < $lineCount)
+ {
+ echo '<tr class="debug_row_'.(($i % 2) ? 'odd' : 'even').'"><td class="debug_cell">'.$this->prepareHTML($i).'</td></tr>';
+ $i++;
+ }
+ ?>
+ </table>
+ </div>
+ </div>
+ <script language="javascript">
+ function getEventKeyCode($e)
{
- // You have to sign the code to enable this or allow the action in about:config by changing user_pref("signed.applets.codebase_principal_support", true);
- netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-
- // Store support string in an object.
- var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
- if (!str) return false;
- str.data=copyText;
-
- // Make transferable.
- var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
- if (!trans) return false;
-
- // Specify what datatypes we want to obtain, which is text in this case.
- trans.addDataFlavor("text/unicode");
- trans.setTransferData("text/unicode",str,copyText.length*2);
-
- var clipid=Components.interfaces.nsIClipboard;
- var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
- if (!clip) return false;
-
- clip.setData(trans,null,clipid.kGlobalClipboard);
+ var $KeyCode = 0;
+ if($e.keyCode) $KeyCode = $e.keyCode;
+ else if($e.which) $KeyCode = $e.which;
+ return $KeyCode;
}
-
- }
- function showProps($Obj, $Name)
- {
- var $ret = '';
- for($Prop in $Obj)
+ function keyProcessor($e)
{
- $ret += $Name+'.'+$Prop+' = '+$Obj[$Prop]+"\n";
+ if(!$e) $e = window.event;
+ var $KeyCode = getEventKeyCode($e);
+ if($KeyCode==123||$KeyCode==27) // F12 or ESC
+ {
+ toggleDebugLayer($KeyCode);
+ $e.cancelBubble = true;
+ if($e.stopPropagation) $e.stopPropagation();
+ }
}
- return $ret;
- }
-
- function editFile($fileName,$lineNo)
- {
- if(!document.all)
+
+ function toggleDebugLayer($KeyCode)
{
- alert('Only works in IE');
- return;
+ var $isVisible=false;
+ var $DebugLayer = document.getElementById('debug_layer');
+ if( typeof($DebugLayer) != 'undefined' )
+ {
+ $isVisible = ($DebugLayer.style.display == 'none')?false:true;
+ if(!$isVisible&&$KeyCode==27) return false;
+
+ resizeDebugLayer(null);
+ $DebugLayer.style.display = $isVisible?'none':'block';
+ }
}
- var $editorPath = '<?php echo defined('WINDOWS_EDITOR') ? addslashes(WINDOWS_EDITOR) : '' ?>';
- if($editorPath)
+ function prepareSizes($Prefix)
{
- var $obj = new ActiveXObject("LaunchinIE.Launch");
- $editorPath = $editorPath.replace('%F',$fileName);
- $editorPath = $editorPath.replace('%L',$lineNo);
- $obj.LaunchApplication($editorPath);
+ var $ret = '';
+ $ret = eval('document.body.'+$Prefix+'Top')+'; ';
+ $ret += eval('document.body.'+$Prefix+'Left')+'; ';
+ $ret += eval('document.body.'+$Prefix+'Height')+'; ';
+ $ret += eval('document.body.'+$Prefix+'Width')+'; ';
+ return $ret;
}
- else
+
+ function resizeDebugLayer($e)
{
- alert('Editor path not defined!');
+ if(!$e) $e = window.event;
+ var $DebugLayer = document.getElementById('debug_layer');
+ var $TopMargin = 1;
+ if( typeof($DebugLayer) != 'undefined' )
+ {
+ $DebugLayer.style.top = parseInt(document.body.offsetTop + document.body.scrollTop) + $TopMargin;
+ $DebugLayer.style.height = document.body.clientHeight - $TopMargin - 5;
+ }
+ //window.parent.status = 'OFFSET: '+prepareSizes('offset')+' | SCROLL: '+prepareSizes('scroll')+' | CLIENT: '+prepareSizes('client');
+ //window.parent.status += 'DL Info: '+$DebugLayer.style.top+'; S.AH: '+screen.availHeight;
+ return true;
}
- }
-
- function toggleTraceArgs($ArgsLayerID)
- {
- var $ArgsLayer = document.getElementById($ArgsLayerID);
- $ArgsLayer.style.display = ($ArgsLayer.style.display == 'none') ? 'block' : 'none';
- }
-
-
- document.onkeydown = keyProcessor;
- window.onresize = resizeDebugLayer;
- window.onscroll = resizeDebugLayer;
- window.focus();
- if( typeof($isFatalError) != 'undefined' && $isFatalError == 1 || <?php echo DBG_RAISE_ON_WARNINGS; ?> )
- {
- toggleDebugLayer();
- }
- if( typeof($isFatalError) != 'undefined' && $isFatalError == 1)
- {
- document.getElementById('debug_layer').scrollTop = 10000000;
- }
- </script>
- <?php
- $this->memoryUsage['debugger_finish']=memory_get_usage();
- $this->memoryUsage['print_report']=$this->memoryUsage['debugger_finish']-$this->memoryUsage['debugger_start'];
- $this->memoryUsage['total']=$this->memoryUsage['print_report']+$this->memoryUsage['error_handling'];
- $this->memoryUsage['application']=memory_get_usage()-$this->memoryUsage['total'];
- if($returnResult)
- {
- $ret = ob_get_contents();
- ob_clean();
- if( ConstOn('DBG_SHOW_MEMORY_USAGE') ) $ret.=$this->getMemoryUsageReport();
- return $ret;
- }
- else
- {
- ob_end_flush();
- if( ConstOn('DBG_SHOW_MEMORY_USAGE') ) echo $this->getMemoryUsageReport();
- }
- }
-
- /**
- * Format's memory usage report by debugger
- *
- * @return string
- * @access private
- */
- function getMemoryUsageReport()
- {
- $info=Array('printReport'=>'print_report',
- 'saveError'=>'error_handling',
- 'Total'=>'total',
- '<u>Application</u>'=>'application');
- $ret=Array();
- foreach($info as $title => $value_key)
- {
- $ret[]=$title.': <b>'.$this->formatSize($this->memoryUsage[$value_key]).'</b>';
+
+ function SetClipboard(copyText)
+ {
+ if(window.clipboardData)
+ {
+ // IE send-to-clipboard method.
+ window.clipboardData.setData('Text', copyText);
+ }
+ else if (window.netscape)
+ {
+ // You have to sign the code to enable this or allow the action in about:config by changing user_pref("signed.applets.codebase_principal_support", true);
+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+ // Store support string in an object.
+ var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
+ if (!str) return false;
+ str.data=copyText;
+
+ // Make transferable.
+ var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
+ if (!trans) return false;
+
+ // Specify what datatypes we want to obtain, which is text in this case.
+ trans.addDataFlavor("text/unicode");
+ trans.setTransferData("text/unicode",str,copyText.length*2);
+
+ var clipid=Components.interfaces.nsIClipboard;
+ var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
+ if (!clip) return false;
+
+ clip.setData(trans,null,clipid.kGlobalClipboard);
+ }
+
+ }
+
+ function showProps($Obj, $Name)
+ {
+ var $ret = '';
+ for($Prop in $Obj)
+ {
+ $ret += $Name+'.'+$Prop+' = '+$Obj[$Prop]+"\n";
+ }
+ return $ret;
+ }
+
+ function editFile($fileName,$lineNo)
+ {
+ if(!document.all)
+ {
+ alert('Only works in IE');
+ return;
+ }
+
+ var $editorPath = '<?php echo defined('WINDOWS_EDITOR') ? addslashes(WINDOWS_EDITOR) : '' ?>';
+ if($editorPath)
+ {
+ var $obj = new ActiveXObject("LaunchinIE.Launch");
+ $editorPath = $editorPath.replace('%F',$fileName);
+ $editorPath = $editorPath.replace('%L',$lineNo);
+ $obj.LaunchApplication($editorPath);
+ }
+ else
+ {
+ alert('Editor path not defined!');
+ }
+ }
+
+ function toggleTraceArgs($ArgsLayerID)
+ {
+ var $ArgsLayer = document.getElementById($ArgsLayerID);
+ $ArgsLayer.style.display = ($ArgsLayer.style.display == 'none') ? 'block' : 'none';
+ }
+
+
+ document.onkeydown = keyProcessor;
+ window.onresize = resizeDebugLayer;
+ window.onscroll = resizeDebugLayer;
+ window.focus();
+ if( typeof($isFatalError) != 'undefined' && $isFatalError == 1 || <?php echo DBG_RAISE_ON_WARNINGS; ?> )
+ {
+ toggleDebugLayer();
+ }
+ if( typeof($isFatalError) != 'undefined' && $isFatalError == 1)
+ {
+ document.getElementById('debug_layer').scrollTop = 10000000;
+ }
+ </script>
+ <?php
+ $this->memoryUsage['debugger_finish']=memory_get_usage();
+ $this->memoryUsage['print_report']=$this->memoryUsage['debugger_finish']-$this->memoryUsage['debugger_start'];
+ $this->memoryUsage['total']=$this->memoryUsage['print_report']+$this->memoryUsage['error_handling'];
+ $this->memoryUsage['application']=memory_get_usage()-$this->memoryUsage['total'];
+ if($returnResult)
+ {
+ $ret = ob_get_contents();
+ ob_clean();
+ if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) $ret.=$this->getMemoryUsageReport();
+ return $ret;
+ }
+ else
+ {
+ ob_end_flush();
+ if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) echo $this->getMemoryUsageReport();
+ }
}
- return implode('<br>',$ret);
- }
-
-
- /**
- * User-defined error handler
- *
- * @param int $errno
- * @param string $errstr
- * @param string $errfile
- * @param int $errline
- * @param array $errcontext
- */
- function saveError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
- {
- $memory_used=Array();
- $memory_used['begin']=memory_get_usage();
- $errorType = $this->getErrorNameByCode($errno);
- if(!$errorType)
- {
- trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR);
- return false;
+ /**
+ * Format's memory usage report by debugger
+ *
+ * @return string
+ * @access private
+ */
+ function getMemoryUsageReport()
+ {
+ $info=Array('<a href="javascript:self.location.reload()">printReport</a>'=>'print_report',
+ 'saveError'=>'error_handling',
+ 'Total'=>'total',
+ 'Application'=>'application');
+ $ret=Array();
+ foreach($info as $title => $value_key)
+ {
+ $ret[]='<tr><td>'.$title.':</td><td><b>'.$this->formatSize($this->memoryUsage[$value_key]).'</b></td></tr>';
+ }
+ return '<table class="dbg_flat_table">'.implode('',$ret).'</table>';
}
- $long_id_pos=strrpos($errstr,'#');
- if($long_id_pos!==false)
- {
- // replace short message with long one (due triger_error limitations on message size)
- $long_id=substr($errstr,$long_id_pos+1,strlen($errstr));
- $errstr=$this->longErrors[$long_id];
- unset($this->longErrors[$long_id]);
- }
- if( strpos($errfile,'eval()\'d code') !== false )
+ /**
+ * User-defined error handler
+ *
+ * @param int $errno
+ * @param string $errstr
+ * @param string $errfile
+ * @param int $errline
+ * @param array $errcontext
+ */
+ function saveError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
{
- $errstr = '[<b>EVAL</b>, line <b>'.$errline.'</b>]: '.$errstr;
- $tmpStr = $errfile;
- $pos = strpos($tmpStr,'(');
- $errfile = substr($tmpStr,0,$pos);
- $pos++;
- $errline = substr($tmpStr,$pos,strpos($tmpStr,')',$pos)-$pos);
+ $memory_used=Array();
+ $memory_used['begin']=memory_get_usage();
+
+ $errorType = $this->getErrorNameByCode($errno);
+ if(!$errorType)
+ {
+ trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR);
+ return false;
+ }
+
+ if( dbg_ConstOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT) ) return;
+
+ $long_id_pos=strrpos($errstr,'#');
+ if($long_id_pos!==false)
+ {
+ // replace short message with long one (due triger_error limitations on message size)
+ $long_id=substr($errstr,$long_id_pos+1,strlen($errstr));
+ $errstr=$this->longErrors[$long_id];
+ unset($this->longErrors[$long_id]);
+ }
+
+
+ /*in /www/kostja/in-commerce4/kernel/kernel4/parser/construct_tags.php(177) : runtime-created function on line
+
+ [PRE-PARSED block, $line 13]: Undefined variable: IdField*/
+
+ if( strpos($errfile,'runtime-created') !== false ) {
+ $errfile = ' PRE-PARSED block <b>'.$this->CurrentPreParsedBlock.'</b> ';
+ }
+
+ if( strpos($errfile,'eval()\'d code') !== false )
+ {
+ $errstr = '[<b>EVAL</b>, line <b>'.$errline.'</b>]: '.$errstr;
+ $tmpStr = $errfile;
+ $pos = strpos($tmpStr,'(');
+ $errfile = substr($tmpStr,0,$pos);
+ $pos++;
+ $errline = substr($tmpStr,$pos,strpos($tmpStr,')',$pos)-$pos);
+ }
+ if($this->TraceNextError)
+ {
+ $this->appendTrace();
+ $this->TraceNextError=false;
+ }
+ $this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error');
+ $memory_used['end']=memory_get_usage();
+ $this->memoryUsage['error_handling']+=$memory_used['end']-$memory_used['begin'];
+ if( substr($errorType,0,5) == 'Fatal')
+ {
+ echo '<script language="javascript">var $isFatalError = 1;</script>';
+ exit;
+ }
}
- if($this->TraceNextError)
+
+ function saveToFile($msg)
{
- $this->appendTrace();
- $this->TraceNextError=false;
+ $fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a');
+ fwrite($fp,$msg."\n");
+ fclose($fp);
}
- $this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error');
- $memory_used['end']=memory_get_usage();
- $this->memoryUsage['error_handling']+=$memory_used['end']-$memory_used['begin'];
- if( substr($errorType,0,5) == 'Fatal')
- {
- echo '<script language="javascript">var $isFatalError = 1;</script>';
- exit;
+
+ /**
+ * Formats file/memory size in nice way
+ *
+ * @param int $bytes
+ * @return string
+ * @access public
+ */
+ function formatSize($bytes)
+ {
+ if ($bytes >= 1099511627776) {
+ $return = round($bytes / 1024 / 1024 / 1024 / 1024, 2);
+ $suffix = "TB";
+ } elseif ($bytes >= 1073741824) {
+ $return = round($bytes / 1024 / 1024 / 1024, 2);
+ $suffix = "GB";
+ } elseif ($bytes >= 1048576) {
+ $return = round($bytes / 1024 / 1024, 2);
+ $suffix = "MB";
+ } elseif ($bytes >= 1024) {
+ $return = round($bytes / 1024, 2);
+ $suffix = "KB";
+ } else {
+ $return = $bytes;
+ $suffix = "Byte";
+ }
+ $return .= ' '.$suffix;
+ return $return;
}
+
}
-
- function saveToFile($msg)
+
+ if( !function_exists('memory_get_usage') )
{
- $fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a');
- fwrite($fp,$msg."\n");
- fclose($fp);
+ function memory_get_usage(){ return -1; }
}
- /**
- * Formats file/memory size in nice way
- *
- * @param int $bytes
- * @return string
- * @access public
- */
- function formatSize($bytes)
- {
- if ($bytes >= 1099511627776) {
- $return = round($bytes / 1024 / 1024 / 1024 / 1024, 2);
- $suffix = "TB";
- } elseif ($bytes >= 1073741824) {
- $return = round($bytes / 1024 / 1024 / 1024, 2);
- $suffix = "GB";
- } elseif ($bytes >= 1048576) {
- $return = round($bytes / 1024 / 1024, 2);
- $suffix = "MB";
- } elseif ($bytes >= 1024) {
- $return = round($bytes / 1024, 2);
- $suffix = "KB";
- } else {
- $return = $bytes;
- $suffix = "Byte";
- }
- $return .= ' '.$suffix;
- return $return;
+ $debugger = new Debugger();
+ if(dbg_ConstOn('DBG_HANDLE_ERRORS')) set_error_handler( array(&$debugger,'saveError') );
+ if(dbg_ConstOn('DBG_USE_SHUTDOWN_FUNC')) {
+ register_shutdown_function( array(&$debugger,'printReport') );
}
-
- }
-
- if( !function_exists('memory_get_usage') )
- {
- function memory_get_usage(){ return -1; }
}
-
- function ConstOn($const_name)
- {
- return defined($const_name)&&constant($const_name);
- }
-
- $debugger = new Debugger();
- if(ConstOn('DBG_HANDLE_ERRORS')) set_error_handler( array(&$debugger,'saveError') );
- if(ConstOn('DBG_USE_SHUTDOWN_FUNC')) register_shutdown_function( array(&$debugger,'printReport') );
-
-
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/debugger.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.6
\ No newline at end of property
+1.7
\ No newline at end of property
Index: trunk/core/kernel/utility/http_query.php
===================================================================
--- trunk/core/kernel/utility/http_query.php (revision 1338)
+++ trunk/core/kernel/utility/http_query.php (revision 1339)
@@ -1,296 +1,465 @@
<?php
class HTTPQuery extends Params {
/**
* $_POST vars
*
* @var Array
* @access private
*/
var $Post;
/**
* $_GET vars
*
* @var Array
* @access private
*/
var $Get;
/**
* $_COOKIE vars
*
* @var Array
* @access private
*/
var $Cookie;
/**
* $_SERVER vars
*
* @var Array
* @access private
*/
var $Server;
/**
* $_ENV vars
*
* @var Array
* @access private
*/
var $Env;
/**
* Order in what write
* all vars together in
* the same array
*
* @var string
*/
var $Order;
/**
* Uploaded files info
*
* @var Array
* @access private
*/
var $Files;
+ var $specialsToRemove = Array();
+
/**
* Loads info from $_POST, $_GET and
* related arrays into common place
*
* @param string $order
* @return HTTPQuery
* @access public
*/
function HTTPQuery($order='CGPF')
{
parent::Params();
$this->Order = $order;
$this->AddAllVars();
- $this->processQueryString();
- ini_set("magic_quotes_gpc", 0);
+
+ $this->specialsToRemove = $this->Get('remove_specials');
+ if($this->specialsToRemove)
+ {
+ $this->_Params = $this->removeSpecials($this->_Params);
+ }
+ ini_set('magic_quotes_gpc', 0);
+ }
+
+ function removeSpecials($array)
+ {
+ $ret = Array();
+ $removed = false;
+ foreach($this->specialsToRemove as $prefix_special => $flag)
+ {
+ if($flag)
+ {
+ $removed = true;
+ list($prefix,$special) = explode('.',$prefix_special);
+ foreach ($array as $key => $val) {
+ $new_key = preg_match("/^".$prefix."[._]{1}".$special."(.*)/", $key, $regs) ? $prefix.$regs[1] : $key;
+ $ret[$new_key] = is_array($val) ? $this->removeSpecials($val) : $val;
+ }
+ }
+ }
+ return $removed ? $ret : $array;
}
/**
* All all requested vars to
* common storage place
*
* @access private
*/
function AddAllVars()
{
for ($i=0; $i < strlen($this->Order); $i++)
{
$current = $this->Order[$i];
switch ($current) {
case 'G':
$this->Get =$this->AddVars($_GET);
+ $this->processQueryString();
break;
case 'P':
- $my_post = $this->post_convert($_POST); // needed ?
+ //$my_post = $this->post_convert($_POST); // needed ?
$this->Post = $this->AddVars($_POST);
+ $this->convertPostEvents();
break;
case 'C':
$this->Cookie = $this->AddVars($_COOKIE);
break;
case 'E';
$this->Env = $this->AddVars($_ENV);
break;
case 'S';
$this->Server = $this->AddVars($_SERVER);
break;
case 'F';
- $this->Files = $this->AddVars($_FILES);
+ $this->convertFiles();
+ $this->Files = $this->MergeVars($_FILES, false); //do not strip slashes!
break;
}
}
}
+
+ function convertFiles()
+ {
+ if (!$_FILES)
+ {
+ return false;
+ }
+
+ $file_keys = Array('error','name','size','tmp_name','type');
+
+ foreach($_FILES as $file_name => $file_info)
+ {
+ if( is_array($file_info['error']) )
+ {
+ $tmp[$file_name] = $this->getArrayLevel( $file_info['error'], $file_name );
+ }
+ else
+ {
+ $normal_files[$file_name] = $file_info;
+ }
+ }
+
+ $files = $_FILES;
+ $_FILES = Array();
+
+ foreach($tmp as $prefix => $prefix_files)
+ {
+ $anchor =& $_FILES;
+ foreach($prefix_files['keys'] as $key)
+ {
+ $anchor =& $anchor[$key];
+ }
+ foreach($prefix_files['value'] as $field_name)
+ {
+ unset($inner_anchor);
+ unset($copy);
+ $work_copy = $prefix_files['keys'];
+ foreach($file_keys as $file_key)
+ {
+ $inner_anchor =& $files[$prefix][$file_key];
+ if (isset($copy))
+ {
+ $work_copy = $copy;
+ }
+ else
+ {
+ $copy = $work_copy;
+ }
+ array_shift($work_copy);
+ foreach($work_copy as $prefix_file_key)
+ {
+ $inner_anchor =& $inner_anchor[$prefix_file_key];
+ }
+ $anchor[$field_name][$file_key] = $inner_anchor[$field_name];
+ }
+ }
+ }
+
+ // keys: img_temp, 0, values: LocalPath, ThumbPath
+ }
+
+ function getArrayLevel(&$level, $prefix='')
+ {
+ $ret['keys'] = $prefix ? Array($prefix) : Array();
+ $ret['value'] = Array();
+
+ foreach($level as $level_key => $level_value)
+ {
+ if( is_array($level_value) )
+ {
+ $ret['keys'][] = $level_key;
+ $tmp = $this->getArrayLevel($level_value);
+
+ $ret['keys'] = array_merge($ret['keys'], $tmp['keys']);
+ $ret['value'] = array_merge($ret['value'], $tmp['value']);
+ }
+ else
+ {
+ $ret['value'][] = $level_key;
+ }
+ }
+
+ return $ret;
+ }
+
+ function convertPostEvents()
+ {
+ $events = $this->Get('events');
+ if (is_array($events)) {
+ foreach ($events as $prefix_special => $event) {
+ $this->Set($prefix_special.'_event', $event);
+ }
+ }
+ }
/**
* Process QueryString only, create
* events, ids, based on config
* set template name and sid in
* desired application variables.
*
* @access private
*/
function processQueryString()
{
// env=SID:TEMPLATE:m-1-1-1-1:l0-0-0:n-0-0-0:bb-0-0-1-1-1-0
-
+
$env_var =& $this->Get(ENV_VAR_NAME);
if($env_var)
{
+ $env_var = str_replace('\:','_&+$$+&_',$env_var); // replace escaped "=" with spec-chars :)
+
$parts=explode(':',$env_var);
- // Save Session ID
- $sid=array_shift($parts);
- if($sid) $this->Set('sid',$sid);
-
- // Save Template Name
- $t=$this->getTemplateName( array_shift($parts) );
- if(!$t) $t='index';
- $this->Set('t',$t);
+ if (defined('INPORTAL_ENV')) {
+ $sub_parts = array_shift($parts);
+
+ list($sid, $t) = explode('-', $sub_parts, 2);
+
+
+ // Save Session ID
+ if($sid) $this->Set('sid',$sid);
+
+ // Save Template Name
+ $t=$this->getTemplateName( $t );
+ if(!$t) $t='index';
+ $this->Set('t',$t);
+ }
+ else {
+ // Save Session ID
+ $sid=array_shift($parts);
+ if($sid) $this->Set('sid',$sid);
+
+ // Save Template Name
+ $t=$this->getTemplateName( array_shift($parts) );
+ if(!$t) $t='index';
+ $this->Set('t',$t);
+ }
if($parts)
{
$query_maps=Array();
$event_manger =& $this->Application->recallObject('EventManager');
+ $passed = Array();
+
foreach($parts as $mixed_part)
{
- $mixed_part=explode('-',$mixed_part);
+ //In-portal old style env conversion - adds '-' between prefix and first var
+ $mixed_part = str_replace('_&+$$+&_',':',$mixed_part);
+ $mixed_part = preg_replace("/^([a-zA-Z]+)([0-9]+)-(.*)/", "$1-$2-$3", $mixed_part);
+
+ $escaped_part = str_replace('\-', '_&+$$+&_', $mixed_part);
+ $escaped_part = explode('-', $escaped_part);
+
+ $mixed_part = array();
+ foreach ($escaped_part as $escaped_val) {
+ $mixed_part[] = str_replace('_&+$$+&_', '-', $escaped_val);
+ }
+
$prefix_special=array_shift($mixed_part); // l.pick, l
list($prefix)=explode('.',$prefix_special);
-
+
$query_maps[$prefix_special]=$this->Application->getUnitOption($prefix,'QueryString');
- foreach($query_maps[$prefix_special] as $index => $var_name)
+
+ // if config is not defined for prefix in QueryString, then don't process it
+ if( $query_maps[$prefix_special] )
+ {
+ array_push($passed, $prefix);
+ foreach($query_maps[$prefix_special] as $index => $var_name)
+ {
+ // l_id, l_page, l_bla-bla-bla
+ $val = $mixed_part[$index-1];
+ if ($val == '') $val = false;
+ $this->Set($prefix_special.'_'.$var_name, $val);
+ }
+ }
+ else
{
- // l_id, l_page, l_bla-bla-bla
- $this->Set($prefix_special.'_'.$var_name,$mixed_part[$index-1]);
+ unset($query_maps[$prefix_special]);
}
+
}
+ $this->Set('passed', implode(',', $passed));
$event_manger->setQueryMaps($query_maps);
}
}
else
{
$t=$this->getTemplateName('index');
$this->Set('t',$t);
}
}
/**
* Decides what template name to
* use from $_GET or from $_POST
*
* @param string $querystring_template
* @return string
* @access private
*/
function getTemplateName($querystring_template)
{
- $t_from_post=$this->Get('t');
- $t=$t_from_post?$t_from_post:$querystring_template;
+ $t_from_post = $this->Get('t');
+ $t= $t_from_post ? $t_from_post : $querystring_template;
+
+ if ( is_numeric($t) ) {
+ $t = $this->Application->DB->GetOne('SELECT CONCAT(FilePath, \'/\', FileName) FROM '.TABLE_PREFIX.'ThemeFiles
+ WHERE FileId = '.$t);
+ }
+ $t = preg_replace("/\.tpl$/", '', $t);
+
return $t;
}
function post_convert($array)
{
$out = Array();
foreach ($array as $key => $val) {
if ( ereg("\|\|",$key)) {
$key = str_replace("||",".",$key);
}
else
$out[$key] = $val;
}
}
/**
* Saves variables from array specified
* into common variable storage place
*
* @param Array $array
* @return Array
* @access private
*/
function AddVars($array)
{
- foreach ($array as $key => $val) {
- if (get_magic_quotes_gpc())
- {
-
- if ( is_array($val) )
- {
- foreach ($val as $key_array => $val_array)
- {
- if( is_array($val_array) )
- {
- $array[$key][$key_array] = $this->AddVars($val_array);
- }
- else
- {
- $array[$key][$key_array] = stripslashes($val_array);
- }
-
- }
- $this->Set($key, $array[$key]);
- }
- else {
- $array[$key] = stripslashes($val);
- $this->Set($key, $array[$key]);
- }
-
-
- }
- else {
- $this->Set($key, $val);
- }
+ $array = $this->StripSlashes($array);
+ foreach($array as $key => $value)
+ {
+ $this->Set($key,$value);
+ }
+ return $array;
+ }
+
+ function MergeVars($array, $strip_slashes=true)
+ {
+ if ($strip_slashes) $array = $this->StripSlashes($array);
+ foreach($array as $key => $value)
+ {
+ $this->_Params = array_merge_recursive2($this->_Params, Array($key=>$value));
+ }
+ return $array;
+ }
+
+ function StripSlashes($array)
+ {
+ if( !get_magic_quotes_gpc() ) return $array;
+ foreach($array as $key=>$value)
+ {
+ $array[$key]=is_array($value)?$this->StripSlashes($value):stripslashes($value);
}
return $array;
}
/**
* Returns the hash of http params
* matching the mask with values
*
* @param string $mask
* @return Array
* @access public
*/
function GetSelectedValues($mask)
{
return $this->Application->ExtractByMask($this->Vars, $mask);
}
/**
* Returns the sprintf'ed by format list of
* http params matching the mask and set to on
*
* @param string $mask
* @param string $format
* @return string
* @access public
*/
function GetSelectedIDs($mask, $format)
{
if ($mask == '') return;
$result = '';
foreach ($this->GetParams() as $name => $val)
{
if (eregi($mask, $name, $regs) && $val == 'on') {
$result.= sprintf($format, $regs[1]);
}
}
return $result;
}
/**
* Returns the sprintf'ed by format list of
* http params matching the mask and set to on
*
* @param string $mask
* @param string $value_mask
* @return Array
* @access public
*/
function GetSelectedIDsArray($mask, $value_mask="%s,")
{
$str = $this->GetSelectedIDs($mask, $value_mask);
$str = rtrim($str, ',');
if (!empty($str)) {
$ids = split(',', $str);
if ($ids !== false)
return $ids;
else return Array();
}
else return Array();
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/http_query.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
\ No newline at end of property
+1.3
\ No newline at end of property
Index: trunk/core/kernel/utility/unit_config_reader.php
===================================================================
--- trunk/core/kernel/utility/unit_config_reader.php (revision 1338)
+++ trunk/core/kernel/utility/unit_config_reader.php (revision 1339)
@@ -1,163 +1,368 @@
<?php
class kUnitConfigReader extends kBase {
/**
* Configs readed
*
* @var Array
* @access private
*/
var $configData=Array();
+ var $configFiles=Array();
+
+ var $CacheExpired = false;
/**
* Module names found during
* config reading
*
* @var Array
*/
var $modules=Array();
/**
* Scan kernel and user classes
* for available configs
*
* @access protected
*/
function Init($prefix,$special)
{
parent::Init($prefix,$special);
$this->scanModules(MODULES_PATH);
}
/**
* Read configs from all directories
* on path specified
*
* @param string $folderPath
* @access public
*/
- function processFolder($folderPath)
+ function processFolder($folderPath, $cached)
{
$fh=opendir($folderPath);
while(($sub_folder=readdir($fh)))
{
$full_path=$folderPath.'/'.$sub_folder;
if( $this->isDir($full_path) && file_exists($this->getConfigName($full_path)) )
{
- include_once $this->getConfigName($full_path);
- $prefix=$config['Prefix'];
- $config['BasePath']=$full_path;
- $this->configData[$prefix] = $config;
- $this->parseConfig($prefix);
+ if (filemtime($full_path) > $cached) {
+ $this->CacheExpired = true;
+
+ $file = $this->getConfigName($full_path);
+ if ( defined('DEBUG_MODE') && dbg_ConstOn('DBG_PROFILE_INCLUDES')) {
+
+ if ( in_array($file, get_required_files()) ) return;
+ global $debugger;
+ $debugger->IncludeLevel++;
+ $before_time = getmicrotime();
+ $before_mem = memory_get_usage();
+ include_once($file);
+ $used_time = getmicrotime() - $before_time;
+ $used_mem = memory_get_usage() - $before_mem;
+ $debugger->IncludeLevel--;
+ $debugger->IncludesData['file'][] = str_replace(DOC_ROOT.BASE_PATH, '', $file);
+ $debugger->IncludesData['mem'][] = $used_mem;
+ $debugger->IncludesData['time'][] = $used_time;
+ $debugger->IncludesData['level'][] = -1;
+ }
+ else {
+ include_once($file);
+ }
+
+ $prefix=$config['Prefix'];
+ $config['BasePath']=$full_path;
+ $this->configData[$prefix] = $config;
+ }
}
}
}
+ function ParseConfigs()
+ {
+ foreach ($this->configData as $prefix => $config)
+ {
+ $this->parseConfig($prefix);
+ }
+ }
- function scanModules($folderPath)
+ function findConfigFiles($folderPath)
{
$fh=opendir($folderPath);
while(($sub_folder=readdir($fh)))
{
$full_path=$folderPath.'/'.$sub_folder;
- if( $this->isDir($full_path) )
+ if( $this->isDir($full_path))
+ {
+ if ( file_exists($this->getConfigName($full_path)) ) {
+ $this->configFiles[] = $this->getConfigName($full_path);
+ }
+ $this->findConfigFiles($full_path);
+
+// if (filemtime($full_path) > $cached) { }
+
+ }
+ }
+ }
+
+ function includeConfigFiles()
+ {
+ foreach ($this->configFiles as $filename) {
+ if ( defined('DEBUG_MODE') && dbg_ConstOn('DBG_PROFILE_INCLUDES')) {
+
+ if ( in_array($filename, get_required_files()) ) return;
+ global $debugger;
+ $debugger->IncludeLevel++;
+ $before_time = getmicrotime();
+ $before_mem = memory_get_usage();
+ include_once($filename);
+ $used_time = getmicrotime() - $before_time;
+ $used_mem = memory_get_usage() - $before_mem;
+ $debugger->IncludeLevel--;
+ $debugger->IncludesData['file'][] = str_replace(DOC_ROOT.BASE_PATH, '', $filename);
+ $debugger->IncludesData['mem'][] = $used_mem;
+ $debugger->IncludesData['time'][] = $used_time;
+ $debugger->IncludesData['level'][] = -1;
+ }
+ else {
+ include_once($filename);
+ }
+
+ $prefix=$config['Prefix'];
+ $config['BasePath']=dirname($filename);
+ $this->configData[$prefix] = $config;
+
+ }
+ }
+
+ function scanModules($folderPath)
+ {
+ global $debugger;
+
+ if (defined('CACHE_CONFIGS_FILES')) {
+ $conn =& $this->Application->GetADODBConnection();
+ $data = $conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "config_files"');
+ if ($data && $data['Cached'] > (time() - 3600) ) {
+ $this->configFiles = unserialize($data['Data']);
+ $files_cached = $data['Cached'];
+ }
+ else {
+ $files_cached = 0;
+ }
+ }
+ else {
+ $files_cached = 0;
+ }
+
+
+ if (defined('CACHE_CONFIGS_DATA')) {
+ $conn =& $this->Application->GetADODBConnection();
+ $data = $conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "config_data"');
+ if ($data && $data['Cached'] > (time() - 3600) ) {
+ $this->configData = unserialize($data['Data']);
+ $data_cached = $data['Cached'];
+ }
+ else {
+ $data_cached = 0;
+ }
+ }
+ else {
+ $data_cached = 0;
+ }
+
+ if ( !defined('CACHE_CONFIGS_FILES') || $files_cached == 0 ) {
+ $this->findConfigFiles($folderPath);
+ }
+
+ if ( !defined('CACHE_CONFIGS_DATA') || $data_cached == 0) {
+ $this->includeConfigFiles();
+ }
+
+ /*// && (time() - $cached) > 600) - to skip checking files modified dates
+ if ( !defined('CACHE_CONFIGS') ) {
+ $fh=opendir($folderPath);
+ while(($sub_folder=readdir($fh)))
{
- $this->processFolder($full_path);
+ $full_path=$folderPath.'/'.$sub_folder.'/units';
+ if( $this->isDir($full_path) )
+ {
+ $this->processFolder($full_path, $cached);
+ }
}
+ }*/
+ $this->ParseConfigs();
+
+ if (defined('CACHE_CONFIGS_FILES') && $files_cached == 0) {
+ $conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("config_files", '.$conn->qstr(serialize($this->configFiles)).', '.time().')');
}
+
+ if (defined('CACHE_CONFIGS_DATA') && $data_cached == 0) {
+ $conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("config_data", '.$conn->qstr(serialize($this->configData)).', '.time().')');
+ }
+
}
/**
* Register nessasary classes
*
* @param string $prefix
* @access private
*/
function parseConfig($prefix)
{
$config =& $this->configData[$prefix];
$event_manager =& $this->Application->recallObject('EventManager');
$class_params=Array('ItemClass','ListClass','EventHandlerClass','TagProcessorClass');
foreach($class_params as $param_name)
{
+ if ( !(isset($config[$param_name]) ) ) continue;
$class_info =& $config[$param_name];
$pseudo_class = $this->getPrefixByParamName($param_name,$prefix);
$this->Application->registerClass( $class_info['class'],
$config['BasePath'].'/'.$class_info['file'],
$pseudo_class);
$event_manager->registerBuildEvent($pseudo_class,$class_info['build_event']);
}
+
+ if ( is_array(getArrayValue($config, 'Hooks')) ) {
+ foreach ($config['Hooks'] as $hook) {
+ $do_prefix = $hook['DoPrefix'] == '' ? $config['Prefix'] : $hook['DoPrefix'];
+
+ if ( !is_array($hook['HookToEvent']) ) {
+ $hook_events = Array( $hook['HookToEvent'] );
+ }
+ else {
+ $hook_events = $hook['HookToEvent'];
+ }
+ foreach ($hook_events as $hook_event) {
+ $this->Application->registerHook($hook['HookToPrefix'], $hook['HookToSpecial'], $hook_event, $hook['Mode'], $do_prefix, $hook['DoSpecial'], $hook['DoEvent'], $hook['Conditional']);
+ }
+ }
+ }
+
+ if ( is_array(getArrayValue($config, 'AggregateTags')) ) {
+ foreach ($config['AggregateTags'] as $aggregate_tag) {
+ $aggregate_tag['LocalPrefix'] = $config['Prefix'];
+ $this->Application->registerAggregateTag($aggregate_tag);
+ }
+ }
+
+ if ( $this->Application->isDebugMode() && dbg_ConstOn('DBG_VALIDATE_CONFIGS') && isset($config['TableName']) )
+ {
+ global $debugger;
+ $tablename = $config['TableName'];
+
+ $conn =& $this->Application->GetADODBConnection();
+ $res = $conn->Query("DESCRIBE $tablename");
+
+ foreach ($res as $field) {
+ $f_name = $field['Field'];
+ if (getArrayValue($config, 'Fields')) {
+ if ( !array_key_exists ($f_name, $config['Fields']) ) {
+ $debugger->appendHTML("<b class='debug_error'>Config Warning: </b>Field $f_name exists in the database, but is not defined in config file for prefix <b>".$config['Prefix']."</b>!");
+ safeDefine('DBG_RAISE_ON_WARNINGS', 1);
+ }
+ else {
+ $options = $config['Fields'][$f_name];
+ if ($field['Null'] == '') {
+ if ( $f_name != $config['IDField'] && !isset($options['not_null']) && !isset($options['required']) ) {
+ $debugger->appendHTML("<b class='debug_error'>Config Error: </b>Field $f_name in config for prefix <b>".$config['Prefix']."</b> is NOT NULL in the database, but is not configured as not_null or required!");
+ safeDefine('DBG_RAISE_ON_WARNINGS', 1);
+ }
+ if ( isset($options['not_null']) && !isset($options['default']) ) {
+ $debugger->appendHTML("<b class='debug_error'>Config Error: </b>Field $f_name in config for prefix <b>".$config['Prefix']."</b> is described as NOT NULL, but does not have DEFAULT value!");
+ safeDefine('DBG_RAISE_ON_WARNINGS', 1);
+ }
+ }
+
+ }
+ }
+ }
+ }
}
/**
* Reads unit (specified by $prefix)
* option specified by $option
*
* @param string $prefix
* @param string $option
* @return string
* @access public
*/
function getUnitOption($prefix,$name)
{
- return $this->configData[$prefix][$name];
+ return isset($this->configData[$prefix][$name])?$this->configData[$prefix][$name]:false;
+ }
+
+ /**
+ * Read all unit with $prefix options
+ *
+ * @param string $prefix
+ * @return Array
+ * @access public
+ */
+ function getUnitOptions($prefix)
+ {
+ return isset($this->configData[$prefix])?$this->configData[$prefix]:false;
}
/**
* Set's new unit option value
*
* @param string $prefix
* @param string $name
* @param string $value
* @access public
*/
function setUnitOption($prefix,$name,$value)
{
$this->configData[$prefix][$name]=$value;
}
function getPrefixByParamName($paramName,$prefix)
{
$pseudo_class_map=Array(
'ItemClass'=>'%s',
'ListClass'=>'%s_List',
'EventHandlerClass'=>'%s_EventHandler',
'TagProcessorClass'=>'%s_TagProcessor'
);
return sprintf($pseudo_class_map[$paramName],$prefix);
}
/**
* Get's config file name based
* on folder name supplied
*
* @param string $folderPath
* @return string
* @access private
*/
function getConfigName($folderPath)
{
return $folderPath.'/'.basename($folderPath).'_config.php';
}
/**
* is_dir ajustment to work with
* directory listings too
*
* @param string $folderPath
* @return bool
* @access private
*/
function isDir($folderPath)
{
$base_name=basename($folderPath);
$ret=!($base_name=='.'||$base_name=='..');
return $ret&&is_dir($folderPath);
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/unit_config_reader.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
\ No newline at end of property
+1.2
\ No newline at end of property
Index: trunk/core/kernel/utility/formatters.php
===================================================================
--- trunk/core/kernel/utility/formatters.php (nonexistent)
+++ trunk/core/kernel/utility/formatters.php (revision 1339)
@@ -0,0 +1,758 @@
+<?php
+
+class kFormatter extends kBase {
+
+
+ /**
+ * Convert's value to match type from config
+ *
+ * @param mixed $value
+ * @param Array $options
+ * @return mixed
+ * @access protected
+ */
+ function TypeCast($value, $options)
+ {
+ $ret = true;
+ if( isset($options['type']) )
+ {
+ $field_type = $options['type'];
+ $type_ok = preg_match('#int|integer|double|float|real|numeric|string#', $field_type);
+ if($field_type == 'string') return $value;
+
+ if ($value != '' && $type_ok)
+ {
+ $ret = is_numeric($value);
+ if($ret)
+ {
+ $f = 'is_'.$field_type;
+ settype($value, $field_type);
+ $ret = $f($value);
+ }
+ }
+ }
+
+ return $ret ? $value : false;
+ }
+
+//function Format($value, $options, &$errors)
+ function Format($value, $field_name, &$object, $format=null)
+ {
+ if ( is_null($value) ) return '';
+
+ $options = $object->GetFieldOptions($field_name);
+ if ( isset($format) ) $options['format'] = $format;
+ $tc_value = $this->TypeCast($value,$options);
+ if( ($tc_value === false) || ($tc_value != $value) ) return $value; // for leaving badly formatted date on the form
+
+ if (isset($options['format'])) return sprintf($options['format'], $tc_value);
+
+ return $tc_value;
+ }
+
+//function Parse($value, $options, &$errors)
+ function Parse($value, $field_name, &$object)
+ {
+ if ($value == '') return NULL;
+
+ $options = $object->GetFieldOptions($field_name);
+ $tc_value = $this->TypeCast($value,$options);
+ if($tc_value === false) return $value; // for leaving badly formatted date on the form
+
+ if( isset($options['type']) )
+ {
+ if( preg_match('#double|float|real|numeric#', $options['type']) ) $tc_value = str_replace(',', '.', $tc_value);
+ }
+ return $tc_value;
+ }
+
+ function HumanFormat($format)
+ {
+ return $format;
+ }
+
+
+ /**
+ * The method is supposed to alter config options or cofigure object in some way based on its usage of formatters
+ * The methods is called for every field with formatter defined when configuring item.
+ * Could be used for adding additional VirtualFields to an object required by some special Formatter
+ *
+ * @param string $field_name
+ * @param array $field_options
+ * @param kDBBase $object
+ */
+ function PrepareOptions($field_name, &$field_options, &$object)
+ {
+
+ }
+
+ /**
+ * Used for split fields like timestamp -> date, time
+ * Called from DBItem to update sub fields values after loading item
+ *
+ * @param unknown_type $field
+ * @param unknown_type $value
+ * @param unknown_type $options
+ * @param unknown_type $object
+ */
+ function UpdateSubFields($field, $value, &$options, &$object)
+ {
+
+ }
+
+ /**
+ * Used for split fields like timestamp -> date, time
+ * Called from DBItem Validate (before validation) to get back master field value from its sub_fields
+ *
+ * @param unknown_type $field
+ * @param unknown_type $value
+ * @param unknown_type $options
+ * @param unknown_type $object
+ */
+ function UpdateMasterFields($field, $value, &$options, &$object)
+ {
+
+ }
+
+/* function GetErrorMsg($pseudo_error, $options)
+ {
+ if ( isset($options['error_msgs'][$pseudo_error]) ) {
+ return $options['error_msgs'][$pseudo_error];
+ }
+ else {
+ return $this->ErrorMsgs[$pseudo_error];
+ }
+ }*/
+
+}
+
+class kOptionsFormatter extends kFormatter {
+
+//function Format($value, $options, &$errors)
+ function Format($value, $field_name, &$object, $format=null)
+ {
+ if ( is_null($value) ) return '';
+
+ $options = $object->GetFieldOptions($field_name);
+ if ( isset($format) ) $options['format'] = $format;
+
+ $label = $options['options'][$value];
+ if( getArrayValue($options,'use_phrases') )
+ {
+ return $this->Application->Phrase($label);
+ }
+ else
+ {
+ return $label;
+ }
+ }
+
+}
+
+/**
+ * Replacement for kOptionsFormatter in case if options
+ * should be selected from database. Use this formatter
+ * only in case if formatter attached field is in edit form.
+ *
+ * For usage in grid just use LEFT JOIN clause to table
+ * where requested options are located.
+ */
+class kLEFTFormatter extends kFormatter {
+
+//function Format($value, $options, &$errors)
+ function Format($value, $field_name, &$object, $format=null)
+ {
+ if ( is_null($value) ) return '';
+
+ $options = $object->GetFieldOptions($field_name);
+ if ( isset($format) ) $options['format'] = $format;
+
+ if( !isset($options['options'][$value]) )
+ {
+ // required option is not defined in config => query for it
+ $db =& $this->Application->GetADODBConnection();
+ $sql = sprintf($options['left_sql'],$options['left_title_field'],$options['left_key_field'],$value);
+ $options['options'][$value] = $db->GetOne($sql);
+ }
+ return $options['options'][$value];
+ }
+
+//function Parse($value, $options, &$errors)
+ function Parse($value, $field_name, &$object)
+ {
+ if ($value == '') return NULL;
+
+ $options = $object->GetFieldOptions($field_name);
+ if( !array_search($value,$options['options']) )
+ {
+ // required option is not defined in config => query for it
+ $db =& $this->Application->GetADODBConnection();
+ $sql = sprintf($options['left_sql'],$options['left_key_field'],$options['left_title_field'],$value);
+ $found = $db->GetOne($sql);
+ if($found !== false) $options['options'][$found] = $value;
+ }
+ else
+ {
+ $found = array_search($value,$options['options']);
+ }
+ if($found === false) $found = $options['default'];
+ return $found;
+ }
+}
+
+
+class kDateFormatter extends kFormatter {
+
+/* function kDateFormatter()
+ {
+ parent::kFormatter();
+ $this->ErrorMsgs['bad_dformat'] = 'Please use correct date format (%s) ex. (%s)';
+ }
+ */
+
+ function PrepareOptions($field_name, &$field_options, &$object)
+ {
+ $date_format = getArrayValue($field_options, 'date_format');
+ $time_format = getArrayValue($field_options, 'time_format');
+
+ $language = $this->Application->recallObject('lang');
+
+ if ($date_format === false) $date_format = $language->GetDBField('DateFormat');
+ if ($time_format === false) $time_format = $language->GetDBField('TimeFormat');
+
+ if (!isset($field_options['date_time_separator'])) $field_options['date_time_separator'] = ' ';
+ $field_options['format'] = $date_format.$field_options['date_time_separator'].$time_format;
+ $field_options['sub_fields'] = Array('date' => $field_name.'_date', 'time' => $field_name.'_time');
+
+ $add_fields = Array();
+
+ $opts = Array('master_field' => $field_name, 'formatter'=>'kDateFormatter', 'format'=>$date_format);
+ if ( isset($field_options['default']) ) $opts['default'] = $field_options['default'];
+ if ( isset($field_options['required']) ) $opts['required'] = $field_options['required'];
+
+ $add_fields[$field_name.'_date'] = $opts;
+ $opts['format'] = $time_format;
+ $add_fields[$field_name.'_time'] = $opts;
+
+ if ( !isset($object->VirtualFields[$field_name]) ) {
+ // adding caluclated field to format date directly in the query
+ if ( !isset($object->CalculatedFields) || !is_array($object->CalculatedFields) ) {
+ $object->CalculatedFields = Array();
+ }
+ $object->CalculatedFields[$field_name.'_formatted'] = 'FROM_UNIXTIME('.'`%1$s`.'.$field_name.', \''.$this->SQLFormat($field_options['format']).'\')';
+ $opts['format'] = $field_options['format'];
+ $opts['required'] = 0;
+ unset($opts['master_field']);
+ $add_fields[$field_name.'_formatted'] = $opts;
+ }
+
+ $add_fields = array_merge_recursive2($add_fields, $object->VirtualFields);
+ $object->setVirtualFields($add_fields);
+ }
+
+ function UpdateSubFields($field, $value, &$options, &$object)
+ {
+ if ( $sub_fields = getArrayValue($options, 'sub_fields') ) {
+ if( isset($value) && $value )
+ {
+ $object->SetDBField( $sub_fields['date'], $value );
+ $object->SetDBField( $sub_fields['time'], $value );
+ }
+ }
+ }
+
+ function UpdateMasterFields($field, $value, &$options, &$object)
+ {
+ // when in master field - set own value from sub_fields
+ if ( $sub_fields = getArrayValue($options, 'sub_fields') ) {
+ // if date is not empty, but time is empty - set time to 0, otherwise master field fomratter will complain
+ // when we have only date field on form, we need time hidden field always empty, don't ask me why!
+ if ( $object->GetDBField($sub_fields['date']) != '' && $object->GetDBField($sub_fields['time']) == '' ) {
+ $object->SetDBField($sub_fields['time'], mktime(0, 0, 0));
+ }
+ $object->SetField($field, $object->GetField($sub_fields['date']).$options['date_time_separator'].$object->GetField($sub_fields['time']));
+ }
+ // when in one of sub_fields - call update for master_field to update its value from sub_fields [are you following ? :) ]
+ elseif ($master_field = getArrayValue($options, 'master_field') ) {
+ $this->UpdateMasterFields($master_field, null, $object->GetFieldOptions($master_field), $object);
+ }
+ }
+
+//function Format($value, $options, &$errors)
+ function Format($value, $field_name, &$object, $format=null)
+ {
+ if ( is_null($value) ) return '';
+ if ( !is_numeric($value) ) return $value; // for leaving badly formatted date on the form
+ settype($value, 'int');
+ if ( !is_int($value) ) return $value;
+
+ $options = $object->GetFieldOptions($field_name);
+ if ( isset($format) ) $options['format'] = $format;
+
+ return date($options['format'], $value);
+ }
+
+ function HumanFormat($format)
+ {
+ $patterns = Array('/m/',
+ '/n/',
+ '/d/',
+ '/j/',
+ '/y/',
+ '/Y/',
+ '/h|H/',
+ '/g|G/',
+ '/i/',
+ '/s/',
+ '/a|A/');
+ $replace = Array( 'mm',
+ 'm',
+ 'dd',
+ 'd',
+ 'yy',
+ 'yyyy',
+ 'hh',
+ 'h',
+ 'mm',
+ 'ss',
+ 'AM');
+ $res = preg_replace($patterns, $replace, $format);
+ return $res;
+ }
+
+ function SQLFormat($format)
+ {
+ $mapping = Array(
+ '/%/' => '%%',
+ '/(?<!%)a/' => '%p', // Lowercase Ante meridiem and Post meridiem => MySQL provides only uppercase
+ '/(?<!%)A/' => '%p', // Uppercase Ante meridiem and Post meridiem
+ '/(?<!%)d/' => '%d', // Day of the month, 2 digits with leading zeros
+ '/(?<!%)D/' => '%a', // A textual representation of a day, three letters
+ '/(?<!%)F/' => '%M', // A full textual representation of a month, such as January or March
+ '/(?<!%)g/' => '%l', // 12-hour format of an hour without leading zeros
+ '/(?<!%)G/' => '%k', // 24-hour format of an hour without leading zeros
+ '/(?<!%)h/' => '%h', // 12-hour format of an hour with leading zeros
+ '/(?<!%)H/' => '%H', // 24-hour format of an hour with leading zeros
+ '/(?<!%)i/' => '%i', // Minutes with leading zeros
+ '/(?<!%)I/' => 'N/A', // Whether or not the date is in daylights savings time
+
+ '/(?<!%)S/' => 'N/A', // English ordinal suffix for the day of the month, 2 characters, see below
+ '/jS/' => '%D', // MySQL can't return separate suffix, but could return date with suffix
+ '/(?<!%)j/' => '%e', // Day of the month without leading zeros
+ '/(?<!%)l/' => '%W', // A full textual representation of the day of the week
+ '/(?<!%)L/' => 'N/A', // Whether it's a leap year
+ '/(?<!%)m/' => '%m', // Numeric representation of a month, with leading zeros
+ '/(?<!%)M/' => '%b', // A short textual representation of a month, three letters
+ '/(?<!%)n/' => '%c', // Numeric representation of a month, without leading zeros
+ '/(?<!%)O/' => 'N/A', // Difference to Greenwich time (GMT) in hours
+ '/(?<!%)r/' => 'N/A', // RFC 2822 formatted date
+ '/(?<!%)s/' => '%s', // Seconds, with leading zeros
+ // S and jS moved before j - see above
+ '/(?<!%)t/' => 'N/A', // Number of days in the given month
+ '/(?<!%)T/' => 'N/A', // Timezone setting of this machine
+ '/(?<!%)U/' => 'N/A', // Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
+ '/(?<!%)w/' => '%w', // Numeric representation of the day of the week
+ '/(?<!%)W/' => '%v', // ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0)
+ '/(?<!%)Y/' => '%Y', // A full numeric representation of a year, 4 digits
+ '/(?<!%)y/' => '%y', // A two digit representation of a year
+ '/(?<!%)z/' => 'N/A', // The day of the year (starting from 0) => MySQL starts from 1
+ '/(?<!%)Z/' => 'N/A', // Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive.
+ );
+
+ $patterns = array_keys($mapping);
+ $replacements = array_values($mapping);
+
+ $res = preg_replace($patterns, $replacements, $format);
+ return $res;
+ }
+
+//function Parse($value, $options, &$errors)
+ function Parse($value, $field_name, &$object)
+ {
+ $options = $object->GetFieldOptions($field_name);
+
+ $dt_separator = getArrayValue($options,'date_time_separator');
+ if($dt_separator) $value = trim($value, $dt_separator);
+ if($value == '') return NULL;
+ //return strtotime($value);
+
+ $format = $options['format'];
+ if($dt_separator) $format = trim($format, $dt_separator);
+
+ $object->FieldErrors[$field_name]['params'] = Array( $this->HumanFormat($format), date($format) );
+ $object->FieldErrors[$field_name]['value'] = $value;
+
+ $hour = 0;
+ $minute = 0;
+ $second = 0;
+ $month = 1;
+ $day = 1;
+ $year = 1970;
+
+ $patterns['n'] = '([0-9]{1,2})';
+ $patterns['m'] = '([0-9]{1,2})';
+ $patterns['d'] = '([0-9]{1,2})';
+ $patterns['j'] = '([0-9]{1,2})';
+ $patterns['Y'] = '([0-9]{4})';
+ $patterns['y'] = '([0-9]{2})';
+ $patterns['G'] = '([0-9]{1,2})';
+ $patterns['g'] = '([0-9]{1,2})';
+ $patterns['H'] = '([0-9]{2})';
+ $patterns['h'] = '([0-9]{2})';
+ $patterns['i'] = '([0-9]{2})';
+ $patterns['s'] = '([0-9]{2})';
+ $patterns['a'] = '(am|pm)';
+ $patterns['A'] = '(AM|PM)';
+
+ $holders_mask = eregi_replace('[a-zA-Z]{1}', '([a-zA-Z]{1})', $format);
+ if (!ereg($holders_mask, $format, $holders)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ $values_mask = '/^'.$format.'$/';
+ foreach ($patterns as $key => $val) {
+ $values_mask = ereg_replace($key, $val, $values_mask);
+ }
+ // echo " values_mask : $values_mask <br>";
+
+ if (!preg_match($values_mask, $value, $values)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ for ($i = 1; $i < count($holders); $i++) {
+ switch ($holders[$i]) {
+ case 'n':
+ case 'm':
+ $month = $values[$i];
+ $month = ereg_replace("^0{1}", '', $month);
+ break;
+ case 'd':
+ $day = $values[$i];
+ $day = ereg_replace("^0{1}", '', $day);
+ break;
+ case 'Y':
+ $year = $values[$i];
+ break;
+ case 'y':
+ $year = $values[$i] >= 70 ? 1900 + $values[$i] : 2000 + $values[$i];
+ break;
+ case 'H':
+ case 'h':
+ case 'G':
+ case 'g':
+ $hour = $values[$i];
+ $hour = ereg_replace("^0{1}", '', $hour);
+ break;
+ case 'i':
+ $minute = $values[$i];
+ $minute = ereg_replace("^0{1}", '', $minute);
+ break;
+ case 's':
+ $second = $values[$i];
+ $second = ereg_replace("^0{1}", '', $second);
+ break;
+ case 'a':
+ case 'A':
+ if ($hour <= 12) { // if AM/PM used with 24-hour - could happen :)
+ if ($values[$i] == 'pm' || $values[$i] == 'PM') {
+ $hour += 12;
+ if ($hour == 24) $hour = 12;
+ }
+ elseif ($values[$i] == 'am' || $values[$i] == 'AM') {
+ if ($hour == 12) $hour = 0;
+ }
+ }
+ break;
+ }
+ }
+
+ //echo "day: $day, month: $month, year: $year, hour: $hour, minute: $minute<br>";
+
+ if (!($year >= 1970 && $year <= 2037)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ if (!($month >= 1 && $month <= 12)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ $months_days = Array ( 1 => 31,2 => 28, 3 => 31, 4 => 30,5 => 31,6 => 30, 7 => 31, 8 => 31,9 => 30,10 => 31,11 => 30,12 => 31);
+ if ($year % 4 == 0) $months_days[2] = 29;
+
+ if (!($day >=1 && $day <= $months_days[$month])) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ if (!($hour >=0 && $hour <= 23)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ if (!($minute >=0 && $minute <= 59)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ if (!($second >=0 && $second <= 59)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+ // echo "day: $day, month: $month, year: $year, hour: $hour, minute: $minute<br>";
+ return (mktime($hour, $minute, $second, $month, $day, $year));
+ }
+}
+
+class kUploadFormatter extends kFormatter
+{
+ var $DestinationPath;
+ var $FullPath;
+
+ function kUploadFormatter()
+ {
+ if ($this->DestinationPath)
+ {
+ $this->FullPath = DOC_ROOT.BASE_PATH.$this->DestinationPath;
+ }
+ parent::kBase();
+ }
+
+
+//function Parse($value, $options, &$errors)
+ function Parse($value, $field_name, &$object)
+ {
+ $ret = '';
+ $options = $object->GetFieldOptions($field_name);
+
+ if (getArrayValue($value, 'upload') && getArrayValue($value, 'error') == UPLOAD_ERR_NO_FILE)
+ {
+ return getArrayValue($value, 'upload');
+ }
+
+ if ( is_array($value) && $value['size'] )
+ {
+ if ( is_array($value) && $value['error'] === UPLOAD_ERR_OK )
+ {
+ if ( !in_array($value['type'], $options['allowed_types']) )
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_file_format';
+ }
+ elseif ( $value['size'] > ($options['max_size'] ? $options['max_size'] : MAX_UPLOAD_SIZE) )
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_file_size';
+ }
+ elseif ( !is_writable($this->FullPath) )
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'cant_save_file';
+ }
+ else
+ {
+ $real_name = $this->ValidateFileName($this->FullPath, $value['name']);
+ $file_name = $this->FullPath.$real_name;
+ if ( !move_uploaded_file($value['tmp_name'], $file_name) )
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'cant_save_file';
+ }
+ else
+ {
+ $ret = $this->DestinationPath.$real_name;
+ }
+ }
+ }
+ else
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'cant_save_file';
+ }
+ }
+
+ if ($value['error'] && !( $value['error'] == UPLOAD_ERR_NO_FILE ) && !$object->FieldErrors[$field_name]['pseudo'])
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'cant_save_file';
+ }
+
+ return $ret;
+ }
+
+ function ValidateFileName($path, $name)
+ {
+ $parts = pathinfo($name);
+ $ext = '.'.$parts['extension'];
+ $filename = substr($parts['basename'], 0, -strlen($ext));
+ $new_name = $filename.$ext;
+ while ( file_exists($path.'/'.$new_name) )
+ {
+ if ( preg_match("/({$filename}_)([0-9]*)($ext)/", $new_name, $regs) ) {
+ $new_name = $regs[1].($regs[2]+1).$regs[3];
+ }
+ else {
+ $new_name = $filename.'_1'.$ext;
+ }
+ }
+ return $new_name;
+ }
+
+}
+
+class kPictureFormatter extends kUploadFormatter
+{
+
+ function kPictureFormatter()
+ {
+ $this->NakeLookupPath = IMAGES_PATH;
+ $this->DestinationPath = IMAGES_PENDING_PATH;
+ parent::kUploadFormatter();
+ }
+
+}
+
+
+class kMultiLanguage extends kFormatter
+{
+
+ function LangFieldName($field_name)
+ {
+ $lang = $this->Application->GetVar('m_lang');
+ return 'l'.$lang.'_'.$field_name;
+ }
+
+ function PrepareOptions($field_name, &$field_options, &$object)
+ {
+ if (getArrayValue($object->Fields, $field_name, 'master_field')) return;
+
+ $lang_field_name = $this->LangFieldName($field_name);
+
+ //substitude title field
+ $title_field = $this->Application->getUnitOption($object->Prefix, 'TitleField');
+ if ($title_field = $field_name) {
+ $this->Application->setUnitOption($object->Prefix, 'TitleField', $lang_field_name);
+ }
+
+ //substitude fields
+ $fields = $this->Application->getUnitOption($object->Prefix, 'Fields');
+ if ( isset($fields[$field_name]) ) {
+
+ $fields[$lang_field_name] = $fields[$field_name];
+ $fields[$lang_field_name]['master_field'] = $field_name;
+ $object->Fields[$lang_field_name] = $fields[$lang_field_name];
+ $fields[$field_name]['required'] = false;
+ $object->Fields[$field_name]['required'] = false;
+ $object->VirtualFields[$field_name] = $object->Fields[$field_name];
+ }
+ $this->Application->setUnitOption($object->Prefix, 'Fields', $fields);
+
+ //substitude virtual fields
+ $virtual_fields = $this->Application->getUnitOption($object->Prefix, 'VirtualFields');
+ if ( isset($virtual_fields[$field_name]) ) {
+ $virtual_fields[$lang_field_name] = $virtual_fields[$field_name];
+ $virtual_fields[$lang_field_name]['master_field'] = $field_name;
+ $object->VirtualFields[$lang_field_name] = $virtual_fields[$lang_field_name];
+ $virtual_fields[$field_name]['required'] = false;
+ $object->VirtualFields[$field_name]['required'] = false;
+ }
+ $this->Application->setUnitOption($object->Prefix, 'VirtualFields', $virtual_fields);
+
+ //substitude grid fields
+ $grids = $this->Application->getUnitOption($object->Prefix, 'Grids');
+ foreach ($grids as $name => $grid) {
+ if ( getArrayValue($grid, 'Fields', $field_name) ) {
+ array_rename_key($grids[$name]['Fields'], $field_name, $lang_field_name);
+ }
+ }
+ $this->Application->setUnitOption($object->Prefix, 'Grids', $grids);
+
+ //substitude default sortings
+ $sortings = $this->Application->getUnitOption($object->Prefix, 'ListSortings');
+ foreach ($sortings as $special => $the_sortings) {
+ if (isset($the_sortings['ForcedSorting'])) {
+ array_rename_key($sortings[$special]['ForcedSorting'], $field_name, $lang_field_name);
+ }
+ if (isset($the_sortings['Sorting'])) {
+ array_rename_key($sortings[$special]['Sorting'], $field_name, $lang_field_name);
+ }
+ }
+ $this->Application->setUnitOption($object->Prefix, 'ListSortings', $sortings);
+
+ //TODO: substitude possible language-fields sortings after changing language
+ }
+
+ function UpdateSubFields($field, $value, &$options, &$object)
+ {
+ /*if ( $sub_fields = getArrayValue($options, 'sub_fields') ) {
+ if( isset($value) && $value )
+ {
+ $object->SetDBField( $sub_fields['date'], $value );
+ $object->SetDBField( $sub_fields['time'], $value );
+ }
+ }*/
+ }
+
+ function UpdateMasterFields($field, $value, &$options, &$object)
+ {
+ /*if ( $master_field = getArrayValue($object->Fields, $field, 'master_field') ) // this is Language field
+ {
+ $object->FieldErrors[$master_field] = $object->FieldErrors[$field]; // copy possible errors to master field
+ }
+ else { // THIS is master field
+ // do nothing
+ }*/
+
+
+ /*// when in master field - set own value from sub_fields
+ if ( $sub_fields = getArrayValue($options, 'sub_fields') ) {
+ // if date is not empty, but time is empty - set time to 0, otherwise master field fomratter will complain
+ // when we have only date field on form, we need time hidden field always empty, don't ask me why!
+ if ( $object->GetDBField($sub_fields['date']) != '' && $object->GetDBField($sub_fields['time']) == '' ) {
+ $object->SetDBField($sub_fields['time'], mktime(0, 0, 0));
+ }
+ $object->SetField($field, $object->GetField($sub_fields['date']).$options['date_time_separator'].$object->GetField($sub_fields['time']));
+ }
+ // when in one of sub_fields - call update for master_field to update its value from sub_fields [are you following ? :) ]
+ elseif ($master_field = getArrayValue($options, 'master_field') ) {
+ $this->UpdateMasterFields($master_field, null, $object->GetFieldOptions($master_field), $object);
+ }*/
+ }
+
+ function Format($value, $field_name, &$object, $format=null)
+ {
+ $master_field = getArrayValue($object->Fields, $field_name, 'master_field');
+ if (!$master_field) { // if THIS field is master it does NOT have reference to it's master_field
+ $lang = $this->Application->GetVar('m_lang');
+ $value = $object->GetDBField('l'.$lang.'_'.$field_name); //getting value of current language
+ $master_field = $field_name; // THIS is master_field
+ }
+ if ( $value == '' && $format != 'no_default') { // try to get default language value
+ $def_lang_value = $object->GetDBField('l'.$this->Application->GetDefaultLanguageId().'_'.$master_field);
+ if ($def_lang_value == '') return NULL;
+ return $def_lang_value; //return value from default language
+ }
+ return $value;
+ }
+
+ function Parse($value, $field_name, &$object)
+ {
+ $lang = $this->Application->GetVar('m_lang');
+ $def_lang = $this->Application->GetDefaultLanguageId();
+ $master_field = getArrayValue($object->Fields, $field_name, 'master_field');
+
+ if ( getArrayValue($object->Fields, $field_name, 'required') && ( (string) $value == '' ) ) {
+ $object->FieldErrors[$master_field]['pseudo'] = 'required';
+ };
+
+ if (!$this->Application->GetVar('allow_translation') && $lang != $def_lang && getArrayValue($object->Fields, $field_name, 'required')) {
+ $def_lang_field = 'l'.$def_lang.'_'.$master_field;
+ if ( !$object->ValidateRequired($def_lang_field, $object->Fields[$field_name]) ) {
+ $object->FieldErrors[$master_field]['pseudo'] = 'primary_lang_required';
+ }
+ }
+
+ if ($value == '') return NULL;
+ return $value;
+ }
+
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/formatters.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.2
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/utility/factory.php
===================================================================
--- trunk/core/kernel/utility/factory.php (revision 1338)
+++ trunk/core/kernel/utility/factory.php (revision 1339)
@@ -1,158 +1,196 @@
<?php
-//include_once(KERNEL_PATH."/mvc/controllers/grid_controller.php");
-//include_once(KERNEL_PATH."/mvc/controllers/item_controller.php");
-
class kFactory extends kBase {
/**
* Where all created objects are stored
*
* @var Array
* @access private
*/
var $Storage=Array();
/**
* Map between class name and file name
* where class definition can be found.
* File path absolute!
*
* @var Array
* @access private
*/
var $Files=Array();
/**
* Map class names to their pseudo
* class names, e.g. key=pseudo_class,
* value=real_class_name
*
* @var Array
* @access private
*/
var $realClasses=Array();
+ var $Dependencies=Array();
/**
* Splits any mixing of prefix and
* special into correct ones
*
* @param string $prefix_special
* @return Array
* @access public
*/
function processPrefix($prefix_special)
{
// l.pick, l, m.test_TagProcessor
+ //preg_match("/(.*)\.*(.*)(_*)(.*)/", $prefix_special, $regs);
+ //return Array('prefix'=>$regs[1].$regs[3].$regs[4], 'special'=>$regs[2]);
+
$tmp=explode('_',$prefix_special,2);
$tmp[0]=explode('.',$tmp[0]);
$prefix=$tmp[0][0];
+ $prefix_special=$prefix; // new1
if( isset($tmp[1]) )
{
$prefix.='_'.$tmp[1];
}
- $special=isset($tmp[0][1])?$tmp[0][1]:'';
-
- return Array('prefix'=>$prefix,'special'=>$special);
+ $special= isset($tmp[0][1]) ? $tmp[0][1] : '';
+ $prefix_special.='.'.$special; // new2
+ return Array('prefix'=>$prefix,'special'=>$special,'prefix_special'=>$prefix_special);
}
/**
* Returns object using params specified,
* creates it if is required
*
* @param string $name
* @param string $pseudo_class
* @param Array $event_params
* @return Object
*/
function &getObject($name,$pseudo_class='',$event_params=Array())
{
// $name = 'l.pick', $pseudo_class = 'l'
//echo 'N: '.$name.' - P: '.$pseudo_class."\n";
$ret=$this->processPrefix($name);
- if(!$pseudo_class)$pseudo_class=$ret['prefix'];
+ if (!$pseudo_class) $pseudo_class = $ret['prefix'];
$name=rtrim($name,'.');
if( isset($this->Storage[$name]) ) return $this->Storage[$name];
if(!isset($this->realClasses[$pseudo_class]))
{
$this->Application->KernelDie('RealClass not defined for pseudo_class <b>'.$pseudo_class.'</b>');
}
- $this->Storage[$name] =& $this->makeClass($pseudo_class);
- $this->Storage[$name]->Init($ret['prefix'],$ret['special']);
+ $funs_args = func_get_args();
+ array_splice($funs_args, 0, 3, Array($pseudo_class) );
+
+ $this->Storage[$name] =& call_user_func_array( Array(&$this,'makeClass'), $funs_args);
+ $this->Storage[$name]->Init($ret['prefix'],$ret['special'],$event_params);
$prefix=$this->Storage[$name]->Prefix;
$special=$this->Storage[$name]->Special;
$event_manager =& $this->getObject('EventManager');
$event =& $event_manager->getBuildEvent($pseudo_class);
if($event)
{
$event->Init($prefix,$special);
foreach($event_params as $param_name=>$param_value)
{
$event->setEventParam($param_name,$param_value);
}
$this->Application->HandleEvent($event);
}
return $this->Storage[$name];
}
+
+ /**
+ * Removes object from storage, so next time it could be created from scratch
+ *
+ * @param string $name Object's name in the Storage
+ */
+ function DestroyObject($name)
+ {
+ unset($this->Storage[$name]);
+ }
+
/**
* Includes file containing class
* definition for real class name
*
* @param string $real_class
* @access private
*/
function includeClassFile($real_class)
{
+ if (class_exists($real_class)) return;
+
if(!$this->Files[$real_class]) $this->Application->KernelDie('<b>Fatal error: Real Class '.$real_class.' is not registered with the Factory</b><br>');
if(!file_exists($this->Files[$real_class])) $this->Application->KernelDie('<b>Fatal error: Include file for class '.$real_class.' ('.$this->Files[$real_class].') does not exists</b><br>');
- include_once($this->Files[$real_class]);
+
+ if ( $deps = getArrayValue($this->Dependencies, $real_class) ) {
+ foreach ($deps as $filename) {
+ k4_include_once($filename);
+ }
+ }
+
+ k4_include_once($this->Files[$real_class]);
}
/**
* Get's real class name for pseudo class,
* includes class file and creates class
- * instance
+ * instance.
+ * All parameters except first one are passed to object constuctor
+ * through mediator method makeClass that creates instance of class
*
* @param string $pseudo_class
* @return Object
* @access private
*/
function &makeClass($pseudo_class)
{
$real_class=$this->realClasses[$pseudo_class];
$this->includeClassFile($real_class);
- /*if (!class_exists($real_class))
+
+ if( func_num_args() == 1 )
{
- $this->Application->KernelDie ("<b>Fatal error: Real Class $real_class (pseudo class $pseudo_class) not found in its registered file ".$this->Files[$pseudo_class].'<br>');
- }*/
- return new $real_class();
+ return new $real_class();
+ }
+ else
+ {
+ $func_args = func_get_args();
+ $pseudo_class = array_shift($func_args);
+ return call_user_func_array( Array($real_class,'makeClass'), $func_args );
+ }
}
/**
* Registers new class in the factory
*
* @param string $real_class
* @param string $file
* @param string $pseudo_class
* @access public
*/
function registerClass($real_class,$file,$pseudo_class=null)
{
if(!isset($pseudo_class)) $pseudo_class = $real_class;
if(!isset($this->Files[$real_class])) $this->Files[$real_class]=$file;
+
+ if (getArrayValue($this->realClasses, $pseudo_class)) {
+ $this->Dependencies[$real_class][] = $this->Files[ $this->realClasses[$pseudo_class] ];
+ }
+
$this->realClasses[$pseudo_class]=$real_class;
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/factory.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
\ No newline at end of property
+1.2
\ No newline at end of property
Index: trunk/core/kernel/utility/filters.php
===================================================================
--- trunk/core/kernel/utility/filters.php (nonexistent)
+++ trunk/core/kernel/utility/filters.php (revision 1339)
@@ -0,0 +1,106 @@
+<?php
+
+ class kMultipleFilter
+ {
+ var $type = FLT_TYPE_AND;
+ var $filters = Array();
+
+ /**
+ * Creates new instance of kMultipleFilter class
+ *
+ * @param int $type
+ * @return kMultipleFilter
+ */
+ function &makeClass($type=null)
+ {
+ return new kMultipleFilter($type);
+ }
+
+ /**
+ * Creates empty multiple filter
+ *
+ * @param int $type
+ * @return MultipleFilter
+ * @access public
+ */
+ function MultipleFilter($type=null)
+ {
+ if(isset($type)) $this->setType($type);
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param unknown_type $new_type
+ */
+ function setType($new_type)
+ {
+ $this->type = $new_type;
+ }
+
+ /**
+ * Adds new or replaces old filter with same name
+ *
+ * @param string $name
+ * @param mixed $clause kMultipleFilter object or where clause ifself
+ * @access public
+ */
+ function addFilter($name, $clause)
+ {
+ if( is_object($clause) && $clause->hasFilters() )
+ {
+ $this->filters[$name] = $clause->getSQL();
+ }
+ elseif( !is_object($clause) && $clause )
+ {
+ $this->filters[$name] = $clause;
+ }
+ }
+
+ /**
+ * Removes specified filter from filters list
+ *
+ * @param string $name
+ * @access public
+ */
+ function removeFilter($name)
+ {
+ unset($this->filters[$name]);
+ }
+
+ /**
+ * Remove all added filters
+ *
+ * @access public
+ */
+ function clearFilters()
+ {
+ $this->filters = Array();
+ }
+
+ /**
+ * Build where clause based on added filters and multiple filter type
+ *
+ * @return string
+ * @access public
+ */
+ function getSQL()
+ {
+ $filter_count = count($this->filters);
+ if(!$filter_count) return '';
+
+ return '('.implode(') '.$this->type.' (',$this->filters).')';
+ }
+
+ /**
+ * Allows to check if some filters are added to multiple filter
+ *
+ * @return bool
+ * @access public
+ */
+ function hasFilters()
+ {
+ return $this->filters ? true : false;
+ }
+ }
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/filters.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.2
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/event_handler.php
===================================================================
--- trunk/core/kernel/event_handler.php (revision 1338)
+++ trunk/core/kernel/event_handler.php (revision 1339)
@@ -1,97 +1,131 @@
<?php
/**
* Note:
* 1. When adressing variables from submit containing
* Prefix_Special as part of their name use
* $event->getPrefixSpecial(true) instead of
* $event->Prefix_Special as usual. This is due PHP
* is converting "." symbols in variable names during
* submit info "_". $event->getPrefixSpecial optional
* 1st parameter returns correct corrent Prefix_Special
* for variables beeing submitted such way (e.g. variable
* name that will be converted by PHP: "users.read_only_id"
* will be submitted as "users_read_only_id".
*
* 2. When using $this->Application-LinkVar on variables submitted
* from form which contain $Prefix_Special then note 1st item. Example:
* LinkVar($event->getPrefixSpecial(true).'_varname',$event->Prefix_Special.'_varname')
*
*/
/**
* Default event handler. Mostly abstract class
*
*/
class kEventHandler extends kBase {
/**
+ * In case if event should be handled with mehod,
+ * which name differs from event name, then it
+ * should be specified here.
+ * key - event name, value - event method
+ *
+ * @var Array
+ * @access protected
+ */
+ var $eventMethods=Array();
+
+ /**
+ * Define alternative event processing method names
+ *
+ * @see $eventMethods
+ * @access protected
+ */
+ function mapEvents()
+ {
+
+ }
+
+ /**
+ * Set's prefix and special
+ *
+ * @param string $prefix
+ * @param string $special
+ * @access public
+ */
+ function Init($prefix,$special)
+ {
+ parent::Init($prefix,$special);
+ $this->mapEvents();
+ }
+
+ /**
* Process Event
*
* @param kEvent $event
* @access public
*/
function processEvent(&$event)
{
- if( method_exists($this,$event->Name) )
+ $event_name=$event->Name;
+ if( isset($this->eventMethods[$event_name]) ) $event_name=$this->eventMethods[$event_name];
+
+ if( method_exists($this,$event_name) )
{
- $event_name = $event->Name;
- $this->$event_name(&$event);
- if($event->status==erSUCCESS && $event->redirect && strlen($event->redirect) > 0 )
- {
- $this->Application->Redirect($event->redirect);
- }
+ $this->$event_name($event);
}
else
{
$this->Application->KernelDie('event <b>'.$event->Name.'</b> not implemented in class <b>'.get_class($this).'</b>');
}
}
/**
* Sample dummy event
*
* @param kEvent $event
* @access protected
*/
function OnBuild(&$event)
{
/*echo 'building: <br>';
print_pre($event);*/
}
/**
* Apply some special processing to
* object beeing recalled before using
* it in other events that call prepareObject
*
* @param Object $object
* @param kEvent $event
* @access protected
*/
function prepareObject(&$object,&$event)
{
// processing here
}
/**
* Creates new event as child of
* event passed as $event param
*
* @param kEvent $event
* @access protected
*/
- function &inheritEvent(&$event)
+ function &inheritEvent(&$event, $name=null)
{
$child_event = new kEvent();
$child_event->MasterEvent =& $event;
$child_event->Prefix=$event->Prefix;
$child_event->Special=$event->Special;
$child_event->Prefix_Special=$event->Prefix_Special;
+ $child_event->Name = $name;
return $child_event;
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/event_handler.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
\ No newline at end of property
+1.3
\ No newline at end of property
Index: trunk/core/kernel/db/db_tag_processor.php
===================================================================
--- trunk/core/kernel/db/db_tag_processor.php (revision 1338)
+++ trunk/core/kernel/db/db_tag_processor.php (revision 1339)
@@ -1,141 +1,845 @@
<?php
class kDBTagProcessor extends TagProcessor {
/**
+ * Description
+ *
+ * @var DBConnection
+ * @access public
+ */
+ var $Conn;
+
+ function kDBTagProcessor()
+ {
+ parent::kBase();
+ $this->Conn =& $this->Application->GetADODBConnection();
+ }
+
+ /**
+ * Returns view menu name for current prefix
+ *
+ * @param Array $params
+ * @return string
+ */
+ function GetItemName($params)
+ {
+ $item_name = $this->Application->getUnitOption($this->Prefix,'ViewMenuPhrase');
+ return $this->Application->Phrase($item_name);
+ }
+
+ /**
+ * Draw filter menu content (for ViewMenu) based on filters defined in config
+ *
+ * @param Array $params
+ * @return string
+ */
+ function DrawFilterMenu($params)
+ {
+ $block_params = $this->prepareTagParams($params);
+ $block_params['name'] = $params['spearator_block'];
+ $separator = $this->Application->ParseBlock($block_params);
+ $filter_menu = $this->Application->getUnitOption($this->Prefix,'FilterMenu');
+
+ // Params: label, filter_action, filter_status
+ $block_params['name'] = $params['item_block'];
+
+ $view_filter = $this->Application->RecallVar($this->getPrefixSpecial().'_view_filter');
+ if($view_filter === false)
+ {
+ $event_params = Array('prefix'=>$this->Prefix,'special'=>$this->Special,'name'=>'OnRemoveFilters');
+ $this->Application->HandleEvent( new kEvent($event_params) );
+ $view_filter = $this->Application->RecallVar($this->getPrefixSpecial().'_view_filter');
+ }
+ $view_filter = unserialize($view_filter);
+
+ $filters = Array();
+ $prefix_special = $this->getPrefixSpecial();
+ foreach($filter_menu['Filters'] as $filter_key => $filter_params)
+ {
+ if(!$filter_params)
+ {
+ $filters[] = $separator;
+ continue;
+ }
+
+ $block_params['label'] = addslashes( $this->Application->Phrase($filter_params['label']) );
+ if( getArrayValue($view_filter,$filter_key) )
+ {
+ $submit = 0;
+ $status = 1;
+ }
+ else
+ {
+ $submit = 1;
+ $status = 0;
+ }
+ $block_params['filter_action'] = 'set_filter("'.$prefix_special.'","'.$filter_key.'","'.$submit.'");';
+ $block_params['filter_status'] = $status;
+ $filters[] = $this->Application->ParseBlock($block_params);
+ }
+ return implode('', $filters);
+ }
+
+ function IterateGridFields($params)
+ {
+ $mode = $params['mode'];
+ $def_block = $params['block'];
+
+ $grids = $this->Application->getUnitOption($this->Prefix,'Grids');
+ $grid_config = $grids[$params['grid']]['Fields'];
+
+ $std_params['pass_params']='true';
+ $std_params['PrefixSpecial']=$this->getPrefixSpecial();
+
+ $o = '';
+ foreach ($grid_config as $field => $options) {
+ $block_params = Array();
+ $block_params['name'] = isset($options[$mode.'_block']) ? $options[$mode.'_block'] : $def_block;
+ $block_params['field'] = $field;
+ $block_params['sort_field'] = isset($options['sort_field']) ? $options['sort_field'] : $field;
+ $block_params = array_merge($std_params, $block_params, $options);
+ $o.= $this->Application->ParseBlock($block_params, 1);
+ }
+ return $o;
+ }
+
+ /**
* Prints list content using block specified
*
* @param Array $params
* @return string
* @access public
*/
function PrintList($params)
{
$list =& $this->Application->recallObject( $this->getPrefixSpecial(), $this->Prefix.'_List',$params);
$id_field = $this->Application->getUnitOption($this->Prefix,'IDField');
- //<inp:cand_MapField field="candidate_id" var_name="cand_id"/>
+
+ $list->Query();
+ $o = '';
+ $list->GoFirst();
+
+ $block_params=$this->prepareTagParams($params);
+ $block_params['name']=$params['block'];
+ $block_params['pass_params']='true';
- /*$parser =& $this->Application->recallObject('TemplateParser');
+ while (!$list->EOL())
+ {
+ $this->Application->SetVar( $this->getPrefixSpecial().'_id', $list->GetDBField($id_field) ); // for edit/delete links using GET
+ $o.= $this->Application->ParseBlock($block_params, 1);
+ $list->GoNext();
+ }
+
+ $this->Application->SetVar( $this->getPrefixSpecial().'_id', '');
+ return $o;
+ }
+
+ /**
+ * Prints list content using block specified
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function PrintList2($params)
+ {
+ $prefix_special = $this->getPrefixSpecial();
+ $list =& $this->Application->recallObject( $prefix_special, $this->Prefix.'_List',$params);
- // only useful in case in inside prinklist block we have another
- // tagprocessor who wants to findout out printlist prefix and special
- $parser->SetParam('prefix', $this->Prefix);
- $parser->SetParam('special', $this->Special);*/
+ if ( !($list->OriginalParams == $params) ) {
+ $this->Application->removeObject($prefix_special);
+ $list =& $this->Application->recallObject($prefix_special,$this->Prefix.'_List',$params);
+ }
+ $id_field = $this->Application->getUnitOption($this->Prefix,'IDField');
+
$list->Query();
$o = '';
+
+ $direction = (isset($params['direction']) && $params['direction']=="H")?"H":"V";
+ $columns = (isset($params['columns']))?$params['columns']:1;
+
+ if ($columns>1 && $direction=="V") {
+ $list->Records = $this->LinearToVertical($list->Records, $columns, $params['per_page']);
+ $list->SelectedCount=count($list->Records);
+ ksort($list->Records);
+ }
+
+
$list->GoFirst();
+
+
$block_params=$this->prepareTagParams($params);
$block_params['name']=$params['block'];
$block_params['pass_params']='true';
+ $block_start_row_params=$this->prepareTagParams($params);
+ $block_start_row_params['name']=$params['row_start_block'];
+
+ $block_end_row_params=$this->prepareTagParams($params);
+ $block_end_row_params['name']=$params['row_end_block'];
+
+ $i=0;
+
+ $backup_id=$this->Application->GetVar($this->Prefix."_id");
+
while (!$list->EOL())
{
- $this->Application->SetVar( $this->getPrefixSpecial().'_id', $list->GetDBField($id_field) );
+ if (!$list->getCurrentRecord()){
+ //$list->GoNext();
+ //continue;
+ $block_params['name']=$params['block_empty_cell'];
+ }else{
+ $block_params['name']=$params['block'];
+ }
+ $this->Application->SetVar( $this->getPrefixSpecial().'_id', $list->GetDBField($id_field) ); // for edit/delete links using GET
+ $this->Application->SetVar( $this->Prefix.'_id', $list->GetDBField($id_field) );
+
+ if ($i%$params['columns'] == 0) $o.= $this->Application->ParseBlock($block_start_row_params, 1);
$o.= $this->Application->ParseBlock($block_params, 1);
+ if (($i+1)%$params['columns'] == 0) $o.= $this->Application->ParseBlock($block_end_row_params, 1);
+
$list->GoNext();
+
+ $i++;
}
+
+ $this->Application->SetVar( $this->Prefix.'_id', $backup_id);
+ $this->Application->SetVar( $this->getPrefixSpecial().'_id', '');
return $o;
}
/**
* Append prefix and special to tag
* params (get them from tagname) like
* they were really passed as params
*
* @param Array $tag_params
* @return Array
* @access protected
*/
function prepareTagParams($tag_params)
{
$ret=$tag_params;
$ret['Prefix']=$this->Prefix;
$ret['Special']=$this->Special;
$ret['PrefixSpecial']=$this->getPrefixSpecial();
return $ret;
}
/**
- * Get's reuested field value
+ * Get's requested field value
*
* @param Array $params
* @return string
* @access public
*/
function Field($params)
{
$field = $params['field'];
$object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
- $value = $object->GetField($field);
+ if ( getArrayValue($params, 'db') !== false )
+ {
+ $value = $object->GetDBField($field);
+ }
+ else
+ {
+ $format = getArrayValue($params, 'format');
+ if (!$format) {
+ $format = null;
+ }
+ else {
+ if (preg_match("/_regional_(.*)/", $format, $regs)) {
+ $lang = $this->Application->recallObject('lang');
+ $format = $lang->GetDBField($regs[1]);
+ }
+ }
+ $value = $object->GetField($field, $format);
+ }
+
+ if( getArrayValue($params,'nl2br' ) ) $value = nl2br($value);
+ if( !getArrayValue($params,'no_special') ) $value = htmlspecialchars($value);
+ if( getArrayValue($params,'checked' ) ) $value = ($value == 1) ? 'checked' : '';
+ if( getArrayValue($params,'as_label') ) $value = $this->Application->Phrase($value);
- if (isset($params['nl2br'])) $value = nl2br($value);
+ $cut_first = getArrayValue($params,'cut_first');
+ if($cut_first)
+ {
+ $needs_cut = strlen($value) > $cut_first;
+ $value = substr($value,0,$cut_first);
+ if($needs_cut) $value .= ' ...';
+ }
+ if ($value != '') $this->Application->Parser->DataExists = true;
+
return $value;
}
+ function Error($params)
+ {
+ $field = $params['field'];
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ $msg = $object->GetErrorMsg($field);
+
+ return $msg;
+ }
+
+ function HasError($params)
+ {
+ return $this->Error($params) != '';
+ }
+
+ function IsRequired($params)
+ {
+ $field = $params['field'];
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ $options = $object->GetFieldOptions($field);
+ return getArrayValue($options,'required');
+ }
+
+ function PredefinedOptions($params)
+ {
+ $field = $params['field'];
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ $value = $object->GetDBField($field);
+ $options = $object->GetFieldOptions($field);
+
+ $block_params['name'] = $params['block'];
+ $block_params['pass_params'] = 'true';
+ $selected = $params['selected'];
+
+ $o = '';
+ foreach ($options['options'] as $key => $val) {
+ $block_params['key'] = $key;
+ $block_params['option'] = $val;
+ $block_params[$selected] = ( $key == $value ? ' '.$selected : '');
+ $o .= $this->Application->ParseBlock($block_params, 1);
+ }
+
+ return $o;
+ }
+
+ function Format($params)
+ {
+ $field = $params['field'];
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ $options = $object->GetFieldOptions($field);
+ if (isset($options['formatter']) && (isset($params['human']) || isset($params['edit_size'])) ) {
+ $formatter =& $this->Application->recallObject($options['formatter']);
+ $format = $formatter->HumanFormat($options['format']);
+ return isset($params['edit_size']) ? strlen($format) : $format;
+ }
+
+ return $options['format'];
+ }
+
/**
* Print grid pagination using
* block names specified
*
* @param Array $params
* @return string
* @access public
*/
function PrintPages($params)
{
+
$prefix_special=$this->getPrefixSpecial();
$object =& $this->Application->recallObject($prefix_special,$this->Prefix.'_List',$params);
+
+ if ( !($object->OriginalParams == $params) ) {
+ $this->Application->removeObject($prefix_special);
+ $object =& $this->Application->recallObject($prefix_special,$this->Prefix.'_List',$params);
+ }
+
$total = $object->GetTotalPages();
$o = '';
+ // what are these 2 lines for?
$this->Application->SetVar($prefix_special.'_event','');
$this->Application->SetVar($prefix_special.'_id','');
- $current_page = $this->Application->RecallVar($prefix_special.'_page');
+ $current_page = $this->Application->RecallVar($prefix_special.'_Page');
- $block_params=$this->prepareTagParams($params);
+ $block_params = $this->prepareTagParams($params);
- for ($i=1; $i<=$total; $i++)
+ $split = ( isset($params['split'])?$params['split']:10 );
+
+ $split_start = $current_page - ceil($split/2);
+ if ($split_start < 1){
+ $split_start = 1;
+ }
+
+ $split_end = $split_start + $split-1;
+ if ($split_end > $total) {
+ $split_end = $total;
+ $split_start = max($split_end - $split + 1, 1);
+ }
+
+ if ($current_page > 1){
+ $prev_block_params=array();
+
+ if ($total > $split){
+ $prev_block_params['page']=max($current_page-$split, 1);
+ $prev_block_params['name'] = getArrayValue($params, 'prev_page_split_block');
+ if ($prev_block_params['name']){
+ $o .= $this->Application->ParseBlock($prev_block_params, 1);
+ }
+ }
+
+ $prev_block_params['name']="page";
+ $prev_block_params['page']=$current_page-1;
+ $prev_block_params['name'] = getArrayValue($params, 'prev_page_block');
+ if ($prev_block_params['name']){
+ $o .= $this->Application->ParseBlock($prev_block_params, 1);
+ }
+ }
+
+
+ for ($i = $split_start; $i<=$split_end; $i++)
{
- $this->Application->SetVar($prefix_special.'_page',$i);
+ //$this->Application->SetVar($prefix_special.'_Page',$i);
$block = $params[ (($i==$current_page)?'active':'inactive').'_block' ];
$block_params['name']=$block;
$block_params['page']=$i;
$o .= $this->Application->ParseBlock($block_params, 1);
}
+ if ($current_page < $total){
+ $next_block_params=array();
+ $next_block_params['page']=$current_page+1;
+ $next_block_params['name'] = getArrayValue($params, 'next_page_block');
+ if ($next_block_params['name']){
+ $o .= $this->Application->ParseBlock($next_block_params, 1);
+ }
+ if ($total > $split){
+ $next_block_params['page']=min($current_page+$split, $total);
+ $next_block_params['name'] = getArrayValue($params, 'next_page_split_block');
+ if ($next_block_params['name']){
+ $o .= $this->Application->ParseBlock($next_block_params, 1);
+ }
+ }
+ }
+
+
+
+
return $o;
}
-
- /*function MapField($params)
- {
- $object =& $this->Application->recallObject($this->Prefix.'.'.$this->Special);
- $value = $object->GetField($params['field']);
- $this->Application->SetVar($params['var_name'],$value);
- }*/
/**
* Returns input field name to
* be placed on form (for correct
* event processing)
*
* @param Array $params
* @return string
* @access public
*/
function InputName($params)
{
$prefix_special=$this->getPrefixSpecial();
$item = $this->Application->recallObject($prefix_special);
- return $prefix_special.'['.$item->GetID().']['.$params['field'].']';
+
+ if ( $formatter = getArrayValue($item->Fields, $params['field'], 'formatter') ) {
+ if ( $formatter == 'kMultiLanguage' ) {
+ $formatter =& $this->Application->recallObject($formatter);
+ $params['field'] = $formatter->LangFieldName($params['field']);
+ }
+ }
+
+ if ( $idfield = getArrayValue($params, 'IdField') ) {
+ $id = $item->GetDBField($idfield);
+ }
+ else {
+ $id = $item->GetID();
+ }
+
+ return $prefix_special.'['.$id.']['.$params['field'].']';
+ }
+
+
+
+ /**
+ * Returns index where 1st changable sorting field begins
+ *
+ * @return int
+ * @access private
+ */
+ function getUserSortIndex()
+ {
+ $list_sortings = $this->Application->getUnitOption($this->Prefix, 'ListSortings');
+ $sorting_prefix = getArrayValue($list_sortings, $this->Special) ? $this->Special : '';
+
+ $user_sorting_start = 0;
+ if ( $forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting') ) {
+ $user_sorting_start = count($forced_sorting);
+ }
+ return $user_sorting_start;
+ }
+
+ /**
+ * Returns order direction for given field
+ *
+ *
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function Order($params)
+ {
+ $field = $params['field'];
+ $user_sorting_start = $this->getUserSortIndex();
+
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+
+ if ($object->GetOrderField($user_sorting_start) == $field)
+ {
+ return $object->GetOrderDirection($user_sorting_start);
+ }
+ elseif($object->GetOrderField($user_sorting_start+1) == $field)
+ {
+ return '2_'.$object->GetOrderDirection($user_sorting_start+1);
+ }
+ else
+ {
+ return 'no';
+ }
+ }
+
+ /**
+ * Get's information of sorting field at "pos" position,
+ * like sorting field name (type="field") or sorting direction (type="direction")
+ *
+ * @param Array $params
+ * @return mixed
+ */
+ function OrderInfo($params)
+ {
+ $user_sorting_start = $this->getUserSortIndex() + --$params['pos'];
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+
+ if($params['type'] == 'field') return $object->GetOrderField($user_sorting_start);
+ if($params['type'] == 'direction') return $object->GetOrderDirection($user_sorting_start);
+ }
+
+ /**
+ * Checks if sorting field/direction matches passed field/direction parameter
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function IsOrder($params)
+ {
+ $params['type'] = isset($params['field']) ? 'field' : 'direction';
+ $value = $this->OrderInfo($params);
+
+ if( isset($params['field']) ) return $params['field'] == $value;
+ if( isset($params['direction']) ) return $params['direction'] == $value;
+ }
+
+ /**
+ * Returns list perpage
+ *
+ * @param Array $params
+ * @return int
+ */
+ function PerPage($params)
+ {
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+ return $object->PerPage;
+ }
+
+ /**
+ * Checks if list perpage matches value specified
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function PerPageEquals($params)
+ {
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+ return $object->PerPage == $params['value'];
+ }
+
+ function SaveEvent($params)
+ {
+ // SaveEvent is set during onbuild, but we may need it before any other tag calls onBuild
+ $prefix_special = $this->getPrefixSpecial();
+ $item = $this->Application->recallObject($prefix_special);
+
+ return $this->Application->GetVar($prefix_special.'_SaveEvent');
+ }
+
+ function NextId($params)
+ {
+ $prefix_special=$this->getPrefixSpecial();
+ $ids = explode(',', $this->Application->RecallVar($prefix_special.'_selected_ids'));
+ $item = $this->Application->recallObject($prefix_special);
+ $cur_id = $item->GetId();
+
+ $i = array_search($cur_id,$ids);
+ if ($i !== false) {
+ return $i < count($ids)-1 ? $ids[$i+1] : '';
+ }
+ return '';
+ }
+
+ function PrevId($params)
+ {
+ $prefix_special=$this->getPrefixSpecial();
+ $ids = explode(',', $this->Application->RecallVar($prefix_special.'_selected_ids'));
+ $item = $this->Application->recallObject($prefix_special);
+ $cur_id = $item->GetId();
+
+ $i = array_search($cur_id,$ids);
+ if ($i !== false) {
+ return $i > 0 ? $ids[$i-1] : '';
+ }
+ return '';
+ }
+
+ function IsSingle($params)
+ {
+ return ($this->NextId($params) === '' && $this->PrevId($params) === '');
+ }
+
+ function IsLast($params)
+ {
+ return ($this->NextId($params) === '');
+ }
+
+ function IsFirst($params)
+ {
+ return ($this->PrevId($params) === '');
+ }
+
+ /**
+ * Checks if field value is equal to proposed one
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function FieldEquals($params)
+ {
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+ $ret = $object->GetDBField($params['field']) == $params['value'];
+ if( getArrayValue($params,'inverse') ) $ret = !$ret;
+ return $ret;
+ }
+
+ function ItemIcon($params)
+ {
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ $grids = $this->Application->getUnitOption($this->Prefix,'Grids');
+ $icons =& $grids[ $params['grid'] ]['Icons'];
+
+ $key = '';
+ $status_fields = $this->Application->getUnitOption($this->Prefix,'StatusField');
+ if(!$status_fields) return $icons['default'];
+
+ foreach($status_fields as $status_field)
+ {
+ $key .= $object->GetDBField($status_field).'_';
+ }
+ $key = rtrim($key,'_');
+ $value = ($key !== false) ? $key : 'default';
+
+ return isset($icons[$value]) ? $icons[$value] : $icons['default'];
}
+ function SectionTitle($params)
+ {
+ $title_presets = $this->Application->getUnitOption($this->Prefix,'TitlePresets');
+ $title_info = getArrayValue($title_presets, $params['title_preset'] );
+ if($title_info === false) return $params['title'];
+
+ if( getArrayValue($title_presets,'default') )
+ {
+ // use default labels + custom labels specified in preset used
+ $title_info = array_merge_recursive2($title_presets['default'], $title_info);
+ }
+
+ $title = $title_info['format'];
+
+ // 1. get objects in use for title construction
+ $objects = Array();
+ $object_status = Array();
+ $status_labels = Array();
+
+ $prefixes = getArrayValue($title_info,'prefixes');
+ if($prefixes)
+ {
+ foreach($prefixes as $prefix_special)
+ {
+ $prefix_data = $this->Application->processPrefix($prefix_special);
+ $prefix_data['prefix_special'] = rtrim($prefix_data['prefix_special'],'.');
+ $objects[ $prefix_data['prefix_special'] ] =& $this->Application->recallObject($prefix_data['prefix_special'], $prefix_data['prefix'], $params);
+ $object_status[ $prefix_data['prefix_special'] ] = $objects[ $prefix_data['prefix_special'] ]->GetID() ? 'edit' : 'new';
+ // a. set object's status field (adding item/editing item) for each object in title
+ if( getArrayValue($title_info[ $object_status[ $prefix_data['prefix_special'] ].'_status_labels' ],$prefix_data['prefix_special']) )
+ {
+ $status_labels[ $prefix_data['prefix_special'] ] = $title_info[ $object_status[ $prefix_data['prefix_special'] ].'_status_labels' ][ $prefix_data['prefix_special'] ];
+ $title = str_replace('#'.$prefix_data['prefix_special'].'_status#', $status_labels[ $prefix_data['prefix_special'] ], $title);
+ }
+
+ // b. setting object's titlefield value (in titlebar ONLY) to default in case if object beeing created with no titlefield filled in
+ if( $object_status[ $prefix_data['prefix_special'] ] == 'new' )
+ {
+ $new_value = $this->getInfo( $objects[ $prefix_data['prefix_special'] ], 'titlefield' );
+ if(!$new_value && getArrayValue($title_info['new_titlefield'],$prefix_data['prefix_special']) ) $new_value = $this->Application->Phrase($title_info['new_titlefield'][ $prefix_data['prefix_special'] ]);
+ $title = str_replace('#'.$prefix_data['prefix_special'].'_titlefield#', $new_value, $title);
+ }
+ }
+ }
+
+ // 2. replace phrases if any found in format string
+ $title = $this->Application->ReplaceLanguageTags($title);
+
+ // 3. find and replace any replacement vars
+ preg_match_all('/#(.*_.*)#/Uis',$title,$rets);
+ if($rets[1])
+ {
+ $replacement_vars = array_keys( array_flip($rets[1]) );
+ foreach($replacement_vars as $replacement_var)
+ {
+ $var_info = explode('_',$replacement_var,2);
+ $object =& $objects[ $var_info[0] ];
+ $new_value = $this->getInfo($object,$var_info[1]);
+ $title = str_replace('#'.$replacement_var.'#', $new_value, $title);
+ }
+ }
+
+ return $title;
+ }
+ function getInfo(&$object, $info_type)
+ {
+ switch ($info_type)
+ {
+ case 'titlefield':
+ $field = $this->Application->getUnitOption($object->Prefix,'TitleField');
+ return $field !== false ? $object->GetField($field) : 'TitleField Missing';
+ break;
+
+ case 'recordcount':
+ $of_phrase = $this->Application->Phrase('la_of');
+ return $object->NoFilterCount != $object->RecordsCount ? $object->RecordsCount.' '.$of_phrase.' '.$object->NoFilterCount : $object->RecordsCount;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Parses block depending on its element type.
+ * For radio and select elements values are taken from 'value_list_field' in key1=value1,key2=value2
+ * format. key=value can be substituted by <SQL>SELECT f1 AS OptionName, f2 AS OptionValue... FROM <PREFIX>TableName </SQL>
+ * where prefix is TABLE_PREFIX
+ *
+ * @param Array $params
+ * @return string
+ */
+ function ConfigFormElement($params)
+ {
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+ $field = $params['field'];
+
+ $helper = $this->Application->recallObject('InpCustomFieldsHelper');
+
+ $element_type = $object->GetDBField($params['element_type_field']);
+
+ if($element_type=='label') $element_type='text';
+ $params['name']= $params['blocks_prefix'] . $element_type;
+
+ switch ($element_type){
+ case 'select':
+ case 'radio':
+ $field_options = $object->GetFieldOptions($field, 'options');
+ $field_options['options'] = $helper->GetValuesHash( $object->GetDBField($params['value_list_field']) );
+ $object->SetFieldOptions($field, $field_options);
+ break;
+
+ case 'textarea':
+ $params['field_params'] = $helper->ParseConfigSQL($object->GetDBField($params['value_list_field']));
+ break;
+
+ case 'password':
+ case 'text':
+ case 'checkbox':
+ default:
+ break;
+ }
+ return $this->Application->ParseBlock($params, 1);
+ }
+
+ /**
+ * Get's requested custom field value
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function CustomField($params)
+ {
+ $prefix = $this->getPrefixSpecial();
+ $object =& $this->Application->recallObject( $prefix );
+
+ $sql = ' SELECT cv.Value FROM '.TABLE_PREFIX.'CustomField cf
+ LEFT JOIN '.TABLE_PREFIX.'CustomMetaData cv
+ ON cf.CustomFieldId = cv.CustomFieldId
+ WHERE cf.Type = '.$this->Application->getUnitOption($prefix, 'ItemType').'
+ AND cv.ResourceId = '.$object->GetDBField('ResourceId').'
+ AND cf.FieldName = "'.$params['field'].'"';
+ return $this->Conn->GetOne($sql);
+ }
+
+ /**
+ * transposes 1-dimensional array elements for vertical alignment according to given columns and per_page parameters
+ *
+ * @param array $arr
+ * @param int $columns
+ * @param int $per_page
+ * @return array
+ */
+ function LinearToVertical(&$arr, $columns, $per_page){
+ $rows=$columns;
+ $cols=min(ceil($per_page/$columns), ceil(sizeof($arr)/$columns));
+ $imatrix=array();
+ for ($row=0; $row<$rows; $row++) {
+ for ($col=0; $col<$cols; $col++){
+ $imatrix[$col*$rows+$row]=$arr[$row*$cols+$col];
+ }
+ }
+ ksort($imatrix);
+ reset($imatrix);
+ return $imatrix;
+ }
+
+ function SaveWarning($params){
+
+ $top_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
+
+ if ( $this->Application->GetVar($top_prefix.'_mode') == 't' && $this->Application->RecallVar($top_prefix."_modified")=="1"){
+ return $this->Application->ParseBlock($params);
+ }else{
+ $this->Application->RemoveVar($top_prefix."_modified");
+ return "";
+ }
+ }
+
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/db/db_tag_processor.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
\ No newline at end of property
+1.3
\ No newline at end of property
Index: trunk/core/kernel/db/dblist.php
===================================================================
--- trunk/core/kernel/db/dblist.php (revision 1338)
+++ trunk/core/kernel/db/dblist.php (revision 1339)
@@ -1,393 +1,641 @@
<?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 {
/**
* Description
*
* @var array
* @access public
*/
var $OrderFields;
/**
- * Holds counted total number of records in the query - without pagination
+ * 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 unknown_type
+ * @var int
*/
var $SelectedCount=0;
/**
* Array of records selected
*
* @var Array
* @access private
*/
var $Records;
var $CurrentIndex = 0;
/**
- * Description
+ * List items per-page
*
* @var int
* @access public
*/
var $PerPage;
/**
- * Description
+ * 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);
+
+ /**
* 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;
}
/**
- * Sets counted part of SELECT query used in grouped queries
- *
- * When using queries containing GROUP BY clause, the SELECT part may contain aggregate functions such as SUM(), COUNT() etc.
- * the part of the query with this functions should be set as 'counted SQL' for {@link dDBList::CountRecs()} to build the correct
- * count query.
- * Example:
- * <code>
- * ...
- * $this->SetSelectSQL('SELECT product_id, SUM(amount) FROM sales');
- * $this->SetCounterSQL('SUM(amount)');
- * ...
- * </code>
- *
- * {@link kDBList::CountRecs()} will replace the SELECT part with COUNT(*), SUM(amount) when counting records, which will give the accurate
- * number of records. The number of records is used in list pagination
- *
- * @access public
- * @param string
- * @return void
- */
- function SetCountedSQL($sql)
+ * 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)
{
- $this->CountedSQL = $sql;
+ $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()
{
- $q = $this->GetSelectSQL();
- $counted_sql = '';
- if ($this->hasCounted) {
- $counted_sql = $this->GetCountedSQL();
- $counted_sql = ", $counted_sql";
- }
-
- if ( preg_match("/DISTINCT(.*?)FROM(?!_)/is",$q,$regs ) )
- $q = preg_replace("/^.*SELECT DISTINCT(.*?)FROM(?!_)/is", "SELECT COUNT(DISTINCT ".$regs[1].") AS count FROM", $q);
+ $sql = $this->GetSelectSQL(true,false);
+ $sql = $this->getCountSQL($sql);
+ $this->RecordsCount = (int)$this->Conn->GetOne($sql);
+
+ $sql = $this->GetSelectSQL(true,true);
+ $sql = $this->getCountSQL($sql);
+ $this->NoFilterCount = (int)$this->Conn->GetOne($sql);
+ }
+
+ 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
- $q = preg_replace("/^.*SELECT(.*?)FROM(?!_)/is", "SELECT COUNT(*) AS count $counted_sql FROM ", $q);
-
- if ($this->DisplayQueries) {
- echo get_class($this)." Count SQL: $q<br>";
+ {
+ return preg_replace("/^.*SELECT(.*?)FROM(?!_)/is", "SELECT COUNT(*) AS count FROM ", $sql);
}
-
- $this->RecordsCount = (int)$this->Conn->GetOne($q);
- $this->hasCounted=true;
}
/**
* 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()
{
$q = $this->GetSelectSQL();
if ($this->DisplayQueries) {
echo get_class($this)." Query SQL: $q LIMIT ".$this->PerPage." OFFSET ".$this->Offset." Page: ".$this->Page."<br>";
}
//$rs = $this->Conn->SelectLimit($q, $this->PerPage, $this->Offset);
$sql = $q.' '.$this->Conn->getLimitClause($this->Offset,$this->PerPage);
$this->Records = $this->Conn->Query($sql);
- $this->SelectedCount=count($this->Records);
+ $this->SelectedCount = count($this->Records);
if ($this->Records === false) {
//handle errors here
return false;
}
return true;
}
/**
* Builds full select query except for LIMIT clause
*
* @access public
* @return string
*/
- function GetSelectSQL()
+ function GetSelectSQL($for_counting=false,$system_filters_only=false)
{
- $q = parent::GetSelectSQL();
+ $q = parent::GetSelectSQL($this->SelectClause);
+ if(!$for_counting) $q = $this->addCalculatedFields($q);
- $where = $this->GetWhereClause();
- $having = $this->GetHavingClause();
+ $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($having)) $q .= ' HAVING ' . $having;
if (!empty($group)) $q .= ' GROUP BY ' . $group;
- if (!empty($order)) $q .= ' ORDER BY ' . $order;
+ if (!empty($having)) $q .= ' HAVING ' . $having;
+ if ( !$for_counting && !empty($order) ) $q .= ' ORDER BY ' . $order;
- return $q;
+ 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()
+ function GetWhereClause($for_counting=false,$system_filters_only=false)
{
- return '';
+ $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
*
- * @access public
+ * @param bool $for_counting don't return having filter in case if this is counting sql
* @return string
+ * @access public
*/
- function GetHavingClause()
+ function GetHavingClause($for_counting=false, $system_filters_only=false)
{
- return '';
+ 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 '';
}
/**
* 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)
{
$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) {
- $ret .= $field[0] . ' ' . $field[1] . ',';
+
+ $name = $field[0];
+ $ret .= isset($this->Fields[$name]) && !isset($this->VirtualFields[$name]) ? '`'.$this->TableName.'`.' : '';
+ $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(!$this->OrderFields[$pos])
+ $pos = 0;
+
+ return $this->OrderFields[$pos][1];
+ }
+
/**
- * Description
+ * Return unformatted field value
*
- * @access public
* @param string
- * @return void
+ * @return mixed
+ * @access public
*/
function GetDBField($name)
{
$row =& $this->getCurrentRecord();
return $row[$name];
}
- function GetField($name)
+ function HasField($name)
{
- return $this->GetDBField($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;
+ $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->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;
}
/**
* 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->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 ti 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');
+ $foreign_key_field = $this->Application->getUnitOption($this->Prefix, 'ForeignKey');
+
+ $parent_object =& $this->Application->recallObject($parent_prefix.'.'.$special);
+ $parent_id = $parent_object->GetDBField($parent_table_key);
+
+ $this->addFilter('parent_filter', $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.1
\ No newline at end of property
+1.2
\ No newline at end of property
Index: trunk/core/kernel/db/db_event_handler.php
===================================================================
--- trunk/core/kernel/db/db_event_handler.php (revision 1338)
+++ trunk/core/kernel/db/db_event_handler.php (revision 1339)
@@ -1,381 +1,1301 @@
<?php
+ define('EH_CUSTOM_PROCESSING_BEFORE',1);
+ define('EH_CUSTOM_PROCESSING_AFTER',2);
+
/**
* Note:
* 1. When adressing variables from submit containing
* Prefix_Special as part of their name use
* $event->getPrefixSpecial(true) instead of
* $event->Prefix_Special as usual. This is due PHP
* is converting "." symbols in variable names during
* submit info "_". $event->getPrefixSpecial optional
* 1st parameter returns correct corrent Prefix_Special
* for variables beeing submitted such way (e.g. variable
* name that will be converted by PHP: "users.read_only_id"
* will be submitted as "users_read_only_id".
*
* 2. When using $this->Application-LinkVar on variables submitted
* from form which contain $Prefix_Special then note 1st item. Example:
* LinkVar($event->getPrefixSpecial(true).'_varname',$event->Prefix_Special.'_varname')
*
*/
/**
* EventHandler that is used to process
* any database related events
*
*/
class kDBEventHandler extends kEventHandler {
/**
- * Get's ID of item to be edited.
- * Returns 1st id in case if many
- * items were selected.
+ * Description
+ *
+ * @var DBConnection
+ * @access public
+ */
+ var $Conn;
+
+ /**
+ * Adds ability to address db connection
+ *
+ * @return kDBEventHandler
+ * @access public
+ */
+ function kDBEventHandler()
+ {
+ parent::kBase();
+ $this->Conn =& $this->Application->GetADODBConnection();
+ }
+
+ function mapEvents()
+ {
+ $events_map = Array('OnRemoveFilters' => 'FilterAction',
+ 'OnApplyFilters' => 'FilterAction');
+
+ $this->eventMethods = array_merge($this->eventMethods, $events_map);
+ }
+
+ /**
+ * Returns ID of current item to be edited
+ * by checking ID passed in get/post as prefix_id
+ * or by looking at first from selected ids, stored.
+ * Returned id is also stored in Session in case
+ * it was explicitly passed as get/post
*
* @param kEvent $event
* @return int
*/
function getPassedID(&$event)
{
- $ret=$this->Application->GetVar($event->getPrefixSpecial().'_id');
- if($ret===false)
- {
- $ids=$this->Application->GetVar($event->getPrefixSpecial().'_selected_ids');
+ //$ret = $this->Application->GetLinkedVar($event->getPrefixSpecial(true).'_id', $event->getPrefixSpecial().'_id');
+
+ // ?? We don't need to store selected id in session, as long as we have pass=all by default, which
+ // means that main item id will be passed to all sub-item screens by default
+ // another prove of that is that sub-items relay on main item '_mode' = 't' for switching to temp tables
+ // Also having id in session raised problems with the id of deleted item stuck in session
+ $ret = $this->Application->GetVar($event->getPrefixSpecial(true).'_id');
+ if ($ret) return $ret; // if id was passed explicity as prefix[_special]_id use it, and store it in session
+
+ // recall selected ids array and use the first one
+ $ids=$this->Application->GetVar($event->getPrefixSpecial().'_selected_ids');
+ if ($ids != '') {
$ids=explode(',',$ids);
if($ids) $ret=array_shift($ids);
}
+ else { // if selected ids are not yet stored
+ $this->StoreSelectedIDs($event);
+ return $this->Application->GetVar($event->getPrefixSpecial(true).'_id'); // StoreSelectedIDs sets this variable
+ }
return $ret;
}
/**
+ * Prepares and stores selected_ids string
+ * in Session and Application Variables
+ * by getting all checked ids from grid plus
+ * id passed in get/post as prefix_id
+ *
+ * @param kEvent $event
+ */
+ function StoreSelectedIDs(&$event)
+ {
+ $ret = Array();
+
+ // May be we don't need this part: ?
+ $passed = $this->Application->GetVar($event->getPrefixSpecial(true).'_id');
+ if($passed !== false && $passed != '')
+ {
+ array_push($ret, $passed);
+ }
+
+ $ids = Array();
+
+ // get selected ids from post & save them to session
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if($items_info)
+ {
+ $id_field = $this->Application->getUnitOption($event->Prefix,'IDField');
+ foreach($items_info as $id => $field_values)
+ {
+ if( getArrayValue($field_values,$id_field) ) array_push($ids,$id);
+ }
+ //$ids=array_keys($items_info);
+ }
+
+ $ret = array_unique(array_merge($ret, $ids));
+
+ $this->Application->SetVar($event->getPrefixSpecial().'_selected_ids',implode(',',$ret));
+ $this->Application->LinkVar($event->getPrefixSpecial().'_selected_ids');
+
+ // This is critical - otherwise getPassedID will return last ID stored in session! (not exactly true)
+ // this smells... needs to be refactored
+ $first_id = getArrayValue($ret,0);
+ if($first_id === false) trigger_error('Requested ID for prefix <b>'.$event->getPrefixSpecial().'</b> <span class="debug_error">not passed</span>',E_USER_NOTICE);
+ $this->Application->SetVar($event->getPrefixSpecial(true).'_id', $first_id);
+ }
+
+ /**
+ * Returns stored selected ids as an array
+ *
+ * @param kEvent $event
+ * @return array
+ */
+ function getSelectedIDs(&$event)
+ {
+ return explode(',', $this->Application->GetVar($event->getPrefixSpecial().'_selected_ids'));
+ }
+
+ /**
+ * Returs associative array of submitted fields for current item
+ * Could be used while creating/editing single item -
+ * meaning on any edit form, except grid edit
+ *
+ * @param kEvent $event
+ */
+ function getSubmittedFields(&$event)
+ {
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ $field_values = $items_info ? array_shift($items_info) : Array();
+ return $field_values;
+ }
+
+ /**
+ * Removes any information about current/selected ids
+ * from Application variables and Session
+ *
+ * @param kEvent $event
+ */
+ function clearSelectedIDs(&$event)
+ {
+ $prefix_special = $event->getPrefixSpecial();
+ $this->Application->RemoveVar($prefix_special.'_selected_ids');
+ $this->Application->SetVar($prefix_special.'_selected_ids', '');
+ $this->Application->RemoveVar($prefix_special.'_id'); // not needed anymore ??
+ $this->Application->SetVar($prefix_special.'_id', '');
+ //$this->Application->RemoveVar($prefix_special.'_modified');
+ }
+
+ /*function SetSaveEvent(&$event)
+ {
+ $this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnUpdate');
+ $this->Application->LinkVar($event->Prefix_Special.'_SaveEvent');
+ }*/
+
+ /**
+ * Common builder part for Item & List
+ *
+ * @param kDBBase $object
+ * @param kEvent $event
+ * @access private
+ */
+ function dbBuild(&$object,&$event)
+ {
+ $object->Configure();
+
+ if( $this->UseTempTables($event) )
+ {
+ $object->SwitchToTemp();
+ }
+
+ // This strange constuction creates hidden field for storing event name in form submit
+ // It pass SaveEvent to next screen, otherwise after unsuccsefull create it will try to update rather than create
+ $current_event = $this->Application->GetVar($event->Prefix_Special.'_event');
+ $this->Application->setEvent($event->Prefix_Special, $current_event);
+
+ $save_event = $this->UseTempTables($event) && $this->Application->GetTopmostPrefix($event->Prefix) == $event->Prefix ? 'OnSave' : 'OnUpdate';
+ $this->Application->SetVar($event->Prefix_Special.'_SaveEvent',$save_event);
+ }
+
+ /**
* Builds item (loads if needed)
*
* @param kEvent $event
* @access protected
*/
function OnItemBuild(&$event)
{
- $object =& $event->createObject();
- $this->dbBuild(&$object,&$event);
+ $object =& $event->getObject();
+ $this->dbBuild($object,$event);
- $sql=$this->getSelectSQL($event,'OnItemPrepareQuery');
+ $sql = $this->ItemPrepareQuery($event);
+ $sql = $this->Application->ReplaceLanguageTags($sql);
$object->setSelectSQL($sql);
- // 1. set from config what needed
- $fields = $this->Application->getUnitOption($event->Prefix,'Fields');
- $object->setConfigFields( array_keys($fields) );
-
// 2. loads if allowed
$auto_load = $this->Application->getUnitOption($event->Prefix,'AutoLoad');
- if($auto_load)
- {
- $id = $this->getPassedID(&$event);
- $object->Load($id);
+ if($auto_load) $this->LoadItem($event);
+
+ $actions =& $this->Application->recallObject('kActions');
+ $actions->Set($event->Prefix_Special.'_GoTab', '');
+
+ $actions->Set($event->Prefix_Special.'_GoId', '');
+ }
+
+ /**
+ * Build subtables array from configs
+ *
+ * @param kEvent $event
+ */
+ function OnTempHandlerBuild(&$event)
+ {
+ $object =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $object->BuildTables( $event->Prefix, $this->getSelectedIDs($event) );
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ * @return unknown
+ */
+ function UseTempTables(&$event)
+ {
+ $object = &$event->getObject();
+ $top_prefix = $this->Application->GetTopmostPrefix($event->Prefix);
+ return $this->Application->GetVar($top_prefix.'_mode') == 't';
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ * @return unknown
+ */
+ function __GetTopmostPrefix(&$event)
+ {
+ $current_prefix = $event->Prefix;
+ while ( $parent_prefix = $this->Application->getUnitOption($current_prefix, 'ParentPrefix') ) {
+ $current_prefix = $parent_prefix;
}
- $this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnUpdate');
+ return $current_prefix;
+ }
+
+ function LoadItem(&$event)
+ {
+ $object =& $event->getObject();
+ if ( $event->getEventParam('ByParent') ) {
+ $parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
+ $parent_table_key = $this->Application->getUnitOption($event->Prefix, 'ParentTableKey');
+ $parent_object =& $this->Application->recallObject($parent_prefix);
+ $id = $parent_object->GetDBField($parent_table_key);
+ $id_field = $this->Application->getUnitOption($event->Prefix, 'ForeignKey');
+ }
+ else {
+ $id = $this->getPassedID($event);
+ $id_field = null;
+ }
+ $object->Load($id, $id_field);
+
+ $actions =& $this->Application->recallObject('kActions');
+ $actions->Set($event->Prefix_Special.'_id', $object->GetId());
}
/**
* Builds list
*
* @param kEvent $event
* @access protected
*/
function OnListBuild(&$event)
{
- $event->setPseudoClass('_List');
- $object =& $event->createObject();
+ //$event->setPseudoClass('_List');
+ $object =& $event->getObject();
- $this->dbBuild(&$object,&$event);
+ $this->dbBuild($object,$event);
- $sql=$this->getSelectSQL($event,'OnListPrepareQuery');
+ $sql = $this->ListPrepareQuery($event);
+ $sql = $this->Application->ReplaceLanguageTags($sql);
$object->setSelectSQL($sql);
- $t=$this->Application->GetVar('t');
- $this->Application->StoreVar('redirect_to',$t);
+ $object->linkToParent('');
+
+ $this->AddFilters($event);
+ $this->SetCustomQuery($event); // new!, use this for dynamic queries based on specials for ex.
+ $this->SetPagination($event);
+ $this->SetSorting($event);
+
+ $actions =& $this->Application->recallObject('kActions');
+ $actions->Set('remove_specials['.$event->Prefix_Special.']', '0');
+ $actions->Set($event->Prefix_Special.'_GoTab', '');
+ }
+
+
+
+ /**
+ * Apply any custom changes to list's sql query
+ *
+ * @param kEvent $event
+ * @access protected
+ * @see OnListBuild
+ */
+ function SetCustomQuery(&$event)
+ {
- $this->SetPagination(&$event);
- $this->SetSorting(&$event);
+ }
+
+ /**
+ * Set's new perpage for grid
+ *
+ * @param kEvent $event
+ */
+ function OnSetPerPage(&$event)
+ {
+ $per_page = $this->Application->GetVar($event->getPrefixSpecial(true).'_PerPage');
+ $this->Application->StoreVar( $event->getPrefixSpecial().'_PerPage', $per_page );
}
/**
* Set's correct page for list
* based on data provided with event
*
* @param kEvent $event
* @access private
* @see OnListBuild
*/
function SetPagination(&$event)
{
+ // get PerPage (forced -> session -> config -> 10)
$per_page = $event->getEventParam('per_page');
if(!$per_page)
{
- $per_page=$this->Application->RecallVar($event->Prefix_Special.'_PerPage');
+ $per_page_var = $event->getPrefixSpecial().'_PerPage';
+
+ $per_page = $this->Application->RecallVar($per_page_var);
if(!$per_page)
{
- $per_page=10;
+ $per_page = $this->Application->ConfigValue($per_page_var);
+ if(!$per_page) $per_page = 10;
}
}
- $event->setPseudoClass('_List');
- $object =& $event->createObject();
+ $object =& $event->getObject();
$object->SetPerPage($per_page);
- $object->CountRecs();
-
- $object->SetPage( $this->Application->GetLinkedVar( $event->Prefix_Special.'_Page' ) );
+
+ if( !$event->getEventParam('skip_counting') )
+ {
+ $object->CountRecs();
+
+ $this->Application->StoreVarDefault($event->getPrefixSpecial().'_Page', 1);
+
+ $page = $this->Application->GetLinkedVar($event->getPrefixSpecial(true).'_Page', $event->getPrefixSpecial().'_Page');
+ $pages = $object->GetTotalPages();
+
+ if($page > $pages)
+ {
+ $this->Application->StoreVar($event->getPrefixSpecial().'_Page', 1);
+ $page = 1;
+ }
+
+ $object->SetPage($page);
+ }
}
/**
* Set's correct sorting for list
* based on data provided with event
*
* @param kEvent $event
* @access private
* @see OnListBuild
*/
function SetSorting(&$event)
{
$event->setPseudoClass('_List');
- $object =& $event->createObject();
+ $object =& $event->getObject();
$cur_sort1 = $this->Application->RecallVar($event->Prefix_Special.'_Sort1');
$cur_sort1_dir = $this->Application->RecallVar($event->Prefix_Special.'_Sort1_Dir');
$cur_sort2 = $this->Application->RecallVar($event->Prefix_Special.'_Sort2');
$cur_sort2_dir = $this->Application->RecallVar($event->Prefix_Special.'_Sort2_Dir');
- //Use default if not specified
- /*if ( $cur_sort1 === false || $cur_sort1_dir == false ) {
- $cur_sort1 = $this->Application->ConfigOption($event->Prefix_Special.'_Sort1');
- $cur_sort1_dir = $this->Application->ConfigOption($event->Prefix_Special.'_Sort1_Dir');
- $cur_sort2 = $this->Application->ConfigOption($event->Prefix_Special.'_Sort2');
- $cur_sort2_dir = $this->Application->ConfigOption($event->Prefix_Special.'_Sort2_Dir');
- }*/
+ $list_sortings = $this->Application->getUnitOption($event->Prefix, 'ListSortings');
+ $sorting_prefix = getArrayValue($list_sortings, $event->Special) ? $event->Special : '';
+
+ // Use default if not specified
+ if ( !$cur_sort1 || !$cur_sort1_dir)
+ {
+ if ( $sorting = getArrayValue($list_sortings, $sorting_prefix, 'Sorting') ) {
+ reset($sorting);
+ $cur_sort1 = key($sorting);
+ $cur_sort1_dir = current($sorting);
+ if (next($sorting)) {
+ $cur_sort2 = key($sorting);
+ $cur_sort2_dir = current($sorting);
+ }
+ }
+ }
+
+ if ( $forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting') ) {
+ foreach ($forced_sorting as $field => $dir) {
+ $object->AddOrderField($field, $dir);
+ }
+ }
if($cur_sort1 != '' && $cur_sort1_dir != '')
{
$object->AddOrderField($cur_sort1, $cur_sort1_dir);
}
if($cur_sort2 != '' && $cur_sort2_dir != '')
{
$object->AddOrderField($cur_sort2, $cur_sort2_dir);
}
}
+
/**
- * Some kind of filter processing stuff.
- * Not in use by now
+ * Add filters found in session
*
+ * @param kEvent $event
*/
- function AddFilters()
+ function AddFilters(&$event)
{
-
+ $object =& $event->getObject();
+
+ $search_filter = $this->Application->RecallVar($event->getPrefixSpecial().'_search_filter');
+ if($search_filter)
+ {
+ $search_filter = unserialize($search_filter);
+ foreach($search_filter as $search_field => $filter_params)
+ {
+ $filter_type = ($filter_params['type'] == 'having') ? HAVING_FILTER : WHERE_FILTER;
+ $object->addFilter($search_field, $filter_params['value'], $filter_type, FLT_SEARCH);
+ }
+ }
+
+ $view_filter = $this->Application->RecallVar($event->getPrefixSpecial().'_view_filter');
+ if($view_filter)
+ {
+ $view_filter = unserialize($view_filter);
+ $temp_filter =& $this->Application->makeClass('kMultipleFilter');
+ $filter_menu = $this->Application->getUnitOption($event->Prefix,'FilterMenu');
+
+ $group_key = 0; $group_count = count($filter_menu['Groups']);
+ while($group_key < $group_count)
+ {
+ $group_info = $filter_menu['Groups'][$group_key];
+
+ $temp_filter->setType( constant('FLT_TYPE_'.$group_info['mode']) );
+ $temp_filter->clearFilters();
+ foreach ($group_info['filters'] as $flt_id)
+ {
+ $sql_key = getArrayValue($view_filter,$flt_id) ? 'on_sql' : 'off_sql';
+ if ($filter_menu['Filters'][$flt_id][$sql_key] != '')
+ {
+ $temp_filter->addFilter('view_filter_'.$flt_id, $filter_menu['Filters'][$flt_id][$sql_key]);
+ }
+ }
+ $object->addFilter('view_group_'.$group_key, $temp_filter, $group_info['type'] , FLT_VIEW);
+ $group_key++;
+ }
+ }
}
/**
* Set's new sorting for list
*
* @param kEvent $event
* @access protected
*/
function OnSetSorting(&$event)
{
- $this->Application->LinkVar($event->getPrefixSpecial(true).'_Sort1',$event->Prefix_Special.'_Sort1');
- $this->Application->LinkVar($event->getPrefixSpecial(true).'_Sort1_Dir',$event->Prefix_Special.'_Sort1_Dir');
+ $cur_sort1 = $this->Application->RecallVar($event->Prefix_Special.'_Sort1');
+ $cur_sort1_dir = $this->Application->RecallVar($event->Prefix_Special.'_Sort1_Dir');
+ $cur_sort2 = $this->Application->RecallVar($event->Prefix_Special.'_Sort2');
+ $cur_sort2_dir = $this->Application->RecallVar($event->Prefix_Special.'_Sort2_Dir');
- //$event->setPseudoClass('_List');
- //$object =& $event->createObject();
+ $passed_sort1 = $this->Application->GetVar($event->getPrefixSpecial(true).'_Sort1');
+ if ($cur_sort1 == $passed_sort1) {
+ $cur_sort1_dir = $cur_sort1_dir == 'asc' ? 'desc' : 'asc';
+ }
+ else {
+ $cur_sort2 = $cur_sort1;
+ $cur_sort2_dir = $cur_sort1_dir;
+ $cur_sort1 = $passed_sort1;
+ $cur_sort1_dir = 'asc';
+ }
+
+ $this->Application->StoreVar($event->Prefix_Special.'_Sort1', $cur_sort1);
+ $this->Application->StoreVar($event->Prefix_Special.'_Sort1_Dir', $cur_sort1_dir);
+ $this->Application->StoreVar($event->Prefix_Special.'_Sort2', $cur_sort2);
+ $this->Application->StoreVar($event->Prefix_Special.'_Sort2_Dir', $cur_sort2_dir);
}
/**
- * Common builder part for Item & List
+ * Set sorting directly to session
*
- * @param Object $object
- * @access private
+ * @param kEvent $event
*/
- function dbBuild(&$object,&$event)
+ function OnSetSortingDirect(&$event)
{
- // set Item & List common parameters from config
- $table = $this->Application->getUnitOption($event->Prefix,'TableName');
- $object->setTableName($table);
-
- $id_field = $this->Application->getUnitOption($event->Prefix,'IDField');
- $object->setIDField($id_field);
-
- // get selected ids from post & save them to session
- $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
- if($items_info)
- {
- $ids=array_keys($items_info);
- $this->Application->SetVar($event->getPrefixSpecial().'_selected_ids',implode(',',$ids));
- }
- $this->Application->LinkVar($event->getPrefixSpecial().'_selected_ids');
-
- // set's any possible hidden fields needed for both Item & List
- $current_event = $this->Application->GetVar($event->Prefix_Special.'_event');
- $this->Application->setEvent($event->Prefix_Special,$current_event);
+ $field_pos = $this->Application->GetVar($event->getPrefixSpecial(true).'_SortPos');
+ $this->Application->LinkVar( $event->getPrefixSpecial(true).'_Sort'.$field_pos, $event->Prefix_Special.'_Sort'.$field_pos);
+ $this->Application->LinkVar( $event->getPrefixSpecial(true).'_Sort'.$field_pos.'_Dir', $event->Prefix_Special.'_Sort'.$field_pos.'_Dir');
}
/**
- * Returns select query for loading item/list
+ * Reset grid sorting to default (from config)
*
* @param kEvent $event
- * @param string $event_name
- * @return string
- * @access protected
*/
- function getSelectSQL(&$event,$event_name)
+ function OnResetSorting(&$event)
{
- $new_event =& $this->inheritEvent(&$event);
- $new_event->Name=$event_name;
- $this->Application->HandleEvent(&$new_event);
- return $event->getEventParam('SQLQuery');
+ $this->Application->RemoveVar($event->Prefix_Special.'_Sort1');
+ $this->Application->RemoveVar($event->Prefix_Special.'_Sort1_Dir');
+ $this->Application->RemoveVar($event->Prefix_Special.'_Sort2');
+ $this->Application->RemoveVar($event->Prefix_Special.'_Sort2_Dir');
}
/**
* Creates needed sql query to load item,
* if no query is defined in config for
* special requested, then use default
* query
*
* @param kEvent $event
* @access protected
*/
- function OnItemPrepareQuery(&$event)
+ function ItemPrepareQuery(&$event)
{
$sqls = $this->Application->getUnitOption($event->Prefix,'ItemSQLs');
- $sql = isset($sqls[$event->Special])?$sqls[$event->Special]:$sqls[''];
- $event->MasterEvent->setEventParam('SQLQuery',$sql);
+ return isset($sqls[$event->Special]) ? $sqls[$event->Special] : $sqls[''];
}
/**
* Creates needed sql query to load list,
* if no query is defined in config for
* special requested, then use default
* query
*
* @param kEvent $event
* @access protected
*/
- function OnListPrepareQuery(&$event)
+ function ListPrepareQuery(&$event)
{
$sqls = $this->Application->getUnitOption($event->Prefix,'ListSQLs');
- $sql = isset($sqls[$event->Special])?$sqls[$event->Special]:$sqls[''];
- $event->MasterEvent->setEventParam('SQLQuery',$sql);
+ return isset( $sqls[$event->Special] ) ? $sqls[$event->Special] : $sqls[''];
}
/**
* Creates new kDBItem
*
* @param kEvent $event
* @access protected
*/
function OnCreate(&$event)
{
- $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false);
- $object =& $event->createObject();
- $this->prepareObject(&$object,&$event);
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if($items_info) $field_values = array_shift($items_info);
$object->SetFieldsFromHash($field_values);
- if( $object->Create() )
+ $this->customProcessing($event,'before');
+
+ //look at kDBItem' Create for ForceCreateId description, it's rarely used and is NOT set by default
+ if( $object->Create($event->getEventParam('ForceCreateId')) )
{
+ if ($this->UseTempTables($event)) $object->setTempID();
+ $this->customProcessing($event,'after');
$event->status=erSUCCESS;
+ $event->redirect_params = Array('opener'=>'u');
}
else
{
- $event->status=erFATAL;
+ $event->status=erFAIL;
$event->redirect=false;
+ $this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
+ $object->setID(0);
}
}
/**
* Updates kDBItem
*
* @param kEvent $event
* @access protected
*/
function OnUpdate(&$event)
{
- $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false);
- $object =& $event->createObject();
- $this->prepareObject(&$object,&$event);
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if($items_info)
{
foreach($items_info as $id => $field_values)
{
- //$object->Load($id);
+ $object->Load($id);
$object->SetFieldsFromHash($field_values);
+ $this->customProcessing($event, 'before');
if( $object->Update($id) )
{
+ $this->customProcessing($event, 'after');
$event->status=erSUCCESS;
}
else
{
- $event->status=erFATAL;
+ $event->status=erFAIL;
$event->redirect=false;
break;
}
}
}
-
+ $event->redirect_params = Array('opener'=>'u');
}
/**
* Delete's kDBItem object
*
* @param kEvent $event
* @access protected
*/
function OnDelete(&$event)
{
- $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false);
- $object =& $event->createObject();
- $object->ID=$this->Application->GetVar($event->Prefix_Special.'_id');
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
+ $object->ID = $this->getPassedID($event);
if( $object->Delete() )
{
- $event->status=erSUCCESS;
+ $event->status = erSUCCESS;
}
else
{
- $event->status=erFATAL;
- $event->redirect=false;
- break;
+ $event->status = erFAIL;
+ $event->redirect = false;
}
}
/**
* Prepares new kDBItem object
*
* @param kEvent $event
* @access protected
*/
function OnNew(&$event)
{
- $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false);
- $object =& $event->createObject();
- $this->prepareObject(&$object,&$event);
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
$object->setID(0);
$this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
+
+ $table_info = $object->getLinkedInfo();
+ $object->SetDBField($table_info['ForeignKey'], $table_info['ParentId']);
+
$event->redirect=false;
}
/**
* Cancel's kDBItem Editing/Creation
*
* @param kEvent $event
* @access protected
*/
function OnCancel(&$event)
{
+ $event->redirect_params = Array('opener'=>'u');
+ }
+
+
+ /**
+ * Deletes all selected items.
+ * Automatically recurse into sub-items using temp handler, and deletes sub-items
+ * by calling its Delete method if sub-item has AutoDelete set to true in its config file
+ *
+ * @param kEvent $event
+ */
+ function OnMassDelete(&$event)
+ {
+ $event->status=erSUCCESS;
+
+ $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+
+ $this->StoreSelectedIDs($event);
+
+ $event->setEventParam('ids', $this->getSelectedIDs($event) );
+ $this->customProcessing($event, 'before');
+ $ids = $event->getEventParam('ids');
+
+ if($ids)
+ {
+ $temp->DeleteItems($event->Prefix, $event->Special, $ids);
+ }
+ $this->clearSelectedIDs($event);
+ }
+
+ /**
+ * Prepare temp tables and populate it
+ * with items selected in the grid
+ *
+ * @param kEvent $event
+ */
+ function OnEdit(&$event)
+ {
+ $this->StoreSelectedIDs($event);
+
+ $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $temp->PrepareEdit();
+
+ $event->redirect=false;
+ }
+
+ /**
+ * Saves content of temp table into live and
+ * redirects to event' default redirect (normally grid template)
+ *
+ * @param kEvent $event
+ */
+ function OnSave(&$event)
+ {
+ $event->CallSubEvent('OnPreSave');
+ if ($event->status==erSUCCESS) {
+ $skip_master=false;
+ $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+
+ // newly created item
+ /*if($this->getPassedID($event) == 0)
+ {
+ $master_id = $temp->CopyMasterToOriginal();
+ $temp->UpdateForeignKeys($master_id); // save linked field values
+ $skip_master = true; //we've already copied master table to get the id
+ }*/
+
+ $temp->SaveEdit($skip_master);
+ $this->clearSelectedIDs($event);
+
+ $event->redirect_params = Array('opener'=>'u');
+ $this->Application->RemoveVar($event->getPrefixSpecial().'_modified');
+ }
+ }
+
+ /**
+ * Cancels edit
+ * Removes all temp tables and clears selected ids
+ *
+ * @param kEvent $event
+ */
+ function OnCancelEdit(&$event)
+ {
+ $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $temp->CancelEdit();
+
+ $this->clearSelectedIDs($event);
+ $event->redirect_params = Array('opener'=>'u');
+ $this->Application->RemoveVar($event->getPrefixSpecial().'_modified');
+ }
+
+ /**
+ * Saves edited item into temp table
+ * If there is no id, new item is created in temp table
+ *
+ * @param kEvent $event
+ */
+ function OnPreSave(&$event)
+ {
+ //$event->redirect = false;
+ // if there is no id - it means we need to create an item
+ $item_id = $this->getPassedID($event);
+ if ($item_id == '') {
+ $event->CallSubEvent('OnPreSaveCreated');
+ return;
+ }
+
+ $object =& $event->getObject();
+
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if($items_info)
+ {
+ foreach($items_info as $id => $field_values)
+ {
+ $object->SetDefaultValues();
+ $object->Load($id);
+ $object->SetFieldsFromHash($field_values);
+ if( $object->Update($id) )
+ {
+ $event->status=erSUCCESS;
+ }
+ else
+ {
+ $event->status=erFAIL;
+ $event->redirect=false;
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Saves edited item in temp table and loads
+ * item with passed id in current template
+ * Used in Prev/Next buttons
+ *
+ * @param kEvent $event
+ */
+ function OnPreSaveAndGo(&$event)
+ {
+ $event->CallSubEvent('OnPreSave');
+ if ($event->status==erSUCCESS) {
+ $event->redirect_params[$event->getPrefixSpecial(true).'_id'] = $this->Application->GetVar($event->Prefix_Special.'_GoId');
+ }
+ }
+
+ /**
+ * Saves edited item in temp table and goes
+ * to passed tabs, by redirecting to it with OnPreSave event
+ *
+ * @param kEvent $event
+ */
+ function OnPreSaveAndGoToTab(&$event)
+ {
+ $event->CallSubEvent('OnPreSave');
+ if ($event->status==erSUCCESS) {
+ $event->redirect=$this->Application->GetVar($event->getPrefixSpecial(true).'_GoTab');
+ }
+ }
+
+ /**
+ * Saves editable list and goes to passed tab,
+ * by redirecting to it with empty event
+ *
+ * @param kEvent $event
+ */
+ function OnUpdateAndGoToTab(&$event)
+ {
+ $event->setPseudoClass('_List');
+ $event->CallSubEvent('OnUpdate');
+ if ($event->status==erSUCCESS) {
+ $event->redirect=$this->Application->GetVar($event->getPrefixSpecial(true).'_GoTab');
+ }
+ }
+
+ /**
+ * Prepare temp tables for creating new item
+ * but does not create it. Actual create is
+ * done in OnPreSaveCreated
+ *
+ * @param kEvent $event
+ */
+ function OnPreCreate(&$event)
+ {
+ $this->clearSelectedIDs($event);
+
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
+
+ $temp =& $this->Application->recallObject($event->Prefix.'_TempHandler', 'kTempTablesHandler');
+ $temp->PrepareEdit();
+
+ $object->setID(0);
+
+ $event->redirect=false;
+ }
+
+ /**
+ * Apply custom processing to item
+ *
+ * @param kEvent $event
+ */
+ function customProcessing(&$event, $type)
+ {
+
+ }
+
+ /**
+ * Creates a new item in temp table and
+ * stores item id in App vars and Session on succsess
+ *
+ * @param kEvent $event
+ */
+ function OnPreSaveCreated(&$event)
+ {
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if($items_info) $field_values = array_shift($items_info);
+
+ $object =& $event->getObject();
+ $object->SetFieldsFromHash($field_values);
+
+ $this->customProcessing($event, 'before');
+
+ if( $object->Create() )
+ {
+ $this->customProcessing($event, 'after');
+ $event->redirect_params[$event->getPrefixSpecial(true).'_id'] = $object->GetId();
+ $event->status=erSUCCESS;
+ }
+ else
+ {
+ $event->status=erFAIL;
+ $event->redirect=false;
+ $object->setID(0);
+ }
+
+ }
+
+ // III. Events that allow to put some code before and after Update,Load,Create and Delete methods of item
+
+ /**
+ * Occurse before loading item, 'id' parameter
+ * allows to get id of item beeing loaded
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnBeforeItemLoad(&$event)
+ {
+ }
+
+ /**
+ * Occurse after loading item, 'id' parameter
+ * allows to get id of item that was loaded
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnAfterItemLoad(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse before creating item
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnBeforeItemCreate(&$event)
+ {
}
+
+ /**
+ * Occurse after creating item
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnAfterItemCreate(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse before updating item
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnBeforeItemUpdate(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse after updating item
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnAfterItemUpdate(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse before deleting item, id of item beeing
+ * deleted is stored as 'id' event param
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnBeforeItemDelete(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse after deleting item, id of deleted item
+ * is stored as 'id' param of event
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnAfterItemDelete(&$event)
+ {
+
+ }
+
+
+ /**
+ * Occures after an item has been copied to temp
+ * Id of copied item is passed as event' 'id' param
+ *
+ * @param kEvent $event
+ */
+ function OnAfterCopyToTemp(&$event)
+ {
+
+ }
+
+ /**
+ * Occures before an item is deleted from live table when copying from temp
+ * (temp handler deleted all items from live and then copy over all items from temp)
+ * Id of item being deleted is passed as event' 'id' param
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeDeleteFromLive(&$event)
+ {
+
+ }
+
+ /**
+ * Occures before an item is copied to live table (after all foreign keys have been updated)
+ * Id of item being copied is passed as event' 'id' param
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeCopyToLive(&$event)
+ {
+
+ }
+
+ /**
+ * !!! NOT FULLY IMPLEMENTED - SEE TEMP HANDLER COMMENTS (search by event name)!!!
+ * Occures after an item has been copied to live table
+ * Id of copied item is passed as event' 'id' param
+ *
+ * @param kEvent $event
+ */
+ function OnAfterCopyToLive(&$event)
+ {
+
+ }
+
+ /**
+ * Occures before an item is cloneded
+ * Id of ORIGINAL item is passed as event' 'id' param
+ * Do not call object' Update method in this event, just set needed fields!
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeClone(&$event)
+ {
+
+ }
+
+ /**
+ * Occures after an item has been cloned
+ * Id of newly created item is passed as event' 'id' param
+ *
+ * @param kEvent $event
+ */
+ function OnAfterClone(&$event)
+ {
+
+ }
+
+ /**
+ * Ensures that popup will be closed automatically
+ * and parent window will be refreshed with template
+ * passed
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function finalizePopup(&$event, $main_prefix, $t)
+ {
+ $event->redirect = 'incs/close_popup';
+
+ // 2. substitute opener
+ $opener_stack = $this->Application->RecallVar('opener_stack');
+ $opener_stack = $opener_stack ? unserialize($opener_stack) : Array();
+ //array_pop($opener_stack);
+
+ $new_level = 'index4.php|'.ltrim($this->Application->BuildEnv($t, Array('m_opener' => 'u'), 'all'), ENV_VAR_NAME.'=');
+ array_push($opener_stack,$new_level);
+ $this->Application->StoreVar('opener_stack',serialize($opener_stack));
+ }
+
+ /**
+ * Create search filters based on search query
+ *
+ * @param kEvent $event
+ * @access protected
+ */
+ function OnSearch(&$event)
+ {
+ $event->setPseudoClass('_List');
+ $object =& $event->getObject();
+
+ $keyword = $this->Application->GetVar( $event->getPrefixSpecial(true).'_search_keyword');
+ $this->Application->StoreVar( $event->getPrefixSpecial().'_search_keyword', $keyword);
+
+ if(!$keyword)
+ {
+ $this->OnSearchReset($event);
+ return true;
+ }
+
+ $grid_name = $this->Application->GetVar('grid_name');
+ $grids = $this->Application->getUnitOption($event->Prefix,'Grids');
+ $search_fields = array_keys($grids[$grid_name]['Fields']);
+
+ $search_filter = Array();
+
+ foreach($search_fields as $search_field)
+ {
+ $filter_type = isset($object->VirtualFields[$search_field]) ? 'having' : 'where';
+ $field_type = getArrayValue($object->Fields[$search_field],'type');
+ if(!$field_type) $field_type = 'string'; // default LIKE filter for all fields without type
+ $keyword = trim($keyword);
+ $filter_value = '';
+ $table_name = ($filter_type == 'where') ? '`'.$object->TableName.'`.' : '';
+
+ // get field clause by formatter name and/or parameters
+ $formatter = getArrayValue($object->Fields[$search_field],'formatter');
+ switch ($formatter)
+ {
+ case 'kOptionsFormatter':
+ $search_keys = Array();
+ $use_phrases = getArrayValue($object->Fields[$search_field], 'use_phrases');
+ foreach($object->Fields[$search_field]['options'] as $key => $val)
+ {
+ $pattern = '#'.$keyword.'#i';
+ if ( preg_match($pattern, $use_phrases ? $this->Application->Phrase($val) : $val) ) {
+ array_push($search_keys, $key);
+ }
+ }
+ if (count($search_keys) > 0) {
+ $filter_value = $table_name.'`'.$search_field.'` IN ('.implode(',', $search_keys).')';
+ }
+
+ $field_processed = true;
+ break;
+
+ default:
+ $field_processed = false;
+ break;
+ }
+
+ // if not already processed by formatter, then get clause by field type
+
+ if(!$field_processed)
+ {
+ switch($field_type)
+ {
+ case 'int':
+ case 'integer':
+ case 'numeric':
+ if( !is_numeric($keyword) ) break;
+ $filter_value = $table_name.'`'.$search_field.'` = \''.$keyword.'\'';
+ break;
+
+ case 'double':
+ case 'float':
+ case 'real':
+ if( !is_numeric($keyword) ) break;
+ $filter_value = 'ABS('.$table_name.'`'.$search_field.'` - \''.str_replace(',','.',$keyword).'\') <= 0.0001';
+ break;
+
+ case 'string':
+ $keywords = explode(' ',$keyword);
+ foreach($keywords as $keyword_pos => $keyword_value)
+ {
+ $keywords[$keyword_pos] = $table_name.'`'.$search_field.'` LIKE \'%'.trim($keyword_value).'%\'';
+ }
+ $filter_value = '('.implode(') OR (',$keywords).')';
+ break;
+ }
+ }
+ if($filter_value) $search_filter[$search_field] = Array('type' => $filter_type, 'value' => $filter_value);
+ }
+
+ $this->Application->StoreVar($event->getPrefixSpecial().'_search_filter', serialize($search_filter) );
+ }
+
+ /**
+ * Clear search keywords
+ *
+ * @param kEvent $event
+ * @access protected
+ */
+ function OnSearchReset(&$event)
+ {
+ $this->Application->RemoveVar($event->getPrefixSpecial().'_search_filter');
+ $this->Application->RemoveVar($event->getPrefixSpecial().'_search_keyword');
+ }
+
+ /**
+ * Set's new filter value (filter_id meaning from config)
+ *
+ * @param kEvent $event
+ */
+ function OnSetFilter(&$event)
+ {
+ $filter_id = $this->Application->GetVar('filter_id');
+ $filter_value = $this->Application->GetVar('filter_value');
+
+ $view_filter = $this->Application->RecallVar($event->getPrefixSpecial().'_view_filter');
+ $view_filter = $view_filter ? unserialize($view_filter) : Array();
+
+ $view_filter[$filter_id] = $filter_value;
+
+ $this->Application->StoreVar( $event->getPrefixSpecial().'_view_filter', serialize($view_filter) );
+ }
+
+ /**
+ * Add/Remove all filters applied to list from "View" menu
+ *
+ * @param kEvent $event
+ */
+ function FilterAction(&$event)
+ {
+ $view_filter = Array();
+ $filter_menu = $this->Application->getUnitOption($event->Prefix,'FilterMenu');
+ switch ($event->Name)
+ {
+ case 'OnRemoveFilters':
+ $filter_value = 1;
+ break;
+
+ case 'OnApplyFilters':
+ $filter_value = 0;
+ break;
+ }
+
+ foreach($filter_menu['Filters'] as $filter_key => $filter_params)
+ {
+ if(!$filter_params) continue;
+ $view_filter[$filter_key] = $filter_value;
+ }
+ $this->Application->StoreVar( $event->getPrefixSpecial().'_view_filter', serialize($view_filter) );
+ }
+
+ function OnPreSaveAndOpenTranslator(&$event)
+ {
+ $this->Application->SetVar('allow_translation', true);
+ $event->CallSubEvent('OnPreSave');
+ $wnd_name = $this->Application->GetVar('translator_wnd_name');
+ if ($event->status == erSUCCESS) {
+ $t = $this->Application->GetVar('translator_t');
+ $object = $this->Application->recallObject($event->getPrefixSpecial());
+ $url = $this->Application->HREF($t, '', Array('pass'=>'all', $event->getPrefixSpecial(true).'_id' => $object->GetId()));
+ $field = $this->Application->GetVar('translator_field');
+ $after_script = "openTranslator('".$event->getPrefixSpecial()."', '".$field."', '".$url."', '".$wnd_name."')";
+ }
+ else {
+ $after_script = "wnd = window.open('', '".$wnd_name."'); wnd.close()";
+ }
+ $this->Application->SetVar('after_script', $after_script);
+ $event->redirect = false;
+ }
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/db/db_event_handler.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.6
\ No newline at end of property
+1.7
\ No newline at end of property
Index: trunk/core/kernel/db/db_connection.php
===================================================================
--- trunk/core/kernel/db/db_connection.php (revision 1338)
+++ trunk/core/kernel/db/db_connection.php (revision 1339)
@@ -1,508 +1,529 @@
<?php
/**
* Multi database connection class
*
*/
- class DBConnection {
+ class kDBConnection {
/**
* Current database type
*
* @var string
* @access private
*/
var $dbType = 'mysql';
/**
* Created connection handle
*
* @var resource
* @access private
*/
var $connectionID = null;
/**
* Handle of currenty processed recordset
*
* @var resource
* @access private
*/
var $queryID = null;
/**
* DB type specific function mappings
*
* @var Array
* @access private
*/
var $metaFunctions = Array();
/**
* Function to handle sql errors
*
* @var string
* @access private
*/
var $errorHandler = '';
/**
* Error code
*
* @var int
* @access private
*/
var $errorCode = 0;
/**
* Error message
*
* @var string
* @access private
*/
var $errorMessage = '';
/**
* Defines if database connection
* operations should generate debug
* information
*
* @var bool
*/
var $debugMode=false;
/**
* Initializes connection class with
* db type to used in future
*
* @param string $dbType
* @return DBConnection
* @access public
*/
- function DBConnection($dbType, $errorHandler = '')
+ function kDBConnection($dbType, $errorHandler = '')
{
$this->dbType = $dbType;
$this->initMetaFunctions();
if(!$errorHandler)
{
$this->errorHandler = Array(&$this,'handleError');
}
else
{
$this->errorHandler=$errorHandler;
}
}
/**
* Set's custom error
*
* @param int $code
* @param string $msg
* @access public
*/
function setError($code,$msg)
{
$this->errorCode=$code;
$this->errorMessage=$msg;
}
/**
* Checks if previous query execution
* raised an error.
*
* @return bool
* @access public
*/
function hasError()
{
return !($this->errorCode == 0);
}
/**
* Caches function specific to requested
* db type
*
* @access private
*/
function initMetaFunctions()
{
$ret = Array();
switch($this->dbType)
{
case 'mysql':
$ret = Array(); // only define functions, that name differs from "dbType_<meta_name>"
break;
}
$this->metaFunctions = $ret;
}
/**
* Get's function for specific db type
* based on it's meta name
*
* @param string $name
* @return string
* @access private
*/
function getMetaFunction($name)
{
if( !isset($this->metaFunctions[$name]) )
{
if(function_exists($this->dbType.'_'.$name)) return $this->dbType.'_'.$name;
}
else
{
return $this->dbType.$name;
}
return false;
}
/**
* Try to connect to database server
* using specified parameters and set
* database to $db if connection made
*
* @param string $host
* @param string $user
* @param string $pass
* @param string $db
* @access public
*/
- function Connect($host,$user,$pass,$db)
+ function Connect($host,$user,$pass,$db,$force_new=false)
{
$func = $this->getMetaFunction('connect');
- $this->connectionID = $func($host,$user,$pass) or die('Can\'t connect to db');
+ $this->connectionID = $func($host,$user,$pass,$force_new) or die('Can\'t connect to db');
if($this->connectionID)
{
$this->setDB($db);
$this->showError();
}
}
+ function ReConnect($host,$user,$pass,$db)
+ {
+ $func = $this->getMetaFunction('close');
+ $func($this->connectionID);
+ $this->Connect($host,$user,$pass,$db);
+ }
+
/**
* Shows error message from previous operation
* if it failed
*
* @access private
*/
function showError($sql='')
{
$this->setError(0,''); // reset error
if($this->connectionID)
{
$func = $this->getMetaFunction('errno'); $this->errorCode = $func($this->connectionID);
if($this->hasError())
{
$func = $this->getMetaFunction('error'); $this->errorMessage = $func($this->connectionID);
if(is_array($this->errorHandler))
{
$func = $this->errorHandler[1];
$ret = $this->errorHandler[0]->$func($this->errorCode,$this->errorMessage,$sql);
}
else
{
$func = $this->errorHandler;
$ret = $func($this->errorCode,$this->errorMessage,$sql);
}
if(!$ret) exit;
}
}
}
/**
* Default error handler for sql errors
*
* @param int $code
* @param string $msg
* @param string $sql
* @return bool
* @access private
*/
function handleError($code,$msg,$sql)
{
echo '<b>Processing SQL</b>: '.$sql.'<br>';
echo '<b>Error ('.$code.'):</b> '.$msg.'<br>';
return false;
}
/**
* Set's database name for connection
* to $new_name
*
* @param string $new_name
* @return bool
* @access public
*/
function setDB($new_name)
{
if(!$this->connectionID) return false;
$func = $this->getMetaFunction('select_db');
return $func($new_name);
}
/**
* Returns first field of first line
* of recordset if query ok or false
* otherwise
*
* @param string $sql
* @return string
* @access public
*/
function GetOne($sql)
{
$row = $this->GetRow($sql);
if(!$row) return false;
return array_shift($row);
}
/**
* Returns first row of recordset
* if query ok, false otherwise
*
* @param stirng $sql
* @return Array
* @access public
*/
function GetRow($sql)
{
$sql .= ' '.$this->getLimitClause(0,1);
$ret = $this->Query($sql);
- if(!$ret) return $ret;
+ if(!$ret) return false;
return array_shift($ret);
}
/**
* Returns 1st column of recordset as
* one-dimensional array or false otherwise
* Optional parameter $key_field can be used
* to set field name to be used as resulting
* array key
*
* @param string $sql
* @param string $key_field
* @return Array
* @access public
*/
function GetCol($sql, $key_field = null)
{
$rows = $this->Query($sql);
if(!$rows) return $rows;
$i = 0; $row_count = count($rows);
$ret = Array();
if(isset($key_field))
{
while ($i < $row_count)
{
$ret[$rows[$i][$key_field]] = array_shift($rows[$i]);
$i++;
}
}
else
{
while ($i < $row_count)
{
$ret[] = array_shift($rows[$i]);
$i++;
}
}
return $ret;
}
/**
* Queries db with $sql query supplied
* and returns rows selected if any, false
* otherwise. Optional parameter $key_field
* allows to set one of the query fields
* value as key in string array.
*
* @param string $sql
* @param string $key_field
* @return Array
*/
function Query($sql,$key_field = null)
{
if($this->debugMode) return $this->debugQuery($sql,$key_field);
$query_func = $this->getMetaFunction('query');
$this->queryID = $query_func($sql,$this->connectionID);
if( is_resource($this->queryID) )
{
$ret = Array();
$fetch_func = $this->getMetaFunction('fetch_assoc');
if( isset($key_field) )
{
while( ($row = $fetch_func($this->queryID)) )
{
$ret[$row[$key_field]] = $row;
}
}
else
{
while( ($row = $fetch_func($this->queryID)) )
{
$ret[] = $row;
}
}
$this->Destroy();
return $ret;
}
$this->showError($sql);
return false;
}
function ChangeQuery($sql)
{
$this->Query($sql);
return $this->errorCode==0 ? true : false;
}
function debugQuery($sql, $key_field = null)
{
global $debugger;
$query_func = $this->getMetaFunction('query');
// set 1st checkpoint: begin
$isSkipTable=true;
$profileSQLs=defined('DBG_SQL_PROFILE')&&DBG_SQL_PROFILE;
if($profileSQLs)
{
$isSkipTable=isSkipTable($sql);
if(!$isSkipTable)
{
$queryID=$debugger->generateID();
$debugger->profileStart('sql_'.$queryID, $debugger->formatSQL($sql) );
}
}
// set 1st checkpoint: end
$this->queryID = $query_func($sql,$this->connectionID);
// set 2nd checkpoint: begin
if(!$isSkipTable) $debugger->profileFinish('sql_'.$queryID);
// set 2nd checkpoint: end
if( is_resource($this->queryID) )
{
$ret = Array();
$fetch_func = $this->getMetaFunction('fetch_assoc');
if( isset($key_field) )
{
while( ($row = $fetch_func($this->queryID)) )
{
$ret[$row[$key_field]] = $row;
}
}
else
{
while( ($row = $fetch_func($this->queryID)) )
{
$ret[] = $row;
}
}
$this->Destroy();
return $ret;
}
$this->showError($sql);
return false;
}
/**
* Free memory used to hold recordset handle
*
* @access private
*/
function Destroy()
{
if($this->queryID)
{
$free_func = $this->getMetaFunction('free_result');
$free_func($this->queryID);
$this->queryID = null;
}
}
/**
* Returns auto increment field value from
* insert like operation if any, zero otherwise
*
* @return int
* @access public
*/
function getInsertID()
{
$func = $this->getMetaFunction('insert_id');
return $func($this->connectionID);
}
/**
* Returns row count affected by last query
*
* @return int
* @access public
*/
function getAffectedRows()
{
$func = $this->getMetaFunction('affected_rows');
return $func($this->connectionID);
}
/**
* Returns LIMIT sql clause part for specific db
*
* @param int $offset
* @param int $rows
* @return string
* @access private
*/
function getLimitClause($offset, $rows)
{
if(!($rows > 0)) return '';
switch ($this->dbType) {
default:
return 'LIMIT '.$offset.','.$rows;
break;
}
}
/**
* Correctly quotes a string so that all strings are escaped. We prefix and append
* to the string single-quotes.
* An example is $db->qstr("Don't bother",magic_quotes_runtime());
*
* @param s the string to quote
* @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
* This undoes the stupidity of magic quotes for GPC.
*
* @return quoted string to be sent back to database
*/
function qstr($s,$magic_quotes=false)
{
- $replace_quote = "\\'";
+ $replaceQuote = "\\'";
if (!$magic_quotes)
{
- return "'".str_replace("'",$replace_quote,$s)."'";
+ if ($replaceQuote[0] == '\\')
+ {
+ // only since php 4.0.5
+ $s = str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+ //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
+ }
+ return "'".str_replace("'",$replaceQuote,$s)."'";
}
// undo magic quotes for "
$s = str_replace('\\"','"',$s);
- return "'$s'";
+
+ if($replaceQuote == "\\'") // ' already quoted, no need to change anything
+ {
+ return "'$s'";
+ }
+ else // change \' to '' for sybase/mssql
+ {
+ $s = str_replace('\\\\','\\',$s);
+ return "'".str_replace("\\'",$replaceQuote,$s)."'";
+ }
}
-
/**
* Returns last error message
*
* @return string
* @access public
*/
function getErrorMsg()
{
return $this->errorMessage;
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/db/db_connection.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.2
\ No newline at end of property
+1.3
\ No newline at end of property
Index: trunk/core/kernel/db/dbitem.php
===================================================================
--- trunk/core/kernel/db/dbitem.php (revision 1338)
+++ trunk/core/kernel/db/dbitem.php (revision 1339)
@@ -1,294 +1,697 @@
<?php
/**
* DBItem
*
* Desciption
* @package kernel4
*/
class kDBItem extends kDBBase {
/**
* Description
*
* @var array Associative array of current item' field values
* @access public
*/
var $FieldValues;
+
+ var $FieldErrors;
+
+ var $ErrorMsgs = Array();
+
/**
* Holds item' primary key value
*
* @var int Value of primary key field for current item
* @access public
*/
var $ID;
- /**
- * 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();
+ function kDBItem()
+ {
+ parent::kDBBase();
+ $this->ErrorMsgs['required'] = 'Field is required';
+ $this->ErrorMsgs['unique'] = 'Field value must be unique';
+ $this->ErrorMsgs['value_out_of_range'] = 'Field is out of range, possible values from %s to %s';
+ $this->ErrorMsgs['length_out_of_range'] = 'Field is out of range';
+ $this->ErrorMsgs['bad_type'] = 'Incorrect data format, please use %s';
+ $this->ErrorMsgs['bad_date_format'] = 'Incorrect date format, please use (%s) ex. (%s)';
+ }
/**
- * Set's field names from table
- * from config
+ * Set's default values for all fields
*
- * @param Array $fields
* @access public
*/
- function setConfigFields($fields)
+ function SetDefaultValues()
{
- $this->Fields=$fields;
+ foreach ($this->Fields as $field => $params) {
+ if ( isset($params['default']) ) {
+ $this->SetDBField($field, $params['default']);
+ }
+ else {
+ $this->SetDBField($field, NULL);
+ }
+ }
}
-
+
/**
* Sets current item field value
* (applies formatting)
*
* @access public
* @param string $name Name of the field
* @param mixed $value Value to set the field to
* @return void
*/
function SetField($name,$value)
{
- $this->SetDBField($name,$value);
+ $options = $this->GetFieldOptions($name);
+ $parsed = $value;
+ if ($value == '') $parsed = NULL;
+ if (isset($options['formatter'])) {
+ $formatter =& $this->Application->recallObject($options['formatter']);
+// $parsed = $formatter->Parse($value, $options, $err);
+ $parsed = $formatter->Parse($value, $name, $this);
+ }
+ $this->SetDBField($name,$parsed);
}
/**
* 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->FieldValues[$name] = $value;
}
-
- /**
- * Return current item' field value by field name
- * (apply formatter)
- *
- * @access public
- * @param string $name field name to return
- * @return mixed
- */
- function GetField($name)
- {
- return $this->GetDBField($name);
- }
-
/**
* Return current item' field value by field name
* (doesn't apply formatter)
*
* @access public
* @param string $name field name to return
* @return mixed
*/
function GetDBField($name)
{
return $this->FieldValues[$name];
}
+ function HasField($name)
+ {
+ return isset($this->FieldValues[$name]);
+ }
+
+ function GetFieldValues()
+ {
+ return $this->FieldValues;
+ }
+
/**
* Sets item' fields corresponding to elements in passed $hash values.
*
* The function sets current item fields to values passed in $hash, by matching $hash keys with field names
* of current item. If current item' fields are unknown {@link kDBItem::PrepareFields()} is called before acutally setting the fields
*
* @access public
* @param Array $hash
+ * @param Array $set_fields Optional param, field names in target object to set, other fields will be skipped
* @return void
*/
- function SetFieldsFromHash($hash)
+ function SetFieldsFromHash($hash, $set_fields=null)
{
foreach ($hash as $field_name => $field_value)
{
- if( eregi("^[0-9]+$", $field_name) || !in_array($field_name,$this->Fields) ) continue;
+ if( eregi("^[0-9]+$", $field_name) || !array_key_exists($field_name,$this->Fields) ) continue;
+ if ( is_array($set_fields) && !in_array($field_name, $set_fields) ) continue;
$this->SetField($field_name,$field_value);
}
}
+ function SetDBFieldsFromHash($hash, $set_fields=null)
+ {
+ foreach ($hash as $field_name => $field_value)
+ {
+ if( eregi("^[0-9]+$", $field_name) || !array_key_exists($field_name,$this->Fields) ) continue;
+ if ( is_array($set_fields) && !in_array($field_name, $set_fields) ) continue;
+ $this->SetDBField($field_name,$field_value);
+ }
+ }
+
/**
* Returns part of SQL WHERE clause identifing the record, ex. id = 25
*
* @access public
* @param string $method Child class may want to know who called GetKeyClause, Load(), Update(), Delete() send its names as method
* @return void
* @see kDBItem::Load()
* @see kDBItem::Update()
* @see kDBItem::Delete()
*/
function GetKeyClause($method=null)
{
- return $this->IDField.' = '.$this->Conn->qstr($this->ID);
+ return '`'.$this->TableName.'`.'.$this->IDField.' = '.$this->Conn->qstr($this->ID);
}
/**
* Loads item from the database by given id
*
* @access public
* @param int $id Primery Key Id to load
* @param string $id_field_name Optional parameter to load item by given Id field
* @return bool True if item has been loaded, false otherwise
*/
function Load($id, $id_field_name=null)
{
+ if (is_array($id)) {
+ $keys = $id;
+ foreach ($keys as $field => $value) {
+ $sqls[] = '`'.$this->TableName.'`.'.$field.' = '.$this->Conn->qstr($value);
+ }
+ $keys_sql = '('.implode(') AND (', $sqls).')';
+ }
+
if (isset($id_field_name)) $this->SetIDField($id_field_name);
+ if (!isset($id) && !isset($keys_sql)) return false;
- if (!isset($id)) return false;
+ if( !$this->raiseEvent('OnBeforeItemLoad',$id) ) return false;
$this->ID = $id;
- $q = $this->GetSelectSQL().' WHERE '.$this->GetKeyClause('load');
+ $q = $this->GetSelectSQL().' WHERE '.(isset($keys_sql) ? $keys_sql : $this->GetKeyClause('load'));
if ($this->DisplayQueries) {
echo get_class($this)." Load SQL: $q<br>";
}
- $this->FieldValues = $this->Conn->GetRow($q);
-
+ $this->FieldValues = array_merge_recursive2( $this->FieldValues, $this->Conn->GetRow($q) );
+
if ($this->FieldValues === false) {
//Error handling could be here
return false;
}
- $this->setID($id);
+ if (isset($keys_sql)) {
+ $this->setID($this->FieldValues[$this->IDField]);
+ }
+ else {
+ $this->setID($id);
+ }
+
+ $this->UpdateFormattersSubFields(); // used for updating separate virtual date/time fields from DB timestamp (for example)
+
+ $this->raiseEvent('OnAfterItemLoad');
return true;
}
+
+ /**
+ * Builds select sql, SELECT ... FROM parts only
+ *
+ * @access public
+ * @return string
+ */
+ function GetSelectSQL()
+ {
+ $sql = $this->addCalculatedFields($this->SelectClause);
+ return parent::GetSelectSQL($sql);
+ }
+
+ function UpdateFormattersMasterFields()
+ {
+ foreach ($this->Fields as $field => $options) {
+ if (isset($options['formatter'])) {
+ $formatter =& $this->Application->recallObject($options['formatter']);
+ $formatter->UpdateMasterFields($field, $this->GetDBField($field), $options, $this);
+ }
+ }
+ }
+
+ function SkipField($field_name, $force_id=false)
+ {
+ $skip = false;
+ $skip = $skip || ( isset($this->VirtualFields[$field_name]) ); //skipping 'virtual' field
+ $skip = $skip || ( !getArrayValue($this->FieldValues, $field_name) && getArrayValue($this->Fields[$field_name], 'skip_empty') ); //skipping 'virtual' field
+ $skip = $skip || ($field_name == $this->IDField && !$force_id); //skipping Primary Key
+
+// $table_name = preg_replace("/^(.*)\./", "$1", $field_name);
+// $skip = $skip || ($table_name && ($table_name != $this->TableName)); //skipping field from other tables
+
+ $skip = $skip || ( !isset($this->Fields[$field_name]) ); //skipping field not in Fields (nor virtual, nor real)
+
+ return $skip;
+ }
/**
* Updates previously loaded record with current item' values
*
* @access public
* @param int Primery Key Id to update
- * @return void
+ * @return bool
*/
- function Update($id=null)
+ function Update($id=null, $system_update=false)
{
- if( isset($id) ) $this->ID=$id;
+ if( isset($id) ) $this->setID($id);
+
+ if( !$this->raiseEvent('OnBeforeItemUpdate') ) return false;
+
if( !isset($this->ID) ) return false;
// Validate before updating
if( !$this->Validate() ) return false;
//Nothing to update
if(!$this->FieldValues) return true;
$sql = sprintf('UPDATE %s SET ',$this->TableName);
foreach ($this->FieldValues as $field_name => $field_value)
{
- if ( isset($this->VirtualFields[$field_name]) ) continue; //skipping 'virtual' field
- if ($field_name == $this->IDField) continue; //skipping Primary Key
+ if ($this->SkipField($field_name)) continue;
$real_field_name = eregi_replace("^.*\.", '',$field_name); //removing table names from field names
//Adding part of SET clause for current field, escaping data with ADODB' qstr
- $sql.= sprintf('%s=%s, ',$real_field_name,$this->Conn->qstr($this->FieldValues[$field_name], 0));
+ if (is_null( $this->FieldValues[$field_name] )) {
+ if (isset($this->Fields[$field_name]['not_null']) && $this->Fields[$field_name]['not_null']) {
+ $sql .= '`'.$real_field_name.'` = '.$this->Conn->qstr($this->Fields[$field_name]['default']).', ';
+ }
+ else {
+ $sql .= '`'.$real_field_name.'` = NULL, ';
+ }
+ }
+ else {
+ $sql.= sprintf('`%s`=%s, ', $real_field_name, $this->Conn->qstr($this->FieldValues[$field_name], 0));
+ }
}
$sql = ereg_replace(", $", '', $sql); //Removing last comma and space
$sql.= sprintf(' WHERE %s', $this->GetKeyClause('update')); //Adding WHERE clause with Primary Key
if ($this->DisplayQueries) echo "Sql: $sql<br>";
if ($this->Conn->ChangeQuery($sql) === false) { //Executing query and checking results
if ($this->DisplayQueries)
{
echo "Error executing statement: ".$adodbConnection->ErrorMsg()."<br>";
}
return false;
}
+
+ $affected = $this->Conn->getAffectedRows();
+ if (!$system_update && $affected == 1){
+ $this->setModifiedFlag();
+ }
+ $this->raiseEvent('OnAfterItemUpdate');
return true;
}
+ /**
+ * Validate all item fields based on
+ * constraints set in each field options
+ * in config
+ *
+ * @return bool
+ * @access private
+ */
function Validate()
{
- return true;
+ $this->UpdateFormattersMasterFields(); //order is critical - should be called BEFORE checking errors
+ $global_res = true;
+ foreach ($this->Fields as $field => $params) {
+ $res = true;
+ $res = $res && $this->ValidateRequired($field, $params);
+ $res = $res && $this->ValidateType($field, $params);
+ $res = $res && $this->ValidateRange($field, $params);
+ $res = $res && $this->ValidateUnique($field, $params);
+
+ // If Formatter has set some error messages during values parsing
+ if (isset($this->FieldErrors[$field]['pseudo']) && $this->FieldErrors[$field] != '') {
+ $global_res = false;
+ }
+
+ $global_res = $global_res && $res;
+ }
+
+ if (!$global_res && $this->Application->isDebugMode() )
+ {
+ global $debugger;
+ $error_msg = "Validation failed in prefix <b>".$this->Prefix."</b>, FieldErrors follow (look at items with 'pseudo' key set)<br>
+ You may ignore this notice if submitted data really has a validation error ";
+ trigger_error( $error_msg, E_USER_NOTICE);
+ $debugger->dumpVars($this->FieldErrors);
+ }
+
+ return $global_res;
}
/**
+ * Check if value in field matches field type specified in config
+ *
+ * @param string $field field name
+ * @param Array $params field options from config
+ * @return bool
+ */
+ function ValidateType($field, $params)
+ {
+ $res = true;
+ $val = $this->FieldValues[$field];
+ if ( $val != '' &&
+ isset($params['type']) &&
+ preg_match("#int|integer|double|float|real|numeric|string#", $params['type'])
+ ) {
+ $res = is_numeric($val);
+ if($params['type']=='string' || $res)
+ {
+ $f = 'is_'.$params['type'];
+ settype($val, $params['type']);
+ $res = $f($val) && ($val==$this->FieldValues[$field]);
+ }
+ if (!$res)
+ {
+ $this->FieldErrors[$field]['pseudo'] = 'bad_type';
+ $this->FieldErrors[$field]['params'] = $params['type'];
+ }
+ }
+ return $res;
+ }
+
+ /**
+ * Check if value is set for required field
+ *
+ * @param string $field field name
+ * @param Array $params field options from config
+ * @return bool
+ * @access private
+ */
+ function ValidateRequired($field, $params)
+ {
+ $res = true;
+ if ( getArrayValue($params,'required') )
+ {
+ $res = ( (string) $this->FieldValues[$field] != '');
+ }
+ if (!$res) $this->FieldErrors[$field]['pseudo'] = 'required';
+ return $res;
+ }
+
+ /**
+ * Validates that current record has unique field combination among other table records
+ *
+ * @param string $field field name
+ * @param Array $params field options from config
+ * @return bool
+ * @access private
+ */
+ function ValidateUnique($field, $params)
+ {
+ $res = true;
+ $unique_fields = getArrayValue($params,'unique');
+ if($unique_fields !== false)
+ {
+ $where = Array();
+ array_push($unique_fields,$field);
+ foreach($unique_fields as $unique_field)
+ {
+ $where[] = '`'.$unique_field.'` = '.$this->Conn->qstr( $this->GetDBField($unique_field) );
+ }
+
+ $sql = 'SELECT COUNT(*) FROM %s WHERE ('.implode(') AND (',$where).') AND ('.$this->IDField.' <> '.(int)$this->ID.')';
+
+ $res_temp = $this->Conn->GetOne( sprintf($sql, $this->TableName ) );
+ $res_live = $this->Conn->GetOne( sprintf($sql, kTempTablesHandler::GetLiveName($this->TableName) ) );
+ $res = ($res_temp == 0) && ($res_live == 0);
+
+ if(!$res) $this->FieldErrors[$field]['pseudo'] = 'unique';
+ }
+ return $res;
+ }
+
+ /**
+ * Check if field value is in range specified in config
+ *
+ * @param string $field field name
+ * @param Array $params field options from config
+ * @return bool
+ * @access private
+ */
+ function ValidateRange($field, $params)
+ {
+ $res = true;
+ $val = $this->FieldValues[$field];
+ if ( isset($params['type']) && preg_match("#int|integer|double|float|real#", $params['type']) && strlen($val) > 0 ) {
+ if ( isset($params['max_value_inc'])) {
+ $res = $res && $val <= $params['max_value_inc'];
+ $max_val = $params['max_value_inc'].' (inclusive)';
+ }
+ if ( isset($params['min_value_inc'])) {
+ $res = $res && $val >= $params['min_value_inc'];
+ $min_val = $params['min_value_inc'].' (inclusive)';
+ }
+ if ( isset($params['max_value_exc'])) {
+ $res = $res && $val < $params['max_value_exc'];
+ $max_val = $params['max_value_exc'].' (exclusive)';
+ }
+ if ( isset($params['min_value_exc'])) {
+ $res = $res && $val > $params['min_value_exc'];
+ $min_val = $params['min_value_exc'].' (exclusive)';
+ }
+ }
+ if (!$res) {
+ $this->FieldErrors[$field]['pseudo'] = 'value_out_of_range';
+
+ if ( !isset($min_val) ) $min_val = '-&infin;';
+ if ( !isset($max_val) ) $max_val = '&infin;';
+
+ $this->FieldErrors[$field]['params'] = Array( $min_val, $max_val );
+ return $res;
+ }
+ if ( isset($params['max_len'])) {
+ $res = $res && strlen($val) <= $params['max_len'];
+ }
+ if ( isset($params['min_len'])) {
+ $res = $res && strlen($val) >= $params['min_len'];
+ }
+ if (!$res) {
+ $this->FieldErrors[$field]['pseudo'] = 'length_out_of_range';
+ $this->FieldErrors[$field]['params'] = Array($params['min_len'], $params['max_len']);
+ return $res;
+ }
+ return $res;
+ }
+
+ /**
+ * Return error message for field
+ *
+ * @param string $field
+ * @return string
+ * @access public
+ */
+ function GetErrorMsg($field)
+ {
+ if( !isset($this->FieldErrors[$field]) ) return '';
+
+ $err = getArrayValue($this->FieldErrors[$field], 'pseudo');
+ if( isset($this->Fields[$field]['error_msgs'][$err]) )
+ {
+ $msg = $this->Fields[$field]['error_msgs'][$err];
+ }
+ else
+ {
+ if( !isset($this->ErrorMsgs[$err]) ) return $err;
+ $msg = $this->ErrorMsgs[$err];
+ }
+
+ if ( isset($this->FieldErrors[$field]['params']) )
+ {
+ return vsprintf($msg, $this->FieldErrors[$field]['params']);
+ }
+ return $msg;
+ }
+
+ /**
* Creates a record in the database table with current item' values
*
+ * @param mixed $force_id Set to TRUE to force creating of item's own ID or to value to force creating of passed id. Do not pass 1 for true, pass exactly TRUE!
* @access public
- * @return void
+ * @return bool
*/
- function Create()
+ function Create($force_id=false, $system_create=false)
{
+ if( !$this->raiseEvent('OnBeforeItemCreate') ) return false;
+
if(!$this->Validate()) //Validating fields before attempting to create record
return false;
+ if (is_int($force_id)) {
+ $this->FieldValues[$this->IDField] = $force_id;
+ }
+
$fields_sql = '';
$values_sql = '';
foreach ($this->FieldValues as $field_name => $field_value)
{
- if ( isset($this->VirtualFields[$field_name]) ) continue; //skipping 'virtual' field
+ if ($this->SkipField($field_name, $force_id)) continue;
$fields_sql .= sprintf('%s, ',$field_name); //Adding field name to fields block of Insert statement
//Adding field' value to Values block of Insert statement, escaping it with ADODB' qstr
- $values_sql .= sprintf('%s, ',$this->Conn->qstr($this->FieldValues[$field_name], 0));
+ if (is_null( $this->FieldValues[$field_name] )) {
+ if (isset($this->Fields[$field_name]['not_null']) && $this->Fields[$field_name]['not_null']) {
+ $values_sql .= $this->Conn->qstr($this->Fields[$field_name]['default']).', ';
+ }
+ else {
+ $values_sql .= 'NULL, ';
+ }
+ }
+ else {
+ $values_sql .= sprintf('%s, ',$this->Conn->qstr($this->FieldValues[$field_name], 0));
+ }
+
}
//Cutting last commas and spaces
$fields_sql = ereg_replace(", $", '', $fields_sql);
$values_sql = ereg_replace(", $", '', $values_sql);
$sql = sprintf('INSERT INTO %s (%s) VALUES (%s)', $this->TableName, $fields_sql, $values_sql); //Formatting query
//Executing the query and checking the result
if ($this->Conn->ChangeQuery($sql) === false)
{
if($this->DisplayQueries)
{
echo "Error executing statement: ".$this->Conn->getErrorMsg().'<br>';
}
return false;
}
$this->setID( $this->Conn->getInsertID() );
- //$this->SetInsertID(); //Setting Primary Key ($this->id) for futher using the object
+
+ if (!$system_create){
+ $this->setModifiedFlag();
+ }
+
+ $this->raiseEvent('OnAfterItemCreate');
return true;
}
/**
* Deletes the record from databse
*
* @access public
- * @return void
+ * @return bool
*/
- function Delete()
+ function Delete($id=null)
{
+ if( isset($id) ) {
+ $this->setID($id);
+ }
+
+ if( !$this->raiseEvent('OnBeforeItemDelete') ) return false;
+
$q = 'DELETE FROM '.$this->TableName.' WHERE '.$this->GetKeyClause('Delete');
if ($this->DisplayQueries)
{
echo get_class($this).' Delete SQL: '.$q.'<br>';
}
- return $this->Conn->ChangeQuery($q);
+ $ret = $this->Conn->ChangeQuery($q);
+
+ $this->setModifiedFlag();
+
+ $this->raiseEvent('OnAfterItemDelete');
+
+ return $ret;
+ }
+
+ /**
+ * Sets new name for item in case if it is beeing copied
+ * in same table
+ *
+ * @param array $master Table data from TempHandler
+ * @param int $foreign_key ForeignKey value to filter name check query by
+ * @access private
+ */
+ function NameCopy($master=null, $foreign_key=null)
+ {
+ $title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
+ if (!$title_field) return;
+
+ $new_name = $this->GetDBField($title_field);
+ $original_checked = false;
+ do {
+ if ( preg_match("/Copy ([0-9]*)[ ]*of(.*)/", $new_name, $regs) ) {
+ $new_name = 'Copy '.($regs[1]+1).' of '.$regs[2];
+ }
+ elseif ($original_checked) {
+ $new_name = 'Copy of '.$new_name;
+ }
+
+ // if we are cloning in temp table this will look for names in temp table,
+ // since object' TableName contains correct TableName (for temp also!)
+ // if we are cloning live - look in live
+ $query = 'SELECT '.$title_field.' FROM '.$this->TableName.'
+ WHERE '.$title_field.' = '.$this->Conn->qstr($new_name);
+
+ if (getArrayValue($master, 'ForeignKey') && isset($foreign_key)) {
+ $query .= ' AND '.$master['ForeignKey'].' = '.$foreign_key;
+ }
+
+ $res = $this->Conn->GetOne($query);
+
+ /*// if not found in live table, check in temp table if applicable
+ if ($res === false && $object->Special == 'temp') {
+ $query = 'SELECT '.$name_field.' FROM '.$this->GetTempName($master['TableName']).'
+ WHERE '.$name_field.' = '.$this->Conn->qstr($new_name);
+ $res = $this->Conn->GetOne($query);
+ }*/
+
+ $original_checked = true;
+ } while ($res !== false);
+ $this->SetDBField($title_field, $new_name);
+ }
+
+ function raiseEvent($name, $id=null)
+ {
+ if( !isset($id) ) $id = $this->GetID();
+ $event = new kEvent( Array('name'=>$name,'prefix'=>$this->Prefix,'special'=>$this->Special) );
+ $event->setEventParam('id', $id);
+ $this->Application->HandleEvent($event);
+ return $event->status == erSUCCESS ? true : false;
}
/**
* Set's new ID for item
*
* @param int $new_id
* @access public
*/
function setID($new_id)
{
$this->ID=$new_id;
$this->SetDBField($this->IDField,$new_id);
}
+
+ /**
+ * Generate and set new temporary id
+ *
+ * @access private
+ */
+ function setTempID()
+ {
+ $new_id = (int)$this->Conn->GetOne('SELECT MIN('.$this->IDField.') FROM '.$this->TableName);
+ if($new_id > 0) $new_id = 0;
+ --$new_id;
+
+ $this->Conn->Query('UPDATE '.$this->TableName.' SET `'.$this->IDField.'` = '.$new_id.' WHERE `'.$this->IDField.'` = '.$this->GetID());
+ $this->SetID($new_id);
+ }
+
+ function setModifiedFlag(){
+
+ $this->Application->StoreVar($this->Application->GetTopmostPrefix($this->Prefix).'_modified', "1");
+ }
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/db/dbitem.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
\ No newline at end of property
+1.2
\ No newline at end of property
Index: trunk/core/kernel/languages/phrases_cache.php
===================================================================
--- trunk/core/kernel/languages/phrases_cache.php (revision 1338)
+++ trunk/core/kernel/languages/phrases_cache.php (revision 1339)
@@ -1,92 +1,165 @@
<?php
class PhrasesCache extends kDBBase {
var $Phrases = Array();
- var $Ids;
+ var $Ids = Array();
+ var $OriginalIds = Array(); //for comparing cache
var $LanguageId = 1;
+ var $fromTag = false;
+
function PhrasesCache($LanguageId=1)
{
parent::kDBBase();
$this->Phrases = Array();
$this->LanguageId = $LanguageId;
$this->LoadPhrases( $this->GetCachedIds() );
}
function GetCachedIds()
{
$query = sprintf("SELECT PhraseList FROM %s WHERE Template = %s",
- 'PhraseCache',
+ TABLE_PREFIX.'PhraseCache',
$this->Conn->Qstr($this->Application->GetVar('t')));
$phrases_ids = $this->Conn->GetOne($query);
if ($phrases_ids === false) return Array();
return explode(',', $phrases_ids);
}
function LoadPhrases($ids)
{
- if (!is_array($ids) || count($ids) == 0) return;
+ if ( !is_array($ids) || !implode('', $ids) ) return;
$query = sprintf("SELECT Translation,Phrase FROM %s WHERE LanguageId = %s AND PhraseId IN (%s)",
- 'Phrase',
+ TABLE_PREFIX.'Phrase',
$this->LanguageId,
join(',', $ids));
$phrases = $this->Conn->GetCol($query,'Phrase');
foreach($phrases as $phrase => $tanslation)
{
$this->AddCachedPhrase(strtoupper($phrase), $tanslation);
}
$this->Ids = $ids;
+ $this->OriginalIds = $ids;
}
function AddCachedPhrase($label, $value)
{
$label = strtoupper($label);
$this->Phrases[$label] = $value;
}
function UpdateCache()
{
- if (!is_array($this->Ids) || count($Ids) == 0) return;
+ if (!is_array($this->Ids) || count($this->Ids) == 0) return;
+ if ($this->Ids == $this->OriginalIds) return; //nothing changed
$query = sprintf("REPLACE %s (PhraseList, CacheDate, Template)
VALUES (%s, %s, %s)",
- 'PhraseCache',
+ TABLE_PREFIX.'PhraseCache',
$this->Conn->Qstr(join(',', $this->Ids)),
mktime(),
$this->Conn->Qstr($this->Application->GetVar('t')));
$this->Conn->Query($query);
}
function GetPhrase($label)
{
+ if (ereg("^!.+!$", $label) > 0) {
+ $label = substr($label, 1, -1); //cut exclamation marks
+ }
+
+ $original_label = $label;
$label = strtoupper($label);
- if (array_key_exists($label, $this->Phrases))
- return $this->Phrases[$label];
+ if( isset($this->Phrases[$label]) ) return $this->Phrases[$label];
- $this->LoadPhraseByLabel($label);
+ $this->LoadPhraseByLabel($label, $original_label);
return $this->GetPhrase($label);
}
- function LoadPhraseByLabel($label)
+ function LoadPhraseByLabel($label, $original_label)
{
$query = sprintf("SELECT PhraseId, Translation FROM %s WHERE LanguageId = %s AND UPPER(Phrase) = UPPER(%s)",
- Phrase,
+ TABLE_PREFIX.'Phrase',
$this->LanguageId,
$this->Conn->qstr($label));
$res = $this->Conn->GetRow($query);
- if ($res === false || count($res) == 0) {
- $this->AddCachedPhrase($label, '!'.$label.'!'); //add it as already cached, as long as we dont need to cache not found phrase
+ if ($res === false || count($res) == 0)
+ {
+ $translation = '!'.$label.'!';
+ if( defined('DEBUG_MODE') && defined('ADMIN') && ADMIN && dbg_ConstOn('DBG_PHRASES'))
+ {
+ $edit_url = $this->Application->HREF('in-commerce/regional/phrases_edit','',Array('m_opener'=>'d','phrases_label'=>$original_label,'phrases_event'=>'OnNew', 'pass'=>'all,phrases','index_file'=>'index4.php') );
+ $translation = '<a href="'.$edit_url.'">!'.$label.'!</a>';
+ if($this->fromTag) $translation = $this->escapeTagReserved($translation);
+ }
+ $this->AddCachedPhrase($label, $translation); //add it as already cached, as long as we dont need to cache not found phrase
return false;
}
$this->Phrases[$label] = $res['Translation'];
array_push($this->Ids, $res['PhraseId']);
- $this->Ids = array_unique ( $this->Ids ); //just to make sure
+ $this->Ids = array_unique($this->Ids); //just to make sure
return true;
}
+
+ /**
+ * Sort params by name and then by length
+ *
+ * @param string $a
+ * @param string $b
+ * @return int
+ * @access private
+ */
+ function CmpParams($a, $b)
+ {
+ $a_len = strlen($a);
+ $b_len = strlen($b);
+ if ($a_len == $b_len) return 0;
+ return $a_len > $b_len ? -1 : 1;
+ }
+
+ /**
+ * Replace language tags in exclamation marks found in text
+ *
+ * @param string $text
+ * @return string
+ * @access public
+ */
+ function ReplaceLanguageTags($text)
+ {
+ $this->fromTag = true;
+ preg_match_all("(!(la|lu)[^!]+!)", $text, $res, PREG_PATTERN_ORDER);
+ $language_tags = $res[0];
+ uasort($language_tags, Array(&$this, 'CmpParams') );
+
+ $values = Array();
+ $i = 0;
+ foreach ($language_tags as $label) {
+ array_push($values, $this->GetPhrase($label) );
+ //array_push($values, $this->Application->Phrase($label) );
+ $language_tags[$i] = '/' . $language_tags[$i] . '/';
+ $i++;
+ }
+ $this->fromTag = false;
+ return preg_replace($language_tags, $values, $text);
+ }
+
+ /**
+ * Escape chars in phrase translation, that could harm parser to process tag
+ *
+ * @param string $text
+ * @return string
+ * @access private
+ */
+ function escapeTagReserved($text)
+ {
+ $reserved = Array('"',"'"); // =
+ $replacement = Array('\"',"\'"); // \=
+ return str_replace($reserved,$replacement,$text);
+ }
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/languages/phrases_cache.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
\ No newline at end of property
+1.2
\ No newline at end of property
Index: trunk/core/kernel/startup.php
===================================================================
--- trunk/core/kernel/startup.php (revision 1338)
+++ trunk/core/kernel/startup.php (revision 1339)
@@ -1,50 +1,91 @@
<?php
+define('KERNEL_PATH', FULL_PATH.'/kernel/kernel4');
+
+if (defined('ADMIN') && ADMIN) {
+ define('SPECIAL_TEMPLATES_FOLDER', '/kernel/admin_templates');
+}
+
+define('INPORTAL_ENV', 1);
+
+define('DOC_ROOT', rtrim($_SERVER['DOCUMENT_ROOT'], '/'));
+
+include_once(KERNEL_PATH.'/globals.php'); // non OOP functions used through kernel, e.g. print_pre
+
+if( file_exists(FULL_PATH.'/debug.php') )
+{
+ k4_include_once(FULL_PATH.'/debug.php');
+ if( defined('DEBUG_MODE')&&DEBUG_MODE ) include_once(KERNEL_PATH.'/utility/debugger.php');
+}
+
+$vars = parse_portal_ini(FULL_PATH.'/config.php');
+
+define('SQL_TYPE', $vars['DBType']);
+define('SQL_SERVER', $vars['DBHost']);
+define('SQL_USER', $vars['DBUser']);
+define('SQL_PASS', $vars['DBUserPassword']);
+define('SQL_DB', $vars['DBName']);
+define('TABLE_PREFIX', $vars['TablePrefix']);
+
ini_set('memory_limit', '50M');
safeDefine('INPORTAL_TAGS', true);
-define('DOC_ROOT', rtrim($_SERVER['DOCUMENT_ROOT'], '/'));
-define('BASE_PATH', $base_path = ereg_replace('/admin', '', ereg_replace(DOC_ROOT, '', FULL_PATH)));
+$reg = '/'.preg_quote (DOC_ROOT, '/').'/i';
+define('BASE_PATH', $base_path = ereg_replace('/admin', '', preg_replace($reg, '', str_replace('\\', '/', FULL_PATH))));
safeDefine( 'SERVER_NAME', $_SERVER['SERVER_NAME']);
-define( 'KERNEL_PATH', DOC_ROOT.BASE_PATH.'/kernel4');
+safeDefine( 'KERNEL_PATH', DOC_ROOT.BASE_PATH.'/kernel4');
safeDefine( 'PROTOCOL', 'http://');
-define( 'MODULES_PATH', DOC_ROOT.BASE_PATH.'/modules');
-define( 'THEMES_PATH', ereg_replace(DOC_ROOT.BASE_PATH,'',FULL_PATH). ( defined('ADMIN') ? '/templates' : '/templates'));
-safeDefine('ENV_VAR_NAME','kenv');
-
-if( file_exists(FULL_PATH.'/debug.php') )
-{
- include_once(FULL_PATH.'/debug.php');
- if( defined('DEBUG_MODE')&&DEBUG_MODE )
- {
- // if debugging with ZDE, then don't override standart error handler
- if( isset($_REQUEST['debug_host']) ) define('DBG_HANDLE_ERRORS',0);
- include_once(KERNEL_PATH.'/utility/debugger.php');
- }
+define( 'MODULES_PATH', DOC_ROOT.BASE_PATH);
+if ( defined('SPECIAL_TEMPLATES_FOLDER') ) {
+ safeDefine( 'THEMES_PATH', preg_replace('/'.preg_quote(DOC_ROOT.BASE_PATH, '/').'/i','',str_replace('\\', '/', FULL_PATH)). SPECIAL_TEMPLATES_FOLDER );
+}
+else {
+ safeDefine( 'THEMES_PATH', preg_replace('/'.preg_quote(DOC_ROOT.BASE_PATH, '/').'/i','',str_replace('\\', '/', FULL_PATH)). ( defined('ADMIN') ? '/admin/templates' : '/themes/default'));
}
-include_once(KERNEL_PATH.'/db/db_connection.php');
+safeDefine('ENV_VAR_NAME','env');
+k4_include_once(KERNEL_PATH.'/db/db_connection.php');
+
+safeDefine('IMAGES_PATH', '/kernel/images/');
+safeDefine('IMAGES_PENDING_PATH', IMAGES_PATH.'pending/');
safeDefine('CUSTOM_UPLOAD_PATH', '/templates/images/custom/');
+safeDefine('MAX_UPLOAD_SIZE', 500000);
+
+k4_include_once(KERNEL_PATH."/kbase.php");
+k4_include_once(KERNEL_PATH.'/utility/event.php');
+k4_include_once(KERNEL_PATH."/utility/factory.php");
+k4_include_once(KERNEL_PATH."/languages/phrases_cache.php");
+
+// We should get rid of these includes:
+k4_include_once(KERNEL_PATH."/db/dblist.php");
+k4_include_once(KERNEL_PATH."/db/dbitem.php");
-include_once(KERNEL_PATH."/application.php");
-include_once(MODULES_PATH."/general/my_application.php");
+k4_include_once(KERNEL_PATH.'/processors/tag_processor.php');
+k4_include_once(KERNEL_PATH."/db/db_tag_processor.php");
+
+k4_include_once(KERNEL_PATH."/event_handler.php");
+
+k4_include_once(KERNEL_PATH.'/db/db_event_handler.php');
+
+k4_include_once(KERNEL_PATH."/utility/temp_handler.php"); // needed because of static calls from kBase
+// up to here
+
+k4_include_once(KERNEL_PATH.'/application.php');
+k4_include_once(MODULES_PATH.'/in-commerce/units/general/my_application.php');
safeDefine('LOGIN_CONTROLLER', 'LoginController');
safeDefine('USER_MODEL', 'User');
-function print_pre($data, $label='')
-{
- echo '<b>',$label,'</b><br><pre>',print_r($data,true),'</pre>';
- //echo var_dump($data);
-}
-function safeDefine($const_name, $const_value)
-{
- if(!defined($const_name)) define($const_name,$const_value);
-}
+// global constants
+define('HAVING_FILTER', 1);
+define('WHERE_FILTER', 2);
+
+define('FLT_TYPE_AND', 'AND');
+define('FLT_TYPE_OR', 'OR');
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/startup.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
\ No newline at end of property
+1.2
\ No newline at end of property
Index: trunk/core/kernel/application.php
===================================================================
--- trunk/core/kernel/application.php (revision 1338)
+++ trunk/core/kernel/application.php (revision 1339)
@@ -1,833 +1,1004 @@
<?php
-//include_once(KERNEL_PATH."/base.php");
-//include_once(KERNEL_PATH."/mvc/models/dbitem.php");
-//include_once(KERNEL_PATH."/mvc/models/dblist.php");
-
-
-
-include_once(KERNEL_PATH."/kbase.php");
-
-include_once(KERNEL_PATH.'/processors/tag_processor.php');
-include_once(KERNEL_PATH."/event_handler.php");
-
-include_once(KERNEL_PATH."/utility/factory.php");
-
-include_once(KERNEL_PATH."/utility/iterator.php");
-include_once(KERNEL_PATH."/languages/phrases_cache.php");
-
-include_once(KERNEL_PATH."/db/dblist.php");
-include_once(KERNEL_PATH."/db/dbitem.php");
-include_once(KERNEL_PATH."/db/db_tag_processor.php");
-
-
-include_once(KERNEL_PATH."/utility/event.php");
-
-$profiler = null;
/**
* Basic class for Kernel3-based Application
*
* This class is a Facade for any other class which needs to deal with Kernel3 framework.<br>
* The class incapsulates the main run-cycle of the script, provide access to all other objects in the framework.<br>
* <br>
* The class is a singleton, which means that there could be only one instance of KernelApplication in the script.<br>
* This could be guranteed by NOT calling the class constuctor directly, but rather calling KernelApplication::Instance() method,
* which returns an instance of the application. The method gurantees that it will return exactly the same instance for any call.<br>
* See singleton pattern by GOF.
* @package kernel4
*/
class kApplication {
/**
* Holds internal TemplateParser object
* @access private
* @var TemplateParser
*/
var $Parser;
var $Profiler;
/**
* Holds parser output buffer
* @access private
* @var string
*/
var $HTML;
var $DocRoot;
var $BasePath;
var $KernelPath;
var $Server;
/**
* The main Factory used to create
* almost any class of kernel and
* modules
*
* @access private
* @var kFactory
*/
var $Factory;
var $XMLFactory; // in use?
/**
* Holds all phrases used
* in code and template
*
* @var PhrasesCache
*/
var $Phrases;
/**
- * Holds connection to database
+ * Holds DBConnection
*
- * @var DBConnection
+ * @var kDBConnection
*/
var $DB;
/**
* Constucts KernelApplication - constructor is PRIVATE
*
* The constuructor of KernelApplication should NOT be called directly
* To create KernelApplication, call its Instance() method
* @see KerenelApplication::Instance
* @access private
*/
function kApplication()
{
global $doc_root, $base_path, $kernel_path, $protocol, $server;
$this->DocRoot = $doc_root;
$this->BasePath = $base_path;
$this->KernelPath = $kernel_path;
$this->Protocol = $protocol;
$this->Server = $server;
}
/**
* Returns kApplication instance anywhere in the script.
*
* This method should be used to get single kApplication object instance anywhere in the
* Kernel-based application. The method is guranteed to return the SAME instance of kApplication.
* Anywhere in the script you could write:
* <code>
* $application =& kApplication::Instance();
* </code>
* or in an object:
* <code>
* $this->Application =& kApplication::Instance();
* </code>
* to get the instance of kApplication. Note that we call the Instance method as STATIC - directly from the class.
* To use descendand of standard kApplication class in your project you would need to define APPLICATION_CLASS constant
* BEFORE calling kApplication::Instance() for the first time. If APPLICATION_CLASS is not defined the method would
* create and return default KernelApplication instance.
* @static
* @access public
* @return kApplication
*/
function &Instance()
{
static $instance = false;
if (!$instance) {
if (!defined('APPLICATION_CLASS')) define('APPLICATION_CLASS', 'kApplication');
$class = APPLICATION_CLASS;
$instance = new $class();
}
return $instance;
}
/**
* Initializes the Application
*
* Creates Utilites instance, HTTPQuery, Session, Profiler, TemplatesCache, Parser
* @access public
* @see HTTPQuery
* @see Session
* @see TemplatesCache
* @return void
*/
function Init()
{
- $this->DB = new DBConnection(SQL_TYPE, Array(&$this,'handleSQLError') );
+ $this->DB = new kDBConnection(SQL_TYPE, Array(&$this,'handleSQLError') );
$this->DB->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB);
$this->DB->debugMode = $this->isDebugMode();
$this->SetDefaultConstants();
- setcookie('CookiesOn', 1, time()+600);
-
$this->Factory = new kFactory();
-
+
$this->registerDefaultClasses();
// 1. to read configs before doing any recallObject
$config_reader =& $this->recallObject('kUnitConfigReader');
- $this->Phrases = new PhrasesCache( $this->RecallVar('LanguageId', DEFAULT_LANGUAGE_ID) );
+ if (!$this->GetVar('m_lang')) $this->SetVar('m_lang', $this->GetDefaultLanguageId());
+ $this->Phrases = new PhrasesCache( $this->GetVar('m_lang') );
+
+ $language =& $this->recallObject('lang');
+ $language->Load($this->GetVar('m_lang'));
$this->ValidateLogin(); // TODO: write that method
+
+ if (defined('DEBUG_MODE')) {
+ global $debugger;
+ $debugger->profileFinish('kernel4_startup');
+ }
+
+ }
+
+ function GetDefaultLanguageId()
+ {
+ return 1;
}
/**
* Registers default classes such as ItemController, GridController and LoginController
*
* Called automatically while initializing Application
* @access private
* @return void
*/
function RegisterDefaultClasses()
{
//$this->registerClass('Utilites',KERNEL_PATH.'/utility/utilities.php');
$this->registerClass('HTTPQuery',KERNEL_PATH.'/utility/http_query.php');
$this->registerClass('Session',KERNEL_PATH.'/session/session.php');
+ $this->registerClass('SessionStorage',KERNEL_PATH.'/session/session.php');
+ $this->registerClass('LoginEventHandler',KERNEL_PATH.'/session/login_event_handler.php','login_EventHandler');
$this->registerClass('kEventManager',KERNEL_PATH.'/event_manager.php','EventManager');
$this->registerClass('kUnitConfigReader',KERNEL_PATH.'/utility/unit_config_reader.php');
+
$this->registerClass('Params',KERNEL_PATH.'/utility/params.php','kActions');
+ $this->registerClass('kArray',KERNEL_PATH.'/utility/params.php','kArray');
+ $this->registerClass('kFormatter', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kOptionsFormatter', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kPictureFormatter', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kDateFormatter', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kLEFTFormatter', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kMultiLanguage', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kTempTablesHandler', KERNEL_PATH.'/utility/temp_handler.php');
+
+ $event_manager =& $this->recallObject('EventManager');
+ $event_manager->registerBuildEvent('kTempTablesHandler','OnTempHandlerBuild');
//$this->registerClass('Configuration',KERNEL_PATH.'/utility/configuration.php');
$this->registerClass('TemplatesCache',KERNEL_PATH.'/parser/template.php');
$this->registerClass('TemplateParser',KERNEL_PATH.'/parser/template_parser.php');
$this->registerClass('MainProcessor', KERNEL_PATH.'/processors/main_processor.php','m_TagProcessor');
+ $this->registerClass('kMultipleFilter', KERNEL_PATH.'/utility/filters.php');
$this->registerClass('kDBList', KERNEL_PATH.'/db/dblist.php');
$this->registerClass('kDBItem', KERNEL_PATH.'/db/dbitem.php');
$this->registerClass('kDBEventHandler', KERNEL_PATH.'/db/db_event_handler.php');
$this->registerClass('kDBTagProcessor', KERNEL_PATH.'/db/db_tag_processor.php');
$this->registerClass('kTagProcessor', KERNEL_PATH.'/processors/tag_processor.php');
/*$this->RegisterClass('LoginController', KERNEL_PATH.'/users/login_controller.php');*/
}
/**
* Defines default constants if it's not defined before - in config.php
*
* Called automatically while initializing Application and defines:
* LOGIN_CONTROLLER, XML_FACTORY etc.
* @access private
* @return void
*/
function SetDefaultConstants()
{
if (!defined('SERVER_NAME')) define('SERVER_NAME', $_SERVER['SERVER_NAME']);
if (!defined('LOGIN_CONTROLLER')) define('LOGIN_CONTROLLER', 'LoginController');
if (!defined('XML_FACTORY')) define('XML_FACTORY', 'XMLFactory');
if (!defined('ADMINS_LIST')) define('ADMINS_LIST', '/users/users.php');
if (!defined('USER_MODEL')) define('USER_MODEL', 'Users');
if (!defined('DEFAULT_LANGUAGE_ID')) define('DEFAULT_LANGUAGE_ID', 1);
}
/**
* Actually runs the parser against current template and stores parsing result
*
* This method gets t variable passed to the script, loads the template given in t variable and
* parses it. The result is store in {@link $this->HTML} property.
* @access public
* @return void
*/
function Run()
{
$event_manager =& $this->recallObject('EventManager');
+
+ if( $this->isDebugMode() && dbg_ConstOn('DBG_SHOW_HTTPQUERY') )
+ {
+ global $debugger;
+ $http_query =& $this->recallObject('HTTPQuery');
+ $debugger->appendHTML('HTTPQuery:');
+ $debugger->dumpVars($http_query->_Params);
+ }
+
$event_manager->ProcessRequest();
$this->Parser =& $this->recallObject('TemplateParser');
$template_cache =& $this->recallObject('TemplatesCache');
$t = $this->GetVar('t');
- $this->HTML = $this->Parser->Parse( $template_cache->GetTemplateBody($t) );
+ $this->HTML = $this->Parser->Parse( $template_cache->GetTemplateBody($t), $t );
}
/**
* Send the parser results to browser
*
* Actually send everything stored in {@link $this->HTML}, to the browser by echoing it.
* @access public
* @return void
*/
function Done()
{
//eval("?".">".$this->HTML);
echo $this->HTML;
$this->Phrases->UpdateCache();
$session =& $this->recallObject('Session');
$session->SaveData();
+ //$this->SaveBlocksCache();
+ }
+
+ function SaveBlocksCache()
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $data = serialize($this->PreParsedCache);
+
+ $this->DB->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("blocks_cache", '.$this->DB->qstr($data).', '.time().')');
+ }
}
// Facade
/**
* Returns current session id (SID)
* @access public
* @return longint
*/
function GetSID()
{
$session =& $this->recallObject('Session');
return $session->GetID();
}
function DestroySession()
{
$session =& $this->recallObject('Session');
$session->DestroySession();
}
/**
* Returns variable passed to the script as GET/POST/COOKIE
*
* @access public
* @param string $var Variable name
* @return mixed
*/
function GetVar($var,$mode=FALSE_ON_NULL)
{
$http_query =& $this->recallObject('HTTPQuery');
return $http_query->Get($var,$mode);
}
/**
* Returns ALL variables passed to the script as GET/POST/COOKIE
*
* @access public
* @return array
*/
function GetVars()
{
$http_query =& $this->recallObject('HTTPQuery');
return $http_query->GetParams();
}
/**
* Set the variable 'as it was passed to the script through GET/POST/COOKIE'
*
* This could be useful to set the variable when you know that
* other objects would relay on variable passed from GET/POST/COOKIE
* or you could use SetVar() / GetVar() pairs to pass the values between different objects.<br>
*
* This method is formerly known as $this->Session->SetProperty.
* @param string $var Variable name to set
* @param mixed $val Variable value
* @access public
* @return void
*/
function SetVar($var,$val)
{
$http_query =& $this->recallObject('HTTPQuery');
$http_query->Set($var,$val);
}
function RemoveVar($var)
{
$session =& $this->recallObject('Session');
return $session->RemoveVar($var);
}
-
+
+ /**
+ * Deletes HTTPQuery variable
+ *
+ * @param string $var
+ * @todo think about method name
+ */
+ function DeleteVar($var)
+ {
+ $http_query =& $this->recallObject('HTTPQuery');
+ return $http_query->Remove($var);
+ }
+
/**
* Returns session variable value
*
* Return value of $var variable stored in Session. An optional default value could be passed as second parameter.
*
* @see SimpleSession
* @access public
* @param string $var Variable name
* @param mixed $default Default value to return if no $var variable found in session
* @return mixed
*/
- function RecallVar($var,$default='')
+ function RecallVar($var,$default=false)
{
$session =& $this->recallObject('Session');
return $session->RecallVar($var,$default);
}
/**
* Stores variable $val in session under name $var
*
* Use this method to store variable in session. Later this variable could be recalled.
* @see RecallVar
* @access public
* @param string $var Variable name
* @param mixed $val Variable value
*/
function StoreVar($var, $val)
{
$session =& $this->recallObject('Session');
$session->StoreVar($var, $val);
}
function StoreVarDefault($var, $val)
{
$session =& $this->recallObject('Session');
$session->StoreVarDefault($var, $val);
}
/**
* Links HTTP Query variable with session variable
*
* If variable $var is passed in HTTP Query it is stored in session for later use. If it's not passed it's recalled from session.
* This method could be used for making sure that GetVar will return query or session value for given
* variable, when query variable should overwrite session (and be stored there for later use).<br>
* This could be used for passing item's ID into popup with multiple tab -
* in popup script you just need to call LinkVar('id', 'current_id') before first use of GetVar('id').
* After that you can be sure that GetVar('id') will return passed id or id passed earlier and stored in session
* @access public
* @param string $var HTTP Query (GPC) variable name
* @param mixed $ses_var Session variable name
* @param mixed $default Default variable value
*/
function LinkVar($var, $ses_var=null, $default='')
{
if (!isset($ses_var)) $ses_var = $var;
- if ($this->GetVar($var) !== false) {
+ if ($this->GetVar($var) !== false)
+ {
$this->StoreVar($ses_var, $this->GetVar($var));
}
else
+ {
$this->SetVar($var, $this->RecallVar($ses_var, $default));
+ }
}
/**
* Returns variable from HTTP Query, or from session if not passed in HTTP Query
*
* The same as LinkVar, but also returns the variable value taken from HTTP Query if passed, or from session if not passed.
* Returns the default value if variable does not exist in session and was not passed in HTTP Query
*
* @see LinkVar
* @access public
* @param string $var HTTP Query (GPC) variable name
* @param mixed $ses_var Session variable name
* @param mixed $default Default variable value
* @return mixed
*/
function GetLinkedVar($var, $ses_var=null, $default='')
{
if (!isset($ses_var)) $ses_var = $var;
$this->LinkVar($var, $ses_var, $default);
return $this->GetVar($var);
}
/*function ExtractByMask($array, $mask, $key_id=1, $ret_mode=1)
{
$utils =& $this->recallObject('Utilities');
return $utils->ExtractByMask($array, $mask, $key_id, $ret_mode);
}
function GetSelectedIDs($mask, $format)
{
$http_query =& $this->recallObject('HTTPQuery');
return $http_query->GetSelectedIDs($mask, $format);
}
function GetSelectedIDsArray($mask, $value_mask="%s,")
{
$http_query =& $this->recallObject('HTTPQuery');
return $http_query->GetSelectedIDsArray($mask, $value_mask);
}*/
/**
* Returns configurtion option
*
* @param string $option
* @return string
* @access public
*/
/*function ConfigOption($option)
{
$config =& $this->recallObject('Configuration');
return $config->Get($option);
}*/
/**
* Sets configuration option
*
* @param string $option
* @param string $value
* @return bool
* @access public
*/
/*function SetConfigOption($option,$value)
{
$config =& $this->recallObject('Configuration');
return $config->Set($option, $value);
}*/
function AddBlock($name, $tpl)
{
$this->cache[$name] = $tpl;
}
function SetTemplateBody($title,$body)
{
$templates_cache =& $this->recallObject('TemplatesCache');
$templates_cache->SetTemplateBody($title,$body);
}
function ProcessTag($tag_data)
{
$a_tag = new Tag($tag_data,$this->Parser);
return $a_tag->DoProcessTag();
}
+ function ProcessParsedTag($prefix, $tag, $params)
+ {
+ $a_tag = new Tag('',$this->Parser);
+ $a_tag->Tag = $tag;
+ $a_tag->Processor = $prefix.'_TagProcessor';
+ $a_tag->NamedParams = $params;
+ return $a_tag->DoProcessTag();
+ }
+
/*function &GetProcessor($prefix)
{
$this->KernelDie('GetProcessor is DEPRICATED, use recallObject');
// return $this->Processors->GetProcessor($prefix, new Tag('empty', $this->Parser));
}*/
/* DEFINETLY NEEDS TO BE MOVED AWAY!!!!! */
/*var $email_body;
function Email($params)
{
$this->email_body = $this->ParseBlock($params);
$from = $this->GetVar('email_from');
$to = $this->GetVar('email_to');
$replay = $this->GetVar('email_replay');
if ( $replay == "" ) $replay = $from;
$subject = $this->GetVar('email_subject');
$charset = $this->GetVar('email_charset');
// $display = $this->GetVar('email_display');
$display = 0;
if (!isset($charset) || $charset == '') $charset = 'US-ASCII';
$mime = $this->GetVar('email_mime');
if ($mime == 'yes') {
$mime_mail = new MIMEMail($to, $from, $subject, $charset);
$mime_mail->mailbody($this->email_body);
if ($f_name = $this->GetVar('email_attach')) {
$full_path = DOC_ROOT.BASE_PATH.'/'.$f_name;
$data = '';
if(file_exists($full_path)) {
$fd = fopen($full_path, "r");
$data = fread($fd, filesize($full_path));
fclose($fd);
}
else exit;
$filename = $this->GetVar('email_attach_filename');
$type = $this->GetVar('email_attach_type');
$mime_mail->attachfile_raw($data, $filename, $type);
$mime_mail->send();
}
}
else {
$headers.="From: $from\n";
$headers.="Reply-To: $replay\n";
$headers.="Content-Type: text/html; charset=\"$charset\"\n";
if ( $display == 1 ) {
echo "<pre>";
echo " from : $from <br>";
echo " to : $to <br>";
echo " replay : $replay <br>";
echo " subject : $subject <br>";
echo " this->email_body : $this->email_body <br>";
echo " headers : $headers <br>";
echo "</pre>";
}
mail($to, $subject, $this->email_body, $headers);
}
}*/
/**
* Return ADODB Connection object
*
* Returns ADODB Connection object already connected to the project database, configurable in config.php
* @access public
* @return ADODBConnection
*/
function &GetADODBConnection()
{
return $this->DB;
}
- function ParseBlock($params,$pass_params=0)
+ function ParseBlock($params,$pass_params=0,$as_template=false)
{
- return $this->Parser->ParseBlock($params,$pass_params);
+ return $this->Parser->ParseBlock($params, $pass_params, $as_template);
}
function &GetXMLFactory()
{
return $this->XMLFactory;
}
/**
* Return href for template
*
* @access public
* @param string $t Template path
* @var string $prefix index.php prefix - could be blank, 'admin'
*/
- function HREF($t, $prefix='')
+ function HREF($t, $prefix='', $params=null, $index_file=null)
{
global $HTTP_SERVER_VARS;
if (defined('ADMIN') && $prefix == '') $prefix='/admin';
if (defined('ADMIN') && $prefix == '_FRONT_END_') $prefix = '';
- $index_file = defined('INDEX_FILE') ? INDEX_FILE : 'index.php';
- $t_path = !empty($t) ? 't='.$t : '';
+ $index_file = isset($index_file) ? $index_file : (defined('INDEX_FILE') ? INDEX_FILE : basename($_SERVER['PHP_SELF']));
+
+ if( isset($params['index_file']) ) $index_file = $params['index_file'];
+ if (getArrayValue($params, 'opener') == 'u') {
+ $opener_stack=$this->RecallVar('opener_stack');
+ if($opener_stack) {
+ $opener_stack=unserialize($opener_stack);
+ list($index_file, $env) = explode('|', $opener_stack[count($opener_stack)-1]);
+ $ret = $this->BaseURL($prefix).$index_file.'?'.ENV_VAR_NAME.'='.$env;
+ return $ret;
+ }
+ }
+
+ $pass = isset($params['pass']) ? $params['pass'] : '';
+ $pass_events = isset($params['pass_events']) ? $params['pass_events'] : false; // pass events with url
+
+ $ret = $this->BaseURL($prefix).$index_file.'?'.$this->BuildEnv($t, $params, $pass, $pass_events);
+
+ return $ret;
+ }
+
+ function BuildEnv($t, $params, $pass='all', $pass_events=false)
+ {
$session =& $this->recallObject('Session');
$sid = $session->NeedQueryString()?$this->GetSID():'';
+ if (defined('INPORTAL_ENV')) {
+ $ret = ENV_VAR_NAME.'='.$sid.'-'.$t;
+ }
+ else {
+ $ret = ENV_VAR_NAME.'='.$sid.':'.$t;
+ }
- $ret = $this->BaseURL($prefix).$index_file.'?'.ENV_VAR_NAME.'='.$sid.':'.$t;
-
- $t_pass=$this->GetVar('t_pass');
- $t_pass_events=$this->GetVar('t_pass_events'); // pass events with url
+ $pass = str_replace('all', trim($this->GetVar('passed'), ','), $pass);
- if($t_pass)
+ if(strlen($pass) > 0)
{
- $pass_info=explode(',',$t_pass); // array( prefix[.special], prefix[.special] ...
+ $pass_info = array_unique( explode(',',$pass) ); // array( prefix[.special], prefix[.special] ...
foreach($pass_info as $pass_element)
{
$ret.=':';
list($prefix)=explode('.',$pass_element);
$query_vars = $this->getUnitOption($prefix,'QueryString');
- if(!$t_pass_events) $this->SetVar($pass_element.'_event',''); // remove event from url if requested
+ //if pass events is off and event is not implicity passed
+ if(!$pass_events && !isset($params[$pass_element.'_event'])) {
+ $params[$pass_element.'_event'] = ''; // remove event from url if requested
+ //otherwise it will use value from get_var
+ }
if($query_vars)
{
$tmp_string=Array(0=>$pass_element);
foreach($query_vars as $index => $var_name)
{
- $tmp_string[$index]=$this->GetVar($pass_element.'_'.$var_name);
+ //if value passed in params use it, otherwise use current from application
+ $tmp_string[$index] = isset( $params[$pass_element.'_'.$var_name] ) ? $params[$pass_element.'_'.$var_name] : $this->GetVar($pass_element.'_'.$var_name);
+ if ( isset($params[$pass_element.'_'.$var_name]) ) {
+ unset( $params[$pass_element.'_'.$var_name] );
+ }
+ }
+
+ $escaped = array();
+ foreach ($tmp_string as $tmp_val) {
+ $escaped[] = str_replace(Array('-',':'), Array('\-','\:'), $tmp_val);
}
- $ret.=implode('-',$tmp_string);
+ if ($this->getUnitOption($prefix, 'PortalStyleEnv') == true) {
+ $ret.= array_shift($escaped).array_shift($escaped).'-'.implode('-',$escaped);
+ }
+ else {
+ $ret.=implode('-',$escaped);
+ }
}
}
}
- $this->SetVar('t_pass',''); // don't pass any prefixes_specials in url by default
- $this->SetVar('t_pass_events',0); // don't pass events in url by default
+ unset($params['pass']);
+ unset($params['opener']);
+ unset($params['m_event']);
+ foreach ($params as $param => $value) {
+ $ret .= '&'.$param.'='.$value;
+ }
+ if( getArrayValue($params,'escape') ) $ret = addslashes($ret);
return $ret;
}
function BaseURL($prefix='')
{
return PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').BASE_PATH.$prefix.'/';
}
- /**
- * Build enviroment variable based on
- * data submitted from previous template
- *
- * @access public
- */
- function ReBuildENV()
+ function Redirect($t='', $params=null, $prefix='', $index_file=null)
{
- $event_manager =& $this->recallObject('EventManager');
- $prefix_specials = array_keys($event_manager->queryMaps);
- $this->SetVar('t_pass', implode(',',$prefix_specials) );
- }
-
- function Redirect($t='', $params='', $prefix='')
- {
- if ($t == '') $t = $this->GetVar('t');
+ if ($t == '' || $t === true) $t = $this->GetVar('t');
// pass prefixes and special from previous url
- $this->ReBuildENV();
+ if (!isset($params['pass'])) $params['pass'] = 'all';
- $location = $this->HREF($t, $prefix);
+ $location = $this->HREF($t, $prefix, $params, $index_file);
$a_location = $location;
- $location = sprintf("Location: %s".($params ? "&" : '')."%s",$location, $params);
+ $location = "Location: $location";
//echo " location : $location <br>";
-
- if (headers_sent() != '') {
+ if (headers_sent() != '' || ($this->isDebugMode() && dbg_ConstOn('DBG_REDIRECT')) ) {
echo "<b>Debug output above!!!</b> Proceed to redirect: <a href=\"$a_location\">$a_location</a><br>";
}
- else
+ else {
header("$location");
-
+ }
+
$session =& $this->recallObject('Session');
$session->SaveData();
+ $this->SaveBlocksCache();
exit;
}
/*function UserError($msg)
{
error_reporting(E_ALL);
trigger_error($msg, E_USER_WARNING );
}*/
function Phrase($label)
{
- if (ereg("^!.+!$", $label) > 0) {
- $label = substr($label, 1, -1); //cut exclamation marks
- }
return $this->Phrases->GetPhrase($label);
}
/**
+ * Replace language tags in exclamation marks found in text
+ *
+ * @param string $text
+ * @return string
+ * @access public
+ */
+ function ReplaceLanguageTags($text)
+ {
+ return $this->Phrases->ReplaceLanguageTags($text);
+ }
+
+ /**
* Validtates user in session if required
*
*/
function ValidateLogin()
{
if (defined('LOGIN_REQUIRED'))
{
// Original Kostja call
//$login_controller =& $this->Factory->MakeClass(LOGIN_CONTROLLER, Array('model' => USER_MODEL, 'prefix' => 'login'));
// Call proposed by Alex
//$login_controller =& $this->RecallObject(LOGIN_CONTROLLER, Array('model' => USER_MODEL, 'prefix' => 'login'));
//$login_controller->CheckLogin();
}
}
function KernelDie($message) {
echo "<b>KernelApplication died</b>: $message<br>Debug backtrace follows:<br>";
print_pre(debug_backtrace());
echo "</pre>";
}
function trigerError($message,$error_type=E_USER_WARNING)
{
trigger_error($message,$error_type);
}
/**
* Allows to process any type of event
*
* @param kEvent $event
* @access public
*/
function HandleEvent(&$event)
{
$event_manager =& $this->recallObject('EventManager');
- $event_manager->HandleEvent(&$event);
+ $event_manager->HandleEvent($event);
}
/**
* Registers new class in the factory
*
* @param string $real_class
* @param string $file
* @param string $pseudo_class
* @access public
*/
function registerClass($real_class,$file,$pseudo_class=null)
{
$this->Factory->registerClass($real_class,$file,$pseudo_class);
}
+ function registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional)
+ {
+ $event_manager =& $this->recallObject('EventManager');
+ $event_manager->registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional);
+ }
+
+ function registerAggregateTag($tag_info)
+ {
+ $aggregator =& $this->recallObject('TagsAggregator', 'kArray');
+ $aggregator->SetArrayValue($tag_info['AggregateTo'], $tag_info['AggregatedTagName'], Array($tag_info['LocalPrefix'], $tag_info['LocalTagName']));
+ }
+
/**
* Returns object using params specified,
* creates it if is required
*
* @param string $name
* @param string $pseudo_class
* @param Array $event_params
* @return Object
*/
function &recallObject($name,$pseudo_class=null,$event_params=Array())
{
- return $this->Factory->getObject($name,$pseudo_class,$event_params);
+ $o1 =& $this->Factory->getObject($name,$pseudo_class,$event_params);
+ //$o1->param1 = 'one';
+
+ /*$func_args = func_get_args();
+ $factory =& $this->Factory;
+ $o2 =& call_user_func_array( Array(&$factory, 'getObject'), $func_args );*/
+
+ //$o2->param1 = 'two';
+ return $o1;
+ }
+
+ function &hasObject($name)
+ {
+ return isset($this->Factory->Storage[$name]);
+ }
+
+ /**
+ * Removes object from storage by given name
+ *
+ * @param string $name Object's name in the Storage
+ */
+ function removeObject($name)
+ {
+ return $this->Factory->DestroyObject($name);
+ }
+
+ /**
+ * Get's real class name for pseudo class,
+ * includes class file and creates class
+ * instance
+ *
+ * @param string $pseudo_class
+ * @return Object
+ * @access private
+ */
+ function &makeClass($pseudo_class)
+ {
+ $func_args = func_get_args();
+ return call_user_func_array( Array(&$this->Factory, 'makeClass'), $func_args);
}
/**
* Checks if application is in debug mode
*
* @return bool
* @access public
*/
function isDebugMode()
{
return defined('DEBUG_MODE')&&DEBUG_MODE;
}
/**
* Reads unit (specified by $prefix)
* option specified by $option
*
* @param string $prefix
* @param string $option
* @return string
* @access public
*/
function getUnitOption($prefix,$option)
{
$unit_config_reader =& $this->recallObject('kUnitConfigReader');
return $unit_config_reader->getUnitOption($prefix,$option);
}
/**
* Set's new unit option value
*
* @param string $prefix
* @param string $name
* @param string $value
* @access public
*/
function setUnitOption($prefix,$option,$value)
{
$unit_config_reader =& $this->recallObject('kUnitConfigReader');
return $unit_config_reader->setUnitOption($prefix,$option,$value);
}
/**
+ * Read all unit with $prefix options
+ *
+ * @param string $prefix
+ * @return Array
+ * @access public
+ */
+ function getUnitOptions($prefix)
+ {
+ $unit_config_reader =& $this->recallObject('kUnitConfigReader');
+ return $unit_config_reader->getUnitOptions($prefix);
+ }
+
+ /**
* Splits any mixing of prefix and
* special into correct ones
*
* @param string $prefix_special
* @return Array
* @access public
*/
function processPrefix($prefix_special)
{
return $this->Factory->processPrefix($prefix_special);
}
/**
* Set's new event for $prefix_special
* passed
*
* @param string $prefix_special
* @param string $event_name
* @access public
*/
function setEvent($prefix_special,$event_name)
{
$event_manager =& $this->recallObject('EventManager');
$event_manager->setEvent($prefix_special,$event_name);
}
/**
* SQL Error Handler
*
* @param int $code
* @param string $msg
* @param string $sql
* @return bool
* @access private
*/
function handleSQLError($code,$msg,$sql)
{
global $debugger;
if($debugger)
{
- $errorLevel=defined('DBG_SQL_FAILURE')&&DBG_SQL_FAILURE?E_USER_ERROR:E_USER_WARNING;
+ $errorLevel=defined('DBG_SQL_FAILURE') && DBG_SQL_FAILURE ? E_USER_ERROR : E_USER_WARNING;
$debugger->dumpVars($_REQUEST);
$debugger->appendTrace();
$error_msg = '<span class="debug_error">'.$msg.' ('.$code.')</span><br><a href="javascript:SetClipboard(\''.htmlspecialchars($sql).'\');"><b>SQL</b></a>: '.$debugger->formatSQL($sql);
$long_id=$debugger->mapLongError($error_msg);
trigger_error( substr($msg.' ('.$code.') ['.$sql.']',0,1000).' #'.$long_id, $errorLevel);
return true;
}
else
{
echo '<b>xProcessing SQL</b>: '.$sql.'<br>';
echo '<b>Error ('.$code.'):</b> '.$msg.'<br>';
return false;
}
}
+
+ function NextResourceId()
+ {
+ $this->DB->Query('LOCK TABLES '.TABLE_PREFIX.'IdGenerator WRITE');
+ $this->DB->Query('UPDATE '.TABLE_PREFIX.'IdGenerator SET lastid = lastid+1');
+ $id = $this->DB->GetOne("SELECT lastid FROM ".TABLE_PREFIX."IdGenerator");
+ $this->DB->Query('UNLOCK TABLES');
+ return $id;
+ }
+
+ function GetTopmostPrefix($current_prefix)
+ {
+ while ( $parent_prefix = $this->getUnitOption($current_prefix, 'ParentPrefix') ) {
+ $current_prefix = $parent_prefix;
+ }
+ return $current_prefix;
+ }
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/application.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.10
\ No newline at end of property
+1.11
\ No newline at end of property
Index: trunk/core/kernel/globals.php
===================================================================
--- trunk/core/kernel/globals.php (nonexistent)
+++ trunk/core/kernel/globals.php (revision 1339)
@@ -0,0 +1,189 @@
+<?php
+
+ /**
+ * array_merge_recursive2()
+ *
+ * Similar to array_merge_recursive but keyed-valued are always overwritten.
+ * Priority goes to the 2nd array.
+ *
+ * @static yes
+ * @param $paArray1 array
+ * @param $paArray2 array
+ * @return array
+ * @access public
+ */
+ function array_merge_recursive2($paArray1, $paArray2)
+ {
+ if (!is_array($paArray1) or !is_array($paArray2)) { return $paArray2; }
+ foreach ($paArray2 AS $sKey2 => $sValue2)
+ {
+ $paArray1[$sKey2] = array_merge_recursive2( getArrayValue($paArray1,$sKey2), $sValue2);
+ }
+ return $paArray1;
+ }
+
+ if (!function_exists('print_pre')) {
+ /**
+ * Same as print_r, budet designed for viewing in web page
+ *
+ * @param Array $data
+ * @param string $label
+ */
+ function print_pre($data, $label='')
+ {
+ if( defined('DEBUG_MODE') && DEBUG_MODE )
+ {
+ global $debugger;
+ if($label) $debugger->appendHTML('<b>'.$label.'</b>');
+ $debugger->dumpVars($data);
+ }
+ else
+ {
+ if($label) echo '<b>',$label,'</b><br>';
+ echo '<pre>',print_r($data,true),'</pre>';
+ }
+ }
+ }
+
+ if (!function_exists('getArrayValue')) {
+ /**
+ * Returns array value if key exists
+ *
+ * @param Array $array
+ * @param int $key
+ * @return string
+ * @access public
+ */
+ function getArrayValue(&$array,$key)
+ {
+ $ret = isset($array[$key]) ? $array[$key] : false;
+ if ($ret && func_num_args() > 2) {
+ for ($i = 2; $i < func_num_args(); $i++) {
+ $cur_key = func_get_arg($i);
+ $ret = getArrayValue( $ret, $cur_key );
+ if ($ret === false) break;
+ }
+ }
+ return $ret;
+ }
+ }
+
+ /**
+ * Rename key in associative array, maintaining keys order
+ *
+ * @param Array $array Associative Array
+ * @param mixed $old Old key name
+ * @param mixed $new New key name
+ * @access public
+ */
+ function array_rename_key(&$array, $old, $new)
+ {
+ foreach ($array as $key => $val)
+ {
+ $new_array[ $key == $old ? $new : $key] = $val;
+ }
+ $array = $new_array;
+ }
+
+ /**
+ * Define constant if it was not already defined before
+ *
+ * @param string $const_name
+ * @param string $const_value
+ * @access public
+ */
+ function safeDefine($const_name, $const_value)
+ {
+ if(!defined($const_name)) define($const_name,$const_value);
+ }
+
+
+if (!function_exists('parse_portal_ini')) {
+ function parse_portal_ini($file, $parse_section = false) {
+ if(!file_exists($file) && !is_readable($file))
+ die('Could Not Open Ini File');
+
+ $contents = file($file);
+
+ $retval = array();
+
+ $section = '';
+ $ln = 1;
+ $resave = false;
+ foreach($contents as $line) {
+ if ($ln == 1 && $line != '<'.'?'.'php die() ?'.">\n") {
+ $resave = true;
+ }
+ $ln++;
+ $line = trim($line);
+ $line = eregi_replace(';[.]*','',$line);
+ if(strlen($line) > 0) {
+ //echo $line . " - ";
+ if(eregi('^[[a-z]+]$',str_replace(' ', '', $line))) {
+ //echo 'section';
+ $section = substr($line,1,(strlen($line)-2));
+ if ($parse_section) {
+ $retval[$section] = array();
+ }
+ continue;
+ } elseif(eregi('=',$line)) {
+ //echo 'main element';
+ list($key,$val) = explode(' = ',$line);
+ if (!$parse_section) {
+ $retval[trim($key)] = str_replace('"', '', $val);
+ }
+ else {
+ $retval[$section][trim($key)] = str_replace('"', '', $val);
+ }
+ } //end if
+ //echo '<br />';
+ } //end if
+ } //end foreach
+ if ($resave) {
+ $fp = fopen($file, "w");
+ reset($contents);
+ fwrite($fp,'<'.'?'.'php die() ?'.">\n\n");
+ foreach($contents as $line) fwrite($fp,"$line");
+ fclose($fp);
+ }
+
+ return $retval;
+ }
+
+if (!function_exists( 'getmicrotime' ) ) {
+ function getmicrotime()
+ {
+ list($usec, $sec) = explode(" ",microtime());
+ return ((float)$usec + (float)$sec);
+ }
+}
+
+ function k4_include_once($file)
+ {
+ if ( defined('DEBUG_MODE') && dbg_ConstOn('DBG_PROFILE_INCLUDES')) {
+
+ if ( in_array($file, get_required_files()) ) return;
+ global $debugger;
+
+ $debugger->IncludeLevel++;
+ $before_time = getmicrotime();
+ $before_mem = memory_get_usage();
+ include_once($file);
+ $used_time = getmicrotime() - $before_time;
+ $used_mem = memory_get_usage() - $before_mem;
+
+ $debugger->IncludeLevel--;
+ $debugger->IncludesData['file'][] = str_replace(DOC_ROOT.BASE_PATH, '', $file);
+ $debugger->IncludesData['mem'][] = $used_mem;
+ $debugger->IncludesData['time'][] = $used_time;
+ $debugger->IncludesData['level'][] = $debugger->IncludeLevel;
+
+
+ }
+ else {
+ include_once($file);
+ }
+ }
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/globals.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.2
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/kbase.php
===================================================================
--- trunk/core/kernel/kbase.php (revision 1338)
+++ trunk/core/kernel/kbase.php (revision 1339)
@@ -1,206 +1,432 @@
<?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)
+ 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
*
* @return string
* @access protected
*/
function getPrefixSpecial()
{
return rtrim($this->Prefix.'.'.$this->Special,'.');
}
- /**
- * Set's application
- *
- * @return kBase
- * @access public
- */
- function kBase()
+ function &getProperty($property_name)
{
- $this->Application =& kApplication::Instance();
+ return $this->$property_name;
+ }
+
+ function setProperty($property_name, &$property_value)
+ {
+ $this->$property_name =& $property_value;
}
}
class kDBBase extends kBase {
/**
* Description
*
* @var DBConnection
* @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;
/**
* Display queries executed by the class
*
* @var bool
* @access public
*/
var $DisplayQueries = false;
/**
- * Object that holds all
- * formatters created
+ * 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 kItemFormatter
+ * @var Array
* @access private
*/
- var $ItemFormatter;
+ 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';
+ }
+
+ /**
* 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()
+ 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)
{
- return sprintf($this->SelectClause,$this->TableName);
+ 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);
+ }
}
/**
* 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->setConfigFields( $this->Application->getUnitOption($this->Prefix, 'Fields') );
+ $this->setVirtualFields( $this->Application->getUnitOption($this->Prefix, 'VirtualFields') );
+ $this->setCalculatedFields( $this->Application->getUnitOption($this->Prefix, 'CalculatedFields') );
+ $this->prepareConfigOptions(); // this should go last, but before setDefaultValues, order is significant!
+ $this->SetDefaultValues();
+ }
+
+ 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;
+ }
+
+ /**
+ * 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()
+ {
+
+ }
+
+ 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($field)
+ 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);
+ $field_options['options'] = $this->Conn->GetCol($sql, $field_options['option_key_field']);
+ unset($field_options['options_sql']);
+ }
+ if ( $formatter_class = getArrayValue($field_options, 'formatter') ) {
+ $formatter =& $this->Application->recallObject($formatter_class);
+ $formatter->PrepareOptions($field_name, $field_options, $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
+ * @return Array
+ */
+ function getLinkedInfo()
+ {
+ $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
+ );
+
+ $main_object = $this->Application->recallObject($parent_prefix);
+ 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.1
\ No newline at end of property
+1.2
\ No newline at end of property
Index: trunk/core/kernel/parser/template.php
===================================================================
--- trunk/core/kernel/parser/template.php (revision 1338)
+++ trunk/core/kernel/parser/template.php (revision 1339)
@@ -1,118 +1,175 @@
<?php
class Template {
var $Body = '';
var $BasePath = '';
var $Filename = '';
- function Template($base_path=null, $filename=null)
+ function Template($base_path=null, $filename=null, $silent=0)
{
if ($this->SetBasePath($base_path)) {
if (isset($filename)) {
$this->Filename = $filename;
- $this->LoadTemplate();
+ $this->LoadTemplate($silent);
}
}
}
function SetBasePath($base_path=null)
{
if (isset($base_path)) {
$base_path = eregi_replace("/$", '', $base_path); //Cutting possible last slash
$this->BasePath = $base_path;
return true;
}
return false;
}
function GetFullPath()
{
return $this->BasePath.'/'.$this->Filename.'.tpl';
}
function LoadTemplate($silent=0)
{
$filename = $this->GetFullPath();
if(file_exists($filename)) {
+ if (filesize ($filename) == 0) {
+ trigger_error("Template file size is 0: <b>$filename</b>", ($silent ? E_USER_NOTICE : E_USER_ERROR) );
+ }
+
$handle = fopen ($filename, "r");
$contents = fread ($handle, filesize ($filename));
$this->SetBody($contents);
fclose ($handle);
return true;
}
else {
- if (!$silent) echo "<b>File or block not found: $filename ($filename)</b><br>";
+ trigger_error("File or block not found: <b>$filename</b>", ($silent ? E_USER_NOTICE : E_USER_ERROR) );
return false;
}
}
function SetBody($body)
{
$this->Body = $body;
}
function GetBody()
{
return $this->Body;
}
}
class TemplatesCache extends kBase {
var $Templates = Array();
var $BasePath;
+ var $FileNames = Array();
+
+ var $ModulesCache = Array();
function TemplatesCache()
{
parent::kBase();
$this->BasePath = DOC_ROOT.BASE_PATH.THEMES_PATH;
+
+ $conn =& $this->Application->GetADODBConnection();
+ $this->ModulesCache = $conn->GetCol('SELECT LOWER(Name) FROM '.TABLE_PREFIX.'Modules');
}
- function LoadTemplate($filename, $title=NULL)
+ function LoadTemplate($filename, $title=NULL, $silent=0)
{
- $template =& new Template($this->BasePath, $filename);
+ if (preg_match('#^[\/]{0,1}([^\/]*)\/(.*)#', $filename, $regs)) {
+ $module_filename = $regs[2];
+ $first_dir = $regs[1];
+ }
+ else {
+ $first_dir = '';
+ $module_filename = $filename;
+ }
+
+ if ( defined('ADMIN') && ADMIN && in_array(strtolower($first_dir), $this->ModulesCache)) {
+ $path = MODULES_PATH.'/'.strtolower($first_dir).'/admin_templates';
+ }
+ else {
+ $path = $this->BasePath;
+ $module_filename = $first_dir.'/'.$module_filename;
+ }
+
+ $template =& new Template($path, $module_filename, $silent);
if (!isset($title)) $title = $filename;
$this->SetTemplate($title, $template);
}
- function SetTemplate($title, &$template)
+ function GetRealFilename($filename) {
+ if (preg_match('#^[\/]{0,1}([^\/]*)\/(.*)#', $filename, $regs)) {
+ $module_filename = $regs[2];
+ $first_dir = $regs[1];
+ }
+ else {
+ $first_dir = '';
+ $module_filename = $filename;
+ }
+
+ if ( defined('ADMIN') && ADMIN && in_array(strtolower($first_dir), $this->ModulesCache)) {
+ $path = MODULES_PATH.'/'.strtolower($first_dir).'/admin_templates';
+ }
+ else {
+ $path = $this->BasePath;
+ $module_filename = $first_dir.'/'.$module_filename;
+ }
+ return $path.'/'.$module_filename;
+ }
+
+ function SetTemplate($title, &$template, $filename=null)
{
+ if (!isset($filename)) $filename=$title;
$this->Templates[$title] = $template;
+ $this->FileNames[$title] = $filename;
}
- function &GetTemplate($title)
+ function &GetTemplate($title, $silent=0)
{
if (!isset($this->Templates[$title])) {
- $this->LoadTemplate($title);
+ $this->LoadTemplate($title, null, $silent);
}
return $this->Templates[$title];
}
- function GetTemplateBody($title)
+ function GetTemplateBody($title, $silent=0)
{
- $template =& $this->GetTemplate($title);
+ $template =& $this->GetTemplate($title, $silent);
+ if ( !is_object($template) ) {
+ return '';
+ }
return $template->GetBody();
}
+ function GetTemplateFileName($title)
+ {
+ return $this->FileNames[$title];
+ }
+
function SetTemplateBody($title, $body)
{
$template =& new Template();
$template->SetBody($body);
$this->SetTemplate($title, $template);
}
function ParseTemplate($template_name)
{
$Parser =& new TemplateParser($this->Application);
return $Parser->Parse( $this->GetTemplateBody($template_name) );
}
function TemplateExists($filename)
{
$template =& new Template($this->BasePath);
$template->Filename = $filename;
return $template->LoadTemplate(1) !== false;
}
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/parser/template.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
\ No newline at end of property
+1.2
\ No newline at end of property
Index: trunk/core/kernel/parser/tags.php
===================================================================
--- trunk/core/kernel/parser/tags.php (revision 1338)
+++ trunk/core/kernel/parser/tags.php (revision 1339)
@@ -1,229 +1,254 @@
<?php
global $kernel_path;
-include_once(KERNEL_PATH.'/parser/construct_tags.php');
-include_once(KERNEL_PATH.'/utility/params.php');
+k4_include_once(KERNEL_PATH.'/parser/construct_tags.php');
+k4_include_once(KERNEL_PATH.'/utility/params.php');
define ('parse', 0);
define ('skip', 1);
define ('skip_tags', 2);
class Tag extends kBase {
var $Processor;
var $Tag;
var $Params = Array();
var $NamedParams = Array();
var $NP;
+ /**
+ * Enter description here...
+ *
+ * @var TemplateParser
+ */
var $Parser;
var $TagData = '';
function Tag($tag_data, &$parser, $inp_tag=0)
{
parent::kBase();
$this->Parser =& $parser;
$this->TagData = $tag_data;
if ($tag_data != '') $this->ParseTagData($tag_data);
$this->NP =& $this->NamedParams;
}
function CopyFrom(&$tag)
{
$this->Processor = $tag->Processor;
$this->Tag = $tag->Tag;
$this->TagData = $tag->TagData;
$this->Params = $tag->Params;
$this->NamedParams = $tag->NamedParams;
$this->Parser =& $tag->Parser;
}
function GetFullTag()
{
return '<%'.$this->TagData.'%>';
}
function RebuildTagData()
{
$res = $this->Processor.':'.$this->Tag.' ';
foreach ($this->NamedParams as $name => $value) {
$res .= "$name='$value' ";
}
return $res;
}
+ /**
+ * Escape chars in phrase translation, that could harm parser to process tag
+ *
+ * @param string $text
+ * @return string
+ * @access private
+ */
+ function EscapeReservedChars($text)
+ {
+ $reserved = Array('"',"'"); // =
+ $replacement = Array('\"',"\'"); // \=
+ return str_replace($reserved,$replacement,$text);
+ }
+
+
function ReplaceParams($tag_data)
{
//print_pre($this->Parser->Pattern, $tag_data);
+ $values = $this->Parser->Values;
+ foreach($values as $param_name => $param_value)
+ {
+ $values[$param_name] = $this->EscapeReservedChars($param_value);
+ }
+
if (is_array($this->Parser->Params)) {
- $tag_data = preg_replace($this->Parser->Pattern, $this->Parser->Values, $tag_data);
+ $tag_data = preg_replace($this->Parser->Pattern, $values, $tag_data);
+ }
+ //echo "got: $tag_data<br>";
+ return $tag_data;
+ }
+
+ function PreParseReplaceParams($tag_data)
+ {
+ //print_pre($this->Parser->Pattern, $tag_data);
+ $values = $this->Parser->Values;
+ foreach($values as $param_name => $param_value)
+ {
+ $values[$param_name] = $this->EscapeReservedChars($param_value);
+ }
+
+ /*$patterns = Array();
+ if ( is_array($this->Parser->Args) ) {
+ foreach ($this->Parser->Args as $arg) {
+
+ }
+ }*/
+
+ if ($this->Parser->SkipMode == parse) {
+ if (is_array($this->Parser->Params)) {
+ $tag_data = preg_replace($this->Parser->Pattern, $values, $tag_data);
+ }
}
//echo "got: $tag_data<br>";
return $tag_data;
}
function CmpParams($a, $b)
{
$a_len = strlen($a);
$b_len = strlen($b);
if ($a_len == $b_len) return 0;
return $a_len > $b_len ? -1 : 1;
}
- function ReplaceLanguageTags($tag_data)
- {
- preg_match_all("(!(la|lu)[^!]+!)", $tag_data, $res, PREG_PATTERN_ORDER);
- $language_tags = $res[0];
- uasort($language_tags, array ("Tag", "CmpParams"));
-
- $values = Array();
- $i = 0;
- foreach ($language_tags as $label) {
- array_push($values, $this->Application->Phrase($label));
- $language_tags[$i] = '/' . $language_tags[$i] . '/';
- $i++;
- }
- $tag_data = preg_replace($language_tags, $values, $tag_data);
- return $tag_data;
- }
-
function ParseTagData($tag_data)
{
- $tag_data = $this->ReplaceParams($tag_data) . ' ';
- $tag_data = $this->ReplaceLanguageTags($tag_data);
+ if (defined('EXPERIMENTAL_PRE_PARSE') ) {
+ $tag_data = $this->PreParseReplaceParams($tag_data) . ' ';
+ }
+ else {
+ $tag_data = $this->ReplaceParams($tag_data) . ' ';
+ $tag_data = $this->Application->ReplaceLanguageTags($tag_data);
+ }
list ($key_data, $params) = explode(' ', $tag_data, 2);
list($this->Processor, $this->Tag) = explode(':', $key_data);
-
+
if ($params != '') $this->ParseNamedParams($params);
}
function ParseNamedParams($params_str)
{
$params =& new Params($params_str);
$this->NamedParams = $params->_Params;
}
function GetParam($param)
{
if (isset($this->NP[$param]))
return $this->NP[$param];
else
return false;
}
function Process()
{
if ($this->Processor == 'm' || $this->Processor == 'm_TagProcessor') { //if we are procssing Main tags
if ($this->Tag == 'block') {
$tag =& new BlockTag('', $this->Parser);
$tag->CopyFrom($this);
$tag->Process();
}
elseif ($this->Parser->SkipMode == skip_tags) {
return;
}
elseif (
$this->Tag == 'if' ||
$this->Tag == 'ifnot' ||
$this->Tag == 'else' ||
$this->Tag == 'elseif'
) {
$tag =& new ConstructTag('', $this->Parser);
$tag->CopyFrom($this);
$tag->Process();
}
- elseif ($this->Tag == 'xml') {
- $tag =& new XMLTag('', $this->Parser);
- $tag->CopyFrom($this);
- $tag->Process();
- }
else {
if ($this->Parser->SkipMode == skip) return;
- //if (!$this->ProcessMainTag()) //other main tags
- $this->ProcessTag();
+ $this->ProcessTag();
}
}
else { //normal tags - processors other than main
if ($this->Parser->SkipMode == skip_tags || $this->Parser->SkipMode == skip) return; //do not parse if we skipping tags
$this->ProcessTag();
- //$this->Parser->AppendOutput('<b>'.$this->Tag.'</b>');
}
}
function DoProcessTag()
{
//$processor =& $this->Application->Processors->GetProcessor($this->Processor, $this);
$processor =& $this->Application->recallObject($this->Processor);
return $processor->ProcessTag($this);
}
function ProcessTag()
{
$o = $this->DoProcessTag();
if ($o !== false)
{
$this->Parser->AppendOutput($o);
}
else
{
- echo "<b>Warning:</b> can't process tag ".$this->Tag."<br>";
+ trigger_error('can\'t process tag '.$this->Tag,E_USER_WARNING);
}
}
-}
-
-
-// ################### TESTS ############################
+
+ function GetCode($echo=false)
+ {
+ $pass_params = $this->NP;
+
+ $code = Array();
-global $suite;
-if (isset($suite)) {
- class TestTags extends TestCase {
+ $to_pass = 'Array(';
+ foreach ($pass_params as $name => $val) {
+ $to_pass .= '"'.$name.'" => "'.$val.'",';
+ }
+ $to_pass .= ')';
- function testTagParsing()
- {
- global $application;
-
- $tag_data = "m:test param1=\"123\"";
- $tag =& new Tag($tag_data, $application->Parser);
- $this->assertEquals('m', $tag->Processor);
- $this->assertEquals('test', $tag->Tag);
- $this->assertEquals('123', $tag->GetParam('param1'));
-
- $this->assertFalse($tag->GetParam('no_such_param'));
- }
+ if ($echo) $code[] = '$o = '."'';\n";
- function testTagParamEscaping()
- {
- global $application;
+ switch ( $this->Tag ) {
+ case 'param':
+ $code[] = '$o .= $params["'.$this->NP['name'].'"];';
+ return $code;
+ case 'if':
+ $code[] = ' $__tag_processor = "'.$pass_params['prefix'].'".\'_TagProcessor\';'."\n";
+ $code[] = ' $processor =& $application->recallObject($__tag_processor);'."\n";
+ $code[] = ' $if_result = $processor->ProcessParsedTag(\''.$pass_params['function'].'\', '.$to_pass.');'."\n";
+ $code[] = ' if ($if_result) {';
+ return $code;
- $tag_data = "m:test escape1='-\"-' \t\t \n \t\n escape2=\"+\\\"+\" \n escape3='*\'*' escape4='=\='";
- //$tag_data = "m:test escape1='-\"-' escape2=\"+\\\"+\" escape3='*\'*' escape4='=\='";
- $tag =& new Tag($tag_data, $application->Parser);
- $this->assertEquals('-"-', $tag->GetParam('escape1'));
- $this->assertEquals('+"+', $tag->GetParam('escape2'));
- $this->assertEquals("*'*", $tag->GetParam('escape3'));
- $this->assertEquals('=\=', $tag->GetParam('escape4'));
+ case 'endif':
+ $code[] = ' }';
+ return $code;
+
+ case 'else':
+ $code[] = ' }';
+ $code[] = ' else {';
+ return $code;
}
- function testTagParamSubstitution()
- {
- global $application;
-
- $application->Parser->SetParams( Array(
- 'prefix' => 'a_prefix',
- 'tag' => 'a_tag',
- 'param_name' => 'a_param_name',
- 'param_value' => 'a_param_value'
- )
- );
-
- $tag_data = '$prefix:$tag $param_name="$param_value"';
- $tag =& new Tag($tag_data, $application->Parser);
- $this->assertEquals('a_prefix', $tag->Processor);
- $this->assertEquals('a_tag', $tag->Tag);
- $this->assertEquals('a_param_value', $tag->GetParam('a_param_name'));
- }
+ $code[] = ' $__tag_processor = "'.$this->Processor.'".\'_TagProcessor\';'."\n";
+ $code[] = ' $processor =& $application->recallObject($__tag_processor);'."\n";
+ $code[] = ' $o .= $processor->ProcessParsedTag(\''.$this->Tag.'\', '.$to_pass.');'."\n";
+
+ /*$code = ' $processor =& $application->recallObject(\''.$this->Processor.'_TagProcessor\');
+ $o .= $processor->ProcessParsedTag(\''.$this->Tag.'\', unserialize(\''.serialize($this->NP).'\'));';*/
+
+ if ($echo) $code[] = ' echo $o;'."\n";
+
+ return $code;
+ //return '$o .= \'tag:'. $this->Tag .'\'';
}
- $suite->addTest(new TestSuite("TestTags"));
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/parser/tags.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
\ No newline at end of property
+1.2
\ No newline at end of property
Index: trunk/core/kernel/parser/construct_tags.php
===================================================================
--- trunk/core/kernel/parser/construct_tags.php (revision 1338)
+++ trunk/core/kernel/parser/construct_tags.php (revision 1339)
@@ -1,268 +1,226 @@
<?php
global $kernel_path;
-include_once(KERNEL_PATH.'/parser/tags.php');
+k4_include_once(KERNEL_PATH.'/parser/tags.php');
//Template language contruct tags (if, block...) which has opening and ending
class ConstructTag extends Tag {
var $StopTag = '';
var $SkipMode = 0;
var $Logic = 0;
function SetStopTag($tag)
{
$this->StopTag = $tag;
}
function StoreSkipMode()
{
$this->SkipMode = $this->Parser->SkipMode;
}
function RestoreSkipMode()
{
$this->Parser->SetSkipMode($this->SkipMode);
}
function RestoreThisLevelSkipMode()
{
$this->SkipMode = $this->Parser->Recursion[$this->Parser->RecursionIndex]->SkipMode;
}
function SuggestSkipMode($mode)
{
if ($mode >= 1) //if we need to skip - always forcing it
$this->Parser->SetSkipMode($mode);
else { //if we need to turn of skipping
if ($this->SkipMode == parse) //check if initially skipping was off
$this->Parser->SetSkipMode(parse); //set it to off only then
}
}
function GetLogic()
{
$prefix = $this->GetParam('prefix');
$function = $this->GetParam('function');
if ($prefix !== false) {
$tag =& new Tag('', $this->Parser);
$tag->Processor = $prefix;
$tag->Tag = $function;
$tag->NamedParams = $this->NP;
$this->Logic = $tag->DoProcessTag();
// echo " this->Logic : ".$this->Logic."<br>";
}
else
$this->Logic = $function;
}
function Process()
{
switch ($this->Tag) {
case 'if':
case 'ifnot':
$this->GetLogic();
$this->SetStopTag('endif'); //This recursion level should end when 'endif' is found
$this->Parser->Recurve($this); //Saving current tag in parser recursion array
$this->StoreSkipMode(); //Storing initial SkipMode
if ($this->Logic) {
$this->SuggestSkipMode(parse); //suggest we parse it
}
else {
$this->SuggestSkipMode(skip); //suggest we don't parse it
}
break;
case 'elseif':
$if_logic = $this->Parser->Recursion[$this->Parser->RecursionIndex]->Logic;
if (!$if_logic) { //if IF or ELSEIF above have not worked
$this->GetLogic();
if ($this->Logic) { //ELSEIF should run
$this->Parser->Recursion[$this->Parser->RecursionIndex]->Logic = $this->Logic; //To escape running ELSE or ELSEIF below
$this->SuggestSkipMode(parse);
}
else { //ELSEIF should NOT run
$this->SuggestSkipMode(skip);
}
}
else //IF or ELSEIF above HAVE worked - this ELSEIF should NOT run
$this->SuggestSkipMode(skip);
break;
case 'else':
$if_logic = $this->Parser->Recursion[$this->Parser->RecursionIndex]->Logic;
$this->RestoreThisLevelSkipMode();
if (!$if_logic) { //IF was false - ELSE should run
$this->SuggestSkipMode(parse);
}
else { //IF was true - ELSE should not run
$this->SuggestSkipMode(skip);
}
break;
}
}
function CheckRecursion(&$tag)
{
if ($this->CheckEndRecursion($tag)) {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ if ($tag->Tag == 'endif') {
+ $this->Parser->AppendCompiledCode('}');
+ }
+ }
$this->RestoreSkipMode(); //Restoring original SkipMode
return true;
}
+ else {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->Parser->AppendCode($tag->GetCode());
+ $this->Parser->AppendCompiledCode(join("\n", $tag->GetCode()));
+ }
+ }
return false;
}
function CheckEndRecursion(&$tag)
{
return ($tag->Tag == $this->StopTag); //Tag matches StopTag we are waiting for to close current recursion
}
}
class BlockTag extends ConstructTag {
var $BlockName = '';
var $InsideBlock = 0;
function Process()
{
switch ($this->Tag) {
case 'block':
$this->SetStopTag('blockend'); //This recursion level should end when 'blockend' is found
$this->Parser->Recurve($this); //Saving current tag in parser recursion array
$this->Parser->SetBuffer('');
$this->BlockName = $this->NP['name']; //Stroing BlockName
+ if (isset($this->NP['args']) ) {
+ $this->Parser->Args = explode(',', $this->NP['args']);
+ }
$this->StoreSkipMode();
$this->SuggestSkipMode(skip_tags); //We need to skip tags from now
break;
}
}
function CheckRecursion(&$tag)
{
if (parent::CheckRecursion($tag)) { //if endtag matches (SkipMode would be restored then)
//Creating template from buffer
+
+ if (defined('EXPERIMENTAL_PRE_PARSE') && isset($this->Application->PreParsedBlocks[$this->BlockName])) return true;
+
$template = new Template();
$template->SetBody($this->Parser->GetBuffer());
$templates_cache =& $this->Application->recallObject('TemplatesCache');
//Adding template to application' cache
- $templates_cache->SetTemplate($this->BlockName,$template);
+ $templates_cache->SetTemplate($this->BlockName, $template, $this->Parser->TemplateName);
+
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $code = $this->Parser->GetCode();
+ array_unshift($code, '$o = \'\';');
+ array_unshift($code, '$application =& kApplication::Instance();');
+ array_unshift($code, 'extract($params);');
+
+ $code[] = 'return $o;';
+
+ global $debugger;
+
+ $dbg_functions = $this->Application->isDebugMode() && dbg_ConstOn('DBG_PRINT_PREPARSED');
+
+ $f_body = '';
+ //echo "<pre>";
+ $l = 0;
+ if ($dbg_functions) echo "<b>function ".$this->BlockName." {</b><br>";
+ foreach ($code as $line) {
+ $l++;
+ if ($dbg_functions) {
+ echo $l.' '.$debugger->highlightString(trim($line)."\n", true);
+ }
+ $f_body .= rtrim($line, "\n")."\n";
+ }
+ if ($dbg_functions) echo "<b>} // function ".$this->BlockName." end</b><br><br>";
+ //echo "</pre>";
+
+ //caching func body
+ $this->Application->PreParsedCache[$this->BlockName] = $f_body;
+
+ $func = create_function('$params', $f_body);
+ $this->Application->PreParsedBlocks[$this->BlockName] = $func;
+ $this->Parser->Args = null;
+ $this->Parser->ResetCode();
+
+ $this->Parser->AppendCompiledFunction($this->BlockName, $f_body);
+ }
return true;
}
else {
// append the tag itself to the block - while in block, we check every tag to be 'blockend'
// if it is not - we need to append the tag to the buffer, which we'll parse later in 'parse_block'
if ($tag->Tag != 'block') {
- $this->Parser->AppendOutput($tag->GetFullTag());
- }
- return false;
- }
- }
-}
-
-class XMLTag extends ConstructTag {
- var $BlockName = '';
-
- function Process()
- {
- switch ($this->Tag) {
- case 'xml':
- $this->SetStopTag('xmlend'); //This recursion level should end when 'blockend' is found
- $this->Parser->Recurve($this); //Saving current tag in parser recursion array
- $this->BlockName = $this->NP['name']; //Storing BlockName
- $this->StoreSkipMode();
- $this->SuggestSkipMode(skip_tags); //We need to skip tags from now
- $this->Parser->SetBuffer('');
- break;
- }
- }
-
- function CheckRecursion(&$tag)
- {
- if (parent::CheckRecursion($tag)) { //if endtag matches (SkipMode would be restored then)
- //Creating template from buffer
- $template = new Template();
- $template->SetBody($this->Parser->GetBuffer());
-
- //Adding template to application' cache
- $this->Parser->Application->Templates->SetTemplate(
- $this->BlockName,
- $template
- );
- $this->Parser->ParseXML($this->BlockName, $this->NP);
- return true;
- }
- else {
- if ($tag->Tag != 'xml') {
- $this->Parser->AppendOutput($tag->GetFullTag());
- }
- return false;
- }
- }
-}
-
-class IterateTag extends ConstructTag {
-
- function Process()
- {
- switch ($this->Tag) {
- case 'iterate':
- $this->SetStopTag('enditerate'); //This recursion level should end when 'blockend' is found
- $this->Parser->Recurve($this); //Saving current tag in parser recursion array
- $this->BlockName = $this->NP['block']; //Storing BlockName
- $this->StoreSkipMode();
- $this->SuggestSkipMode(skip_tags); //We need to skip tags from now
- $this->Parser->SetBuffer('');
- break;
- }
- }
-
- function CheckRecursion(&$tag)
- {
- if (parent::CheckRecursion($tag)) { //if endtag matches (SkipMode would be restored then)
- //Creating template from buffer
- $template = new Template();
- $template->SetBody($this->Parser->GetBuffer());
-
- //Adding template to application' cache
- $this->Parser->Application->Templates->SetTemplate(
- $this->BlockName,
- $template
- );
- $this->Parser->ParseXML($this->BlockName, $this->NP);
- return true;
- }
- else {
- if ($tag->Tag != 'xml') {
- $this->Parser->AppendOutput($tag->GetFullTag());
+ if (defined('EXPERIMENTAL_PRE_PARSE') && isset($this->Application->PreParsedBlocks[$this->BlockName])) {
+ return;
+ }
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ // $this->Parser->AppendCode($tag->GetCode());
+ }
+ else {
+ $this->Parser->AppendOutput($tag->GetFullTag());
+ }
}
return false;
}
}
-
-}
-
-global $suite;
-if (isset($suite)) {
- class TestConstructTag extends TestCase {
-
- function testIFLogic()
- {
- global $application;
-
- $tag =& new ConstructTag('m:if prefix="m" function="true"', $application->Parser);
- $tag->GetLogic();
- $this->assertTrue($tag->Logic);
-
-
- $tag =& new ConstructTag('m:if prefix="m" function="false"', $application->Parser);
- $tag->GetLogic();
- $this->assertFalse($tag->Logic);
- }
-
- }
- $suite->addTest(new TestSuite("TestConstructTag"));
}
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/parser/construct_tags.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
\ No newline at end of property
+1.2
\ No newline at end of property
Index: trunk/core/kernel/parser/template_parser.php
===================================================================
--- trunk/core/kernel/parser/template_parser.php (revision 1338)
+++ trunk/core/kernel/parser/template_parser.php (revision 1339)
@@ -1,232 +1,307 @@
<?php
-include_once(KERNEL_PATH.'/parser/tags.php');
+k4_include_once(KERNEL_PATH.'/parser/tags.php');
class TemplateParser extends kBase {
var $Template;
var $Output = '';
var $Position = 0;
var $LastPosition = 0;
var $Ses;
var $Recursion = Array();
var $RecursionIndex = 0;
var $SkipMode = 0;
var $Params = Array();
var $Pattern = Array();
var $ForSort = Array();
var $Values = Array();
var $Buffers = Array();
+ var $Args;
+
+ var $ParamsRecursionIndex = 0;
+ var $ParamsStack = Array();
+
+ var $CompiledBuffer;
function TemplateParser()
{
parent::kBase();
$this->Ses =& $this->Application->recallObject('Session');
+
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $conn =& $this->Application->GetADODBConnection();
+ if (isset($this->Application->PreParsedBlocks) && is_array($this->Application->PreParsedBlocks)) return;
+ $data = $conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "blocks_cache"');
+ if ($data && $data['Cached'] > (time() - 3600) ) {
+ $blocks = unserialize($data['Data']);
+ foreach ($blocks as $name => $f_body) {
+ $func = create_function('$params', $f_body);
+ $this->Application->PreParsedBlocks[$name] = $func;
+ }
+ $cached = $data['Cached'];
+ }
+ else {
+ $cached = 0;
+ }
+ }
}
function AddParam($pattern, $value, $dont_sort=0)
{
$this->ForSort[] = Array($pattern, $value);
if (!$dont_sort) //used when mass-adding params, to escape sorting after every new param
$this->SortParams(); //but do sort by default!
}
//We need to sort params by its name length desc, so that params starting with same word get parsed correctly
function SortParams()
{
uasort($this->ForSort, array ("TemplateParser", "CmpParams"));
$this->Pattern = Array();
$this->Values = Array();
foreach($this->ForSort as $pair)
{
$this->Pattern[] = $pair[0];
$this->Values[] = $pair[1];
}
}
function CmpParams($a, $b)
{
$a_len = strlen($a[0]);
$b_len = strlen($b[0]);
if ($a_len == $b_len) return 0;
return $a_len > $b_len ? -1 : 1;
}
function SetParams($params)
{
if (!is_array($params)) $params = Array();
$this->Params = $params;
foreach ($params as $key => $val) {
- $this->AddParam('/\$'.$key.'/', $val, 1); //Do not sort every time
+ $this->AddParam('/[{]{0,1}\$'.$key.'[}]{0,1}/i', $val, 1); //Do not sort every time
}
$this->SortParams(); //Sort once after adding is done
}
function GetParam($name)
{
- if (isset($this->Params[$name]))
- return $this->Params[$name];
- else
- return false;
+ //return isset($this->Params[strtolower($name)]) ? $this->Params[strtolower($name)] : false;
+ return isset($this->Params[$name]) ? $this->Params[$name] : false;
}
function SetParam($name, $value)
{
- $this->Params[$name] = $value;
+ $this->Params[strtolower($name)] = $value;
}
function SetBuffer($body)
{
$this->Buffers[$this->RecursionIndex] = $body;
}
function GetBuffer()
{
return $this->Buffers[$this->RecursionIndex];
}
+ function GetCode()
+ {
+ return $this->Code[$this->RecursionIndex];
+ }
+
function AppendBuffer($append)
{
$this->Buffers[$this->RecursionIndex] .= $append;
+ $this->AppendCode( $this->ConvertToCode($append) );
}
- function AppendOutput($append)
+ function AppendOutput($append, $append_code=false)
{
- if ($this->SkipMode == parse)
+ if ($this->SkipMode == parse) {
$this->Output .= $append; //append to Ouput only if we are parsing
+ if ($append_code) $this->AppendCompiledHTML($append);
+ }
elseif ($this->SkipMode == skip_tags) {
$this->AppendBuffer($append); //append to buffer if we are skipping tags
}
}
+ function ConvertToCode($data)
+ {
+ $code = '$o .= \''. str_replace("'", "\'", $data) .'\';';
+ $code = explode("\n", $code);
+ return $code;
+ }
+
+ function AppendCode($code)
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ if (!isset($this->Code[$this->RecursionIndex])) {
+ $this->Code[$this->RecursionIndex] = Array();
+ }
+ if (is_array($code)) {
+ foreach ($code as $line) {
+ $this->Code[$this->RecursionIndex][] = rtrim($line, "\n")."\n";
+ }
+ }
+ else {
+ $this->Code[$this->RecursionIndex][] .= rtrim($code, "\n")."\n";
+ }
+ }
+ }
+
+ function AppendCompiledFunction($f_name, $f_body)
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->CompiledBuffer .= 'function '.$f_name.'($params)'."\n{\n";
+ $this->CompiledBuffer .= $f_body;
+ $this->CompiledBuffer .= "}\n\n";
+ }
+ }
+
+ function AppendCompiledCode($code)
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->CompiledBuffer .= $code;
+ }
+ }
+
+ function AppendCompiledHTML($append)
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->CompiledBuffer .= '?'.'>'."\n";
+ $this->CompiledBuffer .= $append;
+ $this->CompiledBuffer .= '<'.'?php'."\n";
+ }
+ }
+
+ function ResetCode()
+ {
+ $this->Code[$this->RecursionIndex] = Array();
+ }
+
function FindTag()
{
$tagOpen = strpos($this->Template, '<%', $this->Position); //Finding tag start
$inp_tag = false;
$tagOpenLen = 2;
if ($tagOpen === false) { //If not tags left - adding all other data
$this->AppendOutput(substr($this->Template, $this->Position));
return false;
}
//Adding all data before tag open
$this->AppendOutput(substr($this->Template, $this->Position, $tagOpen - $this->Position));
//Finding tag end
$tagCloseLen = 2;
$tagClose = strpos($this->Template, "%>", $tagOpen);
if ($tagClose === false) die ("Can't find tag closing");
//Cutting out the tag itself
$tag = substr($this->Template, $tagOpen + $tagOpenLen, $tagClose - $tagOpen - $tagOpenLen);
//Seting current position right after the tag
$this->Position = $tagClose + $tagCloseLen;
return $tag;
}
- function Parse($template)
+ function CurrentLineNumber()
+ {
+ return substr_count(substr($this->Template, 0, $this->Position), "\n")+1;
+ }
+
+ function SkipModeName()
+ {
+ switch ($this->SkipMode) {
+ case skip: return 'skip';
+ case skip_tags: return 'skip_tags';
+ case parse: return 'parse';
+ }
+ }
+
+ function Parse($template, $name='unknown')
{
$this->Template = $template;
+ $this->TemplateName = $name;
$this->Position = 0;
$this->Output = '';
+ $this->CompiledBuffer .= '<'.'?php'."\n";
//While we have more tags
while ($tag_data = $this->FindTag())
{
//Create tag object from passed tag data
+ if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_SHOW_TAGS') )
+ {
+ global $debugger;
+ $debugger->appendHTML('mode: '.$this->SkipModeName().' tag '.$debugger->highlightString($tag_data).' in '.$debugger->getFileLink($debugger->getLocalFile(DOC_ROOT.BASE_PATH.TEMPLATES_PATH.'/'.$this->TemplateName).'.tpl', $this->CurrentLineNumber(), '', true));
+ }
$tag =& new Tag($tag_data, $this);
if (!$this->CheckRecursion($tag)) //we do NOT process closing tags
{
$tag->Process();
}
}
+ $this->CompiledBuffer .= '?'.'>'."\n";
return $this->Output;
}
- function ParseBlock($params, $force_pass_params=0)
+ function ParseBlock($params, $force_pass_params=0, $as_template=false)
{
- $BlockParser =& $this->Application->Factory->makeClass('TemplateParser');
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ if (isset($this->Application->PreParsedBlocks[$params['name']]) ) {
+ $f = $this->Application->PreParsedBlocks[$params['name']];
+ //$this->SetParams($params);
+ return $f($params);
+ }
+ }
+
+ $BlockParser =& $this->Application->makeClass('TemplateParser');
if (isset($params['pass_params']) || $force_pass_params) {
$BlockParser->SetParams(array_merge($this->Params, $params));
}
else
$BlockParser->SetParams($params);
$this->Application->Parser =& $BlockParser;
- if (!isset($params['name'])) die("<b>***Error: Block name not passed to ParseBlock</b><br>");
+ if (!isset($params['name'])) trigger_error('<b>***Error: Block name not passed to ParseBlock</b>', E_USER_ERROR);
$templates_cache =& $this->Application->recallObject('TemplatesCache');
+
+ $template_name = $as_template ? $params['name'] : $templates_cache->GetTemplateFileName($params['name']) . '-block:'.$params['name'];
+
$o = $BlockParser->Parse(
- $templates_cache->GetTemplateBody($params['name'])
+ $templates_cache->GetTemplateBody($params['name']),
+ $template_name
);
$this->Application->Parser =& $this;
return $o;
}
- function ParseXML($template, $params)
- {
- $templates_cache =& $this->Application->recallObject('TemplatesCache');
- $xml = $templates_cache->GetTemplateBody($template);
-
- $PreParser =& new TemplateParser();
- $PreParser->SetParams($params);
- $this->Application->Parser =& $PreParser;
- $xml = $PreParser->Parse($xml);
- $this->Application->Parser =& $this;
- $XMLParser =& new XMLParser($params);
- $this->AppendOutput($XMLParser->Parse($xml));
- }
-
function Recurve(&$tag)
{
$this->Recursion[++$this->RecursionIndex] =& $tag;
}
function CheckRecursion(&$tag)
{
if ($this->RecursionIndex > 0) { //If we are inside the recursion
if ($this->Recursion[$this->RecursionIndex]->CheckRecursion($tag)) { //If we can close this recursion
unset($this->Recursion[$this->RecursionIndex--]); //unsetting current recursion level and decreasing it at the same time
return true; //we should inform not to process closing tag
}
}
return false;
}
function SetSkipMode($mode)
{
$this->SkipMode = $mode;
}
}
-// ################### TESTS ############################
-
-global $suite;
-if (isset($suite)) {
- class TestTemplateParser extends TestCase {
- function testFindTag()
- {
- $parser =& new TemplateParser();
- $parser->Template = 'before<%first_tag%>between<%second_tag%>after';
- $this->assertEquals('first_tag', $parser->FindTag());
- $this->assertEquals('second_tag', $parser->FindTag());
- $parser->FindTag();
- $this->assertEquals('beforebetweenafter', $parser->Output);
- }
-
- function testAppendOutput()
- {
- $parser =& new TemplateParser();
- $parser->AppendOutput('1');
- $this->assertEquals('1', $parser->Output);
- $parser->SetSkipMode(skip);
- $parser->AppendOutput('2');
- $this->assertEquals('1', $parser->Output);
- }
- }
- $suite->addTest(new TestSuite("TestTemplateParser"));
-}
-
?>
\ No newline at end of file
Property changes on: trunk/core/kernel/parser/template_parser.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1
\ No newline at end of property
+1.2
\ No newline at end of property

Event Timeline