Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sun, Feb 2, 10:10 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 (nonexistent)
+++ trunk/core/kernel/event_manager.php (revision 1560)
@@ -0,0 +1,260 @@
+<?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);
+ 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');
+ }
+ }
+ $actions = $this->Application->GetVar('do');
+ if ($actions) {
+ list($prefix, $event_name) = explode('_', $actions);
+ $events[$prefix] = $event_name;
+ }
+ }
+
+ $passed = explode(',', $this->Application->GetVar('passed'));
+ foreach($events as $prefix_special => $event_name)
+ {
+ if(!$event_name) continue;
+ if( is_array($event_name) )
+ {
+ $event_name = key($event_name);
+ $events[$prefix_special] = $event_name;
+ $this->Application->SetVar($prefix_special.'_event', $event_name);
+ }
+
+ $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_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('events', $events);
+ $this->Application->SetVar('passed', implode(',', $passed));
+ }
+
+ 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++
+ if ($this->Application->GetVar('front')) {
+ array_push($opener_stack, '../'.$this->Application->RecallVar('last_template') );
+ }
+ else {
+ 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
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.6
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/processors/tag_processor.php
===================================================================
--- trunk/core/kernel/processors/tag_processor.php (nonexistent)
+++ trunk/core/kernel/processors/tag_processor.php (revision 1560)
@@ -0,0 +1,161 @@
+<?php
+
+ class TagProcessor extends kBase {
+
+ /**
+ * Processes tag
+ *
+ * @param Tag $tag
+ * @return string
+ * @access public
+ */
+ function ProcessTag(&$tag)
+ {
+ return $this->ProcessParsedTag($tag->Tag, $tag->NP, $tag->getPrefixSpecial());
+
+ /*$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 Tag('', $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();
+ }
+ }
+ trigger_error('Tag '.$Method.' Undefined in '.get_class($this).'[Agregated Tag]:<br><b>'.$tag->RebuildTagData().'</b>',E_USER_WARNING);
+ return false;
+ }*/
+ }
+
+ function ProcessParsedTag($tag, $params, $prefix)
+ {
+ $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
+ {
+ if ($this->Application->hasObject('TagsAggregator')) {
+ $aggregator = $this->Application->recallObject('TagsAggregator');
+ $tmp = $this->Application->processPrefix($prefix);
+ $tag_mapping = $aggregator->GetArrayValue($tmp['prefix'], $Method);
+ if ($tag_mapping) {
+ $tmp = $this->Application->processPrefix($tag_mapping[0]);
+ $__tag_processor = $tmp['prefix'].'_TagProcessor';
+ $processor =& $this->Application->recallObject($__tag_processor);
+ $processor->Prefix = $tmp['prefix'];
+ $processor->Special = $tmp['special'];
+ $params['PrefixSpecial'] = $prefix;
+ return $processor->ProcessParsedTag($tag_mapping[1], $params, $prefix);
+ }
+ trigger_error('Tag '.$Method.' Undefined in '.get_class($this).'[Agregated Tag]:<br><b>'.$tag.'</b>', E_USER_WARNING);
+ }
+ trigger_error('Tag Undefined:<br><b>'.$tag.'</b>',E_USER_WARNING);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if object propery value matches value passed
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function PropertyEquals($params)
+ {
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial(), $this->Prefix, $params );
+ $property_name = $params['property'];
+ return $object->$property_name == $params['value'];
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+/*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
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/processors/main_processor.php
===================================================================
--- trunk/core/kernel/processors/main_processor.php (nonexistent)
+++ trunk/core/kernel/processors/main_processor.php (revision 1560)
@@ -0,0 +1,735 @@
+<?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
+ *
+ * @return string
+ * @access public
+ */
+ function Base_Ref()
+ {
+ $url = $this->Application->BaseURL().substr(THEMES_PATH,1).'/';
+ return '<base href="'.$url.'" />';
+ }
+
+ /**
+ * Returns base url for web-site
+ *
+ * @return string
+ * @access public
+ */
+ function BaseURL()
+ {
+ return $this->Application->BaseURL();
+ }
+
+ 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)
+ {
+ //by default link to current template
+ $t = $this->SelectParam($params, 't,template');
+ if ($t === false) {
+ $t = $this->Application->GetVar('t');
+ }
+ unset($params['t']);
+ unset($params['template']);
+ $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 str_replace('&', '&amp;', $this->Application->HREF($t,$prefix,$params,$index_file));
+ }
+
+ function Link($params)
+ {
+ if (isset($params['template'])) {
+ $params['t'] = $params['template'];
+ unset($params['template']);
+ }
+ if (!isset($params['pass'])) $params['pass'] = 'm';
+ return $this->T($params);
+ }
+
+ function Env($params)
+ {
+ $t = $params['template'];
+ unset($params['template']);
+ return $this->Application->BuildEnv($t, $params, 'm', null, false);
+ }
+
+ function FormAction($params)
+ {
+ return $this->Application->ProcessParsedTag('m', 't', Array( 'pass'=>'all,m' ) );
+ }
+
+ /*// 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 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'];
+ }
+ */
+
+ /**
+ * Returns session variable value by name
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function Recall($params)
+ {
+ $ret = $this->Application->RecallVar( $this->SelectParam($params,'name,var,param') );
+ $ret = ($ret === false && isset($params['no_null'])) ? '' : $ret;
+ if( getArrayValue($params,'special') || getArrayValue($params,'htmlchars')) $ret = htmlspecialchars($ret);
+ return $ret;
+ }
+
+ // 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)
+ {
+ $ret = $this->Application->GetVar($this->SelectParam($params, 'name,var,param'), EMPTY_ON_NULL);
+ return getArrayValue($params, 'htmlchars') ? htmlspecialchars($ret) : $ret;
+ }
+
+ /**
+ * 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 GetFormHiddens($params)
+ {
+ $sid = $this->Application->GetSID();
+ $t = $this->SelectParam($params, 'template,t');
+ unset($params['template']);
+ $env = $this->Application->BuildEnv($t, $params, 'm', null, false);
+ $o = '';
+ if (defined('MOD_REWRITE') && MOD_REWRITE) {
+ $session =& $this->Application->recallObject('Session');
+ if ($session->NeedQueryString()) {
+ $o .= "<input type='hidden' name='sid' id='sid' value='$sid'>\n";
+ }
+ }
+ else {
+ $o .= "<input type='hidden' name='env' id='env' value='$env'>\n";
+ }
+ return $o;
+ }
+
+ function Odd_Even($params)
+ {
+ $odd = $params['odd'];
+ $even = $params['even'];
+ if (!isset($params['var'])) {
+ $var = 'odd_even';
+ }
+ else {
+ $var = $params['var'];
+ }
+
+ if ($this->Application->GetVar($var) == 'even') {
+ $this->Application->SetVar($var, 'odd');
+ return $even;
+ }
+ else {
+ $this->Application->SetVar($var, '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 = $this->SelectParam($params, 'templ,template,t');
+ 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'];
+ }
+
+ if ( preg_match("/^".str_replace('/', '\/', $test_templ)."/", $this->Application->GetVar('t'))) {
+ return $if_true;
+ }
+ else {
+ return $if_false;
+ }
+ }
+
+ function IsNotActive($params)
+ {
+ return !$this->is_active($params);
+ }
+
+ function IsActive($params)
+ {
+ return $this->is_active($params);
+ }
+
+ function is_t_active($params)
+ {
+ return $this->is_active($params);
+ }
+
+ function CurrentTemplate($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 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 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->makeClass('TemplateParser');
+ $BlockParser->SetParams($params);
+ $parser =& $this->Application->Parser;
+ $this->Application->Parser =& $BlockParser;
+
+ $t = $this->SelectParam($params, 't,template,block,name');
+ $t = eregi_replace("\.tpl$", '', $t);
+
+ $templates_cache =& $this->Application->recallObject('TemplatesCache');
+
+ $res = $BlockParser->Parse( $templates_cache->GetTemplateBody($t), $t );
+
+ if ( !$BlockParser->DataExists && (isset($params['data_exists']) || isset($params['block_no_data'])) ) {
+ if ($block_no_data = getArrayValue($params, 'block_no_data')) {
+ $res = $BlockParser->Parse(
+ $templates_cache->GetTemplateBody($block_no_data, $silent),
+ $t
+ );
+ }
+ else {
+ $res = '';
+ }
+ }
+ $this->Application->Parser =& $parser;
+ $this->Application->Parser->DataExists = $this->Application->Parser->DataExists || $BlockParser->DataExists;
+ 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);
+ }
+
+ /**
+ * Checks if debug mode is on
+ *
+ * @return bool
+ * @access public
+ */
+ function IsDebugMode()
+ {
+ 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 LoggedIn($params)
+ {
+ return $this->Application->LoggedIn();
+ }
+
+ /**
+ * Checks if user is logged in and if not redirects it to template passed
+ *
+ * @param Array $params
+ */
+ function RequireLogin($params)
+ {
+ if($permission_groups = getArrayValue($params, 'permissions'))
+ {
+ $permission_groups = explode('|', $permission_groups);
+ $group_has_permission = false;
+ foreach($permission_groups as $permission_group)
+ {
+ $permissions = explode(',', $permission_group);
+ $has_permission = true;
+ foreach($permissions as $permission)
+ {
+ $has_permission = $has_permission && $this->Application->CheckPermission($permission);
+ }
+ $group_has_permission = $group_has_permission || $has_permission;
+
+ if($group_has_permission)
+ {
+ return;
+ }
+ }
+
+ if( !$this->Application->LoggedIn() )
+ {
+ $t = $this->Application->GetVar('t');
+ $this->Application->Redirect( $params['login_template'], Array('next_template'=>$t) );
+ }
+ else
+ {
+ $this->Application->Redirect( $params['no_permissions_template'] );
+ }
+ }
+
+ $condition = getArrayValue($params,'condition');
+ if(!$condition)
+ {
+ $condition = true;
+ }
+ else
+ {
+ if( substr($condition,0,1) == '!' )
+ {
+ $condition = !$this->Application->ConfigValue( substr($condition,1) );
+ }
+ else
+ {
+ $condition = $this->Application->ConfigValue($condition);
+ }
+
+ }
+
+ if( !$this->Application->LoggedIn() && $condition )
+ {
+ $t = $this->Application->GetVar('t');
+ $this->Application->Redirect( $params['login_template'], Array('next_template'=>$t) );
+ }
+ }
+
+ function SaveReturnScript($params)
+ {
+ // admin/save_redirect.php?do=
+ $url = str_replace($this->Application->BaseURL(), '', $this->T($params) );
+ $url = explode('?', $url, 2);
+ $url = 'save_redirect.php?'.$url[1].'&do='.$url[0];
+
+ $this->Application->StoreVar('ReturnScript', $url);
+ }
+
+/*
+ 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');
+ }
+ }
+ */
+
+}
+
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/processors/main_processor.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.7
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/session/session.php
===================================================================
--- trunk/core/kernel/session/session.php (nonexistent)
+++ trunk/core/kernel/session/session.php (revision 1560)
@@ -0,0 +1,632 @@
+<?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 = ' INSERT INTO '.$this->TableName.' ('.$this->IDField.', '.$this->TimestampField.')'.
+ ' VALUES ('.$this->Conn->qstr($session->SID).', '.$session->Expiration.')';
+ $this->Conn->Query($query);
+ }
+
+ function DeleteSession(&$session)
+ {
+ $query = ' DELETE FROM '.$this->TableName.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
+ $this->Conn->Query($query);
+
+ $query = ' DELETE FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
+ $this->Conn->Query($query);
+
+ $this->OriginalData = Array();
+ }
+
+ function UpdateSession(&$session, $timeout=0)
+ {
+ $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 = ' 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 = '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 SetField(&$session, $var_name, $value)
+ {
+ return $this->Conn->Query('UPDATE '.$this->TableName.' SET '.$var_name.' = '.$this->Conn->qstr($value).' 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),",
+ $this->Conn->qstr($session->SID),
+ $this->Conn->qstr($key),
+ $this->Conn->qstr($value));
+ }
+ }
+ $replace = rtrim($replace, ',');
+ if ($replace != '') {
+ $query = ' REPLACE INTO '.$this->SessionDataTable. ' ('.$this->IDField.', '.$this->DataVarField.', '.$this->DataValueField.') VALUES '.$replace;
+ $this->Conn->Query($query);
+ }
+ }
+
+ function RemoveFromData(&$session, $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 =& $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() ) )
+ {
+ $this->SetSession();
+ $this->Application->HandleEvent($event, 'login:OnSessionExpire');
+ }
+
+ if ($this->Check()) {
+ $this->SID = $this->GetPassedSIDValue();
+ $this->Refresh();
+ $this->LoadData();
+ }
+ else {
+ $this->SetSession();
+ }
+ }
+
+ function CheckReferer()
+ {
+ $path = preg_replace("/admin$/", '', $this->CookiePath); // removing /admin for compatability with in-portal (in-link/admin/add_link.php)
+ $reg = '#^'.preg_quote(PROTOCOL.$this->CookieDomain.$path).'#';
+ return preg_match($reg, $_SERVER['HTTP_REFERER']) || (defined('IS_POPUP') && IS_POPUP);
+ }
+
+ function CheckIfCookiesAreOn()
+ {
+ if ($this->Mode == smGET_ONLY || (defined('INPORTAL_ENV')&&INPORTAL_ENV && defined('ADMIN')&&ADMIN && !$this->Application->GetVar('front')) )
+ {
+ //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 = 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 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 = getArrayValue($http_query->Get, $this->GETName);
+
+ if ($this->Application->GetVar('admin') == 1 && $get_sid) {
+ $sid = $get_sid;
+ }
+ else {
+ switch ($this->Mode) {
+ case smAUTO:
+ //Cookies has the priority - we ignore everything else
+ $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;
+ }
+ }
+
+ if ($this->Application->GetVar('front')) {
+ $this->CookiesEnabled = false;
+ }
+
+ $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( IsSerialized($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->StoreVar('last_env', substr($this->Application->BuildEnv($this->Application->GetVar('t'),Array('pass'=>'all')), 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;
+ }
+
+ function RemoveVar($name)
+ {
+ $this->Storage->RemoveFromData($this, $name);
+ $this->Data->Remove($name);
+ }
+
+ function GetField($var_name)
+ {
+ return $this->Storage->GetField($this, $var_name);
+ }
+
+ function SetField($var_name, $value)
+ {
+ $this->Storage->SetField($this, $var_name, $value);
+ }
+
+ /**
+ * 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
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.6
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ 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 1560)
@@ -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.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/utility/iterator.php
===================================================================
--- trunk/core/kernel/utility/iterator.php (nonexistent)
+++ trunk/core/kernel/utility/iterator.php (revision 1560)
@@ -0,0 +1,51 @@
+<?php
+
+ // OLD STUFF
+
+class MyIterator {
+
+ var $Items;
+ var $Index;
+ var $Count;
+ var $CurrentIndex;
+
+ function MyIterator(&$items)
+ {
+ $this->Items =& $items;
+ $this->IndexItems();
+ $this->CurrentIndex = 0;
+ }
+
+ function IndexItems()
+ {
+ $i = 0;
+ foreach ($this->Items as $key => $item) {
+ $this->Index[$i] = $key; // ?????? $i++
+ $i++;
+ }
+ $this->Count = $i;
+ }
+
+ function HasMore()
+ {
+ return $this->CurrentIndex < $this->Count;
+ }
+
+ function GoNext()
+ {
+ $this->CurrentIndex++;
+ }
+
+ function &GetItem()
+ {
+ return $this->Items[$this->Index[$this->CurrentIndex]];
+ }
+
+ function GetKey()
+ {
+ return $this->Index[$this->CurrentIndex];
+ }
+
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/iterator.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/utility/utilities.php
===================================================================
--- trunk/core/kernel/utility/utilities.php (nonexistent)
+++ trunk/core/kernel/utility/utilities.php (revision 1560)
@@ -0,0 +1,41 @@
+<?php
+
+ // OLD STUFF
+
+class Utilites extends kBase {
+
+ function ExtractByMask($array, $mask, $key_id=1, $ret_mode=1)
+ {
+// echo "extracting from <br>";
+// print_pre($array);
+ $rets = Array();
+ foreach ($array as $name => $val)
+ {
+ $regs = Array();
+// echo "checking $name<br>";
+ if (eregi($mask, $name, $regs)) {
+// echo "matched<br>";
+// print_pre($regs);
+ if ($ret_mode == 1) {
+ $rets[$regs[$key_id]] = $val;
+ }
+ else {
+ array_push($regs, $val);
+ $a_key = $regs[$key_id];
+ $i = 0;
+ while (array_key_exists($a_key, $rets)) {
+ $a_key.=$i;
+ $i++;
+ }
+ $rets[$a_key] = $regs;
+ }
+ }
+ }
+// echo "returning ";
+// print_pre($rets);
+ return $rets;
+ }
+
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/utilities.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ 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 (nonexistent)
+++ trunk/core/kernel/utility/event.php (revision 1560)
@@ -0,0 +1,278 @@
+<?php
+/**
+ * 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;
+
+ /**
+ * Do not execute Before hooks
+ * while processing main event
+ *
+ * @var bool
+ * @access public
+ */
+ 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(), $specificParams=null)
+ {
+ parent::kBase();
+ if($params && is_array($params))
+ {
+ $prefix = getArrayValue($params,'prefix');
+ $special = getArrayValue($params,'special');
+ if($prefix) $this->Init($prefix,$special);
+ $this->Name = getArrayValue($params,'name');
+ }
+ elseif ($params && is_string($params)) {
+ if (preg_match('/([^.:]*)[.]{0,1}([^:]*):(.*)/', $params, $regs)) {
+ $prefix = $regs[1];
+ $special = $regs[2];
+ if($prefix) $this->Init($prefix,$special);
+ $this->Name = $regs[3];
+ }
+ else {
+ trigger_error('Invalid event string '.$params.' should be prefix[.special]:OnEvent ', E_USER_ERROR);
+ }
+ }
+ if (isset($specificParams)) $this->specificParams = $specificParams;
+ }
+
+ function setEventParam($name,$value)
+ {
+ $this->specificParams[$name]=$value;
+ }
+
+ function getEventParam($name)
+ {
+ 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='')
+ {
+ $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 &getObject($params=Array())
+ {
+ return $this->Application->recallObject($this->Prefix_Special,$this->pseudoClass,$params);
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Set's redirect param for event
+ *
+ * @param string $name
+ * @param string $value
+ * @access public
+ */
+ function SetRedirectParam($name, $value)
+ {
+ $this->redirect_params[$name] = $value;
+ }
+
+ /**
+ * Allows to merge passed redirect params hash with existing ones
+ *
+ * @param Array $params
+ * @access public
+ */
+ function setRedirectParams($params)
+ {
+ $this->redirect_params = array_merge_recursive2($this->redirect_params, $params);
+ }
+
+ /**
+ * Returns Master event name if any
+ *
+ * @return mixed
+ * @access public
+ */
+ function hasMasterEvent()
+ {
+ return is_object($this->MasterEvent) ? $this->MasterEvent->Name : false;
+ }
+
+ }
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/event.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.5
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/utility/smtp_client.php
===================================================================
--- trunk/core/kernel/utility/smtp_client.php (nonexistent)
+++ trunk/core/kernel/utility/smtp_client.php (revision 1560)
@@ -0,0 +1,829 @@
+<?php
+
+define('SMTP_STATUS_NOT_CONNECTED', 1, TRUE);
+define('SMTP_STATUS_CONNECTED', 2, TRUE);
+
+
+
+class kSmtpClient extends kBase {
+
+ var $connection;
+ var $recipients;
+ var $headers;
+ var $timeout;
+ var $errors;
+ var $status;
+ var $body;
+ var $from;
+ var $host;
+ var $port;
+ var $helo;
+ var $auth;
+ var $user;
+ var $pass;
+ var $debug;
+ var $buffer;
+
+ var $authmethod;
+ var $CRLF = "\r\n";
+
+ var $debugtext='';
+ /**
+ * List of supported authentication methods, in preferential order.
+ * @var array
+ * @access public
+ */
+ var $auth_methods = array('DIGEST-MD5','CRAM-MD5','LOGIN','PLAIN');
+ /**
+ * The most recent server response code.
+ * @var int
+ * @access private
+ */
+ var $_code = -1;
+
+ /**
+ * The most recent server response arguments.
+ * @var array
+ * @access private
+ */
+ var $_arguments = array();
+ /**
+ * Stores detected features of the SMTP server.
+ * @var array
+ * @access private
+ */
+ var $_esmtp = array();
+
+ /***************************************
+ ** Constructor function. Arguments:
+ ** $params - An assoc array of parameters:
+ **
+ ** host - The hostname of the smtp server Default: localhost
+ ** port - The port the smtp server runs on Default: 25
+ ** helo - What to send as the HELO command Default: localhost
+ ** (typically the hostname of the
+ ** machine this script runs on)
+ ** auth - Whether to use basic authentication Default: FALSE
+ ** user - Username for authentication Default: <blank>
+ ** pass - Password for authentication Default: <blank>
+ ** timeout - The timeout in seconds for the call Default: 5
+ ** to fsockopen()
+ ***************************************/
+
+ function kSmtpClient($params = array()){
+
+ $this->timeout = 5;
+ $this->status = SMTP_STATUS_NOT_CONNECTED;
+ $this->host = 'localhost';
+ $this->port = 25;
+ $this->helo = 'localhost';
+ $this->auth = FALSE;
+ $this->user = '';
+ $this->pass = '';
+ $this->errors = array();
+ $this->buffer = array();
+ $this->debug=0;
+ foreach($params as $key => $value){
+ $this->$key = $value;
+ }
+ }
+
+ /***************************************
+ ** Connect function. This will, when called
+ ** statically, create a new smtp object,
+ ** call the connect function (ie this function)
+ ** and return it. When not called statically,
+ ** it will connect to the server and send
+ ** the HELO command.
+ ***************************************/
+
+ function connect($params = array()){
+
+ if(!isset($this->status))
+ {
+ $obj = new kSmtpClient($params);
+ if($obj->connect()){
+ $obj->status = SMTP_STATUS_CONNECTED;
+ }
+
+ return $obj;
+
+ }
+ else
+ {
+ foreach($params as $key => $value){
+ $this->$key = $value;
+ }
+ $this->connection = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
+ if(is_resource($this->connection))
+ {
+ socket_set_timeout($this->connection, 0, 250000);
+ socket_set_blocking($this->connection,TRUE);
+ $greeting = $this->get_data();
+ $this->status = SMTP_STATUS_CONNECTED;
+ return $this->auth ? $this->ehlo() : $this->helo();
+ }
+ else
+ {
+ $this->errors[] = 'Failed to connect to server: '.$errstr;
+ return FALSE;
+ }
+ }
+ }
+
+ function disconnect()
+ {
+ if(is_resource($this->connection))
+ fclose($this->connection);
+ unset($this->connection);
+ $this->status=SMTP_STATUS_NOT_CONNECTED;
+ }
+ /***************************************
+ ** Function which handles sending the mail.
+ ** Arguments:
+ ** $params - Optional assoc array of parameters.
+ ** Can contain:
+ ** recipients - Indexed array of recipients
+ ** from - The from address. (used in MAIL FROM:),
+ ** this will be the return path
+ ** headers - Indexed array of headers, one header per array entry
+ ** body - The body of the email
+ ** It can also contain any of the parameters from the connect()
+ ** function
+ ***************************************/
+
+ function send($params = array()){
+
+ foreach($params as $key => $value){
+ $this->set($key, $value);
+ }
+ if($this->is_connected()){
+
+ // Do we auth or not? Note the distinction between the auth variable and auth() function
+ if($this->auth){
+ if(!$this->auth())
+ return FALSE;
+ }
+ $this->mail($this->from);
+ if(is_array($this->recipients))
+ foreach($this->recipients as $value)
+ $this->rcpt($value);
+ else
+ $this->rcpt($this->recipients);
+
+ if(!$this->data())
+ return FALSE;
+
+ // Transparency
+ $headers = str_replace($this->CRLF.'.', $this->CRLF.'..', trim(implode($this->CRLF, $this->headers)));
+ $body = str_replace($this->CRLF.'.', $this->CRLF.'..', $this->body);
+ $body = $body[0] == '.' ? '.'.$body : $body;
+
+ $this->send_data($headers);
+ $this->send_data('');
+ $this->send_data($body);
+ $this->send_data($this->CRLF.".");
+
+ return (substr(trim($this->get_data()), 0, 3) === '250');
+ }else{
+ $this->errors[] = 'Not connected!';
+ return FALSE;
+ }
+ }
+
+ /***************************************
+ ** Function to implement HELO cmd
+ ***************************************/
+
+ function helo(){
+ if(is_resource($this->connection)
+ AND $this->send_data('HELO '.$this->helo)
+ AND substr(trim($error = $this->get_data()), 0, 3) === '250' ){
+
+ return TRUE;
+
+ }else{
+ $this->errors[] = 'HELO command failed, output: ' . trim(substr(trim($error),3));
+ return FALSE;
+ }
+ }
+
+ /***************************************
+ ** Function to implement EHLO cmd
+ ***************************************/
+
+ function ehlo()
+ {
+ $ret_status=is_resource($this->connection) AND $this->send_data('EHLO '.$this->helo);
+ $success=$this->_parseResponse(250);
+ if(!$ret_status && $success !== true)
+ {
+ $this->errors[] = 'EHLO command failed, output: ' . trim(substr(trim($error),3));
+ return FALSE;
+ }
+
+ foreach ($this->_arguments as $argument) {
+ $verb = strtok($argument, ' ');
+ $arguments = substr($argument, strlen($verb) + 1,
+ strlen($argument) - strlen($verb) - 1);
+ $this->_esmtp[$verb] = $arguments;
+ }
+
+ return TRUE;
+
+
+ }
+
+ /***************************************
+ ** Function to implement AUTH cmd
+ ***************************************/
+
+ function _getBestAuthMethod()
+ {
+ if ($this->authmethod) return $this->authmethod;
+
+ if (!isset($this->_esmtp['AUTH'])) return 'NOAUTH';
+
+ $available_methods = explode(' ', $this->_esmtp['AUTH']);
+
+
+
+ foreach ($this->auth_methods as $method)
+ {
+ if (in_array($method, $available_methods)) return $method;
+ }
+ return false;
+ }
+
+
+ function auth(){
+ if(is_resource($this->connection))
+ {
+ $method=$this->_getBestAuthMethod();
+
+ if ($method == 'NOAUTH') return true;
+
+ switch ($method) {
+ case 'DIGEST-MD5':
+ $result = $this->_authDigest_MD5($this->user, $this->pass);
+ break;
+ case 'CRAM-MD5':
+ $result = $this->_authCRAM_MD5($this->user, $this->pass);
+ break;
+ case 'LOGIN':
+ $result = $this->_authLogin($this->user, $this->pass);
+ break;
+ case 'PLAIN':
+ $result = $this->_authPlain($this->user, $this->pass);
+ break;
+ default:
+ $this->errors[] = 'AUTH command failed: no supported authentication methods';
+ return false;
+ break;
+ }
+ if($result!==true)
+ {
+ $this->errors[] = 'AUTH command failed: '.$result;
+ return FALSE;
+ }
+ return true;
+
+ }else{
+ $this->errors[] = 'AUTH command failed: ' . trim(substr(trim($error),3));
+ return FALSE;
+ }
+ }
+
+// ============= AUTH METHODS: BEGIN ==========================
+/**
+ * Authenticates the user using the DIGEST-MD5 method.
+ *
+ * @param string The userid to authenticate as.
+ * @param string The password to authenticate with.
+ *
+ * @return mixed Returns a PEAR_Error with an error message on any
+ * kind of failure, or true on success.
+ * @access private
+ * @since 1.1.0
+ */
+ function _authDigest_MD5($uid, $pwd)
+ {
+ $this->send_data('AUTH DIGEST-MD5');
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true)
+ {
+ /* 503: Error: already authenticated */
+ if ($this->_code === 503) {
+ return true;
+ }
+ return $error;
+ }
+
+ $challenge = base64_decode($this->_arguments[0]);
+ $auth_str = base64_encode($this->get_digestMD5Auth($uid, $pwd, $challenge,
+ $this->host, "smtp"));
+
+
+ $this->send_data($auth_str);
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true) return $error;
+
+ /*
+ * We don't use the protocol's third step because SMTP doesn't allow
+ * subsequent authentication, so we just silently ignore it.
+ */
+ $this->send_data(' ');
+
+ /* 235: Authentication successful */
+ if(($error=$this->_parseResponse(235)) !== true) return $error;
+ }
+
+
+ /**
+ * Provides the (main) client response for DIGEST-MD5
+ * requires a few extra parameters than the other
+ * mechanisms, which are unavoidable.
+ *
+ * @param string $authcid Authentication id (username)
+ * @param string $pass Password
+ * @param string $challenge The digest challenge sent by the server
+ * @param string $hostname The hostname of the machine you're connecting to
+ * @param string $service The servicename (eg. imap, pop, acap etc)
+ * @param string $authzid Authorization id (username to proxy as)
+ * @return string The digest response (NOT base64 encoded)
+ * @access public
+ */
+ function get_digestMD5Auth($authcid, $pass, $challenge, $hostname, $service, $authzid = '')
+ {
+ $challenge = $this->_parseChallenge($challenge);
+ $authzid_string = '';
+ if ($authzid != '') {
+ $authzid_string = ',authzid="' . $authzid . '"';
+ }
+
+ if (!empty($challenge)) {
+ $cnonce = $this->_getCnonce();
+ $digest_uri = sprintf('%s/%s', $service, $hostname);
+ $response_value = $this->_getResponseValue($authcid, $pass, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $authzid);
+
+ return sprintf('username="%s",realm="%s"' . $authzid_string . ',nonce="%s",cnonce="%s",nc="00000001",qop=auth,digest-uri="%s",response=%s,%d', $authcid, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']);
+ } else {
+ return PEAR::raiseError('Invalid digest challenge');
+ }
+ }
+
+ /**
+ * Parses and verifies the digest challenge*
+ *
+ * @param string $challenge The digest challenge
+ * @return array The parsed challenge as an assoc
+ * array in the form "directive => value".
+ * @access private
+ */
+ function _parseChallenge($challenge)
+ {
+ $tokens = array();
+ while (preg_match('/^([a-z-]+)=("[^"]+(?<!\\\)"|[^,]+)/i', $challenge, $matches)) {
+
+ // Ignore these as per rfc2831
+ if ($matches[1] == 'opaque' OR $matches[1] == 'domain') {
+ $challenge = substr($challenge, strlen($matches[0]) + 1);
+ continue;
+ }
+
+ // Allowed multiple "realm" and "auth-param"
+ if (!empty($tokens[$matches[1]]) AND ($matches[1] == 'realm' OR $matches[1] == 'auth-param')) {
+ if (is_array($tokens[$matches[1]])) {
+ $tokens[$matches[1]][] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
+ } else {
+ $tokens[$matches[1]] = array($tokens[$matches[1]], preg_replace('/^"(.*)"$/', '\\1', $matches[2]));
+ }
+
+ // Any other multiple instance = failure
+ } elseif (!empty($tokens[$matches[1]])) {
+ $tokens = array();
+ break;
+
+ } else {
+ $tokens[$matches[1]] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
+ }
+
+ // Remove the just parsed directive from the challenge
+ $challenge = substr($challenge, strlen($matches[0]) + 1);
+ }
+
+ /**
+ * Defaults and required directives
+ */
+ // Realm
+ if (empty($tokens['realm'])) {
+ $uname = posix_uname();
+ $tokens['realm'] = $uname['nodename'];
+ }
+
+ // Maxbuf
+ if (empty($tokens['maxbuf'])) {
+ $tokens['maxbuf'] = 65536;
+ }
+
+ // Required: nonce, algorithm
+ if (empty($tokens['nonce']) OR empty($tokens['algorithm'])) {
+ return array();
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Creates the response= part of the digest response
+ *
+ * @param string $authcid Authentication id (username)
+ * @param string $pass Password
+ * @param string $realm Realm as provided by the server
+ * @param string $nonce Nonce as provided by the server
+ * @param string $cnonce Client nonce
+ * @param string $digest_uri The digest-uri= value part of the response
+ * @param string $authzid Authorization id
+ * @return string The response= part of the digest response
+ * @access private
+ */
+ function _getResponseValue($authcid, $pass, $realm, $nonce, $cnonce, $digest_uri, $authzid = '')
+ {
+ if ($authzid == '') {
+ $A1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce);
+ } else {
+ $A1 = sprintf('%s:%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce, $authzid);
+ }
+ $A2 = 'AUTHENTICATE:' . $digest_uri;
+ return md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($A1), $nonce, $cnonce, md5($A2)));
+ }
+
+ /**
+ * Creates the client nonce for the response
+ *
+ * @return string The cnonce value
+ * @access private
+ */
+ function _getCnonce()
+ {
+ if (file_exists('/dev/urandom')) {
+ return base64_encode(fread(fopen('/dev/urandom', 'r'), 32));
+
+ } elseif (file_exists('/dev/random')) {
+ return base64_encode(fread(fopen('/dev/random', 'r'), 32));
+
+ } else {
+ $str = '';
+ mt_srand((double)microtime()*10000000);
+ for ($i=0; $i<32; $i++) {
+ $str .= chr(mt_rand(0, 255));
+ }
+
+ return base64_encode($str);
+ }
+ }
+
+
+
+
+
+
+
+ /**
+ * Authenticates the user using the CRAM-MD5 method.
+ *
+ * @param string The userid to authenticate as.
+ * @param string The password to authenticate with.
+ *
+ * @return mixed Returns a PEAR_Error with an error message on any
+ * kind of failure, or true on success.
+ * @access private
+ * @since 1.1.0
+ */
+ function _authCRAM_MD5($uid, $pwd)
+ {
+ $this->send_data('AUTH CRAM-MD5');
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true)
+ {
+ /* 503: Error: already authenticated */
+ if ($this->_code === 503) {
+ return true;
+ }
+ return $error;
+ }
+
+ $challenge = base64_decode($this->_arguments[0]);
+ $auth_str = base64_encode($uid . ' ' . $this->_HMAC_MD5($pwd, $challenge));
+
+ $this->send_data($auth_str);
+
+ /* 235: Authentication successful */
+ if ( ($error = $this->_parseResponse(235)) ) {
+ return $error;
+ }
+ }
+
+ /**
+ * Authenticates the user using the LOGIN method.
+ *
+ * @param string The userid to authenticate as.
+ * @param string The password to authenticate with.
+ *
+ * @return mixed Returns a PEAR_Error with an error message on any
+ * kind of failure, or true on success.
+ * @access private
+ * @since 1.1.0
+ */
+ function _authLogin($uid, $pwd)
+ {
+ $this->send_data('AUTH LOGIN');
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true)
+ {
+ /* 503: Error: already authenticated */
+ if ($this->_code === 503) {
+ return true;
+ }
+ return $error;
+ }
+
+ $this->send_data( base64_encode($uid) );
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true) return $error;
+
+ $this->send_data( base64_encode($pwd) );
+
+ /* 235: Authentication successful */
+ if (($error=$this->_parseResponse(235)) !== true) return $error;
+
+ return true;
+ }
+
+ /**
+ * Authenticates the user using the PLAIN method.
+ *
+ * @param string The userid to authenticate as.
+ * @param string The password to authenticate with.
+ *
+ * @return mixed Returns a PEAR_Error with an error message on any
+ * kind of failure, or true on success.
+ * @access private
+ * @since 1.1.0
+ */
+ function _authPlain($uid, $pwd)
+ {
+ $this->send_data('AUTH PLAIN');
+
+ /* 334: Continue authentication request */
+ if(($error=$this->_parseResponse(334)) !== true)
+ {
+ /* 503: Error: already authenticated */
+ if ($this->_code === 503) {
+ return true;
+ }
+ return $error;
+ }
+
+ $auth_str = base64_encode(chr(0) . $uid . chr(0) . $pwd);
+ $this->send_data($auth_str);
+
+ /* 235: Authentication successful */
+ if (($error=$this->_parseResponse(235)) !== true) return $error;
+
+ return true;
+ }
+// ============= AUTH METHODS: END ==========================
+
+ /**
+ * Function which implements HMAC MD5 digest
+ *
+ * @param string $key The secret key
+ * @param string $data The data to protect
+ * @return string The HMAC MD5 digest
+ */
+ function _HMAC_MD5($key, $data)
+ {
+ if (strlen($key) > 64) {
+ $key = pack('H32', md5($key));
+ }
+
+ if (strlen($key) < 64) {
+ $key = str_pad($key, 64, chr(0));
+ }
+
+ $k_ipad = substr($key, 0, 64) ^ str_repeat(chr(0x36), 64);
+ $k_opad = substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64);
+
+ $inner = pack('H32', md5($k_ipad . $data));
+ $digest = md5($k_opad . $inner);
+
+ return $digest;
+ }
+
+
+
+ /**
+ * Read a reply from the SMTP server. The reply consists of a response
+ * code and a response message.
+ *
+ * @param mixed $valid The set of valid response codes. These
+ * may be specified as an array of integer
+ * values or as a single integer value.
+ *
+ * @return mixed True if the server returned a valid response code or
+ * a PEAR_Error object is an error condition is reached.
+ *
+ * @access private
+ * @since 1.1.0
+ *
+ * @see getResponse
+ */
+ function _parseResponse($valid)
+ {
+
+ $this->_code = -1;
+ $this->_arguments = array();
+
+ if(!is_resource($this->connection)) return false;
+
+ while ($line = fgets($this->connection, 512)) {
+ if ($this->debug) {
+ $this->debugtext.= "DEBUG: Recv: $line\n";
+ }
+
+ /* If we receive an empty line, the connection has been closed. */
+ if (empty($line)) {
+ $this->disconnect();
+ return 'Connection was unexpectedly closed';
+ }
+
+ /* Read the code and store the rest in the arguments array. */
+ $code = substr($line, 0, 3);
+ $this->_arguments[] = trim(substr($line, 4));
+
+ /* Check the syntax of the response code. */
+ if (is_numeric($code)) {
+ $this->_code = (int)$code;
+ } else {
+ $this->_code = -1;
+ break;
+ }
+
+ /* If this is not a multiline response, we're done. */
+ if (substr($line, 3, 1) != '-') {
+ break;
+ }
+ }
+
+ /* Compare the server's response code with the valid code. */
+ if (is_int($valid) && ($this->_code === $valid)) {
+ return true;
+ }
+
+ /* If we were given an array of valid response codes, check each one. */
+ if (is_array($valid)) {
+ foreach ($valid as $valid_code) {
+ if ($this->_code === $valid_code) {
+ return true;
+ }
+ }
+ }
+
+ return 'Invalid response code received from server';
+ }
+
+
+ /***************************************
+ ** Function that handles the MAIL FROM: cmd
+ ***************************************/
+
+ function mail($from){
+
+ if($this->is_connected()
+ AND $this->send_data('MAIL FROM:'.$from.'')
+ AND substr(trim($this->get_data()), 0, 2) === '250' ){
+
+ return TRUE;
+
+ }else
+ return FALSE;
+ }
+
+ /***************************************
+ ** Function that handles the RCPT TO: cmd
+ ***************************************/
+
+ function rcpt($to){
+
+ if($this->is_connected()
+ AND $this->send_data('RCPT TO:'.$to.'')
+ AND substr(trim($error = $this->get_data()), 0, 2) === '25' ){
+
+ return TRUE;
+
+ }else{
+ $this->errors[] = trim(substr(trim($error), 3));
+ return FALSE;
+ }
+ }
+
+ /***************************************
+ ** Function that sends the DATA cmd
+ ***************************************/
+
+ function data(){
+
+ if($this->is_connected()
+ AND $this->send_data('DATA')
+ AND substr(trim($error = $this->get_data()), 0, 3) === '354' ){
+
+ return TRUE;
+
+ }else{
+ $this->errors[] = trim(substr(trim($error), 3));
+ return FALSE;
+ }
+ }
+
+ /***************************************
+ ** Function to determine if this object
+ ** is connected to the server or not.
+ ***************************************/
+
+ function is_connected(){
+
+ return (is_resource($this->connection) AND ($this->status === SMTP_STATUS_CONNECTED));
+ }
+
+ /***************************************
+ ** Function to send a bit of data
+ ***************************************/
+
+ function send_data($data){
+
+ if($this->debug)
+ {
+ $this->buffer[] = "SEND: $data\n";
+ }
+ if ($this->debug) {
+ $this->debugtext.= "DEBUG: Send: $data\n";
+ }
+ if(is_resource($this->connection)){
+ return fwrite($this->connection, $data.$this->CRLF, strlen($data)+2);
+ }else
+ return FALSE;
+ }
+
+ function bytes_left($fp)
+ {
+ $status = socket_get_status ($fp);
+ //print_r($status);
+ $bytes = $status["unread_bytes"];
+ return $bytes;
+ }
+
+ /***************************************
+ ** Function to get data.
+ ***************************************/
+ function &get_data(){
+
+ $return = '';
+ $line = '';
+
+ if(is_resource($this->connection))
+ {
+ while(strpos($return, $this->CRLF) === FALSE OR substr($line,3,1) !== ' ')
+ {
+ $line = fgets($this->connection, 512);
+ $return .= $line;
+ }
+ if($this->debug)
+ {
+ $this->buffer[] = "GET: ".$return."\n";
+ }
+ return $return;
+
+ }else
+ return FALSE;
+ }
+
+ /***************************************
+ ** Sets a variable
+ ***************************************/
+
+ function set($var, $value){
+
+ $this->$var = $value;
+ return TRUE;
+ }
+
+
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/smtp_client.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/temp_handler.php
===================================================================
--- trunk/core/kernel/utility/temp_handler.php (nonexistent)
+++ trunk/core/kernel/utility/temp_handler.php (revision 1560)
@@ -0,0 +1,581 @@
+<?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)
+ {
+ // function is sometimes called as static, so we CAN'T use $this->GetTempTablePrefix() here
+ return TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_'.$table;
+ }
+
+ function GetTempTablePrefix()
+ {
+ return TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_';
+ }
+
+ /**
+ * Return live table name based on temp table name
+ *
+ * @param string $temp_table
+ * @return string
+ */
+ function GetLiveName($temp_table)
+ {
+ if( preg_match('/'.TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_(.*)/',$temp_table,$rets) )
+ {
+ return $rets[1];
+ }
+ else
+ {
+ return $temp_table;
+ }
+ }
+
+ function IsTempTable($table)
+ {
+ return strpos($table, TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_') !== false;
+ }
+
+ /**
+ * Return temporary table name for master table
+ *
+ * @return string
+ * @access public
+ */
+ function GetMasterTempName()
+ {
+ return $this->GetTempName($this->MasterTable);
+ }
+
+ function CreateTempTable($table)
+ {
+ $query = sprintf("CREATE TABLE %s SELECT * FROM %s WHERE 0",
+ $this->GetTempName($table),
+ $table);
+ $this->Conn->Query($query);
+ }
+
+ function BuildTables($prefix, $ids)
+ {
+ $tables = Array(
+ 'TableName' => $this->Application->getUnitOption($prefix,'TableName'),
+ 'IdField' => $this->Application->getUnitOption($prefix,'IDField'),
+ 'IDs' => $ids,
+ 'Prefix' => $prefix,
+ );
+
+ $SubItems = $this->Application->getUnitOption($prefix,'SubItems');
+ if (is_array($SubItems)) {
+ foreach ($SubItems as $prefix) {
+ $this->AddTables($prefix, $tables);
+ }
+ }
+ $this->SetTables($tables);
+ }
+
+ function AddTables($prefix, &$tables)
+ {
+ $tmp = Array(
+ 'TableName' => $this->Application->getUnitOption($prefix,'TableName'),
+ 'IdField' => $this->Application->getUnitOption($prefix,'IDField'),
+ 'ForeignKey' => $this->Application->getUnitOption($prefix,'ForeignKey'),
+ 'ParentTableKey' => $this->Application->getUnitOption($prefix,'ParentTableKey'),
+ 'Prefix' => $prefix,
+ 'AutoClone' => $this->Application->getUnitOption($prefix,'AutoClone'),
+ 'AutoDelete' => $this->Application->getUnitOption($prefix,'AutoDelete'),
+ );
+
+ $constrain = $this->Application->getUnitOption($prefix,'Constrain');
+ if ($constrain) $tmp['Constrain'] = $constrain;
+
+ $SubItems = $this->Application->getUnitOption($prefix,'SubItems');
+ $same_sub_counter = 1;
+ if (is_array($SubItems)) {
+ foreach ($SubItems as $prefix) {
+ if (preg_match("/^SAME:(.*)/", $prefix, $regs)) {
+ $same_sub = $tmp;
+ $same_sub['Prefix'] = $tmp['Prefix'].'.'.$same_sub_counter;
+ $same_sub['Constrain'] = $regs[1];
+ $same_sub['ParentTableKey'] = $tmp['IdField'];
+ $same_sub['ForeignKey'] = $this->Application->getUnitOption($tmp['Prefix'],'ForeignKey'.$same_sub_counter);
+ $tmp['SubTables'][] = $same_sub;
+ $same_sub_counter++;
+ }
+ else {
+ $this->AddTables($prefix, $tmp);
+ }
+ }
+ }
+
+ if ( !is_array(getArrayValue($tables, 'SubTables')) ) {
+ $tables['SubTables'] = array();
+ }
+
+ $tables['SubTables'][] = $tmp;
+ }
+
+ function CloneItems($prefix, $special, $ids, $master=null, $foreign_key=null, $parent_prefix=null)
+ {
+ if (!isset($master)) $master = $this->Tables;
+ if( strpos($prefix,'.') !== false ) list($prefix,$special) = explode('.', $prefix, 2);
+
+ $prefix_special = rtrim($prefix.'.'.$special, '.');
+
+ //recalling by different name, because we may get kDBList, if we recall just by prefix
+ $recall_prefix = $prefix_special.($special ? '' : '.').'-item';
+ $this->Application->setUnitOption($prefix, 'AutoLoad', false);
+
+ $object =& $this->Application->recallObject($recall_prefix, $prefix);
+
+ foreach ($ids as $id)
+ {
+ $mode = 'create';
+ if ( $cloned_ids = getArrayValue($this->AlreadyProcessed, $master['TableName']) ) {
+ // if we have already cloned the id, replace it with cloned id and set mode to update
+ // update mode is needed to update second ForeignKey for items cloned by first ForeignKey
+ if ( getArrayValue($cloned_ids, $id) ) {
+ $id = $cloned_ids[$id];
+ $mode = 'update';
+ }
+ }
+
+ $object->Load($id);
+ $original_values = $object->FieldValues;
+
+ $object->NameCopy($master, $foreign_key);
+
+ if (isset($foreign_key)) {
+ $master_foreign_key_field = is_array($master['ForeignKey']) ? $master['ForeignKey'][$parent_prefix] : $master['ForeignKey'];
+ $object->SetDBField($master_foreign_key_field, $foreign_key);
+ }
+
+ if ($mode == 'create') {
+ $this->RaiseEvent('OnBeforeClone', $master['Prefix'], Array($object->GetId()) );
+ }
+
+ $res = $mode == 'update' ? $object->Update() : $object->Create();
+
+ if( $res )
+ {
+ if ( $mode == 'create' && is_array( getArrayValue($master, 'ForeignKey')) ) {
+ // remember original => clone mapping for dual ForeignKey updating
+ $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;
+ if( strpos($prefix,'.') !== false ) list($prefix,$special) = explode('.', $prefix, 2);
+
+ $prefix_special = rtrim($prefix.'.'.$special, '.');
+
+ //recalling by different name, because we may get kDBList, if we recall just by prefix
+ $recall_prefix = $prefix_special.($special ? '' : '.').'-item';
+ $this->Application->setUnitOption($prefix,'AutoLoad',false);
+ $object =& $this->Application->recallObject($recall_prefix, $prefix);
+
+ foreach ($ids as $id)
+ {
+ $object->Load($id);
+ $original_values = $object->FieldValues;
+ $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 :)
+ if ( !preg_match("/.*\.[0-9]+/", $master['Prefix']) ) {
+ $this->DropTempTable($master['TableName']);
+ $this->CreateTempTable($master['TableName']);
+ }
+
+ if (is_array($ids)) {
+ $ids = join(',', $ids);
+ }
+
+ if ($ids != '') {
+ if ( getArrayValue($master, 'ForeignKey') ) {
+ if ( is_array($master['ForeignKey']) ) {
+ $key_field = $master['ForeignKey'][$parent_prefix];
+ }
+ else {
+ $key_field = $master['ForeignKey'];
+ }
+ }
+ else {
+ $key_field = $master['IdField'];
+ }
+
+ $query = 'INSERT INTO '.$this->GetTempName($master['TableName']).'
+ SELECT * FROM '.$master['TableName'].'
+ WHERE '.$key_field.' IN ('.$ids.')';
+ if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
+ $this->Conn->Query($query);
+
+ $query = 'SELECT '.$master['IdField'].' FROM '.$master['TableName'].'
+ WHERE '.$key_field.' IN ('.$ids.')';
+ if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
+ $this->RaiseEvent( 'OnAfterCopyToTemp', $master['Prefix'], $this->Conn->GetCol($query) );
+ }
+
+ if ( getArrayValue($master, 'SubTables') ) {
+ foreach ($master['SubTables'] as $sub_table) {
+
+ $parent_key = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
+
+ if ( $ids != '' && $parent_key != $key_field ) {
+ $query = 'SELECT '.$parent_key.' FROM '.$master['TableName'].'
+ WHERE '.$key_field.' IN ('.$ids.')';
+ $sub_foreign_keys = join(',', $this->Conn->GetCol($query));
+ }
+ else {
+ $sub_foreign_keys = $ids;
+ }
+ $this->DoCopyLiveToTemp($sub_table, $sub_foreign_keys, $master['Prefix']);
+ }
+ }
+ }
+
+ function GetForeignKeys($master, $sub_table, $live_id, $temp_id=null)
+ {
+ $mode = 1; //multi
+ if (!is_array($live_id)) {
+ $live_id = Array($live_id);
+ $mode = 2; //single
+ }
+ if (isset($temp_id) && !is_array($temp_id)) $temp_id = Array($temp_id);
+
+ if ( isset($sub_table['ParentTableKey']) ) {
+ if ( is_array($sub_table['ParentTableKey']) ) {
+ $parent_key_field = $sub_table['ParentTableKey'][$master['Prefix']];
+ }
+ else {
+ $parent_key_field = $sub_table['ParentTableKey'];
+ }
+ }
+ else {
+ $parent_key_field = $master['IdField'];
+ }
+
+ if ( $cached = getArrayValue($this->FKeysCache, $master['TableName'].'.'.$parent_key_field) ) {
+ if ( array_key_exists(serialize($live_id), $cached) ) {
+ list($live_foreign_key, $temp_foreign_key) = $cached[serialize($live_id)];
+ if ($mode == 1) {
+ return $live_foreign_key;
+ }
+ else {
+ return Array($live_foreign_key[0], $temp_foreign_key[0]);
+ }
+ }
+ }
+
+ if ($parent_key_field != $master['IdField']) {
+ $query = 'SELECT '.$parent_key_field.' FROM '.$master['TableName'].'
+ WHERE '.$master['IdField'].' IN ('.join(',', $live_id).')';
+ $live_foreign_key = $this->Conn->GetCol($query);
+
+ if (isset($temp_id)) {
+ $query = 'SELECT '.$parent_key_field.' FROM '.$this->GetTempName($master['TableName']).'
+ WHERE '.$master['IdField'].' IN ('.join(',', $temp_id).')';
+ $temp_foreign_key = $this->Conn->GetCol($query);
+ }
+ else {
+ $temp_foreign_key = Array();
+ }
+ }
+ else {
+ $live_foreign_key = $live_id;
+ $temp_foreign_key = $temp_id;
+ }
+
+ $this->FKeysCache[$master['TableName'].'.'.$parent_key_field][serialize($live_id)] = Array($live_foreign_key, $temp_foreign_key);
+
+ if ($mode == 1) {
+ return $live_foreign_key;
+ }
+ else {
+ return Array($live_foreign_key[0], $temp_foreign_key[0]);
+ }
+ }
+
+ function DoCopyTempToOriginal($master, $parent_prefix=null)
+ {
+ $query = 'SELECT '.$master['IdField'].' FROM '.$this->GetTempName($master['TableName']);
+ if (isset($master['Constrain'])) $query .= ' WHERE '.$master['Constrain'];
+ $current_ids = $this->Conn->GetCol($query);
+
+ 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';
+ if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
+ $this->Conn->Query($query);
+
+ // copy ALL records to live table
+ $query = 'INSERT INTO '.$master['TableName'].'
+ SELECT * FROM '.$this->GetTempName($master['TableName']);
+ if (isset($master['Constrain'])) $query .= ' WHERE '.$master['Constrain'];
+ $this->Conn->Query($query);
+
+ /*
+
+ !!! 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).')';
+ if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
+
+ $this->RaiseEvent( 'OnBeforeDeleteFromLive', $sub_table['Prefix'], $this->Conn->GetCol($query) );
+
+ $query = 'DELETE FROM '.$sub_table['TableName'].'
+ WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
+ if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
+ $this->Conn->Query($query);
+ }
+ }
+
+ //sub_table passed here becomes master in the method, and recursively updated and copy its sub tables
+ $this->DoCopyTempToOriginal($sub_table, $master['Prefix']);
+ }
+ }
+
+ function RaiseEvent($name, $prefix, $ids)
+ {
+ 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.4
\ 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 (nonexistent)
+++ trunk/core/kernel/utility/params.php (revision 1560)
@@ -0,0 +1,139 @@
+<?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/s', $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[$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);
+ 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($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;
+ }
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/params.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.5
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/utility/debugger.php
===================================================================
--- trunk/core/kernel/utility/debugger.php (nonexistent)
+++ trunk/core/kernel/utility/debugger.php (revision 1560)
@@ -0,0 +1,922 @@
+<?php
+
+ if(!class_exists('Debugger'))
+ {
+ function dbg_ConstOn($const_name)
+ {
+ return defined($const_name)&&constant($const_name);
+ }
+
+ function dbg_safeDefine($const_name,$const_value)
+ {
+ if(!defined($const_name)) define($const_name,$const_value);
+ }
+
+ unset($_REQUEST['debug_host']); // this var messed up whole detection stuff :(
+
+ // Detect fact, that this session beeing debugged by Zend Studio
+ foreach($_REQUEST as $rq_name=>$rq_value)
+ {
+ if( substr($rq_name,0,6)=='debug_' )
+ {
+ define('DBG_ZEND_PRESENT',1);
+ break;
+ }
+ }
+
+ 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:');
+
+ foreach($dbg_constMap as $dbg_constName=>$dbg_constValue)
+ {
+ dbg_safeDefine($dbg_constName,$dbg_constValue);
+ }
+
+ // only for IE, in case if no windows php script editor defined
+ /*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
+ {
+ /**
+ * Debugger data for building report
+ *
+ * @var Array
+ */
+ var $Data = Array();
+ var $ProfilerData = Array();
+ var $ProfilerTotals = 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->profileStart('kernel4_startup', 'Startup and Initialization of kernel4');
+ $this->profileStart('script_runtime', 'Script runtime');
+ 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 initOptions()
+ {
+
+ }
+
+ function mapLongError($msg)
+ {
+ $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)
+ {
+ $this->Options|=$this->OptionsMap[$name];
+ }
+ else
+ {
+ $this->Options=$this->Options&~$this->OptionsMap[$name];
+ }
+ }
+
+ function getOption($name)
+ {
+ if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']<br>');
+ return ($this->Options & $this->OptionsMap[$name]) == $this->OptionsMap[$name];
+ }
+
+ /**
+ * Set's flag, that next error that occurs will
+ * be prepended by backtrace results
+ *
+ */
+ function traceNext()
+ {
+ $this->TraceNextError=true;
+ }
+
+ function dumpVars()
+ {
+ $dumpVars = func_get_args();
+ foreach($dumpVars as $varValue)
+ {
+ $this->Data[] = Array('value' => $varValue, 'debug_type' => 'var_dump');
+ }
+ }
+
+ function prepareHTML($dataIndex)
+ {
+ $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;
+ }
+ }
+
+ function processTraceArguments(&$traceArgs)
+ {
+ if(!$traceArgs) return '';
+ foreach ($traceArgs as $argID => $argValue)
+ {
+ if( is_array($argValue) || is_object($argValue) )
+ {
+ 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
+ {
+ $traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]);
+ }
+ }
+ }
+
+ 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( 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>';
+ }
+
+ }
+
+ function getLocalFile($remoteFile)
+ {
+ return str_replace(DOC_ROOT, DBG_LOCAL_BASE_PATH, $remoteFile);
+ }
+
+ function appendTrace()
+ {
+ $trace = debug_backtrace();
+ array_shift($trace);
+ $this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace');
+ }
+
+ function appendMemoryUsage($msg, $used=null)
+ {
+ if (!isset($used)) $used = round(memory_get_usage()/1024);
+ $this->appendHTML('<b>Memory usage</b> '.$msg.' '.$used.'Kb');
+ }
+
+ 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;
+ }
+
+ 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( !is_array($value) && trim($value) == '' )
+ {
+ $value = '<b class="debug_error">no value</b>';
+ }
+ else
+ {
+ $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 profilerAddTotal($total_key, $key=null, $value=null)
+ {
+ if (!isset($this->ProfilerTotals[$total_key])) {
+ $this->ProfilerTotals[$total_key] = 0;
+ }
+ if (!isset($value)) {
+ $value = $this->ProfilerData[$key]['ends'] - $this->ProfilerData[$key]['begins'];
+ }
+ $this->ProfilerTotals[$total_key] += $value;
+ }
+
+ 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;
+
+ default:
+ return '';
+ break;
+ }
+ }
+
+ /**
+ * Generates report
+ *
+ */
+ function printReport($returnResult = false)
+ {
+ $this->profileFinish('script_runtime');
+ 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_SQL_PROFILE') ) {
+ $this->appendHTML('<b>SQL Total time:</b> '.$this->ProfilerTotals['sql']);
+ }
+
+ if ( dbg_ConstOn('DBG_PROFILE_MEMORY') ) {
+ $this->appendHTML('<b>Memory used by Objects:</b> '.round($this->ProfilerTotals['objects']/1024, 2).'Kb');
+ }
+
+ if ( dbg_ConstOn('DBG_INCLUDED_FILES') ) {
+ $files = get_included_files();
+ $this->appendHTML('<b>Included files:</b>');
+ foreach ($files as $file)
+ {
+ $this->appendHTML($this->getFileLink($this->getLocalFile($file)).' ('.round(filesize($file)/1024, 2).'Kb)');
+ }
+ }
+
+ if ( dbg_ConstOn('DBG_PROFILE_INCLUDES') ) {
+ $this->appendHTML('<b>Included files statistics:</b>'.( dbg_ConstOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)':''));
+ $totals = Array( 'mem' => 0, 'time' => 0);
+ $totals_configs = Array( 'mem' => 0, 'time' => 0);
+ 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']));
+
+
+ }
+
+
+ $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;
+ }
+
+ .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)
+ {
+ var $KeyCode = 0;
+ if($e.keyCode) $KeyCode = $e.keyCode;
+ else if($e.which) $KeyCode = $e.which;
+ return $KeyCode;
+ }
+
+ function keyProcessor($e)
+ {
+ 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();
+ }
+ }
+
+ function toggleDebugLayer($KeyCode)
+ {
+ 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';
+ }
+ }
+
+ function prepareSizes($Prefix)
+ {
+ 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;
+ }
+
+ 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);
+ }
+ 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();
+ }
+ }
+
+ /**
+ * 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>';
+ }
+
+
+ /**
+ * 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;
+ }
+
+ 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 || $errno == E_USER_ERROR)
+ 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;
+ }
+ }
+
+ function saveToFile($msg)
+ {
+ $fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a');
+ fwrite($fp,$msg."\n");
+ fclose($fp);
+ }
+
+ /**
+ * 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;
+ }
+
+ }
+
+ if( !function_exists('memory_get_usage') )
+ {
+ function memory_get_usage(){ return -1; }
+ }
+
+ $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') );
+ }
+ }
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/debugger.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.9
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/utility/http_query.php
===================================================================
--- trunk/core/kernel/utility/http_query.php (nonexistent)
+++ trunk/core/kernel/utility/http_query.php (revision 1560)
@@ -0,0 +1,478 @@
+<?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();
+
+ var $Admin = false;
+
+ /**
+ * 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->Admin = defined('ADMIN') && ADMIN;
+ $this->AddAllVars();
+
+ $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, 2);
+ 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':
+ $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->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;
+ }
+
+ /**
+ * Owerwrites GET events with POST events in case if they are set and not empty
+ *
+ */
+ function convertPostEvents()
+ {
+ $events = $this->Get('events');
+ if( is_array($events) )
+ {
+ foreach ($events as $prefix_special => $event_name)
+ {
+ if($event_name) $this->Set($prefix_special.'_event', $event_name);
+ }
+ }
+ }
+
+ /**
+ * 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)
+ {
+ $sid = $this->Get('sid');
+ if (defined('MOD_REWRITE') && MOD_REWRITE && $sid) $env_var = rtrim($sid.$env_var, '/');
+ $env_var = str_replace('\:','_&+$$+&_',$env_var); // replace escaped "=" with spec-chars :)
+
+ $parts=explode(':',$env_var);
+
+ if (defined('MOD_REWRITE') && MOD_REWRITE) $env_var = str_replace('/', ':', $env_var);
+
+ 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);
+ $this->Get['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)
+ {
+ //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');
+
+ // 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
+ {
+ 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;
+
+ 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;
+ }
+
+ /**
+ * Saves variables from array specified
+ * into common variable storage place
+ *
+ * @param Array $array
+ * @return Array
+ * @access private
+ */
+ function AddVars($array)
+ {
+ $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)
+ {
+ if( is_array($value) )
+ {
+ $array[$key] = $this->StripSlashes($value);
+ }
+ else
+ {
+ if( get_magic_quotes_gpc() ) $value = stripslashes($value);
+ if(!$this->Admin) $value = htmlspecialchars($value);
+ $array[$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
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.5
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ 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 1560)
@@ -0,0 +1,904 @@
+<?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);
+ }
+
+ if( isset($options['regexp']) )
+ {
+ if( !preg_match($options['regexp'], $value) )
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'invalid_format';
+ }
+ }
+
+ 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];
+ }
+ }*/
+
+ function GetSample($field, &$options, &$object)
+ {
+
+ }
+
+}
+
+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 = getArrayValue($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.current');
+
+ 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']) == '' ) {
+ $empty_time = getArrayValue($options,'empty_time');
+ if($empty_time === false) $empty_time = mktime(0,0,0);
+ $object->SetDBField($sub_fields['time'], $empty_time);
+ }
+ $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 = '/^'.str_replace('/','\/',$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));
+ }
+
+ function GetSample($field, &$options, &$object)
+ {
+ return $this->Format( time(), $field, $object);
+ }
+}
+
+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)
+ {
+
+ }
+
+ function UpdateMasterFields($field, $value, &$options, &$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;
+ }
+
+}
+
+
+class kPasswordFormatter extends kFormatter
+{
+
+ function PrepareOptions($field_name, &$field_options, &$object)
+ {
+ if( isset( $field_options['verify_field'] ) )
+ {
+ $add_fields = Array();
+ $options = Array('master_field' => $field_name, 'formatter'=>'kPasswordFormatter');
+ $add_fields[ $field_options['verify_field'] ] = $options;
+
+ $add_fields[$field_name.'_plain'] = Array('type'=>'string', 'error_field'=>$field_name);
+ $add_fields[ $field_options['verify_field'].'_plain' ] = Array('type'=>'string', 'error_field'=>$field_options['verify_field'] );
+
+ $add_fields = array_merge_recursive2($add_fields, $object->VirtualFields);
+ $object->setVirtualFields($add_fields);
+ }
+ }
+
+ function Format($value, $field_name, &$object, $format=null)
+ {
+ return $value;
+ }
+
+ function Parse($value, $field_name, &$object)
+ {
+ $options = $object->GetFieldOptions($field_name);
+
+ $fields = Array('master_field','verify_field');
+ $fields_set = true;
+ $flip_count = 0;
+ while($flip_count < 2)
+ {
+ if( getArrayValue($options,$fields[0]) )
+ {
+ $object->SetDBField($field_name.'_plain', $value);
+ if( !getArrayValue($object->Fields[ $options[ $fields[0] ] ], $fields[1].'_set') )
+ {
+ $object->Fields[ $options[ $fields[0] ] ][$fields[1].'_set'] = true;
+ }
+
+ $password_field = $options[ $fields[0] ];
+ $verify_field = $field_name;
+ }
+ $fields = array_reverse($fields);
+ $flip_count++;
+ }
+
+ if( getArrayValue($object->Fields[$password_field], 'verify_field_set') && getArrayValue($object->Fields[$verify_field], 'master_field_set') )
+ {
+ $new_password = $object->GetDBField($password_field.'_plain');
+ $verify_password = $object->GetDBField($verify_field.'_plain');
+
+ if($new_password == '' && $verify_password == '')
+ {
+ if( $object->GetDBField($password_field) != $this->EncryptPassword('') )
+ {
+ return $this->EncryptPassword($value);
+ }
+ else
+ {
+ $object->Fields[$password_field.'_plain']['required'] = true;
+ $object->Fields[$verify_field.'_plain']['required'] = true;
+ return null;
+ }
+ }
+
+ $min_length = $this->Application->ConfigValue('Min_Password');
+ if( strlen($new_password) >= $min_length )
+ {
+ if($new_password != $verify_password)
+ {
+ $object->ErrorMsgs['passwords_do_not_match'] = $this->Application->Phrase('lu_passwords_do_not_match');
+ $object->FieldErrors[$password_field]['pseudo'] = 'passwords_do_not_match';
+ $object->FieldErrors[$verify_field]['pseudo'] = 'passwords_do_not_match';
+ }
+ }
+ else
+ {
+ $object->FieldErrors[$password_field]['pseudo'] = 'length_out_of_range';
+ $object->FieldErrors[$verify_field]['pseudo'] = 'length_out_of_range';
+ }
+ }
+ if($value == '') return $object->GetDBField($field_name);
+ return $this->EncryptPassword($value);
+ }
+
+ function EncryptPassword($value)
+ {
+ return md5($value);
+ }
+}
+
+
+ /**
+ * Credit card expiration date formatter
+ *
+ */
+ class kCCDateFormatter extends kFormatter
+ {
+ function PrepareOptions($field_name, &$field_options, &$object)
+ {
+ $add_fields = Array();
+
+ $i = 1;
+ $options = Array('00' => '');
+ while($i <= 12)
+ {
+ $options[ sprintf('%02d',$i) ] = sprintf('%02d',$i);
+ $i++;
+ }
+ $add_fields[ $field_options['month_field'] ] = Array('formatter'=>'kOptionsFormatter', 'options' => $options, 'not_null' => true, 'default' => '00');
+ $add_fields[ $field_options['year_field'] ] = Array('type' => 'string', 'default' => '');
+
+ $add_fields = array_merge_recursive2($add_fields, $object->VirtualFields);
+ $object->setVirtualFields($add_fields);
+ }
+
+ function UpdateSubFields($field, $value, &$options, &$object)
+ {
+ if(!$value) return false;
+ $date = explode('/', $value);
+ $object->SetDBField( $options['month_field'], $date[0] );
+ $object->SetDBField( $options['year_field'], $date[1] );
+ }
+
+ /**
+ * Will work in future if we could attach 2 formatters to one field
+ *
+ * @param string $value
+ * @param string $field_name
+ * @param kBase $object
+ * @return string
+ */
+ function Parse($value, $field_name, &$object)
+ {
+// if ( is_null($value) ) return '';
+
+ $options = $object->GetFieldOptions($field_name);
+
+ $month = $object->GetDirtyField($options['month_field']);
+ $year = $object->GetDirtyField($options['year_field']);
+
+ if( !(int)$month && !(int)$year ) return NULL;
+ $is_valid = ($month >= 1 && $month <= 12) && ($year >= 0 && $year <= 99);
+
+ if(!$is_valid) $object->FieldErrors[$field_name]['pseudo'] = 'bad_type';
+ return $month.'/'.$year;
+ }
+
+ }
+
+
+?>
Property changes on: trunk/core/kernel/utility/formatters.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/utility/unit_config_reader.php
===================================================================
--- trunk/core/kernel/utility/unit_config_reader.php (nonexistent)
+++ trunk/core/kernel/utility/unit_config_reader.php (revision 1560)
@@ -0,0 +1,384 @@
+<?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, $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)) )
+ {
+ 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(DOC_ROOT.BASE_PATH.$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 findConfigFiles($folderPath)
+ {
+ $folderPath = str_replace(DOC_ROOT.BASE_PATH, '', $folderPath);
+ $fh=opendir(DOC_ROOT.BASE_PATH.$folderPath);
+ while(($sub_folder=readdir($fh)))
+ {
+ $full_path=DOC_ROOT.BASE_PATH.$folderPath.'/'.$sub_folder;
+ if( $this->isDir($full_path))
+ {
+ if ( file_exists(DOC_ROOT.BASE_PATH.$this->getConfigName($folderPath.'/'.$sub_folder)) ) {
+ $this->configFiles[] = $this->getConfigName($folderPath.'/'.$sub_folder);
+ }
+ $this->findConfigFiles($full_path);
+
+// if (filemtime($full_path) > $cached) { }
+
+ }
+ }
+ }
+
+ function includeConfigFiles()
+ {
+ foreach ($this->configFiles as $filename) {
+ if ( defined('DEBUG_MODE') && 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(DOC_ROOT.BASE_PATH.$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(DOC_ROOT.BASE_PATH.$filename);
+ }
+
+ $prefix=$config['Prefix'];
+
+ $config['BasePath']=dirname(DOC_ROOT.BASE_PATH.$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)))
+ {
+ $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().')');
+ }
+ unset($this->configFiles);
+// unset($this->configData);
+
+ }
+
+ /**
+ * 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']);
+ }
+
+ $register_classes = getArrayValue($config,'RegisterClasses');
+ if($register_classes)
+ {
+ foreach($register_classes as $class_info)
+ {
+ $this->Application->registerClass( $class_info['class'],
+ $config['BasePath'].'/'.$class_info['file'],
+ $class_info['pseudo']);
+ //$event_manager->registerBuildEvent($class_info['pseudo'],$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 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
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/utility/configuration.php
===================================================================
--- trunk/core/kernel/utility/configuration.php (nonexistent)
+++ trunk/core/kernel/utility/configuration.php (revision 1560)
@@ -0,0 +1,87 @@
+<?php
+
+
+// need to be rewrited
+
+class ConfigItem extends kDBItem
+{
+ var $Application;
+
+ function ConfigItem($Id)
+ {
+ $this->Application =& KernelApplication::Instance();
+ $this->id_field = 'name';
+ $this->table_name = 'config';
+ $this->CreateField('name','',1,1);
+ $this->CreateField('value','',1,1);
+ $this->CreateField('config_description','', 0, 0);
+ $this->DisplayErrors = 0;
+ $this->DisplayQueries = 0;
+ parent::DBItem($Id);
+ }
+
+ function Update()
+ {
+ $ret = parent::Update();
+ // echo " update ".$this->GetDBField('name')."<br>";
+ if ( $ret AND ereg("(per_page)",$this->GetDBField('name'))) {
+ $this->Application->StoreVar(
+ $this->GetDBField('name'),
+ $this->GetDBField('value')
+ );
+ }
+ return $ret;
+ }
+}
+
+class ConfigList extends kDBList
+{
+ function ConfigList($sql, $query_now=0, $owner=null)
+ {
+ parent::kDBList($sql, $query_now, $owner);
+ $this->Special = $owner->Params['special'];
+ switch ($this->Special)
+ {
+ default:
+ $this->sql = " SELECT * FROM config ";
+ };
+ $this->DisplayQueries = 0;
+ }
+
+ function &NewItem ()
+ {
+ $new_item = new ConfigItem(NULL);
+ return $new_item;
+ }
+
+ function GetOption($name)
+ {
+ if ($this->Find('name', $name))
+ return $this->GetCurrentFieldValue('value');
+ else
+ return false;
+ }
+
+ function SetOption($name, $value)
+ {
+ if ($this->Find('name', $name)) {;
+ $this->SetCurrentFieldValue('value', $value);
+ $tmp =& $this->GetCurrentRec();
+ $tmp->Update();
+ }
+ else {
+ $push_hash = Array('name'=>$name, 'value'=>$value);
+ $id = array_push($this->Records, $push_hash);
+ if (count($this->IndexFields) > 0) {
+ foreach ($this->IndexFields as $key) {
+ if (is_string($push_hash[$key])) $store_key = strtolower($push_hash[$key]);
+ else $store_key = $push_hash[$key];
+ $this->Indexes[$key][$store_key] = $id-1;
+ }
+ }
+ $this->last_rec++;
+ }
+ }
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/configuration.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.3
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/utility/email.php
===================================================================
--- trunk/core/kernel/utility/email.php (nonexistent)
+++ trunk/core/kernel/utility/email.php (revision 1560)
@@ -0,0 +1,412 @@
+<?php
+
+class kEmailMessage extends kBase {
+
+ var $Compiled;
+ var $Headers;
+ var $HeadersArray;
+ var $BodyText;
+ var $BodyHtml;
+ var $Body;
+// var $Subject;
+// var $From;
+// var $To;
+// var $ReplyTo;
+// var $CC;
+// var $BCC;
+ var $Charset;
+ var $LineFeed;
+ var $TransferEncoding;
+ var $From;
+ var $To;
+
+
+ var $IsMultipart;
+ var $Parts;
+ var $Files;
+
+
+ var $TextBoundary;
+ var $EmailBoundary;
+
+ function kEmailMessage(){
+ //$this->TextBoundary = uniqid(time());
+ $this->EmailBoundary = uniqid(time());
+ $this->LineFeed = "\r\n";
+ $this->Charset='ISO-8859-1';
+ $this->TransferEncoding='8bit';
+ $this->Body = '';
+ $this->setHeader('Subject', 'Automatically generated message');
+ $this->HeadersArray=array();
+
+ $this->setHeader('Mime-Version', '1.0');
+ }
+
+ function setHeader($header, $value){
+ $this->HeadersArray[$header] = $value;
+ $this->Compiled = false;
+ }
+
+ function setHeaders($headers){
+ $headers=str_replace("\r", "", $headers);
+ $headers_lines = explode("\n", $headers);
+ foreach ($headers_lines as $line_num => $line){
+ list($header_field, $header_value) = explode(':', $line, 2);
+ $header_value = trim($header_value);
+ $this->setHeader($header_field, $header_value);
+ }
+
+ }
+
+ function appendHeader($header, $value){
+ $this->HeadersArray[$header][] = $value;
+ $this->Compiled = false;
+ }
+
+
+ function setFrom($from, $name=''){
+
+ $this->From = $from;
+
+ if ($name!=''){
+ $from = trim($name).' <'.$from.'>';
+ }
+ $this->setHeader('From', trim($from));
+ }
+
+ function setTo($to, $name=''){
+
+ $this->To = $to;
+
+ if ($name!=''){
+ $to = trim($name).' <'.$to.'>';
+ }
+
+ $this->setHeader('To', trim($to));
+ }
+
+ function setSubject($subj){
+ $this->setHeader('Subject', $subj);
+ }
+
+ function SetCC($to_cc){
+ $this->appendHeader('CC', $to_cc);
+ }
+
+ function SetBCC($to_bcc){
+ $this->appendHeader('BCC', $to_bcc);
+ }
+
+ function setReplyTo($reply_to){
+ $this->setHeader('Reply-to', $reply_to);
+ }
+
+ function setTextBody($body_text){
+
+ $this->BodyText = $body_text;
+ $this->Compiled = false;
+ }
+
+ function setHTMLBody($body_html){
+
+ $this->BodyHtml = $body_html;
+ $this->IsMultipart = true;
+ $this->Compiled = false;
+ }
+
+ function compileBody(){
+ if($this->BodyHtml){
+ $search = array (
+ "'(<\/td>.*)[\r\n]+(.*<td)'i",//formating text in tables
+ "'(<br[ ]?[\/]?>)|(<\/p>)|(<\/div>)|(<\/tr>)'i",
+ "'<head>(.*?)</head>'si",
+ "'<style(.*?)</style>'si",
+ "'<title>(.*?)</title>'si",
+ "'<script(.*?)</script>'si",
+// "'^[\s\n\r\t]+'", //strip all spacers & newlines in the begin of document
+// "'[\s\n\r\t]+$'", //strip all spacers & newlines in the end of document
+ "'&(quot|#34);'i",
+ "'&(amp|#38);'i",
+ "'&(lt|#60);'i",
+ "'&(gt|#62);'i",
+ "'&(nbsp|#160);'i",
+ "'&(iexcl|#161);'i",
+ "'&(cent|#162);'i",
+ "'&(pound|#163);'i",
+ "'&(copy|#169);'i",
+ "'&#(\d+);'e"
+ );
+
+ $replace = array (
+ "\\1\t\\2",
+ "\n\r",
+ "",
+ "",
+ "",
+ "",
+// "",
+// "",
+ "\"",
+ "&",
+ "<",
+ ">",
+ " ",
+ chr(161),
+ chr(162),
+ chr(163),
+ chr(169),
+ "chr(\\1)"
+ );
+
+ $not_html = preg_replace ($search, $replace, $this->BodyHtml);
+ $not_html = strip_tags($not_html);
+// $not_html = $this->removeBlankLines($not_html);
+ // Fixing problem with add exclamation characters "!" into the body of the email.
+ $not_html = wordwrap($not_html, 72);
+ $this->BodyHtml = wordwrap($this->BodyHtml, 72);
+
+
+ //$this->Body .= 'Content-Type: multipart/alternative;'.$this->LF()." ".'boundary="----='.$this->TextBoundary.'"'.$this->LF();
+ //$this->Body .= $this->LF();
+ $this->Body .= '------='.$this->EmailBoundary.$this->LF();
+ $this->Body .= 'Content-Type: text/plain;'.$this->LF()." ".'charset="'.$this->Charset.'"'.$this->LF();
+ $this->Body .= $this->LF();
+ $this->Body .= $not_html.$this->LF().$this->LF();
+ $this->Body .= '------='.$this->EmailBoundary.$this->LF();
+ $this->Body .= 'Content-Type: text/html;'.$this->LF()." ".'charset="'.$this->Charset.'"'.$this->LF();
+ $this->Body .= 'Content-Transfer-Encoding: '.$this->TransferEncoding.$this->LF();
+ $this->Body .= 'Content-Description: HTML part'.$this->LF();
+ $this->Body .= 'Content-Disposition: inline'.$this->LF();
+ $this->Body .= $this->LF();
+
+ $this->BodyHtml = str_replace("\r", "", $this->BodyHtml);
+ $this->BodyHtml = str_replace("\n", $this->LF(), $this->BodyHtml);
+
+ $this->Body .= $this->BodyHtml;
+ $this->Body .= $this->LF().$this->LF();
+
+
+ $this->IsMultipart = true;
+
+ }else{
+ if ($this->IsMultipart){
+ $this->Body .= '------='.$this->EmailBoundary.$this->LF();
+ $this->Body .= 'Content-Type: text/plain;'.$this->LF()." ".'charset="'.$this->Charset.'"'.$this->LF();
+ $this->Body .= 'Content-Disposition: inline'.$this->LF();
+ $this->Body .= $this->LF();
+ $this->Body .= $not_html.$this->LF().$this->LF();
+ }else{
+ $this->BodyText = str_replace("\r", "", $this->BodyText);
+ $this->BodyText = str_replace("\n", $this->LF(), $this->BodyText);
+ $this->Body = $this->BodyText;
+ }
+
+ }
+
+ }
+
+
+
+ function setCharset($charset){
+ $this->Charset = $charset;
+ $this->Compiled = false;
+ }
+
+ function setLineFeed($linefeed){
+ $this->LineFeed=$linefeed;
+ }
+
+
+
+ function attachFile($filepath, $mime="application/octet-stream"){
+
+ if(is_file($filepath)){
+ $file_info = array('path'=>$filepath, 'mime'=>$mime);
+ $this->Files[] = $file_info;
+ }else{
+ die('File "'.$filepath.'" not exist...'."\n");
+ }
+
+ $this->IsMultipart = true;
+ $this->Compiled = false;
+ }
+
+ function LF($str=''){
+ $str = str_replace("\n", "", $str);
+ $str = str_replace("\r", "", $str);
+ return $str.$this->LineFeed;
+ }
+
+ function getContentType(){
+ $content_type="";
+ if ($this->IsMultipart){
+ $content_type .= $this->LF('multipart/alternative;');
+ $content_type .= $this->LF(" ".'boundary="----='.$this->EmailBoundary.'"');
+ }else{
+ $content_type .= $this->LF('text/plain;');
+ $content_type .= $this->LF(" ".'charset='.$this->Charset);
+ }
+
+ return $content_type;
+
+ }
+
+ // ========================================
+
+ function compileHeaders(){
+
+ $this->Headers="";
+
+// $this->Headers .= "From: ".$this->LF($this->From);
+ //if ($this->ReplyTo){
+// $this->Headers .= "Reply-To: ".$this->ReplyTo.$this->LF();
+ //}
+ //$this->Headers .= "To: ".$this->LF($this->To);
+ //$this->Headers .= "Subject: ".$this->LF($this->Subject);
+ /*
+ if (sizeof($this->CC)){
+ $this->Headers .= "Cc: ";
+ foreach ($this->Cc as $key => $addr){
+ $this->Headers.=$this->LF($addr.',');
+ }
+ }
+
+ if (sizeof($this->BCC)){
+ $this->Headers .= "Bcc: ";
+ foreach ($this->BCC as $key => $addr){
+ $this->Headers.=$this->LF($addr.',');
+ }
+ }
+ */
+
+ foreach ($this->HeadersArray as $key => $val){
+ if ($key=="To" || $key=="") continue; // avoid duplicate "To" field in headers
+ if (is_array($val)){
+ $val = chunk_split(implode(', ', $val),72, $this->LF().' ');
+
+
+ $this->Headers .= $key.": ".$val.$this->LF();
+ }else{
+ $this->Headers .= $key.": ".$val.$this->LF();
+ }
+
+ }
+
+ $this->Headers .= "Content-Type: ".$this->getContentType();
+
+ //$this->Headers .= "Content-Transfer-Encoding: ".$this->TransferEncoding.$this->LF();
+
+
+ }
+
+ function compileFiles(){
+ if ($this->Files){
+ foreach($this->Files as $key => $file_info)
+ {
+ $filepath = $file_info['path'];
+ $mime = $file_info['mime'];
+ $attachment_header = $this->LF('------='.$this->EmailBoundary);
+ $attachment_header .= $this->LF('Content-Type: '.$mime.'; name="'.basename($filepath).'"');
+ $attachment_header .= $this->LF('Content-Transfer-Encoding: base64');
+ $attachment_header .= $this->LF('Content-Description: '.basename($filepath));
+ $attachment_header .= $this->LF('Content-Disposition: attachment; filename="'.basename($filepath).'"');
+ $attachment_header .= $this->LF('');
+
+ $attachment_data = fread(fopen($filepath,"rb"),filesize($filepath));
+ $attachment_data = base64_encode($attachment_data);
+ $attachment_data = chunk_split($attachment_data,72);
+
+ $this->Body .= $attachment_header.$attachment_data.$this->LF('');
+ $this->IsMultipart = true;
+ }
+ }
+ }
+
+ function compile(){
+
+ if ($this->Compiled) return;
+
+ $this->compileBody();
+
+ $this->compileFiles();
+
+ $this->compileHeaders();
+
+ // Compile
+ if ($this->IsMultipart){
+ $this->Body .= '------='.$this->EmailBoundary.'--'.$this->LF();
+ }
+
+ $this->Compiled = true;
+ }
+
+ // ========================================
+
+ function getHeaders(){
+
+ $this->Compile();
+ return $this->Headers;
+ }
+
+ function getBody(){
+
+ $this->Compile();
+ return $this->Body;
+ }
+
+ function send(){
+
+ //mail($this->HeadersArray['To'], $this->HeadersArray['Subject'], "", $this->getHeaders().$this->LF().$this->LF().$this->getBody());
+ return mail($this->HeadersArray['To'], $this->HeadersArray['Subject'], "", $this->getHeaders().$this->LF().$this->LF().$this->getBody(), '-f'.$this->From);
+
+ }
+
+ function sendSMTP(&$smtp_object, $smtp_host, $user, $pass, $auth_used = 0){
+
+ $params['host'] = $smtp_host; // The smtp server host/ip
+ $params['port'] = 25; // The smtp server port
+ $params['helo'] = $_SERVER['HTTP_HOST']; // What to use when sending the helo command. Typically, your domain/hostname
+ $params['auth'] = TRUE; // Whether to use basic authentication or not
+ $params['user'] = $user; // Username for authentication
+
+
+ $params['pass'] = $pass; // Password for authentication
+ $params['debug'] = 1;
+ if ($auth_used == 0){
+ $params['authmethod'] = 'NOAUTH'; // forse disabling auth
+ }
+
+
+ $send_params['recipients'] = array($this->To); // The recipients (can be multiple)
+ $send_params['headers'] = array(
+ 'From: '.$this->HeadersArray['From'], // Headers
+ 'To: '.$this->HeadersArray['To'],
+ 'Subject: '.$this->HeadersArray['Subject'],
+ 'Content-type: '.$this->getContentType(),
+ $this->getBody(),
+ );
+ $send_params['from'] = $this->From; // This is used as in the MAIL FROM: cmd
+ // It should end up as the Return-Path: header
+ $send_params['body']="\r\n";
+
+
+ if($smtp_object->connect($params) && $smtp_object->send($send_params)){
+ return true;
+ }else {
+
+ if (defined('DEBUG_MODE')){
+ global $debugger;
+ $debugger->appendHTML('<pre>'.$smtp_object->debugtext.'</pre>');
+ //define('DBG_REDIRECT', 1);
+ }
+ return false;
+ }
+
+ }
+
+
+}
+
+
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/utility/email.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 (nonexistent)
+++ trunk/core/kernel/utility/factory.php (revision 1560)
@@ -0,0 +1,214 @@
+<?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] : '';
+ $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'];
+ $name=rtrim($name,'.');
+ if( isset($this->Storage[$name]) ) return $this->Storage[$name];
+
+ if(!isset($this->realClasses[$pseudo_class]))
+ {
+ if( $this->Application->isDebugMode() ) $GLOBALS['debugger']->appendTrace();
+ trigger_error('RealClass not defined for pseudo_class <b>'.$pseudo_class.'</b>', E_USER_ERROR);
+ }
+
+ $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]) trigger_error('Real Class <b>'.$real_class.'</b> is not registered with the Factory', E_USER_ERROR);
+ if(!file_exists($this->Files[$real_class])) trigger_error('Include file for class <b>'.$real_class.'</b> (<b>'.$this->Files[$real_class].'</b>) does not exists', E_USER_ERROR);
+
+ 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.
+ * 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);
+
+ $mem_before = memory_get_usage();
+ $time_before = getmicrotime();
+
+ if( func_num_args() == 1 )
+ {
+ $class =& new $real_class();
+ }
+ else
+ {
+ $func_args = func_get_args();
+ $pseudo_class = array_shift($func_args);
+
+ $class =& call_user_func_array( Array($real_class,'makeClass'), $func_args );
+ }
+
+ if (defined('DEBUG_MODE') && DEBUG_MODE && dbg_ConstOn('DBG_PROFILE_MEMORY') )
+ {
+ $mem_after = memory_get_usage();
+ $time_after = getmicrotime();
+ $mem_used = $mem_after - $mem_before;
+ $time_used = $time_after - $time_before;
+ global $debugger;
+ $debugger->appendHTML('Factroy created <b>'.$real_class.'</b> - used '.round($mem_used/1024, 3).'Kb time: '.round($time_used, 5));
+ $debugger->profilerAddTotal('objects', null, $mem_used);
+ }
+ return $class;
+
+ }
+
+ /**
+ * 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
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ 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 1560)
@@ -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.4
\ 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 (nonexistent)
+++ trunk/core/kernel/event_handler.php (revision 1560)
@@ -0,0 +1,136 @@
+<?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()
+ {
+
+ }
+
+ function getPrefixSpecial()
+ {
+ trigger_error('Usage of getPrefixSpecial() this method is forbidden in kEventHandler class children. Use $event->getPrefixSpecial(true); instead', E_USER_ERROR);
+ }
+
+ /**
+ * 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)
+ {
+ $event_name=$event->Name;
+ if( isset($this->eventMethods[$event_name]) ) $event_name=$this->eventMethods[$event_name];
+
+ if( method_exists($this,$event_name) )
+ {
+ $this->$event_name($event);
+ }
+ else
+ {
+ trigger_error('event <b>'.$event->Name.'</b> not implemented in class <b>'.get_class($this).'</b>', E_USER_ERROR);
+ }
+ }
+
+ /**
+ * 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, $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
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.5
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/db/db_tag_processor.php
===================================================================
--- trunk/core/kernel/db/db_tag_processor.php (nonexistent)
+++ trunk/core/kernel/db/db_tag_processor.php (revision 1560)
@@ -0,0 +1,1195 @@
+<?php
+
+class kDBTagProcessor extends TagProcessor {
+
+ /**
+ * Description
+ *
+ * @var DBConnection
+ * @access public
+ */
+ var $Conn;
+
+ function kDBTagProcessor()
+ {
+ parent::kBase();
+ $this->Conn =& $this->Application->GetADODBConnection();
+ }
+
+
+ function IsNew($params)
+ {
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial(), $this->Prefix, $params );
+ return $object->GetID();
+ }
+
+ /**
+ * 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);
+ }
+
+ function ViewMenu($params)
+ {
+ $block_params = $params;
+ unset($block_params['block']);
+ $block_params['name'] = $params['block'];
+
+ $list =& $this->GetList($params);
+ $block_params['PrefixSpecial'] = $list->getPrefixSpecial();
+ return $this->Application->ParseBlock($block_params);
+ }
+
+
+ function SearchKeyword($params)
+ {
+ $list =& $this->GetList($params);
+ return $this->Application->RecallVar($list->getPrefixSpecial().'_search_keyword');
+ }
+
+ /**
+ * 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);
+ $list =& $this->GetList($params);
+ $id_field = $this->Application->getUnitOption($this->Prefix,'IDField');
+
+ $list->Query();
+ $o = '';
+ $list->GoFirst();
+
+ $block_params=$this->prepareTagParams($params);
+ $block_params['name'] = $this->SelectParam($params, 'render_as,block');
+ $block_params['pass_params'] = 'true';
+
+ 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;
+ }
+
+ function InitList($params)
+ {
+ $list_name = $params['list_name'];
+
+ $names_mapping = $this->Application->GetVar('NamesToSpecialMapping');
+
+ if( !getArrayValue($names_mapping,$list_name) )
+ {
+ $list =& $this->GetList($params);
+ }
+ }
+
+ function BuildListSpecial($params)
+ {
+ return $this->Special;
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param unknown_type $params
+ * @return kDBList
+ */
+ function &GetList($params)
+ {
+ $list_name = $this->SelectParam($params, 'list_name,name');
+ if (!$list_name) {
+ $list_name = $this->Application->Parser->GetParam('list_name');
+ }
+
+ $requery = getArrayValue($params, 'requery');
+ if ($list_name && !$requery){
+ $names_mapping = $this->Application->GetVar('NamesToSpecialMapping');
+
+ $special = getArrayValue($names_mapping, $list_name);
+ if(!$special)
+ {
+ $special = $this->BuildListSpecial($params);
+ }
+ }
+ else
+ {
+ $special = $this->BuildListSpecial($params);
+ }
+
+ $prefix_special = rtrim($this->Prefix.'.'.$special, '.');
+ $params['skip_counting'] = true;
+ $list =& $this->Application->recallObject( $prefix_special, $this->Prefix.'_List',$params);
+ $list->Query();
+ $this->Special = $special;
+
+ if ($list_name) {
+ $names_mapping[$list_name] = $special;
+ $this->Application->SetVar('NamesToSpecialMapping', $names_mapping);
+ }
+
+ return $list;
+ }
+
+ function ListMarker($params)
+ {
+ $list =& $this->GetList($params);
+ return $list->getPrefixSpecial();
+ }
+
+ function SubmitName($params)
+ {
+ $list =& $this->GetList($params);
+
+ $prefix_special = $list->getPrefixSpecial();
+
+ return 'events['.$prefix_special.']['.$params['event'].']';
+ }
+
+
+ function CombinedSortingDropDownName($params)
+ {
+ $list =& $this->GetList($params);
+ $prefix_special = $list->getPrefixSpecial();
+
+ return $prefix_special.'_CombinedSorting';
+ }
+
+ function SortingSelected($params)
+ {
+ $list =& $this->GetList($params);
+ $user_sorting_start = $this->getUserSortIndex();
+
+ $sorting = strtolower($list->GetOrderField($user_sorting_start).'|'.$list->GetOrderDirection($user_sorting_start));
+
+ if ($sorting == strtolower($params['sorting'])) return $params['selected'];
+ }
+
+
+
+ /**
+ * Prints list content using block specified
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function PrintList2($params)
+ {
+ $per_page = $this->SelectParam($params, 'per_page,max_items');
+ if ($per_page !== false) $params['per_page'] = $per_page;
+
+ $list =& $this->GetList($params);
+ $o = '';
+
+ $direction = (isset($params['direction']) && $params['direction']=="H")?"H":"V";
+ $columns = (isset($params['columns'])) ? $params['columns'] : 1;
+ $id_field = (isset($params['id_field'])) ? $params['id_field'] : $this->Application->getUnitOption($this->Prefix, 'IDField');
+
+ if ($columns>1 && $direction=="V") {
+ $list->Records = $this->LinearToVertical($list->Records, $columns, $list->GetPerPage());
+ $list->SelectedCount=count($list->Records);
+ ksort($list->Records);
+ }
+
+ $list->GoFirst();
+
+ $block_params=$this->prepareTagParams($params);
+ $block_params['name']=$this->SelectParam($params, 'render_as,block');
+ $block_params['pass_params']='true';
+
+ $block_start_row_params=$this->prepareTagParams($params);
+ $block_start_row_params['name'] = $this->SelectParam($params, 'row_start_render_as,block_row_start,row_start_block');
+
+ $block_end_row_params=$this->prepareTagParams($params);
+ $block_end_row_params['name'] = $this->SelectParam($params, 'row_end_render_as,block_row_end,row_end_block');
+
+ $block_empty_cell_params = $this->prepareTagParams($params);
+ $block_empty_cell_params['name'] = $this->SelectParam($params, 'empty_cell_render_as,block_empty_cell,empty_cell_block');
+
+ $i=0;
+
+ $backup_id=$this->Application->GetVar($this->Prefix."_id");
+ $displayed = array();
+ while (!$list->EOL())
+ {
+ $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 % $columns == 0) {
+ $o.= $block_start_row_params['name'] ? $this->Application->ParseBlock($block_start_row_params, 1) : '<tr>';
+ }
+
+ if (!$list->getCurrentRecord()){
+ $o.= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_params, 1) : '<td>&nbsp;</td>';
+ }
+ else {
+ $o.= $this->Application->ParseBlock($block_params, 1);
+ array_push($displayed, $list->GetDBField($id_field));
+ }
+
+ if (($i+1) % $columns == 0) {
+ $o.= $block_end_row_params['name'] ? $this->Application->ParseBlock($block_end_row_params, 1) : '</tr>';
+ }
+
+ $list->GoNext();
+
+ $i++;
+ }
+ $cur_displayed = $this->Application->GetVar($this->Prefix.'_displayed_ids');
+ if (!$cur_displayed) {
+ $cur_displayed = Array();
+ }
+ else {
+ $cur_displayed = explode(',', $cur_displayed);
+ }
+
+ $displayed = array_unique(array_merge($displayed, $cur_displayed));
+ $this->Application->SetVar($this->Prefix.'_displayed_ids', implode(',',$displayed));
+
+ $this->Application->SetVar( $this->Prefix.'_id', $backup_id);
+ $this->Application->SetVar( $this->getPrefixSpecial().'_id', '');
+
+ if (isset($params['more_link_render_as'])) {
+ $block_params = $params;
+ $params['render_as'] = $params['more_link_render_as'];
+ $o .= $this->MoreLink($params);
+ }
+
+ return $o;
+ }
+
+ function MoreLink($params)
+ {
+ $per_page = $this->SelectParam($params, 'per_page,max_items');
+ if ($per_page !== false) $params['per_page'] = $per_page;
+ $list =& $this->GetList($params);
+ if ($list->PerPage < $list->RecordsCount) {
+ $block_params = array();
+ $block_params['name'] = $this->SelectParam($params, 'render_as,block');
+ return $this->Application->ParseBlock($block_params, 1);
+ }
+ }
+
+ function NotLastItem($params)
+ {
+ $list =& $this->Application->recallObject($this->getPrefixSpecial());
+
+ return ($list->CurrentIndex < min($list->PerPage, $list->RecordsCount)-1);
+ }
+
+ function PageLink($params)
+ {
+ $t = isset($params['template']) ? $param['template'] : '';
+ if (!$t) $t = $this->Application->GetVar('t');
+
+ if (isset($params['page'])) {
+ $this->Application->SetVar($this->getPrefixSpecial().'_Page', $params['page']);
+ }
+
+ $pass = Array('pass' => 'all,'.$this->getPrefixSpecial());
+// $pass = Array('pass' => 'all');
+ $http_query =& $this->Application->recallObject('HTTPQuery');
+ $get = $http_query->Get;
+ unset($get['env']);
+// $pass = array_merge($get, $pass);
+
+ return $this->Application->HREF($t, '', $pass);
+ }
+
+ function ColumnWidth($params)
+ {
+ $columns = $this->Application->Parser->GetParam('columns');
+ return round(100/$columns).'%';
+ }
+
+ /**
+ * 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=Array())
+ {
+ $ret=$tag_params;
+ $ret['Prefix']=$this->Prefix;
+ $ret['prefix']=$this->Prefix;
+ $ret['Special']=$this->Special;
+ $ret['special']=$this->Special;
+ $ret['PrefixSpecial']=$this->getPrefixSpecial();
+ return $ret;
+ }
+
+ function GetISO($currency)
+ {
+ if ($currency == 'selected') {
+ $iso = $this->Application->RecallVar('curr_iso');
+ }
+ elseif ($currency == 'primary' || $currency == '') {
+ $iso = $this->Application->GetPrimaryCurrency();
+ }
+ else { //explicit currency
+ $iso = $currency;
+ }
+ return $iso;
+ }
+
+ function ConvertCurrency($value, $iso)
+ {
+ $converter =& $this->Application->recallObject('kCurrencyRates');
+ // convery primary currency to selected (if they are the same, converter will just return)
+ $value = $converter->Convert($value, 'PRIMARY', $iso);
+ return $value;
+ }
+
+ function AddCurrencySymbol($value, $iso)
+ {
+ $this->Application->setUnitOption('curr', 'AutoLoad', false);
+ $currency =& $this->Application->recallObject('curr.-'.$iso);
+ if (!$currency->Loaded) {
+ $currency->Load($iso, 'ISO');
+ }
+
+ $symbol = $currency->GetDBField('Symbol');
+ if (!$symbol) $symbol = $currency->GetDBField('ISO').'&nbsp;';
+ if ($currency->GetDBField('SymbolPosition') == 0) {
+ $value = $symbol.$value;
+ }
+ if ($currency->GetDBField('SymbolPosition') == 1) {
+ $value = $value.$symbol;
+ }
+ return $value;
+ }
+
+ /**
+ * Get's requested field value
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function Field($params)
+ {
+ $field = $this->SelectParam($params, 'name,field');
+
+ if( !$this->Application->IsAdmin() ) $params['no_special'] = 'no_special';
+
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ if ( getArrayValue($params, 'db') !== false )
+ {
+ $value = $object->GetDBField($field);
+ }
+ else
+ {
+ if (isset($params['currency'])) {
+ $iso = $this->GetISO($params['currency']);
+ $original = $object->GetDBField($field);
+ $value = $this->ConvertCurrency($original, $iso);
+ $object->SetDBField($field, $value);
+ $object->Fields[$field]['converted'] = true;
+ }
+
+ $format = getArrayValue($params, 'format');
+ if( !$format || $format == '$format' )
+ {
+ $format = null;
+ }
+ else
+ {
+ if(preg_match("/_regional_(.*)/", $format, $regs))
+ {
+ $lang =& $this->Application->recallObject('lang.current');
+ $format = $lang->GetDBField($regs[1]);
+ }
+ }
+ $value = $object->GetField($field, $format);
+
+ if (isset($params['currency'])) {
+ $value = $this->AddCurrencySymbol($value, $iso);
+ $params['no_special'] = 1;
+ }
+ }
+
+ if( getArrayValue($params,'nl2br' ) ) $value = nl2br($value);
+ if( !$this->HasParam($params, 'no_special') ) $value = htmlspecialchars($value);
+ if( getArrayValue($params,'checked' ) ) $value = ($value == 1) ? 'checked' : '';
+ if( getArrayValue($params,'as_label') ) $value = $this->Application->Phrase($value);
+
+ $first_chars = $this->SelectParam($params,'first_chars,cut_first');
+ if($first_chars)
+ {
+ $needs_cut = strlen($value) > $first_chars;
+ $value = substr($value,0,$first_chars);
+ if($needs_cut) $value .= ' ...';
+ }
+
+ if ($value != '') $this->Application->Parser->DataExists = true;
+
+ if (isset($params['currency'])) {
+ //restoring value in original currency, for other Field tags to work properly
+ $object->SetDBField($field, $original);
+ }
+
+ return $value;
+ }
+
+ function HasParam($params, $param_name)
+ {
+ $value = getArrayValue($params, $param_name);
+ return $value && ($value != '$'.$param_name);
+ }
+
+ function PhraseField($params)
+ {
+ $field_label = $this->Field($params);
+ $translation = $this->Application->Phrase( $field_label );
+ return $translation;
+ }
+
+ function Error($params)
+ {
+ $field = $params['field'];
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ $msg = $object->GetErrorMsg($field);
+
+ return $msg;
+ }
+
+ function HasError($params)
+ {
+ if ($params['field'] == 'any') {
+ $object =& $this->Application->recallObject($this->getPrefixSpecial());
+ return $object->HasErrors();
+ }
+ else {
+ 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 = $this->prepareTagParams($params);
+
+ $block_params['name'] = $this->SelectParam($params, 'render_as,block');
+ $block_params['field'] = $params['field'];
+ $block_params['pass_params'] = 'true';
+
+ $selected_param_name = getArrayValue($params,'selected_param');
+ if(!$selected_param_name) $selected_param_name = $params['selected'];
+ $selected = $params['selected'];
+
+ $o = '';
+ if( $this->HasParam($params,'no_empty') && !getArrayValue($options['options'],'') ) array_shift($options['options']);
+ foreach ($options['options'] as $key => $val) {
+ $block_params['key'] = $key;
+ $block_params['option'] = $val;
+ $block_params['field_name'] = $this->InputName($params);
+ $block_params[$selected_param_name] = ( $key == $value ? ' '.$selected : '');
+ $block_params['PrefixSpecial'] = $this->getPrefixSpecial();
+ $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);
+
+ $formatter_class = getArrayValue($options,'formatter');
+ if($formatter_class)
+ {
+ $formatter =& $this->Application->recallObject($formatter_class);
+ $human_format = getArrayValue($params,'human');
+ $edit_size = getArrayValue($params,'edit_size');
+ $sample = getArrayValue($params,'sample');
+ if($sample)
+ {
+ return $formatter->GetSample($field, $options, $object);
+ }
+ elseif($human_format || $edit_size)
+ {
+ $format = $formatter->HumanFormat($options['format']);
+ return $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)
+ {
+ $list =& $this->GetList($params);
+ $prefix_special = $list->getPrefixSpecial();
+ $total_pages = $list->GetTotalPages();
+
+ if ($total_pages) $this->Application->Parser->DataExists = true;
+
+ $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');
+
+ $block_params = $this->prepareTagParams($params);
+
+ $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_pages) {
+ $split_end = $total_pages;
+ $split_start = max($split_end - $split + 1, 1);
+ }
+
+ if ($current_page > 1){
+ $prev_block_params = $this->prepareTagParams();
+
+ if ($total_pages > $split){
+ $prev_block_params['page'] = max($current_page-$split, 1);
+ $prev_block_params['name'] = $this->SelectParam($params, 'prev_page_split_render_as,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'] = $this->SelectParam($params, 'prev_page_render_as,block_prev_page,prev_page_block');
+ if ($prev_block_params['name']) {
+ $this->Application->SetVar($this->getPrefixSpecial().'_Page', $current_page-1);
+ $o .= $this->Application->ParseBlock($prev_block_params, 1);
+ }
+ }
+ else {
+ if ( $no_prev_page_block = $this->SelectParam($params, 'no_prev_page_render_as,block_no_prev_page') ) {
+ $block_params['name'] = $no_prev_page_block;
+ $o .= $this->Application->ParseBlock($block_params, 1);
+ }
+ }
+
+ $separator_params['name'] = $this->SelectParam($params, 'separator_render_as,block_separator');
+ for ($i = $split_start; $i <= $split_end; $i++)
+ {
+ if ($i == $current_page) {
+ $block = $this->SelectParam($params, 'current_render_as,active_render_as,block_current,active_block');
+ }
+ else {
+ $block = $this->SelectParam($params, 'link_render_as,inactive_render_as,block_link,inactive_block');
+ }
+
+ $block_params['name'] = $block;
+ $block_params['page'] = $i;
+ $this->Application->SetVar($this->getPrefixSpecial().'_Page', $i);
+ $o .= $this->Application->ParseBlock($block_params, 1);
+
+ if ($this->SelectParam($params, 'separator_render_as,block_separator')
+ && $i < $split_end)
+ {
+ $o .= $this->Application->ParseBlock($separator_params, 1);
+ }
+ }
+
+ if ($current_page < $total_pages){
+ $next_block_params = $this->prepareTagParams();
+ $next_block_params['page']=$current_page+1;
+ $next_block_params['name'] = $this->SelectParam($params, 'next_page_render_as,block_next_page,next_page_block');
+ if ($next_block_params['name']){
+ $this->Application->SetVar($this->getPrefixSpecial().'_Page', $current_page+1);
+ $o .= $this->Application->ParseBlock($next_block_params, 1);
+ }
+ if ($total_pages > $split){
+ $next_block_params['page']=min($current_page+$split, $total_pages);
+ $next_block_params['name'] = $this->SelectParam($params, 'next_page_split_render_as,next_page_split_block');
+ if ($next_block_params['name']){
+ $o .= $this->Application->ParseBlock($next_block_params, 1);
+ }
+ }
+ }
+
+ return $o;
+ }
+
+ /**
+ * Print grid pagination using
+ * block names specified
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function PaginationBar($params)
+ {
+ return $this->PrintPages($params);
+ }
+
+ /**
+ * 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();
+ $object =& $this->Application->recallObject($prefix_special);
+
+ if ( $formatter = getArrayValue($object->Fields, $params['field'], 'formatter') ) {
+ if ( $formatter == 'kMultiLanguage' ) {
+ $formatter =& $this->Application->recallObject($formatter);
+ $params['field'] = $formatter->LangFieldName($params['field']);
+ }
+ }
+
+ if ( $idfield = getArrayValue($params, 'IdField') ) {
+ $id = $object->GetDBField($idfield);
+ }
+ else {
+ $id = $object->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();
+
+ $list =& $this->GetList($params);
+
+ if ($list->GetOrderField($user_sorting_start) == $field)
+ {
+ return strtolower($list->GetOrderDirection($user_sorting_start));
+ }
+ elseif($list->GetOrderField($user_sorting_start+1) == $field)
+ {
+ return '2_'.strtolower($list->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'];
+ $list =& $this->GetList($params);
+// $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+
+ if($params['type'] == 'field') return $list->GetOrderField($user_sorting_start);
+ if($params['type'] == 'direction') return $list->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($this->SelectParam($params, 'name,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,false);
+
+ // 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->Prefix;
+ $object =& $this->Application->recallObject( $prefix );
+
+ $field = $this->SelectParam($params, 'name,field');
+
+ $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 = "'.$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;
+ }
+
+ /**
+ * If data was modfied & is in TempTables mode, then parse block with name passed;
+ * remove modification mark if not in TempTables mode
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ * @author Alexey
+ */
+ function SaveWarning($params)
+ {
+ $main_prefix = getArrayValue($params, 'main_prefix');
+ if($main_prefix && $main_prefix != '$main_prefix')
+ {
+ $top_prefix = $main_prefix;
+ }
+ else
+ {
+ $top_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
+ }
+
+ $temp_tables = $this->Application->GetVar($top_prefix.'_mode') == 't';
+ $modified = $this->Application->RecallVar($top_prefix.'_modified');
+
+ if($temp_tables && $modified)
+ {
+ return $this->Application->ParseBlock($params);
+ }
+ $this->Application->RemoveVar($top_prefix.'_modified');
+ return '';
+ }
+
+ /**
+ * Returns list record count queries (on all pages)
+ *
+ * @param Array $params
+ * @return int
+ */
+ function TotalRecords($params)
+ {
+ $list =& $this->GetList($params);
+ if (!$list->Counted) $list->CountRecs();
+ return $list->RecordsCount;
+ }
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/db/db_tag_processor.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.5
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/db/dblist.php
===================================================================
--- trunk/core/kernel/db/dblist.php (nonexistent)
+++ trunk/core/kernel/db/dblist.php (revision 1560)
@@ -0,0 +1,686 @@
+<?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 (system+user filters)
+ *
+ * @var int
+ * @access public
+ */
+ var $RecordsCount;
+
+
+ /**
+ * Records count with system filters only applied
+ *
+ * @var int
+ * @access private
+ */
+ var $NoFilterCount = 0;
+
+ /**
+ * Record count selected to be
+ * showed on current page
+ *
+ * @var int
+ */
+ var $SelectedCount=0;
+
+ /**
+ * Array of records selected
+ *
+ * @var Array
+ * @access private
+ */
+ var $Records;
+
+ var $CurrentIndex = 0;
+
+ /**
+ * List items per-page
+ *
+ * @var int
+ * @access public
+ */
+ var $PerPage;
+
+ /**
+ * Pages count in list based on PerPage & RecordsCount attributes
+ *
+ * @var int
+ * @access public
+ */
+ var $TotalPages;
+
+ /**
+ * Description
+ *
+ * @var int
+ * @access public
+ */
+
+ var $Direction;
+ /**
+ * Holds current page number - used when forming LIMIT clause of SELECT statement
+ *
+ * @var int
+ * @access public
+ */
+ var $Page;
+
+ /**
+ * Holds offset for LIMIT clause, calculated in {@link kDBList::PerPage()}
+ *
+ * @var int
+ * @access private
+ */
+ var $Offset;
+
+ /**
+ * Count SQL was already issued on query
+ *
+ * @var bool
+ * @access private
+ */
+ var $hasCounted = false;
+
+ /**
+ * Holds list WHERE filter object
+ *
+ * @var kMultipleFilter
+ * @access private
+ */
+ var $WhereFilter = Array(FLT_SYSTEM => null, FLT_NORMAL => null, FLT_SEARCH => null, FLT_VIEW => null);
+
+ /**
+ * Holds list HAVING filter object
+ *
+ * @var kMultipleFilter
+ * @access private
+ */
+ var $HavingFilter = Array(FLT_SYSTEM => null, FLT_NORMAL => null, FLT_SEARCH => null, FLT_VIEW => null);
+
+ var $GroupByFields = Array();
+
+ var $Queried = false;
+ var $Counted = false;
+
+ /**
+ * Creates kDBList
+ *
+ * @return kDBList
+ */
+ function kDBList() {
+ parent::kDBBase();
+ $this->OrderFields = Array();
+
+ $this->WhereFilter[FLT_SYSTEM] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
+ $this->WhereFilter[FLT_NORMAL] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
+
+ $this->WhereFilter[FLT_SEARCH] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
+ $this->WhereFilter[FLT_SEARCH]->setType(FLT_TYPE_OR);
+
+ $this->WhereFilter[FLT_VIEW] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
+
+ $this->HavingFilter[FLT_SYSTEM] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
+ $this->HavingFilter[FLT_NORMAL] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
+
+ $this->HavingFilter[FLT_SEARCH] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
+ $this->HavingFilter[FLT_SEARCH]->setType(FLT_TYPE_OR);
+
+ $this->HavingFilter[FLT_VIEW] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
+
+ $this->PerPage = -1;
+ }
+
+ /**
+ * Adds new or replaces old filter with same name
+ *
+ * @param string $name filter name (for internal use)
+ * @param string $clause where/having clause part (no OR/AND allowed)
+ * @param int $filter_type is filter having filter or where filter
+ * @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW
+ * @access public
+ */
+ function addFilter($name, $clause, $filter_type = WHERE_FILTER, $filter_scope = FLT_SYSTEM)
+ {
+ $filter_name = ($filter_type == WHERE_FILTER) ? 'WhereFilter' : 'HavingFilter';
+
+ $filter =& $this->$filter_name;
+ $filter =& $filter[$filter_scope];
+ $filter->addFilter($name,$clause);
+ }
+
+ /**
+ * Removes specified filter from filters list
+ *
+ * @param string $name filter name (for internal use)
+ * @param int $filter_type is filter having filter or where filter
+ * @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW
+ * @access public
+ */
+ function removeFilter($name, $filter_type = WHERE_FILTER, $filter_scope = FLT_SYSTEM)
+ {
+ $filter_name = ($filter_type == WHERE_FILTER) ? 'WhereFilter' : 'HavingFilter';
+
+ $filter =& $this->$filter_name;
+ $filter =& $filter[$filter_scope];
+ $filter->removeFilter($name);
+ }
+
+ /**
+ * Clear list filters
+ *
+ * @param bool $user clear user filters
+ * @param bool $system clear system filters
+ */
+ function clearFilters($user=true,$system=true,$search=true,$view=true)
+ {
+ if($system)
+ {
+ $this->WhereFilter[FLT_SYSTEM]->clearFilters();
+ $this->HavingFilter[FLT_SYSTEM]->clearFilters();
+ }
+ if($user)
+ {
+ $this->WhereFilter[FLT_NORMAL]->clearFilters();
+ $this->HavingFilter[FLT_NORMAL]->clearFilters();
+ }
+ if($search)
+ {
+ $this->WhereFilter[FLT_SEARCH]->clearFilters();
+ $this->HavingFilter[FLT_SEARCH]->clearFilters();
+ }
+ if($view)
+ {
+ $this->WhereFilter[FLT_VIEW]->clearFilters();
+ $this->HavingFilter[FLT_VIEW]->clearFilters();
+ }
+ }
+
+ /**
+ * Counts the total number of records base on the query resulted from {@link kDBList::GetSelectSQL()}
+ *
+ * The method modifies the query to substitude SELECT part (fields listing) with COUNT(*).
+ * Special care should be applied when working with lists based on grouped queries, all aggregate function fields
+ * like SUM(), AVERAGE() etc. should be added to CountedSQL by using {@link kDBList::SetCountedSQL()}
+ *
+ * @access public
+ * @param string
+ * @return void
+ */
+ function CountRecs()
+ {
+ $all_sql = $this->GetSelectSQL(true,false);
+ $sql = $this->getCountSQL($all_sql);
+ $this->RecordsCount = (int)$this->Conn->GetOne($sql);
+
+ $system_sql = $this->GetSelectSQL(true,true);
+ if ($system_sql == $all_sql) { //no need to query the same again
+ $this->NoFilterCount = $this->RecordsCount;
+ return;
+ }
+ $sql = $this->getCountSQL($system_sql);
+ $this->NoFilterCount = (int)$this->Conn->GetOne($sql);
+ $this->Counted = true;
+ }
+
+ function getCountSQL($sql)
+ {
+ if ( preg_match("/DISTINCT(.*?)FROM(?!_)/is",$sql,$regs ) )
+ {
+ return preg_replace("/^.*SELECT DISTINCT(.*?)FROM(?!_)/is", "SELECT COUNT(DISTINCT ".$regs[1].") AS count FROM", $sql);
+ }
+ else
+ {
+ return preg_replace("/^.*SELECT(.*?)FROM(?!_)/is", "SELECT COUNT(*) AS count FROM ", $sql);
+ }
+ }
+
+ /**
+ * Queries the database with SQL resulted from {@link kDBList::GetSelectSQL()} and stores result in {@link kDBList::SelectRS}
+ *
+ * All the sorting, pagination, filtration of the list should be set prior to calling Query().
+ *
+ * @access public
+ * @param string
+ * @return void
+ */
+ function Query($force=false)
+ {
+ if (!$force && $this->Queried) return true;
+ $q = $this->GetSelectSQL();
+ 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);
+
+ //in case we have not counted records try to select one more item to find out if we have something more than perpage
+ $limit = $this->Counted ? $this->PerPage : $this->PerPage+1;
+
+ $sql = $q.' '.$this->Conn->getLimitClause($this->Offset,$limit);
+
+ $this->Records = $this->Conn->Query($sql);
+ $this->SelectedCount = count($this->Records);
+ if (!$this->Counted) $this->RecordsCount = $this->SelectedCount;
+ if (!$this->Counted && $this->SelectedCount > $this->PerPage && $this->PerPage != -1) $this->SelectedCount--;
+
+ if ($this->Records === false) {
+ //handle errors here
+ return false;
+ }
+ $this->Queried = true;
+ return true;
+ }
+
+ /**
+ * Builds full select query except for LIMIT clause
+ *
+ * @access public
+ * @return string
+ */
+ function GetSelectSQL($for_counting=false,$system_filters_only=false)
+ {
+ $q = parent::GetSelectSQL($this->SelectClause);
+ if(!$for_counting) $q = $this->addCalculatedFields($q);
+
+ $where = $this->GetWhereClause($for_counting,$system_filters_only);
+ $having = $this->GetHavingClause($for_counting,$system_filters_only);
+ $order = $this->GetOrderClause();
+ $group = $this->GetGroupClause();
+
+ if (!empty($where)) $q .= ' WHERE ' . $where;
+ if (!empty($group)) $q .= ' GROUP BY ' . $group;
+ if (!empty($having)) $q .= ' HAVING ' . $having;
+ if ( !$for_counting && !empty($order) ) $q .= ' ORDER BY ' . $order;
+
+ return str_replace('%1$s',$this->TableName,$q);
+ }
+
+ function extractCalculatedFields($clause)
+ {
+ if ( is_array($this->CalculatedFields) ) {
+ foreach($this->CalculatedFields as $field_name => $field_expression)
+ {
+ $clause = preg_replace('/`'.$field_name.'`/', $field_expression, $clause);
+ }
+ }
+ return $clause;
+ }
+
+ /**
+ * Returns WHERE clause of the query
+ *
+ * @access public
+ * @param bool $for_counting merge where filters with having filters + replace field names for having fields with their values
+ * @return string
+ */
+ function GetWhereClause($for_counting=false,$system_filters_only=false)
+ {
+ $where =& $this->Application->makeClass('kMultipleFilter');
+
+ $where->addFilter('system_where', $this->WhereFilter[FLT_SYSTEM] );
+
+ if (!$system_filters_only) {
+ $where->addFilter('view_where', $this->WhereFilter[FLT_VIEW] );
+ $search_w = $this->WhereFilter[FLT_SEARCH]->getSQL();
+ if( $search_w || $for_counting ) // move search_having to search_where in case search_where isset or we are counting
+ {
+ $search_h = $this->extractCalculatedFields( $this->HavingFilter[FLT_SEARCH]->getSQL() );
+ $search_w = ($search_w && $search_h) ? $search_w.' OR '.$search_h : $search_w.$search_h;
+ $where->addFilter('search_where', $search_w );
+ }
+ }
+
+ if( $for_counting ) // add system_having and view_having to where
+ {
+ $where->addFilter('system_having', $this->extractCalculatedFields( $this->HavingFilter[FLT_SYSTEM]->getSQL() ) );
+ if (!$system_filters_only) $where->addFilter('view_having', $this->extractCalculatedFields( $this->HavingFilter[FLT_VIEW]->getSQL() ) );
+ }
+
+ return $where->getSQL();
+ }
+
+ /**
+ * Depricated method
+ *
+ * @param string $clause
+ * @todo REMOVE
+ */
+ function SetWhereClause($clause)
+ {
+ if( $this->Application->isDebugMode() )
+ {
+ global $debugger;
+ $debugger->appendTrace();
+ }
+ trigger_error('Depricated method <b>kDBList->SetWhereClause</b>. Use <b>kDBList->addFilter</b> instead.', E_USER_ERROR);
+ }
+
+ /**
+ * Returns HAVING clause of the query
+ *
+ * @param bool $for_counting don't return having filter in case if this is counting sql
+ * @return string
+ * @access public
+ */
+ function GetHavingClause($for_counting=false, $system_filters_only=false)
+ {
+ if( $for_counting ) return '';
+
+ $having =& $this->Application->makeClass('kMultipleFilter');
+
+ $having->addFilter('system_having', $this->HavingFilter[FLT_SYSTEM] );
+ if (!$system_filters_only) {
+ $having->addFilter('view_having', $this->HavingFilter[FLT_VIEW] );
+ $search_w = $this->WhereFilter[FLT_SEARCH]->getSQL();
+ if (!$search_w) {
+ $having->addFilter('search_having', $this->HavingFilter[FLT_SEARCH] );
+ }
+ }
+
+ return $having->getSQL();
+ }
+
+ /**
+ * Returns GROUP BY clause of the query
+ *
+ * @access public
+ * @return string
+ */
+ function GetGroupClause()
+ {
+ return $this->GroupByFields ? implode(',', $this->GroupByFields) : '';
+ }
+
+ function AddGroupByField($field)
+ {
+ $this->GroupByFields[$field] = $field;
+ }
+
+ function RemoveGroupByField($field)
+ {
+ unset($this->GroupByFields[$field]);
+ }
+
+ /**
+ * Adds order field to ORDER BY clause
+ *
+ * @access public
+ * @param string $field Field name
+ * @param string $direction Direction of ordering (asc|desc)
+ * @return void
+ */
+ function AddOrderField($field, $direction)
+ {
+ // original multilanguage field - convert to current lang field
+ if (getArrayValue($this->Fields, $field, 'formatter') == 'kMultiLanguage' && !getArrayValue($this->Fields, $field, 'master_field')) {
+ $lang = $this->Application->GetVar('m_lang');
+ $field = 'l'.$lang.'_'.$field;
+ }
+
+ $this->OrderFields[] = Array($field, $direction);
+ }
+
+ /**
+ * Removes all order fields
+ *
+ * @access public
+ * @return void
+ */
+ function ClearOrderFields()
+ {
+ $this->OrderFields = Array();
+ }
+
+ /**
+ * Returns ORDER BY Clause of the query
+ *
+ * The method builds order by clause by iterating {@link kDBList::OrderFields} array and concatenating it.
+ *
+ * @access public
+ * @return string
+ */
+ function GetOrderClause()
+ {
+ $ret = '';
+ foreach ($this->OrderFields as $field) {
+
+ $name = $field[0];
+ $ret .= isset($this->Fields[$name]) && !isset($this->VirtualFields[$name]) ? '`'.$this->TableName.'`.' : '';
+ if ($field[0] == 'RAND()') {
+ $ret .= $field[0].' '.$field[1].',';
+ }
+ else {
+ $ret .= '`'.$field[0] . '` ' . $field[1] . ',';
+ }
+ }
+ $ret = rtrim($ret, ',');
+ return $ret;
+ }
+
+ function GetOrderField($pos=NULL)
+ {
+ if(!(isset($this->OrderFields[$pos]) && $this->OrderFields[$pos]) )
+ {
+ $pos = 0;
+ }
+ return isset($this->OrderFields[$pos][0]) ? $this->OrderFields[$pos][0] : '';
+ }
+
+ function GetOrderDirection($pos=NULL)
+ {
+ if(!$this->OrderFields[$pos])
+ $pos = 0;
+
+ return $this->OrderFields[$pos][1];
+ }
+
+ /**
+ * Return unformatted field value
+ *
+ * @param string
+ * @return mixed
+ * @access public
+ */
+ function GetDBField($name)
+ {
+ $row =& $this->getCurrentRecord();
+ return $row[$name];
+ }
+
+ function HasField($name)
+ {
+ $row =& $this->getCurrentRecord();
+ return isset($row[$name]);
+ }
+
+ function GetFieldValues()
+ {
+ return $this->getCurrentRecord();
+ }
+
+ function &getCurrentRecord()
+ {
+ return $this->Records[$this->CurrentIndex];
+ }
+
+ /**
+ * Description
+ *
+ * @access public
+ * @param string
+ * @return void
+ */
+ function GoFirst()
+ {
+ $this->CurrentIndex = 0;
+ }
+
+ /**
+ * Description
+ *
+ * @access public
+ * @return void
+ */
+ function GoNext()
+ {
+ $this->CurrentIndex++;
+ }
+
+ /**
+ * Description
+ *
+ * @access public
+ * @return void
+ */
+ function GoPrev()
+ {
+ if ($this->CurrentIndex>0)
+ $this->CurrentIndex--;
+ }
+
+ /**
+ * Description
+ *
+ * @access public
+ * @return bool
+ */
+ function EOL()
+ {
+ return ($this->CurrentIndex >= $this->SelectedCount);
+ }
+
+ /**
+ * Description
+ *
+ * @access public
+ * @param string
+ * @return void
+ */
+ function GetTotalPages()
+ {
+ if (!$this->Counted) $this->CountRecs();
+ if ($this->PerPage == -1) return 1;
+ $this->TotalPages = (($this->RecordsCount - ($this->RecordsCount % $this->PerPage)) / $this->PerPage) // integer part of division
+ + (($this->RecordsCount % $this->PerPage) != 0); // adds 1 if there is a reminder
+ return $this->TotalPages;
+ }
+
+ /**
+ * Sets number of records to query per page
+ *
+ * @access public
+ * @param int $per_page Number of records to display per page
+ * @return void
+ */
+ function SetPerPage($per_page)
+ {
+ $this->PerPage = $per_page;
+ }
+
+ function GetPerPage()
+ {
+ return $this->PerPage == -1 ? $this->RecordsCount : $this->PerPage;
+ }
+
+ /**
+ * Description
+ *
+ * @access public
+ * @param int $page
+ * @return void
+ */
+ function SetPage($page)
+ {
+ if ($this->PerPage == -1) {
+ $this->Page = 1;
+ return;
+ }
+ if ($page < 1) $page = 1;
+ $this->Offset = ($page-1)*$this->PerPage;
+ if ($this->Counted && $this->Offset > $this->RecordsCount) {
+ $this->SetPage(1);
+ }
+ else {
+ $this->Page = $page;
+ }
+ //$this->GoFirst();
+ }
+
+ /**
+ * Sets current item field value
+ * (doesn't apply formatting)
+ *
+ * @access public
+ * @param string $name Name of the field
+ * @param mixed $value Value to set the field to
+ * @return void
+ */
+ function SetDBField($name,$value)
+ {
+ $this->Records[$this->CurrentIndex][$name] = $value;
+ }
+
+ /**
+ * Apply where clause, that links this object to it's parent item
+ *
+ * @param string $special
+ * @access public
+ */
+ function linkToParent($special)
+ {
+ $parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix');
+ if($parent_prefix)
+ {
+ $parent_table_key = $this->Application->getUnitOption($this->Prefix, 'ParentTableKey');
+ $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', '`'.$this->TableName.'`.`'.$foreign_key_field.'` = '.$parent_id); // only for list in this case
+ }
+ }
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/db/dblist.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/db/db_event_handler.php
===================================================================
--- trunk/core/kernel/db/db_event_handler.php (nonexistent)
+++ trunk/core/kernel/db/db_event_handler.php (revision 1560)
@@ -0,0 +1,1423 @@
+<?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 {
+
+ /**
+ * 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->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
+
+
+ // 1. get id from post (used in admin)
+ $ret = $this->Application->GetVar($event->getPrefixSpecial(true).'_id');
+ if($ret) return $ret;
+
+ // 2. get id from env (used in front)
+ $ret = $this->Application->GetVar($event->getPrefixSpecial().'_id');
+ if($ret) return $ret;
+
+ // 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();
+ $ids = $this->Application->RecallVar($prefix_special.'_selected_ids');
+ $event->setEventParam('ids', $ids);
+
+ $this->Application->RemoveVar($prefix_special.'_selected_ids');
+ $this->Application->SetVar($prefix_special.'_selected_ids', '');
+
+ $this->Application->SetVar($prefix_special.'_id', ''); // $event->getPrefixSpecial(true).'_id' too may be
+ }
+
+ /*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();
+
+ $live_table = $event->getEventParam('live_table');
+
+ if( $this->UseTempTables($event) && !$live_table )
+ {
+ $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);
+ $this->Application->setEvent($event->Prefix_Special, '');
+
+ $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->getObject();
+ $this->dbBuild($object,$event);
+
+ $sql = $this->ItemPrepareQuery($event);
+ $sql = $this->Application->ReplaceLanguageTags($sql);
+ $object->setSelectSQL($sql);
+
+ // 2. loads if allowed
+ $auto_load = $this->Application->getUnitOption($event->Prefix,'AutoLoad');
+ 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';
+ }
+
+ function TablePrefix(&$event)
+ {
+ return $this->UseTempTables(&$event) ? kTempTablesHandler::GetTempTablePrefix().TABLE_PREFIX : TABLE_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;
+ }
+ if ($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->getObject();
+
+ $this->dbBuild($object,$event);
+
+ $sql = $this->ListPrepareQuery($event);
+ $sql = $this->Application->ReplaceLanguageTags($sql);
+ $object->setSelectSQL($sql);
+
+ $object->linkToParent( $this->getMainSpecial($event) );
+
+// $object->linkToParent($special);
+
+ $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', '');
+ }
+
+
+ /**
+ * Get's special of main item for linking with subitem
+ *
+ * @param kEvent $event
+ * @return string
+ */
+ function getMainSpecial(&$event)
+ {
+ $special = $event->getEventParam('main_special');
+ if($special === false || $special == '$main_special')
+ {
+ $special = $event->Special;
+ }
+ return $special;
+ }
+
+ /**
+ * Apply any custom changes to list's sql query
+ *
+ * @param kEvent $event
+ * @access protected
+ * @see OnListBuild
+ */
+ function SetCustomQuery(&$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');
+
+ $config_mapping = $this->Application->getUnitOption($event->Prefix, 'ConfigMapping');
+
+ if ( $config_mapping ) {
+ switch ( $per_page ){
+ case 'short_list' :
+ $per_page = $this->Application->ConfigValue($config_mapping['ShortListPerPage']);
+ break;
+ case 'default' :
+ $per_page = $this->Application->ConfigValue($config_mapping['PerPage']);
+ break;
+ }
+ }
+
+ if(!$per_page)
+ {
+ $per_page_var = $event->getPrefixSpecial().'_PerPage';
+
+ $per_page = $this->Application->RecallVar($per_page_var);
+ if(!$per_page)
+ {
+
+ if ( $config_mapping ) {
+ $per_page = $this->Application->ConfigValue($config_mapping['PerPage']);
+ }
+ if(!$per_page) $per_page = 10;
+ }
+ }
+
+ $object =& $event->getObject();
+ $object->SetPerPage($per_page);
+ $this->Application->StoreVarDefault($event->getPrefixSpecial().'_Page', 1);
+
+ $page = $this->Application->GetVar($event->getPrefixSpecial().'_Page');
+ if (!$page) {
+ $page = $this->Application->GetVar($event->getPrefixSpecial(true).'_Page');
+ }
+ if (!$page) {
+ $page = $this->Application->RecallVar($event->getPrefixSpecial().'_Page');
+ }
+ else {
+ $this->Application->StoreVar($event->getPrefixSpecial().'_Page', $page);
+ }
+
+// $page = $this->Application->GetLinkedVar($event->getPrefixSpecial(true).'_Page', $event->getPrefixSpecial().'_Page');
+ if( !$event->getEventParam('skip_counting') )
+ {
+ $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->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');
+
+
+ $sorting_configs = $this->Application->getUnitOption($event->Prefix, 'ConfigMapping');
+ $list_sortings = $this->Application->getUnitOption($event->Prefix, 'ListSortings');
+ $sorting_prefix = getArrayValue($list_sortings, $event->Special) ? $event->Special : '';
+
+ $tag_sort_by = $event->getEventParam('sort_by');
+ if ($tag_sort_by) {
+ list($by, $dir) = explode(',', $tag_sort_by);
+ if ($by == 'random') $by = 'RAND()';
+ $object->AddOrderField($by, $dir);
+ }
+
+ if ($sorting_configs && isset ($sorting_configs['DefaultSorting1Field'])){
+ $list_sortings[$sorting_prefix]['Sorting'] = Array(
+ $this->Application->ConfigValue($sorting_configs['DefaultSorting1Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting1Dir']),
+ $this->Application->ConfigValue($sorting_configs['DefaultSorting2Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting2Dir']),
+ );
+ }
+
+ // 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);
+ }
+ }
+
+
+ /**
+ * Add filters found in session
+ *
+ * @param kEvent $event
+ */
+ 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)
+ {
+ $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');
+
+ $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);
+ }
+
+ /**
+ * Set sorting directly to session
+ *
+ * @param kEvent $event
+ */
+ function OnSetSortingDirect(&$event)
+ {
+ $combined = $this->Application->GetVar($event->getPrefixSpecial(true).'_CombinedSorting');
+ if ($combined) {
+ list($field,$dir) = explode('|',$combined);
+ $this->Application->StoreVar($event->Prefix_Special.'_Sort1', $field);
+ $this->Application->StoreVar($event->Prefix_Special.'_Sort1_Dir', $dir);
+ return;
+ }
+
+ $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');
+ }
+
+ /**
+ * Reset grid sorting to default (from config)
+ *
+ * @param kEvent $event
+ */
+ function OnResetSorting(&$event)
+ {
+ $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 ItemPrepareQuery(&$event)
+ {
+ $sqls = $this->Application->getUnitOption($event->Prefix,'ItemSQLs');
+ 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 ListPrepareQuery(&$event)
+ {
+ $sqls = $this->Application->getUnitOption($event->Prefix,'ListSQLs');
+ return isset( $sqls[$event->Special] ) ? $sqls[$event->Special] : $sqls[''];
+ }
+
+ /**
+ * Apply custom processing to item
+ *
+ * @param kEvent $event
+ */
+ function customProcessing(&$event, $type)
+ {
+
+ }
+
+/* Edit Events mostly used in Admin */
+
+ /**
+ * Creates new kDBItem
+ *
+ * @param kEvent $event
+ * @access protected
+ */
+ function OnCreate(&$event)
+ {
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
+
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if($items_info)
+ {
+ list($id,$field_values) = each($items_info);
+ $object->SetFieldsFromHash($field_values);
+ }
+
+ $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( $object->IsTempTable() ) $object->setTempID();
+ $this->customProcessing($event,'after');
+ $event->status=erSUCCESS;
+ $event->redirect_params = Array('opener'=>'u');
+ }
+ else
+ {
+ $event->status=erFAIL;
+ $event->redirect=false;
+ $this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
+ $object->setID($id);
+ }
+ }
+
+ /**
+ * Updates kDBItem
+ *
+ * @param kEvent $event
+ * @access protected
+ */
+ function OnUpdate(&$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->SetFieldsFromHash($field_values);
+ $this->customProcessing($event, 'before');
+ if( $object->Update($id) )
+ {
+ $this->customProcessing($event, 'after');
+ $event->status=erSUCCESS;
+ }
+ else
+ {
+ $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($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
+ $object->ID = $this->getPassedID($event);
+ if( $object->Delete() )
+ {
+ $event->status = erSUCCESS;
+ }
+ else
+ {
+ $event->status = erFAIL;
+ $event->redirect = false;
+ }
+ }
+
+ /**
+ * Prepares new kDBItem object
+ *
+ * @param kEvent $event
+ * @access protected
+ */
+ function OnNew(&$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']);
+
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',true);
+ $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
+ if (is_object($event->MasterEvent)) {
+ $event->MasterEvent->setEventParam('IsNew',false);
+ }
+ $item_id = $this->getPassedID($event);
+ if($item_id == '')
+ {
+ $event->CallSubEvent('OnPreSaveCreated');
+ if (is_object($event->MasterEvent)) {
+ $event->MasterEvent->setEventParam('IsNew',true);
+ }
+ return;
+ }
+
+ $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->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;
+ }
+
+ /**
+ * 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);
+ }
+
+ }
+
+/* End of Edit events */
+
+ // 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)
+ {
+
+ }
+
+ /**
+ * Occurs after successful item validation
+ *
+ * @param kEvent $event
+ */
+ function OnAfterItemValidate(&$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);
+ $keyword = str_replace(Array('"',"'"),'',$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':
+ $like_keyword = preg_replace( '/\'(.*)\'/U', '\\1', $this->Conn->qstr( str_replace('\\','\\\\', $keyword) ) );
+ $keywords = explode(' ', $like_keyword);
+ foreach($keywords as $keyword_pos => $keyword_value)
+ {
+ $keyword_value = trim($keyword_value);
+ if($keyword_value)
+ {
+ $keywords[$keyword_pos] = $table_name.'`'.$search_field.'` LIKE \'%'.$keyword_value.'%\'';
+ }
+ else
+ {
+ unset($keywords[$keyword_pos]);
+ }
+ }
+ $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);
+ $object =& $event->getObject();
+ $this->RemoveRequiredFields($object);
+ $event->CallSubEvent('OnPreSave');
+ if ($event->status == erSUCCESS) {
+// $url = $this->Application->HREF($t, '', Array('pass'=>'all', $event->getPrefixSpecial(true).'_id' => $object->GetId()));
+// $field = $this->Application->GetVar('translator_field');
+ $event->redirect = $this->Application->GetVar('translator_t');
+ $event->redirect_params = Array('pass'=>'all,trans',
+ $event->getPrefixSpecial(true).'_id' => $object->GetId(),
+ 'trans_event'=>'OnLoad',
+ 'trans_prefix'=>$event->Prefix,
+ 'trans_field'=>$this->Application->GetVar('translator_field'),
+ );
+ //$after_script = "openTranslator('".$event->getPrefixSpecial()."', '".$field."', '".$url."', '".$wnd_name."')";
+ }
+
+// $this->Application->SetVar('after_script', $after_script);
+// $event->redirect = false;
+ }
+
+ function RemoveRequiredFields(&$object)
+ {
+ // making all field non-required to achieve successful presave
+ foreach($object->Fields as $field => $options)
+ {
+ if(isset($options['required']))
+ {
+ unset($object->Fields[$field]['required']);
+ }
+ }
+ }
+
+
+
+ }
+
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/db/db_event_handler.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.9
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/db/db_connection.php
===================================================================
--- trunk/core/kernel/db/db_connection.php (nonexistent)
+++ trunk/core/kernel/db/db_connection.php (revision 1560)
@@ -0,0 +1,542 @@
+<?php
+
+ /**
+ * Multi database connection class
+ *
+ */
+ 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 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,$force_new=false)
+ {
+ $func = $this->getMetaFunction('connect');
+ $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 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);
+ $debugger->profilerAddTotal('sql', '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)
+ {
+ $replaceQuote = "\\'";
+ if (!$magic_quotes)
+ {
+ 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);
+
+ 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 code occured
+ *
+ * @return int
+ */
+ function getErrorCode()
+ {
+ return $this->errorCode;
+ }
+
+ /**
+ * 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
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.5
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/db/dbitem.php
===================================================================
--- trunk/core/kernel/db/dbitem.php (nonexistent)
+++ trunk/core/kernel/db/dbitem.php (revision 1560)
@@ -0,0 +1,818 @@
+<?php
+
+/**
+* DBItem
+*
+* Desciption
+* @package kernel4
+*/
+class kDBItem extends kDBBase {
+
+ /**
+ * Description
+ *
+ * @var array Associative array of current item' field values
+ * @access public
+ */
+ var $FieldValues;
+
+ /**
+ * Unformatted field values, before parse
+ *
+ * @var Array
+ * @access private
+ */
+ var $DirtyFieldValues = Array();
+
+ var $FieldErrors;
+
+ var $ErrorMsgs = Array();
+
+ /**
+ * If set to true, Update will skip Validation before running
+ *
+ * @var array Associative array of current item' field values
+ * @access public
+ */
+ var $IgnoreValidation = false;
+
+ var $Loaded = false;
+
+ /**
+ * Holds item' primary key value
+ *
+ * @var int Value of primary key field for current item
+ * @access public
+ */
+ var $ID;
+
+ 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)';
+ }
+
+ function SetDirtyField($field_name, $field_value)
+ {
+ $this->DirtyFieldValues[$field_name] = $field_value;
+ }
+
+ function GetDirtyField($field_name)
+ {
+ return $this->DirtyFieldValues[$field_name];
+ }
+
+ /**
+ * Set's default values for all fields
+ *
+ * @access public
+ */
+ function SetDefaultValues()
+ {
+ 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)
+ {
+ $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;
+ /*if (isset($this->Fields[$name]['formatter'])) {
+ $formatter =& $this->Application->recallObject($this->Fields[$name]['formatter']);
+ $formatter->UpdateSubFields($name, $value, $this->Fields[$name], $this);
+ }*/
+ }
+
+ /**
+ * Set's field error, if pseudo passed not found then create it with message text supplied.
+ * Don't owerrite existing pseudo translation.
+ *
+ * @param string $field
+ * @param string $pseudo
+ * @param string $error_label
+ */
+ function SetError($field, $pseudo, $error_label = '')
+ {
+ $error_msg = $this->Application->Phrase($error_label);
+ if( !($error_msg && getArrayValue($this->ErrorMsgs,$pseudo)) )
+ {
+ $this->ErrorMsgs[$pseudo] = $error_msg;
+ }
+ $this->FieldErrors[$field]['pseudo'] = $pseudo;
+ }
+
+ /**
+ * 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, $set_fields=null)
+ {
+ // used in formatter which work with multiple fields together
+ 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->SetDirtyField($field_name, $field_value);
+ }
+
+ // formats all fields using associated formatters
+ 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->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->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( !$this->raiseEvent('OnBeforeItemLoad',$id) ) return false;
+
+ $this->ID = $id;
+
+ $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 = array_merge_recursive2( $this->FieldValues, $this->Conn->GetRow($q) );
+
+ if ($this->FieldValues === false) {
+ //Error handling could be here
+ return false;
+ }
+ 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');
+ $this->Loaded = true;
+ 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 bool
+ */
+ function Update($id=null, $system_update=false)
+ {
+ if( isset($id) ) $this->setID($id);
+
+ if( !$this->raiseEvent('OnBeforeItemUpdate') ) return false;
+
+ if( !isset($this->ID) ) return false;
+
+ // Validate before updating
+ if( !$this->IgnoreValidation && !$this->Validate() ) return false;
+ if( !$this->raiseEvent('OnAfterItemValidate') ) 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 ($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
+ 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()
+ {
+ $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->ValidateType($field, $params);
+ $res = $res && $this->ValidateRange($field, $params);
+ $res = $res && $this->ValidateUnique($field, $params);
+ $res = $res && $this->ValidateRequired($field, $params);
+
+ // If Formatter has set some error messages during values parsing
+ $error_field = isset($params['error_field']) ? $params['error_field'] : $field;
+ if (isset($this->FieldErrors[$error_field]['pseudo']) && $this->FieldErrors[$error_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;
+ }
+
+ function HasErrors()
+ {
+ $global_res = false;
+ foreach ($this->Fields as $field => $params) {
+ // If Formatter has set some error messages during values parsing
+ if (isset($this->FieldErrors[$field]['pseudo']) && $this->FieldErrors[$field] != '') {
+ $global_res = true;
+ }
+ }
+ 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];
+ $error_field = isset($params['error_field']) ? $params['error_field'] : $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[$error_field]['pseudo'] = 'bad_type';
+ $this->FieldErrors[$error_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;
+ $error_field = isset($params['error_field']) ? $params['error_field'] : $field;
+ if ( getArrayValue($params,'required') )
+ {
+ $res = ( (string) $this->FieldValues[$field] != '');
+ }
+ if (!$res) $this->FieldErrors[$error_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;
+ $error_field = isset($params['error_field']) ? $params['error_field'] : $field;
+ $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[$error_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];
+ $error_field = isset($params['error_field']) ? $params['error_field'] : $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[$error_field]['pseudo'] = 'value_out_of_range';
+
+ if ( !isset($min_val) ) $min_val = '-&infin;';
+ if ( !isset($max_val) ) $max_val = '&infin;';
+
+ $this->FieldErrors[$error_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[$error_field]['pseudo'] = 'length_out_of_range';
+ $this->FieldErrors[$error_field]['params'] = Array( getArrayValue($params,'min_len'), getArrayValue($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];
+ $msg = $this->Application->ReplaceLanguageTags($msg);
+ }
+ 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 bool
+ */
+ function Create($force_id=false, $system_create=false)
+ {
+ if( !$this->raiseEvent('OnBeforeItemCreate') ) return false;
+
+ // Validating fields before attempting to create record
+ if( !$this->IgnoreValidation && !$this->Validate() ) return false;
+ if( !$this->raiseEvent('OnAfterItemValidate') ) return false;
+
+ if (is_int($force_id)) {
+ $this->FieldValues[$this->IDField] = $force_id;
+ }
+ elseif (!$force_id || !is_bool($force_id)) {
+ $this->FieldValues[$this->IDField] = $this->generateID();
+ }
+
+
+ $fields_sql = '';
+ $values_sql = '';
+ foreach ($this->FieldValues as $field_name => $field_value)
+ {
+ 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
+ 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;
+ }
+
+ $insert_id = $this->Conn->getInsertID();
+ if($insert_id == 0) $insert_id = $this->FieldValues[$this->IDField];
+ $this->setID($insert_id);
+
+ if (!$system_create){
+ $this->setModifiedFlag();
+ }
+
+ $this->raiseEvent('OnAfterItemCreate');
+ return true;
+ }
+
+ /**
+ * Deletes the record from databse
+ *
+ * @access public
+ * @return bool
+ */
+ 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>';
+ }
+ $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 || isset($this->CalculatedFields[$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);
+ }
+
+ /**
+ * Set's modification flag for main prefix of current prefix to true
+ *
+ * @access private
+ * @author Alexey
+ */
+ function setModifiedFlag()
+ {
+ $main_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
+ $this->Application->StoreVar($main_prefix.'_modified', '1');
+ }
+
+ /**
+ * Returns ID of currently processed record
+ *
+ * @return int
+ * @access public
+ */
+ function GetID()
+ {
+ return $this->ID;
+ }
+
+ /**
+ * Generates ID for new items before inserting into database
+ *
+ * @return int
+ * @access private
+ */
+ function generateID()
+ {
+ return 0;
+ }
+}
+
+
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/db/dbitem.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/languages/phrases_cache.php
===================================================================
--- trunk/core/kernel/languages/phrases_cache.php (nonexistent)
+++ trunk/core/kernel/languages/phrases_cache.php (revision 1560)
@@ -0,0 +1,175 @@
+<?php
+
+class PhrasesCache extends kDBBase {
+
+ var $Phrases = Array();
+ 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",
+ TABLE_PREFIX.'PhraseCache',
+ $this->Conn->Qstr(md5($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) || !implode('', $ids) ) return;
+ $query = sprintf("SELECT Translation,Phrase FROM %s WHERE LanguageId = %s AND PhraseId IN (%s)",
+ 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($this->Ids) == 0) return;
+ if ($this->Ids == $this->OriginalIds) return; //nothing changed
+ $query = sprintf("REPLACE %s (PhraseList, CacheDate, Template)
+ VALUES (%s, %s, %s)",
+ TABLE_PREFIX.'PhraseCache',
+ $this->Conn->Qstr(join(',', $this->Ids)),
+ mktime(),
+ $this->Conn->Qstr(md5($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( isset($this->Phrases[$label]) ) {
+ $translated_label = $this->Phrases[$label];
+ if($this->Application->isDebugMode() && dbg_ConstOn('DBG_PHRASES_HILIGHT') && !$this->Application->IsAdmin())
+ $translated_label = '<span style="border: 1px solid #999999; background-color: #cccccc; color: #999999; ">'.$translated_label.'</span>';
+ return $translated_label;
+ }
+
+ $this->LoadPhraseByLabel($label, $original_label);
+ return $this->GetPhrase($label);
+ }
+
+ function LoadPhraseByLabel($label, $original_label)
+ {
+ $query = sprintf("SELECT PhraseId, Translation FROM %s WHERE LanguageId = %s AND UPPER(Phrase) = UPPER(%s)",
+ TABLE_PREFIX.'Phrase',
+ $this->LanguageId,
+ $this->Conn->qstr($label));
+ $res = $this->Conn->GetRow($query);
+ if ($res === false || count($res) == 0)
+ {
+ $translation = '!'.$label.'!';
+ if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_PHRASES') )
+ {
+ list($edit_tpl, $index_file) = $this->Application->IsAdmin() ? Array('in-commerce/regional/phrases_edit', 'index4.php') : Array('organized/phrases_edit', 'index.php');
+
+ $edit_url = $this->Application->HREF($edit_tpl,'',Array('m_opener'=>'d','phrases_label'=>$original_label,'phrases_event'=>'OnNew', 'pass'=>'all,phrases'), $index_file );
+ $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
+ 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
+ * @param bool $force_escape force escaping, not escaping of resulting string
+ * @return string
+ * @access public
+ */
+ function ReplaceLanguageTags($text,$forse_escaping=null)
+ {
+ $this->fromTag = true;
+ if( isset($forse_escaping) ) $this->fromTag = $forse_escaping;
+ 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
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/startup.php
===================================================================
--- trunk/core/kernel/startup.php (nonexistent)
+++ trunk/core/kernel/startup.php (revision 1560)
@@ -0,0 +1,92 @@
+<?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);
+
+$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']);
+safeDefine( 'KERNEL_PATH', DOC_ROOT.BASE_PATH.'/kernel4');
+safeDefine( 'PROTOCOL', 'http://');
+
+define('MODULES_PATH', DOC_ROOT.BASE_PATH);
+define('EXPORT_PATH', DOC_ROOT.BASE_PATH.'/admin/export');
+define('GW_CLASS_PATH', MODULES_PATH.'/in-commerce/units/gateways/gw_classes'); // Payment Gateway Classes Path
+
+
+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");
+
+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.'/kernel/units/general/my_application.php');
+
+safeDefine('LOGIN_CONTROLLER', 'LoginController');
+safeDefine('USER_MODEL', 'User');
+
+
+// global constants
+define('HAVING_FILTER', 1);
+define('WHERE_FILTER', 2);
+
+define('FLT_TYPE_AND', 'AND');
+define('FLT_TYPE_OR', 'OR');
+
+safeDefine('STATUS_DISABLED', 0);
+safeDefine('STATUS_ACTIVE', 1);
+safeDefine('STATUS_PENDING', 2);
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/startup.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/application.php
===================================================================
--- trunk/core/kernel/application.php (nonexistent)
+++ trunk/core/kernel/application.php (revision 1560)
@@ -0,0 +1,1280 @@
+<?php
+
+/**
+* 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;
+
+
+ /**
+ * Prevents request from beeing proceeded twice in case if application init is called mere then one time
+ *
+ * @var bool
+ * @todo This is not good anyway (by Alex)
+ */
+ var $RequestProcessed = false;
+
+ /**
+ * 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 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()
+ {
+ if (defined('DEBUG_MODE') && DEBUG_MODE && dbg_ConstOn('DBG_PROFILE_MEMORY') ) {
+ global $debugger;
+ $debugger->appendMemoryUsage('Application before Init:');
+ }
+
+ if( !$this->isDebugMode() ) set_error_handler( Array(&$this,'handleError') );
+
+ $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();
+
+ $this->Factory = new kFactory();
+
+ $this->registerDefaultClasses();
+
+ // 1. to read configs before doing any recallObject
+ $config_reader =& $this->recallObject('kUnitConfigReader');
+
+ if( !$this->GetVar('m_lang') ) $this->SetVar('m_lang', $this->GetDefaultLanguageId() );
+ if( !$this->GetVar('m_theme') ) $this->SetVar('m_theme', $this->GetDefaultThemeId());
+ $this->Phrases = new PhrasesCache( $this->GetVar('m_lang') );
+
+ $this->SetVar('lang.current_id', $this->GetVar('m_lang') );
+ $language =& $this->recallObject('lang.current', null, Array('live_table'=>true) );
+
+ if( !$this->GetVar('m_theme') ) $this->SetVar('m_theme', $this->GetDefaultThemeId() );
+ $this->SetVar('theme.current_id', $this->GetVar('m_theme') );
+
+ if ( $this->GetVar('m_cat_id') === false ) $this->SetVar('m_cat_id', 2); //need to rewrite
+
+ if( !$this->RecallVar('UserGroups') )
+ {
+ $this->StoreVar('UserGroups', $this->ConfigValue('User_GuestGroup'));
+ }
+
+ if( !$this->RecallVar('curr_iso') ) $this->StoreVar('curr_iso', $this->GetPrimaryCurrency() );
+
+ $this->ValidateLogin(); // TODO: write that method
+
+ if( $this->isDebugMode() )
+ {
+ global $debugger;
+ $debugger->profileFinish('kernel4_startup');
+ }
+ }
+
+ function GetDefaultLanguageId()
+ {
+ $table = $this->getUnitOption('lang','TableName');
+ $id_field = $this->getUnitOption('lang','IDField');
+ return $this->DB->GetOne('SELECT '.$id_field.' FROM '.$table.' WHERE PrimaryLang = 1');
+ }
+
+ function GetDefaultThemeId()
+ {
+ if (defined('DBG_FORCE_THEME') && DBG_FORCE_THEME){
+ return DBG_FORCE_THEME;
+ }
+ $table = $this->getUnitOption('theme','TableName');
+ $id_field = $this->getUnitOption('theme','IDField');
+ return $this->DB->GetOne('SELECT '.$id_field.' FROM '.$table.' WHERE PrimaryTheme = 1');
+ }
+
+ function GetPrimaryCurrency()
+ {
+ $table = $this->getUnitOption('curr','TableName');
+ return $this->DB->GetOne('SELECT ISO FROM '.$table.' WHERE IsPrimary = 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('kPasswordFormatter', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kCCDateFormatter', 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('Template',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('kEmailMessage',KERNEL_PATH.'/utility/email.php');
+ $this->registerClass('kSmtpClient',KERNEL_PATH.'/utility/smtp_client.php');
+
+ if (file_exists(MODULES_PATH.'/in-commerce/units/rates/currency_rates.php')) {
+ $this->registerClass('kCurrencyRates',MODULES_PATH.'/in-commerce/units/rates/currency_rates.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);
+ }
+
+ function ProcessRequest()
+ {
+ $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->RequestProcessed = true;
+ }
+
+ /**
+ * 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()
+ {
+ if (defined('DEBUG_MODE') && DEBUG_MODE && dbg_ConstOn('DBG_PROFILE_MEMORY') ) {
+ global $debugger;
+ $debugger->appendMemoryUsage('Application before Run:');
+ }
+
+ if (!$this->RequestProcessed) $this->ProcessRequest();
+
+ $this->InitParser();
+ $template_cache =& $this->recallObject('TemplatesCache');
+ $t = $this->GetVar('t');
+
+
+ if (defined('CMS') && CMS) {
+ if (!$template_cache->TemplateExists($t)) {
+ $cms_handler =& $this->recallObject('cms_EventHandler');
+ $t = $cms_handler->GetDesignTemplate();
+ }
+ }
+
+ if (defined('DEBUG_MODE') && DEBUG_MODE && dbg_ConstOn('DBG_PROFILE_MEMORY') ) {
+ global $debugger;
+ $debugger->appendMemoryUsage('Application before Parsing:');
+ }
+
+ $this->HTML = $this->Parser->Parse( $template_cache->GetTemplateBody($t), $t );
+
+ if (defined('DEBUG_MODE') && DEBUG_MODE && dbg_ConstOn('DBG_PROFILE_MEMORY') ) {
+ global $debugger;
+ $debugger->appendMemoryUsage('Application after Parsing:');
+ }
+ }
+
+ function InitParser()
+ {
+ if( !is_object($this->Parser) ) $this->Parser =& $this->recallObject('TemplateParser');
+ }
+
+ /**
+ * 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()
+ {
+ if (defined('DEBUG_MODE') && DEBUG_MODE && dbg_ConstOn('DBG_PROFILE_MEMORY') ) {
+ global $debugger;
+ $debugger->appendMemoryUsage('Application before 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->Destroy();
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Deletes Session variable
+ *
+ * @param string $var
+ */
+ 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=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)
+ {
+ $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;
+ $a_tag->NamedParams = $params;
+ return $a_tag->DoProcessTag();
+ }
+
+ /* 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,$as_template=false)
+ {
+ if (substr($params['name'], 0, 5) == 'html:') return substr($params['name'], 6);
+ 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='', $params=null, $index_file=null)
+ {
+ global $HTTP_SERVER_VARS;
+ if (defined('ADMIN') && $prefix == '') $prefix='/admin';
+ if (defined('ADMIN') && $prefix == '_FRONT_END_') $prefix = '';
+ $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);
+ if (count($opener_stack) > 0) {
+ list($index_file, $env) = explode('|', $opener_stack[count($opener_stack)-1]);
+ $ret = $this->BaseURL($prefix).$index_file.'?'.ENV_VAR_NAME.'='.$env;
+ if( getArrayValue($params,'escape') ) $ret = addslashes($ret);
+ return $ret;
+ }
+ else {
+ //define('DBG_REDIRECT', 1);
+ $t = $this->GetVar('t');
+ }
+ }
+ else {
+ //define('DBG_REDIRECT', 1);
+ $t = $this->GetVar('t');
+ }
+ }
+
+ $pass = isset($params['pass']) ? $params['pass'] : '';
+ $pass_events = isset($params['pass_events']) ? $params['pass_events'] : false; // pass events with url
+
+
+
+ if (defined('MOD_REWRITE') && MOD_REWRITE) {
+ $env = $this->BuildEnv('', $params, $pass, $pass_events, false);
+ $env = ltrim($env, ':-');
+
+ $session =& $this->recallObject('Session');
+ $sid = $session->NeedQueryString() ? '?sid='.$this->GetSID() : '';
+// $env = str_replace(':', '/', $env);
+ $ret = $this->BaseURL($prefix).$t.'.html/'.$env.'/'.$sid;
+
+ }
+ else {
+ $env = $this->BuildEnv($t, $params, $pass, $pass_events);
+ $ret = $this->BaseURL($prefix).$index_file.'?'.$env;
+ }
+
+ return $ret;
+ }
+
+ function BuildEnv($t, $params, $pass='all', $pass_events=false, $env_var=true)
+ {
+ $session =& $this->recallObject('Session');
+ $sid = $session->NeedQueryString() && !(defined('MOD_REWRITE') && MOD_REWRITE) ? $this->GetSID() : '';
+ $ret = '';
+ if ($env_var) {
+ $ret = ENV_VAR_NAME.'=';
+ }
+ $ret .= defined('INPORTAL_ENV') ? $sid.'-'.$t : $sid.':'.$t;
+
+ $pass = str_replace('all', trim($this->GetVar('passed'), ','), $pass);
+
+ if(strlen($pass) > 0)
+ {
+ $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 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)
+ {
+ //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);
+ }
+
+ if ($this->getUnitOption($prefix, 'PortalStyleEnv') == true) {
+ $ret.= array_shift($escaped).array_shift($escaped).'-'.implode('-',$escaped);
+ }
+ else {
+ $ret.=implode('-',$escaped);
+ }
+ }
+ }
+ }
+ unset($params['pass']);
+ unset($params['opener']);
+ unset($params['m_event']);
+
+ if ($this->GetVar('admin') && !isset($params['admin'])) {
+ $params['admin'] = 1;
+ }
+
+ 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.'/';
+ }
+
+ function Redirect($t='', $params=null, $prefix='', $index_file=null)
+ {
+ if ($t == '' || $t === true) $t = $this->GetVar('t');
+
+ // pass prefixes and special from previous url
+ if (!isset($params['pass'])) $params['pass'] = 'all';
+
+ $location = $this->HREF($t, $prefix, $params, $index_file);
+ $a_location = $location;
+ $location = "Location: $location";
+ //echo " location : $location <br>";
+
+ if (headers_sent() != '' || ($this->isDebugMode() && dbg_ConstOn('DBG_REDIRECT')) ) {
+ /*$GLOBALS['debugger']->appendTrace();
+ echo "<b>Debug output above!!!</b> Proceed to redirect: <a href=\"$a_location\">$a_location</a><br>";*/
+ echo '<script language="javascript" type="text/javascript">window.location.href = \''.$a_location.'\';</script>';
+ }
+ else {
+ header("$location");
+ }
+
+ $session =& $this->recallObject('Session');
+ $session->SaveData();
+ $this->SaveBlocksCache();
+ exit;
+ }
+
+ function Phrase($label)
+ {
+ return $this->Phrases->GetPhrase($label);
+ }
+
+ /**
+ * Replace language tags in exclamation marks found in text
+ *
+ * @param string $text
+ * @param bool $force_escape force escaping, not escaping of resulting string
+ * @return string
+ * @access public
+ */
+ function ReplaceLanguageTags($text, $force_escape=null)
+ {
+ return $this->Phrases->ReplaceLanguageTags($text,$force_escape);
+ }
+
+ /**
+ * 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();
+ }
+ }
+
+ /**
+ * Returns configuration option value by name
+ *
+ * @param string $name
+ * @return string
+ */
+ function ConfigValue($name)
+ {
+ return $this->DB->GetOne('SELECT VariableValue FROM '.TABLE_PREFIX.'ConfigurationValues WHERE VariableName = '.$this->DB->qstr($name) );
+ }
+
+ /**
+ * Allows to process any type of event
+ *
+ * @param kEvent $event
+ * @access public
+ * @author Alex
+ */
+ function HandleEvent(&$event, $params=null, $specificParams=null)
+ {
+ if ( isset($params) ) {
+ $event = new kEvent( $params, $specificParams );
+ }
+ $event_manager =& $this->recallObject('EventManager');
+ $event_manager->HandleEvent($event);
+ }
+
+ /**
+ * Registers new class in the factory
+ *
+ * @param string $real_class
+ * @param string $file
+ * @param string $pseudo_class
+ * @access public
+ * @author Alex
+ */
+ function registerClass($real_class,$file,$pseudo_class=null)
+ {
+ $this->Factory->registerClass($real_class,$file,$pseudo_class);
+ }
+
+ /**
+ * Registers Hook from subprefix event to master prefix event
+ *
+ * @param string $hookto_prefix
+ * @param string $hookto_special
+ * @param string $hookto_event
+ * @param string $mode
+ * @param string $do_prefix
+ * @param string $do_special
+ * @param string $do_event
+ * @param string $conditional
+ * @access public
+ * @todo take care of a lot parameters passed
+ * @author Kostja
+ */
+ 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);
+ }
+
+ /**
+ * Allows one TagProcessor tag act as other TagProcessor tag
+ *
+ * @param Array $tag_info
+ * @author Kostja
+ */
+ 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
+ * @author Alex
+ */
+ function &recallObject($name,$pseudo_class=null,$event_params=Array())
+ {
+ $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;
+ }
+
+ /**
+ * Checks if object with prefix passes was already created in factory
+ *
+ * @param string $name object presudo_class, prefix
+ * @return bool
+ * @author Kostja
+ */
+ 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
+ * @author Kostja
+ */
+ function removeObject($name)
+ {
+ $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 public
+ * @author Alex
+ */
+ 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
+ * @author Alex
+ */
+ function isDebugMode()
+ {
+ return defined('DEBUG_MODE') && DEBUG_MODE;
+ }
+
+ /**
+ * Checks if it is admin
+ *
+ * @return bool
+ * @author Alex
+ */
+ function IsAdmin()
+ {
+ return defined('ADMIN') && ADMIN;
+ }
+
+ /**
+ * Reads unit (specified by $prefix)
+ * option specified by $option
+ *
+ * @param string $prefix
+ * @param string $option
+ * @return string
+ * @access public
+ * @author Alex
+ */
+ 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
+ * @author Alex
+ * @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
+ * @author Alex
+ */
+ 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
+ * @author Alex
+ */
+ 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
+ * @author Alex
+ */
+ function handleSQLError($code,$msg,$sql)
+ {
+ global $debugger;
+ if($debugger)
+ {
+ $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
+ {
+ $errorLevel = defined('IS_INSTALL') && IS_INSTALL ? E_USER_WARNING : E_USER_ERROR;
+ trigger_error('<b>SQL Error</b> in sql: '.$sql.', code <b>'.$code.'</b> ('.$msg.')', $errorLevel);
+ /*echo '<b>xProcessing SQL</b>: '.$sql.'<br>';
+ echo '<b>Error ('.$code.'):</b> '.$msg.'<br>';*/
+ return $errorLevel == E_USER_ERROR ? false : true;
+ }
+ }
+
+ /**
+ * Default error handler
+ *
+ * @param int $errno
+ * @param string $errstr
+ * @param string $errfile
+ * @param int $errline
+ * @param Array $errcontext
+ */
+ function handleError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
+ {
+ $fp = fopen(DOC_ROOT.BASE_PATH.'/silent_log.txt','a');
+ $time = date('d/m/Y H:i:s');
+ fwrite($fp, '['.$time.'] #'.$errno.': '.strip_tags($errstr).' in ['.$errfile.'] on line '.$errline."\n");
+ fclose($fp);
+ }
+
+ /**
+ * Returns & blocks next ResourceId available in system
+ *
+ * @return int
+ * @access public
+ * @author Eduard
+ */
+ 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;
+ }
+
+ /**
+ * Returns main prefix for subtable prefix passes
+ *
+ * @param string $current_prefix
+ * @return string
+ * @access public
+ * @author Kostja
+ */
+ function GetTopmostPrefix($current_prefix)
+ {
+ while ( $parent_prefix = $this->getUnitOption($current_prefix, 'ParentPrefix') )
+ {
+ $current_prefix = $parent_prefix;
+ }
+ return $current_prefix;
+ }
+
+ function EmailEventAdmin($email_event_name, $to_user_id = -1, $send_params = false)
+ {
+ return $this->EmailEvent($email_event_name, 1, $to_user_id, $send_params);
+ }
+
+ function EmailEventUser($email_event_name, $to_user_id = -1, $send_params = false)
+ {
+ return $this->EmailEvent($email_event_name, 0, $to_user_id, $send_params);
+ }
+
+ function EmailEvent($email_event_name, $email_event_type, $to_user_id = -1, $send_params = false)
+ {
+ $event = new kEvent('emailevents:OnEmailEvent');
+ $event->setEventParam('EmailEventName', $email_event_name);
+ $event->setEventParam('EmailEventToUserId', $to_user_id);
+ $event->setEventParam('EmailEventType', $email_event_type);
+ if ($send_params){
+ $event->setEventParam('DirectSendParams', $send_params);
+ }
+ $this->HandleEvent($event);
+
+ return $event;
+ }
+
+
+ function LoggedIn()
+ {
+ $user =& $this->recallObject('u');
+ return ($user->GetDBField('PortalUserId') > 0);
+ }
+
+ function CheckPermission($name, $cat_id = null)
+ {
+ if(!$cat_id)
+ {
+ $cat_id = $this->GetVar('m_cat_id');
+ }
+ $sql = 'SELECT ParentPath FROM '.$this->getUnitOption('c', 'TableName').'
+ WHERE CategoryId = '.$cat_id;
+ $cat_hierarchy = $this->DB->GetOne($sql);
+ $cat_hierarchy = explode('|', $cat_hierarchy);
+ array_shift($cat_hierarchy);
+ array_pop($cat_hierarchy);
+ $cat_hierarchy = array_reverse($cat_hierarchy);
+
+ $groups = $this->RecallVar('UserGroups');
+
+ foreach($cat_hierarchy as $category_id)
+ {
+ $sql = 'SELECT PermissionValue FROM '.TABLE_PREFIX.'Permissions
+ WHERE Permission = "'.$name.'"
+ AND CatId = '.$category_id.'
+ AND GroupId IN ('.$groups.')';
+ $res = $this->DB->GetOne($sql);
+ if( $res !== false )
+ {
+ return $res;
+ }
+ }
+
+ return 0;
+ }
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/application.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.13
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/globals.php
===================================================================
--- trunk/core/kernel/globals.php (nonexistent)
+++ trunk/core/kernel/globals.php (revision 1560)
@@ -0,0 +1,297 @@
+<?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 searchable array
+ * @param int $key array 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);
+ }
+}
+
+if( !function_exists('k4_include_once') )
+{
+ function k4_include_once($file)
+ {
+ if ( defined('DEBUG_MODE') && 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);
+ }
+ }
+}
+
+ /**
+ * Checks if string passed is serialized array
+ *
+ * @param string $string
+ * @return bool
+ */
+ function IsSerialized($string)
+ {
+ if( is_array($string) ) return false;
+ return preg_match('/a:([\d]+):{/', $string);
+ }
+
+ if (!function_exists('makepassword4')){
+
+ function makepassword4($length=10)
+ {
+ $pass_length=$length;
+
+ $p1=array('b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','y','z');
+ $p2=array('a','e','i','o','u');
+ $p3=array('1','2','3','4','5','6','7','8','9');
+ $p4=array('(','&',')',';','%'); // if you need real strong stuff
+
+ // how much elements in the array
+ // can be done with a array count but counting once here is faster
+
+ $s1=21;// this is the count of $p1
+ $s2=5; // this is the count of $p2
+ $s3=9; // this is the count of $p3
+ $s4=5; // this is the count of $p4
+
+ // possible readable combinations
+
+ $c1='121'; // will be like 'bab'
+ $c2='212'; // will be like 'aba'
+ $c3='12'; // will be like 'ab'
+ $c4='3'; // will be just a number '1 to 9' if you dont like number delete the 3
+ // $c5='4'; // uncomment to active the strong stuff
+
+ $comb='4'; // the amount of combinations you made above (and did not comment out)
+
+
+
+ for ($p=0;$p<$pass_length;)
+ {
+ mt_srand((double)microtime()*1000000);
+ $strpart=mt_rand(1,$comb);
+ // checking if the stringpart is not the same as the previous one
+ if($strpart<>$previous)
+ {
+ $pass_structure.=${'c'.$strpart};
+
+ // shortcutting the loop a bit
+ $p=$p+strlen(${'c'.$strpart});
+ }
+ $previous=$strpart;
+ }
+
+
+ // generating the password from the structure defined in $pass_structure
+ for ($g=0;$g<strlen($pass_structure);$g++)
+ {
+ mt_srand((double)microtime()*1000000);
+ $sel=substr($pass_structure,$g,1);
+ $pass.=${'p'.$sel}[mt_rand(0,-1+${'s'.$sel})];
+
+ }
+ return $pass;
+ }
+ }
+
+ if( !function_exists('unhtmlentities') )
+ {
+ function unhtmlentities($string)
+ {
+ $trans_tbl = get_html_translation_table(HTML_ENTITIES);
+ $trans_tbl = array_flip ($trans_tbl);
+ return strtr($string, $trans_tbl);
+ }
+ }
+
+ /**
+ * submits $url with $post as POST
+ *
+ * @param string $url
+ * @param unknown_type $post
+ * @return unknown
+ */
+ function curl_post($url, $post)
+ {
+ $ch = curl_init($url);
+ curl_setopt($ch, CURLOPT_POST, 1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ $ret = curl_exec($ch);
+ curl_close($ch);
+ return $ret;
+ }
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/globals.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ 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 (nonexistent)
+++ trunk/core/kernel/kbase.php (revision 1560)
@@ -0,0 +1,454 @@
+<?php
+/**
+* Base
+*
+* Desciption
+* @package kernel4
+*/
+class kBase {
+ /**
+ * Holds reference to global KernelApplication instance
+ * @access public
+ * @var kApplication
+ */
+ var $Application;
+
+ /**
+ * Prefix, that was used
+ * to create an object
+ *
+ * @var string
+ * @access public
+ */
+ var $Prefix='';
+
+ /**
+ * Special, that was used
+ * to create an object
+ *
+ * @var string
+ * @access public
+ */
+ var $Special='';
+
+ var $OriginalParams;
+
+ /**
+ * Set's application
+ *
+ * @return kBase
+ * @access public
+ */
+ function kBase()
+ {
+ $this->Application =& kApplication::Instance();
+ }
+
+ /**
+ * Create new instance of object
+ *
+ * @return kBase
+ */
+ function &makeClass()
+ {
+ return new kBase();
+ }
+
+ /**
+ * Set's prefix and special
+ *
+ * @param string $prefix
+ * @param string $special
+ * @access public
+ */
+ function Init($prefix,$special,$event_params=null)
+ {
+ $prefix=explode('_',$prefix,2);
+ $this->Prefix=$prefix[0];
+ $this->Special=$special;
+ $this->OriginalParams = $event_params;
+ }
+
+ /**
+ * Returns joined prefix
+ * and special if any
+ *
+ * @return string
+ * @access protected
+ */
+ function getPrefixSpecial()
+ {
+ return rtrim($this->Prefix.'.'.$this->Special,'.');
+ }
+
+ function &getProperty($property_name)
+ {
+ 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;
+
+ /**
+ * Fields allowed to be set (from table + virtual)
+ *
+ * @var Array
+ * @access private
+ */
+ var $Fields=Array();
+
+ /**
+ * All virtual field names
+ *
+ * @var Array
+ * @access private
+ */
+ var $VirtualFields=Array();
+
+ /**
+ * Fields that need to be queried using custom expression, e.g. IF(...) AS value
+ *
+ * @var Array
+ * @access private
+ */
+ var $CalculatedFields = Array();
+
+ /**
+ * Description
+ *
+ * @var string Item' database table name, without prefix
+ * @access public
+ */
+ var $TableName;
+
+ /**
+ * Allows to determine object's table status ('temp' - temp table, '' - live table)
+ *
+ * @var string
+ * @access public
+ */
+ var $mode='';
+
+ function kDBBase()
+ {
+ parent::kBase();
+ $this->Conn =& $this->Application->GetADODBConnection();
+ }
+
+ /**
+ * Set current item' database table name
+ *
+ * @access public
+ * @param string $table_name
+ * @return void
+ */
+ function setTableName($table_name)
+ {
+ $this->TableName = $table_name;
+ }
+
+ /**
+ * Set object' TableName to Live table from config
+ *
+ * @access public
+ */
+ function SwitchToLive()
+ {
+ $this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName');
+ }
+
+ /**
+ * Set object' TableName to Temp table from config
+ *
+ * @access public
+ */
+ function SwitchToTemp()
+ {
+ $this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName');
+ $this->SetTableName( kTempTablesHandler::GetTempName($this->TableName) );
+ $this->mode = 't';
+ }
+
+ /**
+ * Checks if object uses temp table
+ *
+ * @return bool
+ */
+ function IsTempTable()
+ {
+ return kTempTablesHandler::IsTempTable($this->TableName);
+ }
+
+ /**
+ * Sets SELECT part of list' query
+ *
+ * @access public
+ * @param string $sql SELECT and FROM [JOIN] part of the query up to WHERE
+ * @return void
+ */
+ function SetSelectSQL($sql)
+ {
+ $this->SelectClause = $sql;
+ }
+
+ function GetSelectSQL($base_query=null)
+ {
+ if( !isset($base_query) ) $base_query = $this->SelectClause;
+ return $q = str_replace( Array('%1$s','%s'), $this->TableName, $base_query);
+ }
+
+ /**
+ * Insert calculated fields sql into query in place of %2$s,
+ * return processed query.
+ *
+ * @param string $query
+ * @return string
+ */
+ function addCalculatedFields($query)
+ {
+ if($this->CalculatedFields)
+ {
+ $sql = Array();
+ foreach($this->CalculatedFields as $field_name => $field_expression)
+ {
+ $sql[] = '('.$field_expression.') AS '.$field_name;
+ }
+ $sql = implode(',',$sql);
+ return $this->Application->ReplaceLanguageTags( str_replace('%2$s', ','.$sql, $query) );
+ }
+ else
+ {
+ return str_replace('%2$s', '', $query);
+ }
+ }
+
+ /**
+ * 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($name, $format=null)
+ {
+ $options = $this->GetFieldOptions($name);
+ $val = $this->GetDBField($name);
+ $res = $val;
+ if (isset($options['formatter'])) {
+ $formatter =& $this->Application->recallObject($options['formatter']);
+ $res = $formatter->Format($val, $name, $this, $format );
+ }
+ return $res;
+ }
+
+ function HasField($name)
+ {
+
+ }
+
+ function GetFieldValues()
+ {
+
+ }
+
+ function UpdateFormattersSubFields()
+ {
+ foreach ($this->Fields as $field => $options) {
+ if (isset($options['formatter'])) {
+ $formatter =& $this->Application->recallObject($options['formatter']);
+ $formatter->UpdateSubFields($field, $this->GetDBField($field), $options, $this);
+ }
+ }
+ }
+
+ function prepareConfigOptions()
+ {
+ foreach (array_keys($this->Fields) as $field_name)
+ {
+ $field_options =& $this->Fields[$field_name];
+ if( isset($field_options['options_sql']) )
+ {
+ // replace with query result
+ $select_clause = $field_options['option_title_field'].','.$field_options['option_key_field'];
+ $sql = sprintf($field_options['options_sql'], $select_clause);
+
+ $options_hash = getArrayValue($field_options,'options');
+ if($options_hash === false) $options_hash = Array();
+
+ $dynamic_options = $this->Conn->GetCol($sql, $field_options['option_key_field']);
+ $field_options['options'] = array_merge_recursive2($options_hash, $dynamic_options);
+
+ unset($field_options['options_sql']);
+ }
+ $this->PrepareOptions($field_name);
+ }
+ }
+
+ function PrepareOptions($field_name)
+ {
+ if( $formatter_class = getArrayValue($this->Fields[$field_name], 'formatter') )
+ {
+ $formatter =& $this->Application->recallObject($formatter_class);
+ $formatter->PrepareOptions($field_name, $this->Fields[$field_name], $this);
+ }
+ }
+
+ /**
+ * Returns unformatted field value
+ *
+ * @param string $field
+ * @return string
+ * @access public
+ */
+ function GetDBField($field)
+ {
+
+ }
+
+ /**
+ * Returns ID of currently processed record
+ *
+ * @return int
+ * @access public
+ */
+ function GetID()
+ {
+ return $this->GetDBField($this->IDField);
+ }
+
+ /**
+ * Returns parent table information
+ *
+ * @param bool $from_temp load parent item from temp table
+ * @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
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/parser/template.php
===================================================================
--- trunk/core/kernel/parser/template.php (nonexistent)
+++ trunk/core/kernel/parser/template.php (revision 1560)
@@ -0,0 +1,192 @@
+<?php
+
+class Template {
+ var $Body = '';
+ var $BasePath = '';
+ var $Filename = '';
+
+ function Template($base_path=null, $filename=null, $silent=0)
+ {
+ if ($this->SetBasePath($base_path)) {
+ if (isset($filename)) {
+ $this->Filename = $filename;
+ $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 {
+ /*global $debugger;
+ if($debugger) $debugger->appendTrace();*/
+ 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->SetThemePath();
+ $this->BasePath = DOC_ROOT.BASE_PATH.THEMES_PATH;
+
+ $conn =& $this->Application->GetADODBConnection();
+ $this->ModulesCache = $conn->GetCol('SELECT LOWER(Name) FROM '.TABLE_PREFIX.'Modules');
+ }
+
+ function SetThemePath()
+ {
+ 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 {
+
+ $current_theme = $this->Application->GetVar('m_theme');
+ $folder = $this->Application->DB->GetOne('SELECT Name FROM '.TABLE_PREFIX.'Theme WHERE ThemeId = '.$current_theme);
+
+ safeDefine( 'THEMES_PATH', preg_replace('/'.preg_quote(DOC_ROOT.BASE_PATH, '/').'/i','',str_replace('\\', '/', FULL_PATH)). ( defined('ADMIN') ? '/admin/templates' : '/themes/'.$folder));
+ }
+ }
+
+ function LoadTemplate($filename, $title=NULL, $silent=0)
+ {
+ 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 GetRealFilename($filename, $base=null) {
+ 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 = isset($base) ? $base : $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, $silent=0)
+ {
+ if (!isset($this->Templates[$title])) {
+ $this->LoadTemplate($title, null, $silent);
+ }
+ return $this->Templates[$title];
+ }
+
+ function GetTemplateBody($title, $silent=0)
+ {
+ $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)
+ {
+ if (!preg_match("/\.tpl$/", $filename)) $filename .= '.tpl';
+ $real_file = $this->GetRealFilename($filename);
+ return file_exists($real_file);
+ }
+}
+
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/parser/template.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/parser/tags.php
===================================================================
--- trunk/core/kernel/parser/tags.php (nonexistent)
+++ trunk/core/kernel/parser/tags.php (revision 1560)
@@ -0,0 +1,380 @@
+<?php
+
+global $kernel_path;
+k4_include_once(KERNEL_PATH.'/parser/construct_tags.php');
+
+define ('parse', 0);
+define ('skip', 1);
+define ('skip_tags', 2);
+
+class MyTagHolder extends kBase {
+
+ var $_Tag;
+
+ function MyTagHolder()
+ {
+
+ }
+
+ function &GetTag($tag_data, &$parser, $inp_tag=0) {
+ if (!isset($this->_Tag)) {
+ $this->_Tag =& new Tag($tag_data, $parser, $inp_tag);
+ }
+ else {
+// $this->_Tag->Parser =& $parser;
+ $this->_Tag->TagData = $tag_data;
+ if ($tag_data != '') $this->_Tag->ParseTagData($tag_data);
+ $this->_Tag->NP =& $this->_Tag->NamedParams;
+ }
+ return $this->_Tag;
+ }
+
+}
+
+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, $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;
+ }
+
+ /**
+ * Set's Prefix and Special for Tag object
+ * based on ones from tagname
+ *
+ * @param string $tag_data
+ * @access protected
+ */
+ function ParseTagData($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) = split("[ \t\n]{1}", $tag_data, 2);
+ $key_data = trim($key_data);
+
+ $tmp=explode(':',$key_data);
+ $this->Tag=$tmp[1];
+
+ $tmp=$this->Application->processPrefix($tmp[0]);
+ $this->Prefix=$tmp['prefix'];
+ $this->Special=$tmp['special'];
+ $this->Processor=$this->Prefix;
+
+ if ($params != '') {
+ $this->ParseNamedParams($params);
+ }
+ else {
+ $this->NamedParams = array();
+ }
+ }
+
+ 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;
+ }
+
+ /**
+ * Process IF tags in specific way
+ *
+ */
+ function Process()
+ {
+ if ($this->Processor == 'm' || $this->Processor == 'm_TagProcessor') { //if we are procssing Main tags
+ if ($this->Tag == 'block' || $this->Tag == 'DefineElement') {
+ $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'
+ )
+ {
+ if ( defined('EXPERIMENTAL_PRE_PARSE') ) {
+ $this->Parser->AppendCompiledCode( $this->GetCode() );
+ }
+ $tag =& new ConstructTag('', $this->Parser);
+ $tag->CopyFrom($this);
+ $tag->Process();
+ }
+ else {
+ if ($this->Parser->SkipMode == skip) {
+ if ( defined('EXPERIMENTAL_PRE_PARSE') ) {
+ $this->Parser->AppendCompiledCode( $this->GetCode() );
+ }
+ return;
+ }
+ $this->ProcessTag();
+ if ( defined('EXPERIMENTAL_PRE_PARSE') ) {
+ $this->Parser->AppendCompiledCode( $this->GetCode() );
+ }
+ }
+ }
+ else { //normal tags - processors other than main
+ if ($this->Parser->SkipMode == skip) { // inside if - add statements inside if to compiled code
+ if ( defined('EXPERIMENTAL_PRE_PARSE') ) {
+ $this->Parser->AppendCompiledCode( $this->GetCode() );
+ }
+ return;
+ }
+ elseif ($this->Parser->SkipMode == skip_tags) return; //do not parse if we skipping tags
+ $this->ProcessTag();
+ if ( defined('EXPERIMENTAL_PRE_PARSE') ) {
+ $this->Parser->AppendCompiledCode( $this->GetCode() );
+ }
+ }
+ }
+
+ /**
+ * Set's Prefix and Special for TagProcessor
+ * based on tag beeing processed
+ *
+ * @return string
+ * @access protected
+ */
+ function DoProcessTag()
+ {
+ // $tag->Prefix - l_TagProcessor
+ $tmp = $this->Application->processPrefix($this->Processor);
+
+ $processor =& $this->Application->recallObject($tmp['prefix'].'_TagProcessor'); // $this->Processor
+
+ $tmp=explode('_',$tmp['prefix'],2);
+ $processor->Prefix=$tmp[0];
+ $processor->Special=$this->Special;
+
+ // pass_params for non ParseBlock tags :)
+ $parser_params = $this->Application->Parser->Params;
+ if( getArrayValue($this->NamedParams,'pass_params') )
+ {
+ unset( $this->NamedParams['pass_params'] );
+ $this->NamedParams = array_merge_recursive2($parser_params, $this->NamedParams);
+ }
+
+ return $processor->ProcessTag($this);
+ }
+
+ function ProcessTag()
+ {
+ $o = $this->DoProcessTag();
+ if ($o !== false)
+ {
+ $this->Parser->AppendOutput($o);
+ }
+ else
+ {
+ trigger_error('can\'t process tag '.$this->Tag,E_USER_WARNING);
+ }
+ }
+
+ function GetCode($echo=false)
+ {
+ $pass_params = $this->NP;
+
+ $code = Array();
+
+ $to_pass = 'Array(';
+ foreach ($pass_params as $name => $val) {
+ $to_pass .= '"'.$name.'" => "'.str_replace('"', '\"', $val).'",';
+ }
+ $to_pass .= ')';
+
+ if ($echo) $code[] = '$o = '."'';\n";
+
+ switch ( $this->Tag ) {
+ case 'param':
+ $code[] = '$o .= $params["'.$this->NP['name'].'"];';
+ return $code;
+ case 'if':
+ if (isset($this->NP['_closing_tag_'])) {
+ $code[] = ' }';
+ }
+ else {
+
+ $check = $this->GetParam('check');
+ if ($check) {
+ if (strpos($check, '_') !== false) {
+ list($prefix, $function) = explode('_', $check, 2);
+ }
+ else {
+ $function = $check;
+ $prefix = $this->Parser->GetParam('PrefixSpecial');
+ }
+ }
+ else {
+ $prefix = $this->GetParam('prefix');
+ $function = $this->GetParam('function');
+ }
+
+ $code[] = '$tmp = $application->processPrefix("'.$prefix.'");'."\n";
+ $code[] = '$__tag_processor = $tmp[\'prefix\'].\'_TagProcessor\';'."\n";
+ $code[] = '$processor =& $application->recallObject($__tag_processor);'."\n";
+ $code[] = '$processor->Prefix = $tmp[\'prefix\'];'."\n";
+ $code[] = '$processor->Special = $tmp[\'special\'];'."\n";
+ $code[] = '$if_result = $processor->ProcessParsedTag(\''.$function.'\', '.$to_pass.', "'.$prefix.'");'."\n";
+ if (isset($pass_params['inverse'])) {
+ $code[] = 'if (!$if_result) {';
+ }
+ else {
+ $code[] = 'if ($if_result) {';
+ }
+ }
+ return $code;
+
+ case 'endif':
+ $code[] = ' }';
+ return $code;
+
+ case 'else':
+ $code[] = ' }';
+ $code[] = ' else {';
+ return $code;
+ }
+
+ if (!$this->Processor) {
+ echo '';
+ }
+ $code[] = '$tmp = $application->processPrefix("'.$this->getPrefixSpecial().'");'."\n";
+ $code[] = '$__tag_processor = $tmp[\'prefix\'].\'_TagProcessor\';'."\n";
+ $code[] = '$processor =& $application->recallObject($__tag_processor);'."\n";
+ $code[] = '$processor->Prefix = $tmp[\'prefix\'];'."\n";
+ $code[] = '$processor->Special = $tmp[\'special\'];'."\n";
+
+
+ $code[] = '$o .= $processor->ProcessParsedTag(\''.$this->Tag.'\', '.$to_pass.', "'.$this->Processor.'");'."\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 .'\'';
+ }
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/parser/tags.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/parser/construct_tags.php
===================================================================
--- trunk/core/kernel/parser/construct_tags.php (nonexistent)
+++ trunk/core/kernel/parser/construct_tags.php (revision 1560)
@@ -0,0 +1,260 @@
+<?php
+
+global $kernel_path;
+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()
+ {
+ $check = $this->GetParam('check');
+ if ($check) {
+ if (strpos($check, '_') !== false) {
+ list($prefix, $function) = explode('_', $check, 2);
+ }
+ else {
+ $function = $check;
+ $prefix = $this->Parser->GetParam('PrefixSpecial');
+ }
+ }
+ else {
+ $prefix = $this->GetParam('prefix');
+ $function = $this->GetParam('function');
+ }
+ $this->NP['prefix'] = $prefix;
+ $this->NP['function'] = $function;
+
+ $inverse = $this->GetParam('inverse');
+
+ if ($prefix !== false) {
+ $tag =& new Tag('', $this->Parser);
+ $tag->Tag = $function;
+
+ $tmp = $this->Application->processPrefix($prefix);
+ $tag->Processor = $tmp['prefix'];
+
+ $tag->Prefix=$tmp['prefix'];
+ $tag->Special=$tmp['special'];
+ $tag->NamedParams = $this->NP;
+ $this->Logic = $tag->DoProcessTag();
+ // echo " this->Logic : ".$this->Logic."<br>";
+ }
+ else
+ {
+ $this->Logic = $function;
+ }
+ if($inverse) $this->Logic = !$this->Logic;
+ }
+
+ 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 == 'if' || $tag->Tag == 'endif') {
+ $this->Parser->AppendCompiledCode('}');
+ $this->Parser->ResetCode();
+ }
+ }
+ $this->RestoreSkipMode(); //Restoring original SkipMode
+ return true;
+ }
+ else {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->Parser->AppendCode($tag->GetCode());
+// $this->Parser->AppendCompiledCode( $tag->GetCode() );
+ }
+ }
+ return false;
+ }
+
+ function CheckEndRecursion(&$tag)
+ {
+ if ($tag->GetParam('_closing_tag_') == 1 && $tag->Tag == $this->Tag) {
+ return true;
+ }
+ 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':
+ case 'DefineElement':
+ if ($this->Tag == 'DefineElement') {
+ $this->SetStopTag('end_define'); //This recursion level should end when 'blockend' is found
+ }
+ else {
+ $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, $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 .= "\t\t".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') {
+ 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;
+ }
+ }
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/parser/construct_tags.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/kernel/parser/template_parser.php
===================================================================
--- trunk/core/kernel/parser/template_parser.php (nonexistent)
+++ trunk/core/kernel/parser/template_parser.php (revision 1560)
@@ -0,0 +1,480 @@
+<?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;
+
+ var $DataExists = false;
+
+ function TemplateParser()
+ {
+ parent::kBase();
+ $this->Ses =& $this->Application->recallObject('Session');
+ }
+
+ 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('/[{]{0,1}\$'.$key.'[}]{0,1}/i', $val, 1); //Do not sort every time
+ }
+ $this->SortParams(); //Sort once after adding is done
+ }
+
+ function GetParam($name)
+ {
+ //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[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, $append_code=false)
+ {
+ 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) {
+ 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')) {
+ if ( isset($this->Application->CompiledFunctions[$f_name]) ||
+ function_exists($f_name)
+ ) {
+ if (!isset($this->Application->CompiledFunctions[$f_name])) {
+ $real_name = $f_name.'_';
+ }
+ else {
+ $real_name = $this->Application->CompiledFunctions[$f_name].'_';
+ }
+ }
+ else {
+ $real_name = $f_name;
+ }
+
+ $this->CompiledBuffer .= 'if (!function_exists(\''.$real_name.'\')) {'."\n";
+
+
+ $this->CompiledBuffer .= "\t".'$application->PreParsedBlocks[\''.$f_name.'\'] = \''.$real_name.'\';';
+ $this->CompiledBuffer .= "\n\t".'function '.$real_name.'($params)'."\n\t{\n";
+ $this->CompiledBuffer .= $f_body;
+ $this->CompiledBuffer .= "\t}\n\n";
+
+ $this->CompiledBuffer .= '}'."\n";
+
+ $this->Application->CompiledFunctions[$f_name] = $real_name;
+
+ }
+ }
+
+ function AppendCompiledCode($code)
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ if (is_array($code)) {
+ foreach ($code as $line) {
+ $this->CompiledBuffer .= "\t".rtrim($line, "\n")."\n";
+ }
+ }
+ else {
+ $this->CompiledBuffer .= $code;
+ }
+ $this->CompiledBuffer .= "\t".'echo $o;'."\n\t".'$o = \'\';'."\n";
+ }
+ }
+
+ function AppendCompiledHTML($append)
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->CompiledBuffer .= '?'.'>'."\n";
+ $this->CompiledBuffer .= rtrim($append, "\t");
+ $this->CompiledBuffer .= '<'.'?php'."\n";
+ }
+ }
+
+ function ResetCode()
+ {
+ $this->Code[$this->RecursionIndex] = Array();
+ }
+
+ function FindTag2()
+ {
+ $openings = Array('<%' => '%>', '<inp2:' => Array('>', '/>'), '</inp2:' => '>', '</inp2>' => '');
+
+ $tag_open_pos = false;
+ foreach ($openings as $an_opening => $closings) {
+ $pos = strpos($this->Template, $an_opening, $this->Position);
+ if ($pos !== false && ($tag_open_pos === false || (int) $pos <= (int) $tag_open_pos)) {
+ $tag_open_pos = $pos;
+ $open_len = strlen($an_opening);
+ $opening_tag = $an_opening;
+ $tag_closings = $closings;
+ }
+ }
+
+ if ($tag_open_pos === false) { //If no tags left - adding all other data
+ $this->AppendOutput(substr($this->Template, $this->Position), true);
+ return false;
+ }
+
+ //Adding all data before tag open
+ $this->AppendOutput(substr($this->Template, $this->Position, $tag_open_pos - $this->Position), true);
+
+
+ if (is_array($tag_closings)) {
+ $tag_close_pos = false;
+ foreach ($tag_closings as $a_closing) {
+ $pos = strpos($this->Template, $a_closing, $tag_open_pos);
+ if ($pos !== false && ($tag_close_pos === false || (int) $pos <= (int) $tag_close_pos)) {
+ $tag_close_pos = $pos;
+ $closing_tag = $a_closing;
+ }
+ }
+ }
+ elseif ($opening_tag == '</inp2>') {
+ $closing_tag = '';
+ $tag_close_pos = $tag_open_pos + $open_len;
+ }
+ else {
+ $closing_tag = $tag_closings;
+ $tag_close_pos = strpos($this->Template, $closing_tag, $tag_open_pos);
+ }
+ $close_len = strlen($closing_tag);
+
+ //Cutting out the tag itself
+ $tag = substr($this->Template, $tag_open_pos + $open_len, $tag_close_pos - $tag_open_pos - $open_len);
+
+
+ if ($opening_tag == '<inp2:') {
+ //getting prefix_tag upto first space, tab or line break into regs[1]
+ preg_match("/^([^ \t\n]*)(.*)/", $tag, $regs);
+ $tag_part = $regs[1];
+ if (strpos($tag_part, '_') !== false) {
+ list($prefix, $the_tag) = explode('_', $tag, 2);
+ $tag = $prefix.':'.$the_tag;
+ }
+ else {
+ $the_tag = $tag;
+ $tag = ':'.$tag;
+ }
+ }
+
+ if ($opening_tag == '</inp2>') { //empty closing means old style in-portal if <inp2:tag>....</inp2>
+ $tag = 'm:endif';
+ }
+
+ if ($opening_tag == '</inp2:') {
+ preg_match("/^([^ \t\n]*)(.*)/", $tag, $regs);
+ $tag_part = $regs[1];
+ if (strpos($tag_part, '_') !== false) {
+ list($prefix, $the_tag) = explode('_', $tag, 2);
+ $tag = $prefix.':'.$the_tag;
+ }
+ $tag .= ' _closing_tag_="1"';
+ }
+
+ // if there is no prefix for the tag
+ if (strpos($tag, ':') === 0) {
+ $prefix = getArrayValue($this->Params, 'PrefixSpecial');
+ $tag = $prefix.$tag;
+ }
+
+ // temporary - for backward compatability with in-portal style if
+ if ($opening_tag == '<inp2:' && $closing_tag == '>' && $tag_part != 'm_if' && $tag_part != 'm_DefineElement') {
+ if (strpos($the_tag, ' ') !== false) {
+ list($function, $params) = explode(' ', $the_tag, 2);
+ }
+ else {
+ $function = $the_tag;
+ $params = '';
+ }
+ $tag = 'm:if prefix="'.$prefix.'" function="'.$function.'" '.$params;
+ }
+
+ $this->Position = $tag_close_pos + $close_len;
+ return $tag;
+ }
+
+ 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->TagHolder = new MyTagHolder();
+
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $template_cache =& $this->Application->recallObject('TemplatesCache');
+ $fname = $template_cache->GetRealFilename($this->TemplateName).'.php';
+ $tname = $template_cache->GetRealFilename($this->TemplateName).'.tpl';
+
+ if (file_exists($fname) && filemtime($fname) > filemtime($tname)) {
+ ob_start();
+ include($fname);
+ $output = ob_get_contents();
+ ob_end_clean();
+ return $output;
+ }
+
+ $this->CompiledBuffer .= '<'.'?php'."\n";
+ $this->CompiledBuffer .= 'global $application;'."\n";
+ $this->CompiledBuffer .= '$o = \'\';'."\n";
+ }
+
+ if (!getArrayValue($this->Params, 'PrefixSpecial')) {
+ $this->Params['PrefixSpecial'] = '$PrefixSpecial';
+ }
+
+ //While we have more tags
+ while ($tag_data = $this->FindTag2())
+ {
+ //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.THEMES_PATH.'/'.$this->TemplateName).'.tpl', $this->CurrentLineNumber(), '', true));
+ }
+// $tag =& new MyTag($tag_data, $this);
+ $tag =& $this->TagHolder->GetTag($tag_data, $this);
+
+ if (!$this->CheckRecursion($tag)) //we do NOT process closing tags
+ {
+ $tag->Process();
+ }
+ }
+
+ if ( !$this->GetParam('from_inportal') ) {
+ if ( strpos($this->Output, '<inp:') !== false) {
+ $inp1_parser =& $this->Application->recallObject('Inp1Parser');
+ $this->Output = $inp1_parser->Parse($name, $this->Output);
+ }
+ }
+
+
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+// $this->CompiledBuffer .= 'echo $o;'."\n";
+ $this->CompiledBuffer .= '?'.'>'."\n";
+
+ $compiled = fopen($fname, 'w');
+ fwrite($compiled, $this->CompiledBuffer);
+ fclose($compiled);
+ }
+
+ return $this->Output;
+ }
+
+ function ParseBlock($params, $force_pass_params=0, $as_template=false)
+ {
+ if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_SHOW_TAGS') )
+ {
+ global $debugger;
+ $debugger->appendHTML('ParseBlock '.$params['name'].' pass_params is '.$params['pass_params'].' force is '.$force_pass_params.' in '.$debugger->getFileLink($debugger->getLocalFile(DOC_ROOT.BASE_PATH.THEMES_PATH.'/'.$this->TemplateName).'.tpl', $this->CurrentLineNumber(), '', true));
+
+ }
+ if ( $this->Application->isDebugMode() && dbg_ConstOn('DBG_PRE_PARSE') ) {
+ global $debugger;
+ $debugger->CurrentPreParsedBlock = $params['name'];
+ }
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->MainParser = false;
+ if (isset($this->Application->PreParsedBlocks[$params['name']]) ) {
+
+ if ($this->ParamsRecursionIndex == 0) {
+ $this->ParamsStack[$this->ParamsRecursionIndex] = $this->Params;
+ }
+
+ if (isset($params['pass_params']) || $force_pass_params) {
+ $pass_params = array_merge($this->ParamsStack[$this->ParamsRecursionIndex], $params);
+ }
+ else {
+ $pass_params = $params;
+ }
+
+ $this->ParamsStack[++$this->ParamsRecursionIndex] = $pass_params;
+ $this->Params = $pass_params;
+
+ $f = $this->Application->PreParsedBlocks[$params['name']];
+
+// $this->ParamsRecursionIndex--;
+
+ //$this->SetParams($params);
+ $ret = $f($pass_params);
+
+ unset($this->ParamsStack[$this->ParamsRecursionIndex--]);
+ $this->Params = $this->ParamsStack[$this->ParamsRecursionIndex];
+ $this->MainParser = true;
+ return $ret;
+ }
+ }
+
+ $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'])) 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'];
+
+ $silent = getArrayValue($params, 'from_inportal') && !defined('DBG_TEMPLATE_FAILURE');
+
+ $o = $BlockParser->Parse(
+ $templates_cache->GetTemplateBody($params['name'], $silent),
+ $template_name
+ );
+ if (getArrayValue($params, 'BlockNoData') && !$BlockParser->DataExists) {
+ $template_name = $as_template ? $params['BlockNoData'] : $templates_cache->GetTemplateFileName($params['BlockNoData']) . '-block:'.$params['BlockNoData'];
+ $o = $BlockParser->Parse(
+ $templates_cache->GetTemplateBody($params['BlockNoData'], $silent),
+ $template_name
+ );
+ }
+ $this->Application->Parser =& $this;
+ $this->Application->Parser->DataExists = $this->Application->Parser->DataExists || $BlockParser->DataExists;
+ return $o;
+ }
+
+ 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;
+ }
+}
+
+?>
\ No newline at end of file
Property changes on: trunk/core/kernel/parser/template_parser.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.4
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property

Event Timeline