Index: trunk/core/kernel/startup.php =================================================================== diff -u --- trunk/core/kernel/startup.php (revision 0) +++ trunk/core/kernel/startup.php (revision 932) @@ -0,0 +1,50 @@ +',$label,'
',print_r($data,true),'
'; + //echo var_dump($data); +} + +function safeDefine($const_name, $const_value) +{ + if(!defined($const_name)) define($const_name,$const_value); +} + +?> \ No newline at end of file Index: trunk/core/kernel/parser/template_parser.php =================================================================== diff -u --- trunk/core/kernel/parser/template_parser.php (revision 0) +++ trunk/core/kernel/parser/template_parser.php (revision 932) @@ -0,0 +1,232 @@ +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('/\$'.$key.'/', $val, 1); //Do not sort every time + } + $this->SortParams(); //Sort once after adding is done + } + + function GetParam($name) + { + if (isset($this->Params[$name])) + return $this->Params[$name]; + else + return false; + } + + function SetParam($name, $value) + { + $this->Params[$name] = $value; + } + + function SetBuffer($body) + { + $this->Buffers[$this->RecursionIndex] = $body; + } + + function GetBuffer() + { + return $this->Buffers[$this->RecursionIndex]; + } + + function AppendBuffer($append) + { + $this->Buffers[$this->RecursionIndex] .= $append; + } + + function AppendOutput($append) + { + if ($this->SkipMode == parse) + $this->Output .= $append; //append to Ouput only if we are parsing + elseif ($this->SkipMode == skip_tags) { + $this->AppendBuffer($append); //append to buffer if we are skipping tags + } + } + + function FindTag() + { + $tagOpen = strpos($this->Template, '<%', $this->Position); //Finding tag start + + $inp_tag = false; + $tagOpenLen = 2; + + if ($tagOpen === false) { //If not tags left - adding all other data + $this->AppendOutput(substr($this->Template, $this->Position)); + return false; + } + + //Adding all data before tag open + $this->AppendOutput(substr($this->Template, $this->Position, $tagOpen - $this->Position)); + + //Finding tag end + $tagCloseLen = 2; + $tagClose = strpos($this->Template, "%>", $tagOpen); + + if ($tagClose === false) die ("Can't find tag closing"); + + //Cutting out the tag itself + $tag = substr($this->Template, $tagOpen + $tagOpenLen, $tagClose - $tagOpen - $tagOpenLen); + + //Seting current position right after the tag + $this->Position = $tagClose + $tagCloseLen; + return $tag; + } + + function Parse($template) + { + $this->Template = $template; + $this->Position = 0; + $this->Output = ''; + + //While we have more tags + while ($tag_data = $this->FindTag()) + { + //Create tag object from passed tag data + $tag =& new Tag($tag_data, $this); + if (!$this->CheckRecursion($tag)) //we do NOT process closing tags + { + $tag->Process(); + } + } + return $this->Output; + } + + function ParseBlock($params, $force_pass_params=0) + { + $BlockParser =& $this->Application->Factory->makeClass('TemplateParser'); + if (isset($params['pass_params']) || $force_pass_params) { + $BlockParser->SetParams(array_merge($this->Params, $params)); + } + else + $BlockParser->SetParams($params); + $this->Application->Parser =& $BlockParser; + if (!isset($params['name'])) die("***Error: Block name not passed to ParseBlock
"); + $templates_cache =& $this->Application->recallObject('TemplatesCache'); + $o = $BlockParser->Parse( + $templates_cache->GetTemplateBody($params['name']) + ); + $this->Application->Parser =& $this; + return $o; + } + + function ParseXML($template, $params) + { + $templates_cache =& $this->Application->recallObject('TemplatesCache'); + $xml = $templates_cache->GetTemplateBody($template); + + $PreParser =& new TemplateParser(); + $PreParser->SetParams($params); + $this->Application->Parser =& $PreParser; + $xml = $PreParser->Parse($xml); + $this->Application->Parser =& $this; + $XMLParser =& new XMLParser($params); + $this->AppendOutput($XMLParser->Parse($xml)); + } + + function Recurve(&$tag) + { + $this->Recursion[++$this->RecursionIndex] =& $tag; + } + + function CheckRecursion(&$tag) + { + if ($this->RecursionIndex > 0) { //If we are inside the recursion + if ($this->Recursion[$this->RecursionIndex]->CheckRecursion($tag)) { //If we can close this recursion + unset($this->Recursion[$this->RecursionIndex--]); //unsetting current recursion level and decreasing it at the same time + return true; //we should inform not to process closing tag + } + } + return false; + } + + function SetSkipMode($mode) + { + $this->SkipMode = $mode; + } +} + +// ################### TESTS ############################ + +global $suite; +if (isset($suite)) { + class TestTemplateParser extends TestCase { + function testFindTag() + { + $parser =& new TemplateParser(); + $parser->Template = 'before<%first_tag%>between<%second_tag%>after'; + $this->assertEquals('first_tag', $parser->FindTag()); + $this->assertEquals('second_tag', $parser->FindTag()); + $parser->FindTag(); + $this->assertEquals('beforebetweenafter', $parser->Output); + } + + function testAppendOutput() + { + $parser =& new TemplateParser(); + $parser->AppendOutput('1'); + $this->assertEquals('1', $parser->Output); + $parser->SetSkipMode(skip); + $parser->AppendOutput('2'); + $this->assertEquals('1', $parser->Output); + } + } + $suite->addTest(new TestSuite("TestTemplateParser")); +} + +?> \ No newline at end of file Index: trunk/core/kernel/db/dbitem.php =================================================================== diff -u --- trunk/core/kernel/db/dbitem.php (revision 0) +++ trunk/core/kernel/db/dbitem.php (revision 932) @@ -0,0 +1,294 @@ +Fields=$fields; + } + + /** + * Sets current item field value + * (applies formatting) + * + * @access public + * @param string $name Name of the field + * @param mixed $value Value to set the field to + * @return void + */ + function SetField($name,$value) + { + $this->SetDBField($name,$value); + } + + /** + * Sets current item field value + * (doesn't apply formatting) + * + * @access public + * @param string $name Name of the field + * @param mixed $value Value to set the field to + * @return void + */ + function SetDBField($name,$value) + { + $this->FieldValues[$name] = $value; + } + + + /** + * Return current item' field value by field name + * (apply formatter) + * + * @access public + * @param string $name field name to return + * @return mixed + */ + function GetField($name) + { + return $this->GetDBField($name); + } + + /** + * Return current item' field value by field name + * (doesn't apply formatter) + * + * @access public + * @param string $name field name to return + * @return mixed + */ + function GetDBField($name) + { + return $this->FieldValues[$name]; + } + + /** + * 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 + * @return void + */ + function SetFieldsFromHash($hash) + { + foreach ($hash as $field_name => $field_value) + { + if( eregi("^[0-9]+$", $field_name) || !in_array($field_name,$this->Fields) ) continue; + $this->SetField($field_name,$field_value); + } + } + + /** + * Returns part of SQL WHERE clause identifing the record, ex. id = 25 + * + * @access public + * @param string $method Child class may want to know who called GetKeyClause, Load(), Update(), Delete() send its names as method + * @return void + * @see kDBItem::Load() + * @see kDBItem::Update() + * @see kDBItem::Delete() + */ + function GetKeyClause($method=null) + { + return $this->IDField.' = '.$this->Conn->qstr($this->ID); + } + + /** + * 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 (isset($id_field_name)) $this->SetIDField($id_field_name); + + if (!isset($id)) return false; + + $this->ID = $id; + + $q = $this->GetSelectSQL().' WHERE '.$this->GetKeyClause('load'); + if ($this->DisplayQueries) { + echo get_class($this)." Load SQL: $q
"; + } + $this->FieldValues = $this->Conn->GetRow($q); + + if ($this->FieldValues === false) { + //Error handling could be here + return false; + } + $this->setID($id); + return true; + } + + /** + * Updates previously loaded record with current item' values + * + * @access public + * @param int Primery Key Id to update + * @return void + */ + function Update($id=null) + { + if( isset($id) ) $this->ID=$id; + if( !isset($this->ID) ) return false; + + // Validate before updating + if( !$this->Validate() ) return false; + + //Nothing to update + if(!$this->FieldValues) return true; + + $sql = sprintf('UPDATE %s SET ',$this->TableName); + foreach ($this->FieldValues as $field_name => $field_value) + { + if ( isset($this->VirtualFields[$field_name]) ) continue; //skipping 'virtual' field + if ($field_name == $this->IDField) continue; //skipping Primary Key + + $real_field_name = eregi_replace("^.*\.", '',$field_name); //removing table names from field names + + //Adding part of SET clause for current field, escaping data with ADODB' qstr + $sql.= sprintf('%s=%s, ',$real_field_name,$this->Conn->qstr($this->FieldValues[$field_name], 0)); + } + $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
"; + + if ($this->Conn->ChangeQuery($sql) === false) { //Executing query and checking results + if ($this->DisplayQueries) + { + echo "Error executing statement: ".$adodbConnection->ErrorMsg()."
"; + } + return false; + } + return true; + } + + function Validate() + { + return true; + } + + /** + * Creates a record in the database table with current item' values + * + * @access public + * @return void + */ + function Create() + { + if(!$this->Validate()) //Validating fields before attempting to create record + return false; + + $fields_sql = ''; + $values_sql = ''; + foreach ($this->FieldValues as $field_name => $field_value) + { + if ( isset($this->VirtualFields[$field_name]) ) continue; //skipping 'virtual' field + + $fields_sql .= sprintf('%s, ',$field_name); //Adding field name to fields block of Insert statement + //Adding field' value to Values block of Insert statement, escaping it with ADODB' qstr + $values_sql .= sprintf('%s, ',$this->Conn->qstr($this->FieldValues[$field_name], 0)); + } + //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().'
'; + } + return false; + } + $this->setID( $this->Conn->getInsertID() ); + //$this->SetInsertID(); //Setting Primary Key ($this->id) for futher using the object + return true; + } + + /** + * Deletes the record from databse + * + * @access public + * @return void + */ + function Delete() + { + $q = 'DELETE FROM '.$this->TableName.' WHERE '.$this->GetKeyClause('Delete'); + if ($this->DisplayQueries) + { + echo get_class($this).' Delete SQL: '.$q.'
'; + } + return $this->Conn->ChangeQuery($q); + } + + /** + * 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); + } +} + + + +?> \ No newline at end of file Index: trunk/core/kernel/utility/http_query.php =================================================================== diff -u --- trunk/core/kernel/utility/http_query.php (revision 0) +++ trunk/core/kernel/utility/http_query.php (revision 932) @@ -0,0 +1,225 @@ +Order = $order; + $this->AddAllVars(); + ini_set("magic_quotes_gpc", 0); + } + + /** + * 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); + break; + case 'P': + $my_post = $this->post_convert($_POST); // needed ? + $this->Post = $this->AddVars($_POST); + break; + case 'C': + $this->Cookie = $this->AddVars($_COOKIE); + break; + case 'E'; + $this->Env = $this->AddVars($_ENV); + break; + case 'S'; + $this->Server = $this->AddVars($_SERVER); + break; + case 'F'; + $this->Files = $this->AddVars($_FILES); + break; + } + } + } + + function post_convert($array) + { + $out = Array(); + foreach ($array as $key => $val) { + if ( ereg("\|\|",$key)) { + $key = str_replace("||",".",$key); + } + else + $out[$key] = $val; + } + } + + /** + * Saves variables from array specified + * into common variable storage place + * + * @param Array $array + * @return Array + * @access private + */ + function AddVars($array) + { + foreach ($array as $key => $val) { + if (get_magic_quotes_gpc()) + { + + if ( is_array($val) ) + { + foreach ($val as $key_array => $val_array) + { + if( is_array($val_array) ) + { + $array[$key][$key_array] = $this->AddVars($val_array); + } + else + { + $array[$key][$key_array] = stripslashes($val_array); + } + + } + $this->Set($key, $array[$key]); + } + else { + $array[$key] = stripslashes($val); + $this->Set($key, $array[$key]); + } + + + } + else { + $this->Set($key, $val); + } + } + 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 Index: trunk/core/kernel/event_manager.php =================================================================== diff -u --- trunk/core/kernel/event_manager.php (revision 0) +++ trunk/core/kernel/event_manager.php (revision 932) @@ -0,0 +1,192 @@ +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) + { + $event_handler =& $this->Application->recallObject($event->Prefix.'_EventHandler'); + $event_handler->processEvent(&$event); + } + + function getTemplateName($querystring_template) + { + $t_from_post=$this->Application->GetVar('t'); + $t=$t_from_post?$t_from_post:$querystring_template; + return $t; + } + + function ProcessRequest() + { + // env=SID:TEMPLATE:m-1-1-1-1:l0-0-0:n-0-0-0:bb-0-0-1-1-1-0 + + // 1. process QueryString + $env_var =& $this->Application->GetVar(ENV_VAR_NAME); + $query_maps=Array(); + + if($env_var) + { + $parts=explode(':',$env_var); + + // Save Session ID + $sid=array_shift($parts); + if($sid) $this->Application->SetVar('sid',$sid); + + // Save Template Name + $t=$this->getTemplateName( array_shift($parts) ); + if(!$t) $t='index'; + $this->Application->SetVar('t',$t); + + if($parts) + { + foreach($parts as $mixed_part) + { + $mixed_part=explode('-',$mixed_part); + $prefix_special=array_shift($mixed_part); // l.pick, l + list($prefix)=explode('.',$prefix_special); + + $query_maps[$prefix_special]=$this->Application->getUnitOption($prefix,'QueryString'); + foreach($query_maps[$prefix_special] as $index => $var_name) + { + // l_id, l_page, l_bla-bla-bla + $this->Application->SetVar($prefix_special.'_'.$var_name,$mixed_part[$index-1]); + } + } + } + } + else + { + $t=$this->getTemplateName('index'); + $this->Application->SetVar('t',$t); + } + + // 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($query_maps && !$events) + { + // if we got $_GET type submit (links, not javascript) + foreach($query_maps as $prefix_special => $query_map) + { + $query_map=array_flip($query_map); + if(isset($query_map['event'])) + { + $events[$prefix_special]=$this->Application->GetVar($prefix_special.'_event'); + } + } + } + + //print_pre($events); + $t=$this->Application->GetVar('t'); + foreach($events as $prefix_special => $event_name) + { + if(!$event_name) continue; + $event = new kEvent(); + $event->Name=$event_name; + $event->Prefix_Special=$prefix_special; + + $prefix_special=explode('.',$prefix_special); + $event->Prefix=$prefix_special[0]; + $event->Special=isset($prefix_special[1])?$prefix_special[1]:''; + + $event->redirect=$this->Application->RecallVar('redirect_to'); + $this->HandleEvent(&$event); + } + } + + function registerHook($hookto_unit, $hookto_event_name, $mode, $do_unit, $do_event_name) + { + + + + + } + + function processHooks(&$event, $mode) + { + + + + + } + + /** + * 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 Index: trunk/core/kernel/parser/tags.php =================================================================== diff -u --- trunk/core/kernel/parser/tags.php (revision 0) +++ trunk/core/kernel/parser/tags.php (revision 932) @@ -0,0 +1,229 @@ +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; + } + + function ReplaceParams($tag_data) + { + //print_pre($this->Parser->Pattern, $tag_data); + if (is_array($this->Parser->Params)) { + $tag_data = preg_replace($this->Parser->Pattern, $this->Parser->Values, $tag_data); + } + //echo "got: $tag_data
"; + return $tag_data; + } + + function CmpParams($a, $b) + { + $a_len = strlen($a); + $b_len = strlen($b); + if ($a_len == $b_len) return 0; + return $a_len > $b_len ? -1 : 1; + } + + function ReplaceLanguageTags($tag_data) + { + preg_match_all("(!(la|lu)[^!]+!)", $tag_data, $res, PREG_PATTERN_ORDER); + $language_tags = $res[0]; + uasort($language_tags, array ("Tag", "CmpParams")); + + $values = Array(); + $i = 0; + foreach ($language_tags as $label) { + array_push($values, $this->Application->Phrase($label)); + $language_tags[$i] = '/' . $language_tags[$i] . '/'; + $i++; + } + $tag_data = preg_replace($language_tags, $values, $tag_data); + return $tag_data; + } + + function ParseTagData($tag_data) + { + $tag_data = $this->ReplaceParams($tag_data) . ' '; + $tag_data = $this->ReplaceLanguageTags($tag_data); + + + list ($key_data, $params) = explode(' ', $tag_data, 2); + list($this->Processor, $this->Tag) = explode(':', $key_data); + + if ($params != '') $this->ParseNamedParams($params); + } + + function ParseNamedParams($params_str) + { + $params =& new Params($params_str); + $this->NamedParams = $params->_Params; + } + + function GetParam($param) + { + if (isset($this->NP[$param])) + return $this->NP[$param]; + else + return false; + } + + function Process() + { + if ($this->Processor == 'm' || $this->Processor == 'm_TagProcessor') { //if we are procssing Main tags + if ($this->Tag == 'block') { + $tag =& new BlockTag('', $this->Parser); + $tag->CopyFrom($this); + $tag->Process(); + } + elseif ($this->Parser->SkipMode == skip_tags) { + return; + } + elseif ( + $this->Tag == 'if' || + $this->Tag == 'ifnot' || + $this->Tag == 'else' || + $this->Tag == 'elseif' + ) { + $tag =& new ConstructTag('', $this->Parser); + $tag->CopyFrom($this); + $tag->Process(); + } + elseif ($this->Tag == 'xml') { + $tag =& new XMLTag('', $this->Parser); + $tag->CopyFrom($this); + $tag->Process(); + } + else { + if ($this->Parser->SkipMode == skip) return; + //if (!$this->ProcessMainTag()) //other main tags + $this->ProcessTag(); + } + } + else { //normal tags - processors other than main + if ($this->Parser->SkipMode == skip_tags || $this->Parser->SkipMode == skip) return; //do not parse if we skipping tags + $this->ProcessTag(); + //$this->Parser->AppendOutput(''.$this->Tag.''); + } + } + + function DoProcessTag() + { + //$processor =& $this->Application->Processors->GetProcessor($this->Processor, $this); + $processor =& $this->Application->recallObject($this->Processor); + return $processor->ProcessTag($this); + } + + function ProcessTag() + { + $o = $this->DoProcessTag(); + if ($o !== false) + { + $this->Parser->AppendOutput($o); + } + else + { + echo "Warning: can't process tag ".$this->Tag."
"; + } + } +} + + +// ################### TESTS ############################ + +global $suite; +if (isset($suite)) { + class TestTags extends TestCase { + + function testTagParsing() + { + global $application; + + $tag_data = "m:test param1=\"123\""; + $tag =& new Tag($tag_data, $application->Parser); + $this->assertEquals('m', $tag->Processor); + $this->assertEquals('test', $tag->Tag); + $this->assertEquals('123', $tag->GetParam('param1')); + + $this->assertFalse($tag->GetParam('no_such_param')); + } + + function testTagParamEscaping() + { + global $application; + + $tag_data = "m:test escape1='-\"-' \t\t \n \t\n escape2=\"+\\\"+\" \n escape3='*\'*' escape4='=\='"; + //$tag_data = "m:test escape1='-\"-' escape2=\"+\\\"+\" escape3='*\'*' escape4='=\='"; + $tag =& new Tag($tag_data, $application->Parser); + $this->assertEquals('-"-', $tag->GetParam('escape1')); + $this->assertEquals('+"+', $tag->GetParam('escape2')); + $this->assertEquals("*'*", $tag->GetParam('escape3')); + $this->assertEquals('=\=', $tag->GetParam('escape4')); + } + + function testTagParamSubstitution() + { + global $application; + + $application->Parser->SetParams( Array( + 'prefix' => 'a_prefix', + 'tag' => 'a_tag', + 'param_name' => 'a_param_name', + 'param_value' => 'a_param_value' + ) + ); + + $tag_data = '$prefix:$tag $param_name="$param_value"'; + $tag =& new Tag($tag_data, $application->Parser); + $this->assertEquals('a_prefix', $tag->Processor); + $this->assertEquals('a_tag', $tag->Tag); + $this->assertEquals('a_param_value', $tag->GetParam('a_param_name')); + } + } + $suite->addTest(new TestSuite("TestTags")); +} + +?> \ No newline at end of file Index: trunk/core/kernel/db/dblist.php =================================================================== diff -u --- trunk/core/kernel/db/dblist.php (revision 0) +++ trunk/core/kernel/db/dblist.php (revision 932) @@ -0,0 +1,393 @@ +OrderFields = Array(); + $this->PerPage = -1; + } + + /** + * Sets counted part of SELECT query used in grouped queries + * + * When using queries containing GROUP BY clause, the SELECT part may contain aggregate functions such as SUM(), COUNT() etc. + * the part of the query with this functions should be set as 'counted SQL' for {@link dDBList::CountRecs()} to build the correct + * count query. + * Example: + * + * ... + * $this->SetSelectSQL('SELECT product_id, SUM(amount) FROM sales'); + * $this->SetCounterSQL('SUM(amount)'); + * ... + * + * + * {@link kDBList::CountRecs()} will replace the SELECT part with COUNT(*), SUM(amount) when counting records, which will give the accurate + * number of records. The number of records is used in list pagination + * + * @access public + * @param string + * @return void + */ + function SetCountedSQL($sql) + { + $this->CountedSQL = $sql; + } + + /** + * Counts the total number of records base on the query resulted from {@link kDBList::GetSelectSQL()} + * + * The method modifies the query to substitude SELECT part (fields listing) with COUNT(*). + * Special care should be applied when working with lists based on grouped queries, all aggregate function fields + * like SUM(), AVERAGE() etc. should be added to CountedSQL by using {@link kDBList::SetCountedSQL()} + * + * @access public + * @param string + * @return void + */ + function CountRecs() + { + $q = $this->GetSelectSQL(); + $counted_sql = ''; + if ($this->hasCounted) { + $counted_sql = $this->GetCountedSQL(); + $counted_sql = ", $counted_sql"; + } + + if ( preg_match("/DISTINCT(.*?)FROM(?!_)/is",$q,$regs ) ) + $q = preg_replace("/^.*SELECT DISTINCT(.*?)FROM(?!_)/is", "SELECT COUNT(DISTINCT ".$regs[1].") AS count FROM", $q); + else + $q = preg_replace("/^.*SELECT(.*?)FROM(?!_)/is", "SELECT COUNT(*) AS count $counted_sql FROM ", $q); + + if ($this->DisplayQueries) { + echo get_class($this)." Count SQL: $q
"; + } + + $this->RecordsCount = (int)$this->Conn->GetOne($q); + $this->hasCounted=true; + } + + /** + * Queries the database with SQL resulted from {@link kDBList::GetSelectSQL()} and stores result in {@link kDBList::SelectRS} + * + * All the sorting, pagination, filtration of the list should be set prior to calling Query(). + * + * @access public + * @param string + * @return void + */ + function Query() + { + $q = $this->GetSelectSQL(); + if ($this->DisplayQueries) { + echo get_class($this)." Query SQL: $q LIMIT ".$this->PerPage." OFFSET ".$this->Offset." Page: ".$this->Page."
"; + } + //$rs = $this->Conn->SelectLimit($q, $this->PerPage, $this->Offset); + + $sql = $q.' '.$this->Conn->getLimitClause($this->Offset,$this->PerPage); + + $this->Records = $this->Conn->Query($sql); + $this->SelectedCount=count($this->Records); + + if ($this->Records === false) { + //handle errors here + return false; + } + return true; + } + + /** + * Builds full select query except for LIMIT clause + * + * @access public + * @return string + */ + function GetSelectSQL() + { + $q = parent::GetSelectSQL(); + + $where = $this->GetWhereClause(); + $having = $this->GetHavingClause(); + $order = $this->GetOrderClause(); + $group = $this->GetGroupClause(); + + if (!empty($where)) $q .= ' WHERE ' . $where; + if (!empty($having)) $q .= ' HAVING ' . $having; + if (!empty($group)) $q .= ' GROUP BY ' . $group; + if (!empty($order)) $q .= ' ORDER BY ' . $order; + + return $q; + } + + /** + * Returns WHERE clause of the query + * + * @access public + * @return string + */ + function GetWhereClause() + { + return ''; + } + + /** + * Returns HAVING clause of the query + * + * @access public + * @return string + */ + function GetHavingClause() + { + return ''; + } + + /** + * Returns GROUP BY clause of the query + * + * @access public + * @return string + */ + function GetGroupClause() + { + return ''; + } + + /** + * Adds order field to ORDER BY clause + * + * @access public + * @param string $field Field name + * @param string $direction Direction of ordering (asc|desc) + * @return void + */ + function AddOrderField($field, $direction) + { + $this->OrderFields[] = Array($field, $direction); + } + + /** + * Removes all order fields + * + * @access public + * @return void + */ + function ClearOrderFields() + { + $this->OrderFields = Array(); + } + + /** + * Returns ORDER BY Clause of the query + * + * The method builds order by clause by iterating {@link kDBList::OrderFields} array and concatenating it. + * + * @access public + * @return string + */ + function GetOrderClause() + { + $ret = ''; + foreach ($this->OrderFields as $field) { + $ret .= $field[0] . ' ' . $field[1] . ','; + } + $ret = rtrim($ret, ','); + return $ret; + } + + /** + * Description + * + * @access public + * @param string + * @return void + */ + function GetDBField($name) + { + $row =& $this->getCurrentRecord(); + return $row[$name]; + } + + function GetField($name) + { + return $this->GetDBField($name); + } + + + 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 bool + */ + function EOL() + { + return ($this->CurrentIndex >= $this->SelectedCount); + } + + /** + * Description + * + * @access public + * @param string + * @return void + */ + function GetTotalPages() + { + if ($this->PerPage == -1) return 1; + $this->TotalPages = (($this->RecordsCount - ($this->RecordsCount % $this->PerPage)) / $this->PerPage) // integer part of division + + (($this->RecordsCount % $this->PerPage) != 0); // adds 1 if there is a reminder + return $this->TotalPages; + } + + /** + * Sets number of records to query per page + * + * @access public + * @param int $per_page Number of records to display per page + * @return void + */ + function SetPerPage($per_page) + { + $this->PerPage = $per_page; + } + + /** + * Description + * + * @access public + * @param int $page + * @return void + */ + function SetPage($page) + { + if ($this->PerPage == -1) { + $this->Page = 1; + return; + } + if ($page < 1) $page = 1; + $this->Offset = ($page-1)*$this->PerPage; + if ($this->Offset > $this->RecordsCount) + $this->SetPage(1); + else { + $this->Page = $page; + } + //$this->GoFirst(); + } +} + +?> \ No newline at end of file Index: trunk/core/kernel/application.php =================================================================== diff -u --- trunk/core/kernel/application.php (revision 0) +++ trunk/core/kernel/application.php (revision 932) @@ -0,0 +1,779 @@ + +* The class incapsulates the main run-cycle of the script, provide access to all other objects in the framework.
+*
+* The class is a singleton, which means that there could be only one instance of KernelApplication in the script.
+* 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.
+* See singleton pattern by GOF. +* @package kernel4 +*/ + +class kApplication { + + /** + * Holds internal TemplateParser object + * @access private + * @var TemplateParser + */ + var $Parser; + + var $Profiler; + + /** + * Holds parser output buffer + * @access private + * @var string + */ + var $HTML; + + var $DocRoot; + var $BasePath; + var $KernelPath; + var $Server; + + /** + * The main Factory used to create + * almost any class of kernel and + * modules + * + * @access private + * @var kFactory + */ + var $Factory; + + var $XMLFactory; // in use? + + /** + * Holds all phrases used + * in code and template + * + * @var PhrasesCache + */ + var $Phrases; + + /** + * Holds connection to database + * + * @var DBConnection + */ + 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: + * + * $application =& kApplication::Instance(); + * + * or in an object: + * + * $this->Application =& kApplication::Instance(); + * + * to get the instance of kApplication. Note that we call the Instance method as STATIC - directly from the class. + * To use descendand of standard kApplication class in your project you would need to define APPLICATION_CLASS constant + * BEFORE calling kApplication::Instance() for the first time. If APPLICATION_CLASS is not defined the method would + * create and return default KernelApplication instance. + * @static + * @access public + * @return kApplication + */ + function &Instance() + { + static $instance = false; + + if (!$instance) { + if (!defined('APPLICATION_CLASS')) define('APPLICATION_CLASS', 'kApplication'); + $class = APPLICATION_CLASS; + $instance = new $class(); + } + return $instance; + } + + /** + * Initializes the Application + * + * Creates Utilites instance, HTTPQuery, Session, Profiler, TemplatesCache, Parser + * @access public + * @see HTTPQuery + * @see Session + * @see TemplatesCache + * @return void + */ + function Init() + { + $this->DB = new DBConnection(SQL_TYPE); + $this->DB->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB); + $this->DB->debugMode = $this->isDebugMode(); + + $this->SetDefaultConstants(); + + setcookie('CookiesOn', 1, time()+600); + + $this->Factory = new kFactory(); + + $this->registerDefaultClasses(); + + // to read configs before doing any recallObject + $config_reader =& $this->recallObject('kUnitConfigReader'); + + $this->Phrases =& new PhrasesCache($this->RecallVar('LanguageId', DEFAULT_LANGUAGE_ID)); + + $this->ValidateLogin(); // TODO: write that method + } + + /** + * 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('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('Configuration',KERNEL_PATH.'/utility/configuration.php'); + + $this->registerClass('TemplatesCache',KERNEL_PATH.'/parser/template.php'); + $this->registerClass('TemplateParser',KERNEL_PATH.'/parser/template_parser.php'); + + $this->registerClass('MainProcessor', KERNEL_PATH.'/processors/main_processor.php','m_TagProcessor'); + + $this->registerClass('kDBList', KERNEL_PATH.'/db/dblist.php'); + $this->registerClass('kDBItem', KERNEL_PATH.'/db/dbitem.php'); + $this->registerClass('kDBEventHandler', KERNEL_PATH.'/db/db_event_handler.php'); + $this->registerClass('kDBTagProcessor', KERNEL_PATH.'/db/db_tag_processor.php'); + + $this->registerClass('kTagProcessor', KERNEL_PATH.'/processors/tag_processor.php'); + + /*$this->RegisterClass('LoginController', KERNEL_PATH.'/users/login_controller.php');*/ + } + + /** + * Defines default constants if it's not defined before - in config.php + * + * Called automatically while initializing Application and defines: + * LOGIN_CONTROLLER, XML_FACTORY etc. + * @access private + * @return void + */ + function SetDefaultConstants() + { + if (!defined('SERVER_NAME')) define('SERVER_NAME', $_SERVER['SERVER_NAME']); + if (!defined('LOGIN_CONTROLLER')) define('LOGIN_CONTROLLER', 'LoginController'); + if (!defined('XML_FACTORY')) define('XML_FACTORY', 'XMLFactory'); + if (!defined('ADMINS_LIST')) define('ADMINS_LIST', '/users/users.php'); + if (!defined('USER_MODEL')) define('USER_MODEL', 'Users'); + if (!defined('DEFAULT_LANGUAGE_ID')) define('DEFAULT_LANGUAGE_ID', 1); + } + + /** + * Actually runs the parser against current template and stores parsing result + * + * This method gets t variable passed to the script, loads the template given in t variable and + * parses it. The result is store in {@link $this->HTML} property. + * @access public + * @return void + */ + function Run() + { + $event_manager =& $this->recallObject('EventManager'); + $event_manager->ProcessRequest(); + + $this->Parser =& $this->recallObject('TemplateParser'); + $template_cache =& $this->recallObject('TemplatesCache'); + $t = $this->GetVar('t'); + $this->HTML = $this->Parser->Parse( $template_cache->GetTemplateBody($t) ); + } + + /** + * Send the parser results to browser + * + * Actually send everything stored in {@link $this->HTML}, to the browser by echoing it. + * @access public + * @return void + */ + function Done() + { + //eval("?".">".$this->HTML); + echo $this->HTML; + $this->Phrases->UpdateCache(); + + $session =& $this->recallObject('Session'); + $session->SaveData(); + } + + // Facade + + /** + * Returns current session id (SID) + * @access public + * @return longint + */ + function GetSID() + { + $session =& $this->recallObject('Session'); + return $session->GetID(); + } + + function DestroySession() + { + $session =& $this->recallObject('Session'); + $session->DestroySession(); + } + + /** + * Returns variable passed to the script as GET/POST/COOKIE + * + * @access public + * @param string $var Variable name + * @return mixed + */ + function GetVar($var,$mode=FALSE_ON_NULL) + { + $http_query =& $this->recallObject('HTTPQuery'); + return $http_query->Get($var,$mode); + } + + /** + * Returns ALL variables passed to the script as GET/POST/COOKIE + * + * @access public + * @return array + */ + function GetVars() + { + $http_query =& $this->recallObject('HTTPQuery'); + return $http_query->GetParams(); + } + + /** + * Set the variable 'as it was passed to the script through GET/POST/COOKIE' + * + * This could be useful to set the variable when you know that + * other objects would relay on variable passed from GET/POST/COOKIE + * or you could use SetVar() / GetVar() pairs to pass the values between different objects.
+ * + * This method is formerly known as $this->Session->SetProperty. + * @param string $var Variable name to set + * @param mixed $val Variable value + * @access public + * @return void + */ + function SetVar($var,$val) + { + $http_query =& $this->recallObject('HTTPQuery'); + $http_query->Set($var,$val); + } + + function RemoveVar($var) + { + $session =& $this->recallObject('Session'); + return $session->RemoveVar($var); + } + + /** + * 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='') + { + $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).
+ * 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) + { + $this->Templates->SetTemplateBody($title, $body); + } + + function ProcessTag($tag_data) + { + $a_tag = new Tag($tag_data, $this->Parser); + return $a_tag->DoProcessTag(); + } + + function &GetProcessor($prefix) + { + $this->KernelDie('GetProcessor is DEPRICATED, use recallObject'); +// return $this->Processors->GetProcessor($prefix, new Tag('empty', $this->Parser)); + } + + + /* DEFINETLY NEEDS TO BE MOVED AWAY!!!!! */ + var $email_body; + function Email($params) + { + $this->email_body = $this->ParseBlock($params); + $from = $this->GetVar('email_from'); + $to = $this->GetVar('email_to'); + $replay = $this->GetVar('email_replay'); + if ( $replay == "" ) $replay = $from; + $subject = $this->GetVar('email_subject'); + $charset = $this->GetVar('email_charset'); + // $display = $this->GetVar('email_display'); + $display = 0; + if (!isset($charset) || $charset == '') $charset = 'US-ASCII'; + $mime = $this->GetVar('email_mime'); + + if ($mime == 'yes') { + $mime_mail = new MIMEMail($to, $from, $subject, $charset); + $mime_mail->mailbody($this->email_body); + + if ($f_name = $this->GetVar('email_attach')) { + $full_path = DOC_ROOT.BASE_PATH.'/'.$f_name; + $data = ''; + if(file_exists($full_path)) { + $fd = fopen($full_path, "r"); + $data = fread($fd, filesize($full_path)); + fclose($fd); + } + else exit; + + $filename = $this->GetVar('email_attach_filename'); + $type = $this->GetVar('email_attach_type'); + + $mime_mail->attachfile_raw($data, $filename, $type); + $mime_mail->send(); + } + } + else { + $headers.="From: $from\n"; + $headers.="Reply-To: $replay\n"; + $headers.="Content-Type: text/html; charset=\"$charset\"\n"; + if ( $display == 1 ) { + echo "
";
+	 			echo " from : $from 
"; + echo " to : $to
"; + echo " replay : $replay
"; + echo " subject : $subject
"; + echo " this->email_body : $this->email_body
"; + echo " headers : $headers
"; + echo "
"; + } + 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) + { + return $this->Parser->ParseBlock($params,$pass_params); + } + + 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='') + { + global $HTTP_SERVER_VARS; + if (defined('ADMIN') && $prefix == '') $prefix='/admin'; + if (defined('ADMIN') && $prefix == '_FRONT_END_') $prefix = ''; + $index_file = defined('INDEX_FILE') ? INDEX_FILE : 'index.php'; + $t_path = !empty($t) ? 't='.$t : ''; + + $session =& $this->recallObject('Session'); + $sid = $session->NeedQueryString()?$this->GetSID():''; + + $ret = $this->BaseURL($prefix).$index_file.'?'.ENV_VAR_NAME.'='.$sid.':'.$t; + + $t_pass=$this->GetVar('t_pass'); + if($t_pass) + { + $ret.=':'; + $pass_info=explode(',',$t_pass); // array( prefix[.special], prefix[.special] ... + foreach($pass_info as $pass_element) + { + list($prefix)=explode('.',$pass_element); + $query_vars = $this->getUnitOption($prefix,'QueryString'); + if($query_vars) + { + $tmp_string=Array(0=>$pass_element); + foreach($query_vars as $index => $var_name) + { + $tmp_string[$index]=$this->GetVar($pass_element.'_'.$var_name); + } + + $ret.=implode('-',$tmp_string); + } + } + + + } + + return $ret; + } + + function BaseURL($prefix='') + { + return PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').BASE_PATH.$prefix.'/'; + } + + function Redirect($t='', $params='', $prefix='') + { + if ($t == '') $t = $this->GetVar('t'); + $location = $this->HREF($t, $prefix); + $a_location = $location; + $location = sprintf("Location: %s".($params ? "&" : '')."%s",$location, $params); + //echo " location : $location
"; + + + if (headers_sent() != '') { + echo "Debug output above!!! Proceed to redirect: $a_location
"; + } + else + header("$location"); + + $session =& $this->recallObject('Session'); + $session->SaveData(); + exit; + } + + function UserError($msg) + { + error_reporting(E_ALL); + trigger_error($msg, E_USER_WARNING ); + } + + function Phrase($label) + { + if (ereg("^!.+!$", $label) > 0) { + $label = substr($label, 1, -1); //cut exclamation marks + } + return $this->Phrases->GetPhrase($label); + } + + /** + * Validtates user in session if required + * + */ + function ValidateLogin() + { + if (defined('LOGIN_REQUIRED')) + { + // Original Kostja call + //$login_controller =& $this->Factory->MakeClass(LOGIN_CONTROLLER, Array('model' => USER_MODEL, 'prefix' => 'login')); + + // Call proposed by Alex + //$login_controller =& $this->RecallObject(LOGIN_CONTROLLER, Array('model' => USER_MODEL, 'prefix' => 'login')); + + //$login_controller->CheckLogin(); + } + } + + function KernelDie($message) { + echo "KernelApplication died: $message
Debug backtrace follows:
"; + print_pre(debug_backtrace()); + echo ""; + } + + function trigerError($message,$error_type=E_USER_WARNING) + { + trigger_error($message,$error_type); + } + + /** + * Allows to process any type of event + * + * @param kEvent $event + * @access public + */ + function HandleEvent(&$event) + { + $event_manager =& $this->recallObject('EventManager'); + $event_manager->HandleEvent(&$event); + } + + /** + * Registers new class in the factory + * + * @param string $real_class + * @param string $file + * @param string $pseudo_class + * @access public + */ + function registerClass($real_class,$file,$pseudo_class=null) + { + $this->Factory->registerClass($real_class,$file,$pseudo_class); + } + + /** + * Returns object using params specified, + * creates it if is required + * + * @param string $name + * @param string $pseudo_class + * @param Array $event_params + * @return Object + */ + function &recallObject($name,$pseudo_class=null,$event_params=Array()) + { + return $this->Factory->getObject($name,$pseudo_class,$event_params); + } + + /** + * Checks if application is in debug mode + * + * @return bool + * @access public + */ + function isDebugMode() + { + return defined('DEBUG_MODE')&&DEBUG_MODE; + } + + /** + * Reads unit (specified by $prefix) + * option specified by $option + * + * @param string $prefix + * @param string $option + * @return string + * @access public + */ + function getUnitOption($prefix,$option) + { + $unit_config_reader =& $this->recallObject('kUnitConfigReader'); + return $unit_config_reader->getUnitOption($prefix,$option); + } + + /** + * Set's new unit option value + * + * @param string $prefix + * @param string $name + * @param string $value + * @access public + */ + function setUnitOption($prefix,$option,$value) + { + $unit_config_reader =& $this->recallObject('kUnitConfigReader'); + return $unit_config_reader->setUnitOption($prefix,$option,$value); + } + + /** + * Splits any mixing of prefix and + * special into correct ones + * + * @param string $prefix_special + * @return Array + * @access public + */ + function processPrefix($prefix_special) + { + return $this->Factory->processPrefix($prefix_special); + } + + /** + * Set's new event for $prefix_special + * passed + * + * @param string $prefix_special + * @param string $event_name + * @access public + */ + function setEvent($prefix_special,$event_name) + { + $event_manager =& $this->recallObject('EventManager'); + $event_manager->setEvent($prefix_special,$event_name); + } +} + +?> \ No newline at end of file Index: trunk/core/kernel/utility/debugger.php =================================================================== diff -u --- trunk/core/kernel/utility/debugger.php (revision 0) +++ trunk/core/kernel/utility/debugger.php (revision 932) @@ -0,0 +1,690 @@ + 'c:\Program Files\UltraEdit\uedit32.exe', 'params' => '%F/%L'); + $dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-4.0Beta\bin\ZDE.exe', 'params' => '%F'); + define('WINDOWS_EDITOR',$dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']); + unset($dbg_editors,$dbg_editor); + } + + class Debugger + { + /** + * Debugger data for building report + * + * @var Array + */ + var $Data = Array(); + var $ProfilerData = Array(); + var $RecursionStack = Array(); // prevent recursion when processing debug_backtrace() function results + + var $TraceNextError=false; + + var $Options = 0; + var $OptionsMap = Array('shutdown_func' => 1, 'error_handler' => 2, + 'output_buffer' => 4, 'highlight_output' => 8); + + function Debugger() + { + $this->appendRequest(); + } + + function initOptions() + { + + + } + + function setOption($name,$value) + { + if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']
'); + 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.']
'); + 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 = ''.$this->getErrorNameByCode($Data['no']).': '.$Data['str']; + $ret .= ' in '.$fileLink.' on line '.$Data['line'].''; + return $ret; + break; + + case 'var_dump': + $ret = $this->highlightString( print_r($Data['value'], true) ); + return addslashes($ret); + break; + + case 'trace': + ini_set('memory_limit','500M'); + $trace =& $Data['trace']; + + //return 'sorry'; + //return $this->highlightString(print_r($trace,true)); + + + $i = 0; $traceCount = count($trace); + $ret = ''; + while($i < $traceCount) + { + $traceRec =& $trace[$i]; + $argsID = 'trace_args_'.$dataIndex.'_'.$i; + if(isset($traceRec['file'])) + { + $ret .= 'Function: '.$this->getFileLink($traceRec['file'],$traceRec['line'],$traceRec['class'].$traceRec['type'].$traceRec['function']); + $ret .= ' in '.basename($traceRec['file']).' on line '.$traceRec['line'].'
'; + } + 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 .= ''; + $i++; + } + return $ret; + break; + + case 'profiler': + $profileKey = $Data['profile_key']; + $Data =& $this->ProfilerData[$profileKey]; + $runtime = ($Data['ends'] - $Data['begins']); // in seconds + return 'Name: '.$Data['description'].'
Runtime: '.$runtime.'s'; + break; + + default: + return 'incorrect debug data'; + break; + } + } + + function processTraceArguments(&$traceArgs) + { + 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|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|WHERE|HAVING|GROUP BY|ORDER BY) /is', "\n\t$1 ",$sql); + return $this->highlightString($sql); + } + + function highlightString($string) + { + if( defined('DBG_USE_HIGHLIGHT')&&DBG_USE_HIGHLIGHT ) + { + $string = highlight_string('', true); + return preg_replace('/<\?(.*)php (.*)\?>/s','$2',$string); + } + else + { + return $string; + } + } + + function getFileLink($file, $lineno = 1, $title = '') + { + if(!$title) $title = $file; + return ''.$title.''; + } + + function getLocalFile($remoteFile) + { + return str_replace(DOC_ROOT, WINDOWS_ROOT, $remoteFile); + } + + function appendTrace() + { + $trace = debug_backtrace(); + array_shift($trace); + $this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace'); + } + + function appendHTML($html) + { + $this->Data[] = Array('html' => $html,'debug_type' => 'html'); + } + + /** + * Change debugger info that was already generated before. + * Returns true if html was set. + * + * @param int $index + * @param string $html + * @param string $type = {'append','prepend','replace'} + * @return bool + */ + function setHTMLByIndex($index,$html,$type='append') + { + if( !isset($this->Data[$index]) || $this->Data[$index]['debug_type'] != 'html' ) + { + return false; + } + + switch ($type) + { + case 'append': + $this->Data[$index]['html'] .= '
'.$html; + break; + case 'prepend': + $this->Data[$index]['html'] = $this->Data[$index]['html'].'
'.$html; + break; + case 'replace': + $this->Data[$index]['html'] = $html; + break; + } + return true; + } + + /** + * Move $debugLineCount lines of input from debug output + * end to beginning. + * + * @param int $debugLineCount + */ + function moveToBegin($debugLineCount) + { + $lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount); + $this->Data = array_merge($lines,$this->Data); + } + + function appendRequest() + { + $script = $_SERVER['PATH_TRANSLATED']; + $this->appendHTML('ScriptName: '.$this->getFileLink($script,1,basename($script)).' ('.dirname($script).')'); + ob_start(); + ?> + + + + + $value) + { + if( !is_array($value) && trim($value) == '' ) + { + $value = 'no value'; + } + else + { + $value = htmlspecialchars(print_r($value, true)); + } + $src = isset($_GET[$key]) ? 'GE' : (isset($_POST[$key]) ? 'PO' : (isset($_COOKIE[$key]) ? 'CO' : '?') ); + echo ''; + } + ?> +
SrcNameValue
'.$src.''.$key.''.$value.'
+ appendHTML( ob_get_contents() ); + ob_end_clean(); + } + + function appendSession() + { + if( isset($_SESSION)&&$_SESSION ) + { + $this->appendHTML('PHP Session: ['.ini_get('session.name').']'); + $this->dumpVars($_SESSION); + $this->moveToBegin(2); + } + } + + function profileStart($key, $description) + { + $timeStamp = $this->getMoment(); + $this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data), 'description' => $description); + $this->Data[] = array('profile_key' => $key, 'debug_type' => 'profiler'); + } + + function profileFinish($key) + { + $this->ProfilerData[$key]['ends'] = $this->getMoment(); + } + + function getMoment() + { + list($usec, $sec) = explode(' ', microtime()); + return ((float)$usec + (float)$sec); + } + + function generateID() + { + list($usec, $sec) = explode(" ",microtime()); + + $id_part_1 = substr($usec, 4, 4); + $id_part_2 = mt_rand(1,9); + $id_part_3 = substr($sec, 6, 4); + $digit_one = substr($id_part_1, 0, 1); + if ($digit_one == 0) { + $digit_one = mt_rand(1,9); + $id_part_1 = ereg_replace("^0","",$id_part_1); + $id_part_1=$digit_one.$id_part_1; + } + return $id_part_1.$id_part_2.$id_part_3; + } + + + function getErrorNameByCode($errorCode) + { + switch($errorCode) + { + case E_USER_ERROR: + return 'Fatal Error'; + break; + + case E_WARNING: + case E_USER_WARNING: + return 'Warning'; + break; + + case E_NOTICE: + case E_USER_NOTICE: + return 'Notice'; + break; + + default: + return ''; + break; + } + } + + /** + * Generates report + * + */ + function printReport($returnResult = false) + { + // show php session if any + $this->appendSession(); + + // ensure, that 1st line of debug output always is this one: + $this->appendHTML('Hide Debugger'); + $this->moveToBegin(1); + + $i = 0; $lineCount = count($this->Data); + ob_start(); + ?> + + + + error ['.$errno.'] = ['.$errstr.']
'; + $errorType = $this->getErrorNameByCode($errno); + if(!$errorType) + { + trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR); + return false; + } + if( strpos($errfile,'eval()\'d code') !== false ) + { + $errstr = '[EVAL, line '.$errline.']: '.$errstr; + $tmpStr = $errfile; + $pos = strpos($tmpStr,'('); + $errfile = substr($tmpStr,0,$pos); + $pos++; + $errline = substr($tmpStr,$pos,strpos($tmpStr,')',$pos)-$pos); + } + if($this->TraceNextError) + { + $this->appendTrace(); + $this->TraceNextError=false; + } + $this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error'); + + if( substr($errorType,0,5) == 'Fatal') + { + echo ''; + exit; + } + } + + function saveToFile($msg) + { + $fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a'); + fwrite($fp,$msg."\n"); + fclose($fp); + } + + } + + function ConstOn($const_name) + { + return defined($const_name)&&constant($const_name); + } + + $debugger = new Debugger(); + if(ConstOn('DBG_HANDLE_ERRORS')) set_error_handler( array(&$debugger,'saveError') ); + if(ConstOn('DBG_USE_SHUTDOWN_FUNC')) register_shutdown_function( array(&$debugger,'printReport') ); + + +?> \ No newline at end of file Index: trunk/core/kernel/utility/configuration.php =================================================================== diff -u --- trunk/core/kernel/utility/configuration.php (revision 0) +++ trunk/core/kernel/utility/configuration.php (revision 932) @@ -0,0 +1,87 @@ +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')."
"; + 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 Index: trunk/core/kernel/db/db_event_handler.php =================================================================== diff -u --- trunk/core/kernel/db/db_event_handler.php (revision 0) +++ trunk/core/kernel/db/db_event_handler.php (revision 932) @@ -0,0 +1,409 @@ +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 { + + /** + * Loads item only + * + * @param kEvent $event + * @access protected + */ + function OnLoad(&$event) + { + $object =& $this->createObject(&$event); + $this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnUpdate'); + $event->redirect=false; + } + + /** + * Get's ID of item to be edited. + * Returns 1st id in case if many + * items were selected. + * + * @param kEvent $event + * @return int + */ + function getPassedID(&$event) + { + $ret=$this->Application->GetVar($event->getPrefixSpecial().'_id'); + if($ret===false) + { + $ids=$this->Application->GetVar($event->getPrefixSpecial().'_selected_ids'); + $ids=explode(',',$ids); + if($ids) $ret=array_shift($ids); + } + return $ret; + } + + /** + * Builds item (loads if needed) + * + * @param kEvent $event + * @access protected + */ + function OnItemBuild(&$event) + { + $object =& $this->createObject(&$event); + $this->dbBuild(&$object,&$event); + + $sql=$this->getSelectSQL($event,'OnItemPrepareQuery'); + $object->setSelectSQL($sql); + + // 1. set from config what needed + $fields = $this->Application->getUnitOption($event->Prefix,'Fields'); + $object->setConfigFields( array_keys($fields) ); + + // 2. loads if allowed + $auto_load = $this->Application->getUnitOption($event->Prefix,'AutoLoad'); + if($auto_load) + { + $id = $this->getPassedID(&$event); + $object->Load($id); + } + } + + /** + * Builds list + * + * @param kEvent $event + * @access protected + */ + function OnListBuild(&$event) + { + $event->setPseudoClass('_List'); + $object =& $this->createObject(&$event); + + $this->dbBuild(&$object,&$event); + + $sql=$this->getSelectSQL($event,'OnListPrepareQuery'); + $object->setSelectSQL($sql); + + $t=$this->Application->GetVar('t'); + $this->Application->StoreVar('redirect_to',$t); + + $this->SetPagination(&$event); + $this->SetSorting(&$event); + } + + /** + * Set's correct page for list + * based on data provided with event + * + * @param kEvent $event + * @access private + * @see OnListBuild + */ + function SetPagination(&$event) + { + $per_page = $event->getEventParam('per_page'); + if(!$per_page) + { + $per_page=$this->Application->RecallVar($event->Prefix_Special.'_PerPage'); + if(!$per_page) + { + $per_page=10; + } + } + + $event->setPseudoClass('_List'); + $object =& $this->createObject(&$event); + $object->SetPerPage($per_page); + $object->CountRecs(); + + $object->SetPage( $this->Application->GetLinkedVar( $event->Prefix_Special.'_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 =& $this->createObject(&$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'); + + //Use default if not specified + /*if ( $cur_sort1 === false || $cur_sort1_dir == false ) { + $cur_sort1 = $this->Application->ConfigOption($event->Prefix_Special.'_Sort1'); + $cur_sort1_dir = $this->Application->ConfigOption($event->Prefix_Special.'_Sort1_Dir'); + $cur_sort2 = $this->Application->ConfigOption($event->Prefix_Special.'_Sort2'); + $cur_sort2_dir = $this->Application->ConfigOption($event->Prefix_Special.'_Sort2_Dir'); + }*/ + + if($cur_sort1 != '' && $cur_sort1_dir != '') + { + $object->AddOrderField($cur_sort1, $cur_sort1_dir); + } + if($cur_sort2 != '' && $cur_sort2_dir != '') + { + $object->AddOrderField($cur_sort2, $cur_sort2_dir); + } + } + + /** + * Some kind of filter processing stuff. + * Not in use by now + * + */ + function AddFilters() + { + + } + + /** + * Set's new page for list + * + * @param kEvent $event + * @access protected + */ + function OnSetPage(&$event) + { + $event->setPseudoClass('_List'); + $object =& $this->createObject(&$event); + $new_page =& $this->Application->GetVar($event->Prefix_Special.'_page'); + $object->SetPage($new_page); + } + + /** + * Set's new sorting for list + * + * @param kEvent $event + * @access protected + */ + function OnSetSorting(&$event) + { + $this->Application->LinkVar($event->getPrefixSpecial(true).'_Sort1',$event->Prefix_Special.'_Sort1'); + $this->Application->LinkVar($event->getPrefixSpecial(true).'_Sort1_Dir',$event->Prefix_Special.'_Sort1_Dir'); + + //$event->setPseudoClass('_List'); + //$object =& $this->createObject(&$event); + } + + /** + * Common builder part for Item & List + * + * @param Object $object + * @access private + */ + function dbBuild(&$object,&$event) + { + // set Item & List common parameters from config + $table = $this->Application->getUnitOption($event->Prefix,'TableName'); + $object->setTableName($table); + + $id_field = $this->Application->getUnitOption($event->Prefix,'IDField'); + $object->setIDField($id_field); + + // get selected ids from post & save them to session + $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); + $ids=array_keys($items_info); + if($ids) + { + $this->Application->SetVar($event->getPrefixSpecial().'_selected_ids',implode(',',$ids)); + } + $this->Application->LinkVar($event->getPrefixSpecial().'_selected_ids'); + + // set's any possible hidden fields needed for both Item & List + $current_event = $this->Application->GetVar($event->Prefix_Special.'_event'); + $this->Application->setEvent($event->Prefix_Special,$current_event); + } + + /** + * Returns select query for loading item/list + * + * @param kEvent $event + * @param string $event_name + * @return string + * @access protected + */ + function getSelectSQL(&$event,$event_name) + { + $new_event =& $this->inheritEvent(&$event); + $new_event->Name=$event_name; + $this->Application->HandleEvent(&$new_event); + return $event->getEventParam('SQLQuery'); + } + + /** + * Creates needed sql query to load item, + * if no query is defined in config for + * special requested, then use default + * query + * + * @param kEvent $event + * @access protected + */ + function OnItemPrepareQuery(&$event) + { + $sqls = $this->Application->getUnitOption($event->Prefix,'ItemSQLs'); + $sql = isset($sqls[$event->Special])?$sqls[$event->Special]:$sqls['']; + $event->MasterEvent->setEventParam('SQLQuery',$sql); + } + + /** + * Creates needed sql query to load list, + * if no query is defined in config for + * special requested, then use default + * query + * + * @param kEvent $event + * @access protected + */ + function OnListPrepareQuery(&$event) + { + $sqls = $this->Application->getUnitOption($event->Prefix,'ListSQLs'); + $sql = isset($sqls[$event->Special])?$sqls[$event->Special]:$sqls['']; + $event->MasterEvent->setEventParam('SQLQuery',$sql); + } + + /** + * Creates new kDBItem + * + * @param kEvent $event + * @access protected + */ + function OnCreate(&$event) + { + $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false); + $object =& $this->createObject(&$event); + $this->prepareObject(&$object,&$event); + + $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); + if($items_info) $field_values = array_shift($items_info); + + $object->SetFieldsFromHash($field_values); + if( $object->Create() ) + { + $event->status=erSUCCESS; + } + else + { + $event->status=erFATAL; + $event->redirect=false; + } + } + + /** + * Updates kDBItem + * + * @param kEvent $event + * @access protected + */ + function OnUpdate(&$event) + { + $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false); + $object =& $this->createObject(&$event); + $this->prepareObject(&$object,&$event); + + $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); + if( $object->Update($id) ) + { + $event->status=erSUCCESS; + } + else + { + $event->status=erFATAL; + $event->redirect=false; + break; + } + } + } + + } + + /** + * Delete's kDBItem object + * + * @param kEvent $event + * @access protected + */ + function OnDelete(&$event) + { + $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false); + $object =& $this->createObject(&$event); + $object->ID=$this->Application->GetVar($event->Prefix_Special.'_id'); + if( $object->Delete() ) + { + $event->status=erSUCCESS; + } + else + { + $event->status=erFATAL; + $event->redirect=false; + break; + } + } + + /** + * Prepares new kDBItem object + * + * @param kEvent $event + * @access protected + */ + function OnNew(&$event) + { + $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false); + $object =& $this->createObject(&$event); + $this->prepareObject(&$object,&$event); + $object->setID(0); + $this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate'); + + + $event->redirect=false; + } + + /** + * Cancel's kDBItem Editing/Creation + * + * @param kEvent $event + * @access protected + */ + function OnCancel(&$event) + { + + + } + } + + +?> \ No newline at end of file Index: trunk/core/kernel/utility/unit_config_reader.php =================================================================== diff -u --- trunk/core/kernel/utility/unit_config_reader.php (revision 0) +++ trunk/core/kernel/utility/unit_config_reader.php (revision 932) @@ -0,0 +1,163 @@ +scanModules(MODULES_PATH); + } + + /** + * Read configs from all directories + * on path specified + * + * @param string $folderPath + * @access public + */ + function processFolder($folderPath) + { + $fh=opendir($folderPath); + while(($sub_folder=readdir($fh))) + { + $full_path=$folderPath.'/'.$sub_folder; + if( $this->isDir($full_path) && file_exists($this->getConfigName($full_path)) ) + { + include_once $this->getConfigName($full_path); + $prefix=$config['Prefix']; + $config['BasePath']=$full_path; + $this->configData[$prefix] = $config; + $this->parseConfig($prefix); + } + } + } + + + function scanModules($folderPath) + { + $fh=opendir($folderPath); + while(($sub_folder=readdir($fh))) + { + $full_path=$folderPath.'/'.$sub_folder; + if( $this->isDir($full_path) ) + { + $this->processFolder($full_path); + } + } + } + + /** + * 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) + { + $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']); + } + } + + /** + * Reads unit (specified by $prefix) + * option specified by $option + * + * @param string $prefix + * @param string $option + * @return string + * @access public + */ + function getUnitOption($prefix,$name) + { + return $this->configData[$prefix][$name]; + } + + /** + * 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 Index: trunk/core/kernel/db/db_connection.php =================================================================== diff -u --- trunk/core/kernel/db/db_connection.php (revision 0) +++ trunk/core/kernel/db/db_connection.php (revision 932) @@ -0,0 +1,483 @@ +dbType = $dbType; + $this->initMetaFunctions(); + if(!$errorHandler) + { + $this->errorHandler = Array(&$this,'handleError'); + } + } + + /** + * 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_" + + 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) + { + $func = $this->getMetaFunction('connect'); + $this->connectionID = $func($host,$user,$pass) or die('Can\'t connect to db'); + if($this->connectionID) + { + $this->setDB($db); + $this->showError(); + } + } + + /** + * 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 'Processing SQL: '.$sql.'
'; + echo 'Error ('.$code.'): '.$msg.'
'; + return false; + } + + /** + * Set's database name for connection + * to $new_name + * + * @param string $new_name + * @return bool + * @access public + */ + function setDB($new_name) + { + if(!$this->connectionID) return false; + $func = $this->getMetaFunction('select_db'); + return $func($new_name); + } + + /** + * Returns first field of first line + * of recordset if query ok or false + * otherwise + * + * @param string $sql + * @return string + * @access public + */ + function GetOne($sql) + { + $row = $this->GetRow($sql); + if(!$row) return false; + + return array_shift($row); + } + + /** + * Returns first row of recordset + * if query ok, false otherwise + * + * @param stirng $sql + * @return Array + * @access public + */ + function GetRow($sql) + { + $sql .= ' '.$this->getLimitClause(0,1); + $ret = $this->Query($sql); + if(!$ret) return $ret; + + 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) + { + $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; + } + + /** + * Free memory used to hold recordset handle + * + * @access private + */ + function Destroy() + { + if($this->queryID) + { + $free_func = $this->getMetaFunction('free_result'); + $free_func($this->queryID); + $this->queryID = null; + } + } + + /** + * Returns auto increment field value from + * insert like operation if any, zero otherwise + * + * @return int + * @access public + */ + function getInsertID() + { + $func = $this->getMetaFunction('insert_id'); + return $func($this->connectionID); + } + + /** + * Returns row count affected by last query + * + * @return int + * @access public + */ + function getAffectedRows() + { + $func = $this->getMetaFunction('affected_rows'); + return $func($this->connectionID); + } + + /** + * Returns LIMIT sql clause part for specific db + * + * @param int $offset + * @param int $rows + * @return string + * @access private + */ + function getLimitClause($offset, $rows) + { + if(!($rows > 0)) return ''; + + switch ($this->dbType) { + + default: + return 'LIMIT '.$offset.','.$rows; + break; + } + } + + /** + * Correctly quotes a string so that all strings are escaped. We prefix and append + * to the string single-quotes. + * An example is $db->qstr("Don't bother",magic_quotes_runtime()); + * + * @param s the string to quote + * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc(). + * This undoes the stupidity of magic quotes for GPC. + * + * @return quoted string to be sent back to database + */ + function qstr($s,$magic_quotes=false) + { + $replace_quote = "\\'"; + if (!$magic_quotes) + { + return "'".str_replace("'",$replace_quote,$s)."'"; + } + + // undo magic quotes for " + $s = str_replace('\\"','"',$s); + return "'$s'"; + } + + + /** + * Returns last error message + * + * @return string + * @access public + */ + function getErrorMsg() + { + return $this->errorMessage; + } + } +?> \ No newline at end of file Index: trunk/core/kernel/db/db_tag_processor.php =================================================================== diff -u --- trunk/core/kernel/db/db_tag_processor.php (revision 0) +++ trunk/core/kernel/db/db_tag_processor.php (revision 932) @@ -0,0 +1,138 @@ +Application->recallObject( $this->getPrefixSpecial(), $this->Prefix.'_List',$params); + $id_field = $this->Application->getUnitOption($this->Prefix,'IDField'); + // + + /*$parser =& $this->Application->recallObject('TemplateParser'); + + // only useful in case in inside prinklist block we have another + // tagprocessor who wants to findout out printlist prefix and special + $parser->SetParam('prefix', $this->Prefix); + $parser->SetParam('special', $this->Special);*/ + + $list->Query(); + $o = ''; + $list->GoFirst(); + + $block_params=$this->prepareTagParams($params); + $block_params['name']=$params['block']; + $block_params['pass_params']='true'; + + while (!$list->EOL()) + { + $this->Application->SetVar( $this->getPrefixSpecial().'_id', $list->GetDBField($id_field) ); + $o.= $this->Application->ParseBlock($block_params, 1); + $list->GoNext(); + } + return $o; + } + + /** + * Append prefix and special to tag + * params (get them from tagname) like + * they were really passed as params + * + * @param Array $tag_params + * @return Array + * @access protected + */ + function prepareTagParams($tag_params) + { + $ret=$tag_params; + $ret['Prefix']=$this->Prefix; + $ret['Special']=$this->Special; + $ret['PrefixSpecial']=$this->getPrefixSpecial(); + return $ret; + } + + /** + * Get's reuested field value + * + * @param Array $params + * @return string + * @access public + */ + function Field($params) + { + $field = $params['field']; + $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params); + + $value = $object->GetField($field); + + if (isset($params['nl2br'])) $value = nl2br($value); + + return $value; + } + + /** + * Print grid pagination using + * block names specified + * + * @param Array $params + * @return string + * @access public + */ + function PrintPages($params) + { + $prefix_special=$this->getPrefixSpecial(); + $object =& $this->Application->recallObject($prefix_special,$this->Prefix.'_List',$params); + $total = $object->GetTotalPages(); + + $o = ''; + $this->Application->SetVar($prefix_special.'_event','OnSetPage'); + $current_page = $this->Application->RecallVar($prefix_special.'_page'); + + $block_params=$this->prepareTagParams($params); + + for ($i=1; $i<=$total; $i++) + { + $this->Application->SetVar($prefix_special.'_page',$i); + $block = $params[ (($i==$current_page)?'active':'inactive').'_block' ]; + $block_params['name']=$block; + $block_params['page']=$i; + $o .= $this->Application->ParseBlock($block_params, 1); + } + + return $o; + } + + /*function MapField($params) + { + $object =& $this->Application->recallObject($this->Prefix.'.'.$this->Special); + $value = $object->GetField($params['field']); + $this->Application->SetVar($params['var_name'],$value); + }*/ + + /** + * Returns input field name to + * be placed on form (for correct + * event processing) + * + * @param Array $params + * @return string + * @access public + */ + function InputName($params) + { + $prefix_special=$this->getPrefixSpecial(); + $item = $this->Application->recallObject($prefix_special); + return $prefix_special.'['.$item->GetID().']['.$params['field'].']'; + } + + + +} + +?> \ No newline at end of file Index: trunk/core/kernel/session/session.php =================================================================== diff -u --- trunk/core/kernel/session/session.php (revision 0) +++ trunk/core/kernel/session/session.php (revision 932) @@ -0,0 +1,486 @@ +SetCookieDomain('my.domain.com'); +$session->SetCookiePath('/myscript'); +$session->SetCookieName('my_sid_cookie'); +$session->SetGETName('sid'); +$session->InitSession(); + +... + +//link output: + +echo "NeedQueryString() ? 'sid='.$session->SID : '' ) .">My Link"; + +*/ + +//Implements session storage in the database +class SessionStorage extends kDBBase { + + var $Expiration; + + var $OriginalData; + + function SessionStorage() + { + parent::kDBBase(); + $this->OriginalData = Array(); + } + + function StoreSession(&$session) + { + $query = sprintf( "INSERT INTO %sSessions (sid, expire) VALUES (%s, %s)", + TABLE_PREFIX, + $session->SID, + $session->Expiration); + $this->Conn->Query($query); + } + + function DeleteSession(&$session) + { + $query = sprintf( "DELETE FROM %sSessions WHERE %s = %s", + TABLE_PREFIX, + 'sid', + $session->SID); + $this->Conn->Query($query); + + $query = sprintf( "DELETE FROM %sSessionData WHERE %s = %s", + TABLE_PREFIX, + 'sid', + $session->SID); + $this->Conn->Query($query); + + $this->OriginalData = Array(); + } + + function UpdateSession(&$session) + { + $query = sprintf( "UPDATE %sSessions SET expire = %s WHERE %s = %s", + TABLE_PREFIX, + $session->Expiration, + 'sid', + $session->SID); + $this->Conn->Query($query); + } + + function LocateSession($sid) + { + $query = sprintf( "SELECT * FROM %sSessions WHERE %s = %s", + TABLE_PREFIX, + 'sid', + $sid); + $result = $this->Conn->GetRow($query); + if ($result === false || $result == NULL) { + return false; + } + $this->Expiration = $result['expire']; + return true; + } + + function GetExpiration() + { + return $this->Expiration; + } + + function LoadData(&$session) + { + $query = sprintf( "SELECT value,name FROM %sSessionData WHERE %s = %s", + TABLE_PREFIX, + 'sid', + $session->SID); + $this->OriginalData = $this->Conn->GetCol($query,'name'); + return $this->OriginalData; + } + + function SaveData(&$session) + { + $ses_data = $session->Data->GetParams(); + + $replace = ''; + foreach ($ses_data as $key => $value) { + if (array_key_exists($key, $this->OriginalData) && $this->OriginalData[$key] == $value) + continue; //skip unchanged session data + else { + $replace .= sprintf("(%s, %s, %s),", + $session->SID, + $this->Conn->qstr($key), + $this->Conn->qstr($value)); + } + } + $replace = rtrim($replace, ','); + if ($replace != '') { + $query = sprintf( 'REPLACE INTO %sSessionData (sid, name, value) VALUES %s', + TABLE_PREFIX, + $replace); + $this->Conn->Query($query); + } + } + + function RemoveFromData(&$session, $var) + { + $query = sprintf( "DELETE FROM %sSessionData WHERE %s = %s AND %s = %s", + TABLE_PREFIX, + 'sid', + $session->SID, + 'name', + $this->Conn->qstr($var)); + $this->Conn->Query($query); + unset($this->OriginalData[$var]); + } +} + +define('smAUTO', 1); +define('smCOOKIES_ONLY', 2); +define('smGET_ONLY', 3); +define('smCOOKIES_AND_GET', 4); + +class Session extends kBase { + var $Checkers; + + var $Mode; + var $GETName = 'sid'; + + var $CookiesEnabled = true; + var $CookieName = 'sid'; + var $CookieDomain; + var $CookiePath; + var $CookieSecure = 0; + + var $SessionTimeout = 3600; + var $Expiration; + + var $SID; + + var $Storage; + + var $CachedNeedQueryString = null; + + var $Data; + + + function Session($mode = smAUTO) + { + parent::kBase(); + $this->SetMode($mode); + } + + function SetMode($mode) + { + $this->Mode = $mode; + } + + function SetCookiePath($path) + { + $this->CookiePath = $path; + } + + function SetCookieDomain($domain) + { + $this->CookieDomain = $domain; + } + + function SetGETName($get_name) + { + $this->GETName = $get_name; + } + + function SetCookieName($cookie_name) + { + $this->CookieName = $cookie_name; + } + + function InitStorage() + { + $this->Storage =& new SessionStorage(); + } + + function Init($prefix,$special) + { + parent::Init($prefix,$special); + + $this->CheckIfCookiesAreOn(); + $this->Checkers = Array(); + $this->InitStorage(); + $this->Data =& new Params(); + if ($this->Check()) { + $this->SID = $this->GetPassedSIDValue(); + $this->Refresh(); + $this->LoadData(); + } + else { + $this->SetSession(); + } + } + + function CheckReferer() + { + $reg = '#^'.preg_quote(PROTOCOL.$this->CookieDomain.$this->CookiePath).'#'; + return preg_match($reg, $_SERVER['HTTP_REFERER']); + } + + function CheckIfCookiesAreOn() + { + if ($this->Mode == smGET_ONLY) { + //we don't need to bother checking if we would not use it + $this->CookiesEnabled = false; + return; + } + $http_query =& $this->Application->recallObject('HTTPQuery'); + $cookies_on = $http_query->Cookie['cookies_on']; + + 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'); + + switch ($this->Mode) { + case smAUTO: + if ($this->CookiesEnabled) { //Cookies has the priority - we ignore everything else + $sid = $http_query->Cookie[$this->CookieName]; + } + else { + $sid = $http_query->Get($this->GETName); + } + break; + case smCOOKIES_ONLY: + $sid = $http_query->Cookie[$this->CookieName]; + break; + case smGET_ONLY: + $sid = $http_query->Get($this->GETName); + break; + case smCOOKIES_AND_GET: + $cookie_sid = $http_query->Cookie[$this->CookieName]; + $get_sid = $http_query->Get($this->GETName); + //both sids should match if cookies are enabled + if (!$this->CookiesEnabled || ($cookie_sid == $get_sid)) + $sid = $get_sid; //we use get here just in case cookies are disabled + else + $sid = ''; + break; + } + $this->CachedSID = $sid; + return $this->CachedSID; + } + + function GetID() + { + return $this->SID; + } + + 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->SID = $sid_part_1.$sid_part_2.$sid_part_3; + return $this->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 + ); + } + + 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 SaveData() + { + $this->Storage->SaveData($this); + } + + function StoreVar($name, $value) + { + $this->Data->Set($name, $value); + } + + function RecallVar($name) + { + return $this->Data->Get($name); + } + + function RemoveVar($name) + { + $this->Storage->RemoveFromData($this, $name); + $this->Data->Remove($name); + } +} + +?> \ No newline at end of file Index: trunk/core/kernel/utility/iterator.php =================================================================== diff -u --- trunk/core/kernel/utility/iterator.php (revision 0) +++ trunk/core/kernel/utility/iterator.php (revision 932) @@ -0,0 +1,49 @@ +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 Index: trunk/core/kernel/event_handler.php =================================================================== diff -u --- trunk/core/kernel/event_handler.php (revision 0) +++ trunk/core/kernel/event_handler.php (revision 932) @@ -0,0 +1,108 @@ +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 { + + /** + * Process Event + * + * @param kEvent $event + * @access public + */ + function processEvent(&$event) + { + if( method_exists($this,$event->Name) ) + { + $event_name = $event->Name; + $this->$event_name(&$event); + if($event->status==erSUCCESS && $event->redirect && strlen($event->redirect) > 0 ) + { + $this->Application->Redirect($event->redirect); + } + } + else + { + $this->Application->KernelDie('event '.$event->Name.' not implemented in class '.get_class($this).''); + } + } + + /** + * Sample dummy event + * + * @param kEvent $event + * @access protected + */ + function OnBuild(&$event) + { + /*echo 'building:
'; + print_pre($event);*/ + } + + /** + * Retunrs object used in event + * + * @param kEvent $event + * @access protected + */ + function &createObject(&$event) + { + return $this->Application->recallObject($event->Prefix_Special,$event->pseudoClass); + } + + /** + * 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) + { + $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; + return $child_event; + } + } + + +?> \ No newline at end of file Index: trunk/core/kernel/utility/utilities.php =================================================================== diff -u --- trunk/core/kernel/utility/utilities.php (revision 0) +++ trunk/core/kernel/utility/utilities.php (revision 932) @@ -0,0 +1,45 @@ +Application =& KernelApplication::Instance(); + } + + function ExtractByMask($array, $mask, $key_id=1, $ret_mode=1) + { +// echo "extracting from
"; +// print_pre($array); + $rets = Array(); + foreach ($array as $name => $val) + { + $regs = Array(); +// echo "checking $name
"; + if (eregi($mask, $name, $regs)) { +// echo "matched
"; +// 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 Index: trunk/core/kernel/utility/factory.php =================================================================== diff -u --- trunk/core/kernel/utility/factory.php (revision 0) +++ trunk/core/kernel/utility/factory.php (revision 932) @@ -0,0 +1,158 @@ +$prefix,'special'=>$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])) + { + $this->Application->KernelDie('RealClass not defined for pseudo_class '.$pseudo_class.''); + } + + $this->Storage[$name] =& $this->makeClass($pseudo_class); + $this->Storage[$name]->Init($ret['prefix'],$ret['special']); + + $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]; + } + + /** + * Includes file containing class + * definition for real class name + * + * @param string $real_class + * @access private + */ + function includeClassFile($real_class) + { + if(!$this->Files[$real_class]) $this->Application->KernelDie('Fatal error: Real Class '.$real_class.' is not registered with the Factory
'); + if(!file_exists($this->Files[$real_class])) $this->Application->KernelDie('Fatal error: Include file for class '.$real_class.' ('.$this->Files[$real_class].') does not exists
'); + include_once($this->Files[$real_class]); + } + + /** + * Get's real class name for pseudo class, + * includes class file and creates class + * instance + * + * @param string $pseudo_class + * @return Object + * @access private + */ + function &makeClass($pseudo_class) + { + $real_class=$this->realClasses[$pseudo_class]; + $this->includeClassFile($real_class); + /*if (!class_exists($real_class)) + { + $this->Application->KernelDie ("Fatal error: Real Class $real_class (pseudo class $pseudo_class) not found in its registered file ".$this->Files[$pseudo_class].'
'); + }*/ + return new $real_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; + $this->realClasses[$pseudo_class]=$real_class; + } + + } + +?> \ No newline at end of file Index: trunk/core/kernel/languages/phrases_cache.php =================================================================== diff -u --- trunk/core/kernel/languages/phrases_cache.php (revision 0) +++ trunk/core/kernel/languages/phrases_cache.php (revision 932) @@ -0,0 +1,92 @@ +Phrases = Array(); + $this->LanguageId = $LanguageId; + $this->LoadPhrases( $this->GetCachedIds() ); + } + + function GetCachedIds() + { + $query = sprintf("SELECT PhraseList FROM %s WHERE Template = %s", + 'PhraseCache', + $this->Conn->Qstr($this->Application->GetVar('t'))); + $phrases_ids = $this->Conn->GetOne($query); + if ($phrases_ids === false) return Array(); + return explode(',', $phrases_ids); + } + + function LoadPhrases($ids) + { + if (!is_array($ids) || count($ids) == 0) return; + $query = sprintf("SELECT Translation,Phrase FROM %s WHERE LanguageId = %s AND PhraseId IN (%s)", + 'Phrase', + $this->LanguageId, + join(',', $ids)); + $phrases = $this->Conn->GetCol($query,'Phrase'); + foreach($phrases as $phrase => $tanslation) + { + $this->AddCachedPhrase(strtoupper($phrase), $tanslation); + } + $this->Ids = $ids; + } + + function AddCachedPhrase($label, $value) + { + $label = strtoupper($label); + $this->Phrases[$label] = $value; + } + + function UpdateCache() + { + if (!is_array($this->Ids) || count($Ids) == 0) return; + $query = sprintf("REPLACE %s (PhraseList, CacheDate, Template) + VALUES (%s, %s, %s)", + 'PhraseCache', + $this->Conn->Qstr(join(',', $this->Ids)), + mktime(), + $this->Conn->Qstr($this->Application->GetVar('t'))); + $this->Conn->Query($query); + } + + function GetPhrase($label) + { + $label = strtoupper($label); + if (array_key_exists($label, $this->Phrases)) + return $this->Phrases[$label]; + + $this->LoadPhraseByLabel($label); + return $this->GetPhrase($label); + } + + function LoadPhraseByLabel($label) + { + $query = sprintf("SELECT PhraseId, Translation FROM %s WHERE LanguageId = %s AND UPPER(Phrase) = UPPER(%s)", + Phrase, + $this->LanguageId, + $this->Conn->qstr($label)); + $res = $this->Conn->GetRow($query); + if ($res === false || count($res) == 0) { + $this->AddCachedPhrase($label, '!'.$label.'!'); //add it as already cached, as long as we dont need to cache not found phrase + 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; + } + +} + + +?> \ No newline at end of file Index: trunk/core/kernel/parser/template.php =================================================================== diff -u --- trunk/core/kernel/parser/template.php (revision 0) +++ trunk/core/kernel/parser/template.php (revision 932) @@ -0,0 +1,118 @@ +SetBasePath($base_path)) { + if (isset($filename)) { + $this->Filename = $filename; + $this->LoadTemplate(); + } + } + } + + 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)) { + $handle = fopen ($filename, "r"); + $contents = fread ($handle, filesize ($filename)); + $this->SetBody($contents); + fclose ($handle); + return true; + } + else { + if (!$silent) echo "File or block not found: $filename ($filename)
"; + return false; + } + } + + function SetBody($body) + { + $this->Body = $body; + } + + function GetBody() + { + return $this->Body; + } +} + +class TemplatesCache extends kBase { + var $Templates = Array(); + var $BasePath; + + function TemplatesCache() + { + parent::kBase(); + $this->BasePath = DOC_ROOT.BASE_PATH.THEMES_PATH; + } + + function LoadTemplate($filename, $title=NULL) + { + $template =& new Template($this->BasePath, $filename); + if (!isset($title)) $title = $filename; + $this->SetTemplate($title, $template); + } + + function SetTemplate($title, &$template) + { + $this->Templates[$title] = $template; + } + + function &GetTemplate($title) + { + if (!isset($this->Templates[$title])) { + $this->LoadTemplate($title); + } + return $this->Templates[$title]; + } + + function GetTemplateBody($title) + { + $template =& $this->GetTemplate($title); + return $template->GetBody(); + } + + function SetTemplateBody($title, $body) + { + $template =& new Template(); + $template->SetBody($body); + $this->SetTemplate($title, $template); + } + + function ParseTemplate($template_name) + { + $Parser =& new TemplateParser($this->Application); + return $Parser->Parse( $this->GetTemplateBody($template_name) ); + } + + function TemplateExists($filename) + { + $template =& new Template($this->BasePath); + $template->Filename = $filename; + return $template->LoadTemplate(1) !== false; + } +} + + +?> \ No newline at end of file Index: trunk/core/kernel/processors/tag_processor.php =================================================================== diff -u --- trunk/core/kernel/processors/tag_processor.php (revision 0) +++ trunk/core/kernel/processors/tag_processor.php (revision 932) @@ -0,0 +1,74 @@ +Tag; + if(method_exists($this, $Method)) + { + //echo htmlspecialchars($tag->GetFullTag()).'
'; + return $this->$Method($tag->NP); + } + else + { + $this->Application->trigerError('Tag Undefined:
'.$tag->RebuildTagData().''); + 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
"; + $prefix_item = Array( + 'path' => $path, + 'class' => $class + ); + $this->Prefixes[$prefix] = $prefix_item; + } + + function CreateProcessor($prefix, &$tag) + { + // echo " prefix : $prefix
"; + if (!isset($this->Prefixes[$prefix])) + die ("Filepath and ClassName for prefix $prefix not defined while processing ".htmlspecialchars($tag->GetFullTag())."!"); + 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 Index: trunk/core/kernel/parser/construct_tags.php =================================================================== diff -u --- trunk/core/kernel/parser/construct_tags.php (revision 0) +++ trunk/core/kernel/parser/construct_tags.php (revision 932) @@ -0,0 +1,268 @@ +StopTag = $tag; + } + + function StoreSkipMode() + { + $this->SkipMode = $this->Parser->SkipMode; + } + + function RestoreSkipMode() + { + $this->Parser->SetSkipMode($this->SkipMode); + } + + function RestoreThisLevelSkipMode() + { + $this->SkipMode = $this->Parser->Recursion[$this->Parser->RecursionIndex]->SkipMode; + } + + function SuggestSkipMode($mode) + { + if ($mode >= 1) //if we need to skip - always forcing it + $this->Parser->SetSkipMode($mode); + else { //if we need to turn of skipping + if ($this->SkipMode == parse) //check if initially skipping was off + $this->Parser->SetSkipMode(parse); //set it to off only then + } + } + + function GetLogic() + { + $prefix = $this->GetParam('prefix'); + $function = $this->GetParam('function'); + + if ($prefix !== false) { + $tag =& new Tag('', $this->Parser); + $tag->Processor = $prefix; + $tag->Tag = $function; + $tag->NamedParams = $this->NP; + $this->Logic = $tag->DoProcessTag(); + // echo " this->Logic : ".$this->Logic."
"; + } + else + $this->Logic = $function; + } + + function Process() + { + switch ($this->Tag) { + case 'if': + case 'ifnot': + $this->GetLogic(); + + $this->SetStopTag('endif'); //This recursion level should end when 'endif' is found + $this->Parser->Recurve($this); //Saving current tag in parser recursion array + $this->StoreSkipMode(); //Storing initial SkipMode + + if ($this->Logic) { + $this->SuggestSkipMode(parse); //suggest we parse it + } + else { + $this->SuggestSkipMode(skip); //suggest we don't parse it + } + break; + case 'elseif': + $if_logic = $this->Parser->Recursion[$this->Parser->RecursionIndex]->Logic; + if (!$if_logic) { //if IF or ELSEIF above have not worked + $this->GetLogic(); + + if ($this->Logic) { //ELSEIF should run + $this->Parser->Recursion[$this->Parser->RecursionIndex]->Logic = $this->Logic; //To escape running ELSE or ELSEIF below + $this->SuggestSkipMode(parse); + } + else { //ELSEIF should NOT run + $this->SuggestSkipMode(skip); + } + } + else //IF or ELSEIF above HAVE worked - this ELSEIF should NOT run + $this->SuggestSkipMode(skip); + break; + case 'else': + $if_logic = $this->Parser->Recursion[$this->Parser->RecursionIndex]->Logic; + $this->RestoreThisLevelSkipMode(); + if (!$if_logic) { //IF was false - ELSE should run + $this->SuggestSkipMode(parse); + } + else { //IF was true - ELSE should not run + $this->SuggestSkipMode(skip); + } + break; + } + } + + function CheckRecursion(&$tag) + { + if ($this->CheckEndRecursion($tag)) { + $this->RestoreSkipMode(); //Restoring original SkipMode + return true; + } + return false; + } + + function CheckEndRecursion(&$tag) + { + return ($tag->Tag == $this->StopTag); //Tag matches StopTag we are waiting for to close current recursion + } +} + +class BlockTag extends ConstructTag { + var $BlockName = ''; + var $InsideBlock = 0; + + function Process() + { + switch ($this->Tag) { + case 'block': + $this->SetStopTag('blockend'); //This recursion level should end when 'blockend' is found + $this->Parser->Recurve($this); //Saving current tag in parser recursion array + $this->Parser->SetBuffer(''); + $this->BlockName = $this->NP['name']; //Stroing BlockName + $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 + $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); + return true; + } + else { + // append the tag itself to the block - while in block, we check every tag to be 'blockend' + // if it is not - we need to append the tag to the buffer, which we'll parse later in 'parse_block' + if ($tag->Tag != 'block') { + $this->Parser->AppendOutput($tag->GetFullTag()); + } + return false; + } + } +} + +class XMLTag extends ConstructTag { + var $BlockName = ''; + + function Process() + { + switch ($this->Tag) { + case 'xml': + $this->SetStopTag('xmlend'); //This recursion level should end when 'blockend' is found + $this->Parser->Recurve($this); //Saving current tag in parser recursion array + $this->BlockName = $this->NP['name']; //Storing BlockName + $this->StoreSkipMode(); + $this->SuggestSkipMode(skip_tags); //We need to skip tags from now + $this->Parser->SetBuffer(''); + break; + } + } + + function CheckRecursion(&$tag) + { + if (parent::CheckRecursion($tag)) { //if endtag matches (SkipMode would be restored then) + //Creating template from buffer + $template = new Template(); + $template->SetBody($this->Parser->GetBuffer()); + + //Adding template to application' cache + $this->Parser->Application->Templates->SetTemplate( + $this->BlockName, + $template + ); + $this->Parser->ParseXML($this->BlockName, $this->NP); + return true; + } + else { + if ($tag->Tag != 'xml') { + $this->Parser->AppendOutput($tag->GetFullTag()); + } + return false; + } + } +} + +class IterateTag extends ConstructTag { + + function Process() + { + switch ($this->Tag) { + case 'iterate': + $this->SetStopTag('enditerate'); //This recursion level should end when 'blockend' is found + $this->Parser->Recurve($this); //Saving current tag in parser recursion array + $this->BlockName = $this->NP['block']; //Storing BlockName + $this->StoreSkipMode(); + $this->SuggestSkipMode(skip_tags); //We need to skip tags from now + $this->Parser->SetBuffer(''); + break; + } + } + + function CheckRecursion(&$tag) + { + if (parent::CheckRecursion($tag)) { //if endtag matches (SkipMode would be restored then) + //Creating template from buffer + $template = new Template(); + $template->SetBody($this->Parser->GetBuffer()); + + //Adding template to application' cache + $this->Parser->Application->Templates->SetTemplate( + $this->BlockName, + $template + ); + $this->Parser->ParseXML($this->BlockName, $this->NP); + return true; + } + else { + if ($tag->Tag != 'xml') { + $this->Parser->AppendOutput($tag->GetFullTag()); + } + return false; + } + } + +} + +global $suite; +if (isset($suite)) { + class TestConstructTag extends TestCase { + + function testIFLogic() + { + global $application; + + $tag =& new ConstructTag('m:if prefix="m" function="true"', $application->Parser); + $tag->GetLogic(); + $this->assertTrue($tag->Logic); + + + $tag =& new ConstructTag('m:if prefix="m" function="false"', $application->Parser); + $tag->GetLogic(); + $this->assertFalse($tag->Logic); + } + + } + $suite->addTest(new TestSuite("TestConstructTag")); +} + +?> \ No newline at end of file Index: trunk/core/kernel/utility/event.php =================================================================== diff -u --- trunk/core/kernel/utility/event.php (revision 0) +++ trunk/core/kernel/utility/event.php (revision 932) @@ -0,0 +1,136 @@ +specificParams[$name]=$value; + } + + function getEventParam($name) + { + return isset($this->specificParams[$name])?$this->specificParams[$name]:false; + } + + 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,'.'); + } + + } + +?> \ No newline at end of file Index: trunk/core/kernel/utility/params.php =================================================================== diff -u --- trunk/core/kernel/utility/params.php (revision 0) +++ trunk/core/kernel/utility/params.php (revision 932) @@ -0,0 +1,170 @@ +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})(.*?)(? $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: ".get_class($this).")
"; + $this->_Params[strtolower($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
"; + $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); + //} + } + + /** + * Return all paramters as hash + * + * @return Array + * @access public + */ + function GetParams() + { + return $this->_Params; + } +} + +/*class RefParams extends Params { + + function Set($name, &$val) + { + $this->_Params[$name] =& $val; + } + + function &Get($name) + { + if (isset($this->_Params[$name])) + return $this->_Params[$name]; + else + return false; + } +}*/ + +// ################### TESTS ############################ + +global $suite; +if (isset($suite)) { + class TestParams extends TestCase { + + function testParamsOperations() + { + $params =& new Params(); + $params->Set('test_var', 24); + $this->AssertEquals(24, $params->Get('test_var')); + $this->AssertFalse($params->Get('none_existant_param')); + $res = $params->GetParams(); + $this->AssertEquals(24, $res['test_var']); + } + + function testSplitParams() + { + $params =& new Params('test_param="abc" another_param="7"'); + $this->AssertEquals('abc', $params->Get('test_param')); + $this->AssertEquals('7', $params->Get('another_param')); + } + } + $suite->addTest(new TestSuite("TestParams")); +} + +/* +function getmicrotime(){ + list($usec, $sec) = explode(" ",microtime()); + //echo "Usec: $usec, sec: $sec
"; + return ((float)$usec + (float)$sec); +} + +$total = 0; +$params =& new MyParams(); +$param_str = "param1=\"1\" param2='atessafa \'sdf' + params3=\"asd ' \\\"f\""; + +$param_str = "m:test escape1='-\"-' \t\t \n \t\n escape2=\"+\\\"+\" \n escape3='*\'*' escape4='=\='"; + +//3852 +for ($i=0; $i<1; $i++) +{ + $start = getmicrotime(); + $params->SplitParamsStr($param_str); + $end = getmicrotime(); + $total += $end-$start; +} + +printf ("total: %.8f; average: %.8f
", $total, $total/100); +*/ +?> \ No newline at end of file Index: trunk/core/kernel/processors/main_processor.php =================================================================== diff -u --- trunk/core/kernel/processors/main_processor.php (revision 0) +++ trunk/core/kernel/processors/main_processor.php (revision 932) @@ -0,0 +1,459 @@ +Application->recallObject('kActions'); + $actions->Set('t', $this->Application->GetVar('t')); + $actions->Set('sid', $this->Application->GetSID()); + } + + /** + * 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); + } + + function Base_Ref($params) + { + $templates_path = substr(THEMES_PATH,1); + return ""; + } + + function Base_URL($params) + { + $templates_path = substr(THEMES_PATH,1); + return $this->Application->BaseURL().$templates_path; + } + + function Base($params) + { + return $this->Application->BaseURL().$params['add']; + } + + /** + * Returns sid of current object + * + * @param Array $params + * @return int + * @todo Is really called ? + */ + /*function Sid($params) + { + $session =& $this->Application->recallObject('Session'); + return $session->GetId(); + }*/ + + //NEEDS TEST + function T($params) + { + if(!isset($params['pass'])) $params['pass']=''; + $t = (isset($params['t']) && $params['t']) ? $params['t'] : $this->Application->GetVar('t'); + $this->Application->SetVar('t_pass',$params['pass']); + return $this->Application->HREF($t, isset($params['prefix']) ? $params['prefix'] : ''); + } + + // 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
"; + } + else + echo "Object $name does not exist in the appliaction
"; + } + + function True($params) + { + return true; + } + + function False($params) + { + return false; + } + + 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; + } + + function Param_Equals($params) + { + //$parser =& $this->Application->recallObject('TemplateParser'); + $name = $this->SelectParam($params, 'name,var,param'); + $value = $params['value']; + return ($this->Application->Parser->GetParam($name) == $value); + } + + /** + * Returns hidden field for template name + * + * @param Array $params + * @return string + * @todo Is really called ? + */ + /*function Hidden_t($params) + { + return ""; + }*/ + + /** + * Returns hidden field for SID + * + * @param Array $params + * @return string + * @todo Is really called ? + */ + /*function Hidden_SID($params) + { + $session =& $this->Application->recallObject('Session'); + return ""; + }*/ + + function PHP_Self($params) + { + return $HTTP_SERVER_VARS['PHP_SELF']; + } + + 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 (array_key_exists($name, $params)) return $params[$name]; + } + return false; + } + + function Recall($params) + { + $res = $this->Application->RecallVar($this->SelectParam($params, 'name,var,param')); + if ($res === false && isset($params['no_null'])) + return ''; + else + return $res; + } + + function Store($params) + { + //echo"Store $params[name]
"; + $name = $params['name']; + $value = $params['value']; + $this->Application->StoreVar($name,$value); + } + + function Set($params) + { + foreach ($params as $param => $value) { + $this->Application->SetVar($param, $value); + } + } + + function Inc($params) + { + $this->Application->SetVar($params['param'], $this->Application->GetVar($params['param']) + $params['by']); + } + + function Get($params) + { + return $this->Application->GetVar($this->SelectParam($params, 'name,var,param'), EMPTY_ON_NULL); + } + + 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; + } + + 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 .= "\n"; + } + return $o; + } + + function Odd_Even($params) + { + $odd = $params['odd']; + $even = $params['even']; + + if ($this->Session->GetProperty('odd_even') == 'even') { + $this->Session->SetProperty('odd_even', 'odd'); + return $even; + } + else { + $this->Session->SetProperty('odd_even', 'even'); + return $odd; + } + } + + 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) + { + // echo " is_active
"; + $test_templ = $params["templ"]; + if (!$params['allow_empty']) { + $if_true = $params["true"] != '' ? $params["true"] : 1; + $if_false = $params["false"] != '' ? $params["false"] : 0; + } + else { + $if_true = $params["true"]; + $if_false = $params["false"]; + } + + if ( eregi("^$test_templ", $this->Application->GetVar('t'))) + return $if_true; + else + return $if_false; + } + + function is_t_active($params) + { + return $this->is_active($params); + } + + function Recall_Equals($params) + { + $name = $params['var']; + $value = $params['value']; + return ($this->Application->RecallVar($name) == $value); + } + + function Get_Equals($params) + { + $name = $this->SelectParam($params, 'var,name,param'); + $value = $params['value']; + if ($this->Application->GetVar($name) == $value) { + return 1; + } + } + + function MyInclude($params) + { + $BlockParser =& $this->Application->Factory->makeClass('TemplateParser'); + $BlockParser->SetParams($params); + $parser =& $this->Application->Parser; + + $t = $params['t']; + $t = eregi_replace("\.tpl$", '', $t); + + $templates_cache =& $this->Application->recallObject('TemplatesCache'); + + $res = $BlockParser->Parse( $templates_cache->GetTemplateBody($t) ); + + $this->Application->Parser =& $parser; + return $res; + } + + function Kernel_Scripts($params) + { + return ''; + } + + + 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]; + } + } + + function t_url($params) + { + $url = $this->Application->HREF($this->Application->GetVar('t')); + return $url; + } + + 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); + } + + function ParseBlock($params) + { + $parser =& $this->Application->Parser; // recallObject('TemplateParser'); + return $parser->ParseBlock($params); + } + + +/* + 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
"; + $candidate_id = $candidate->Login($this->Session->GetProperty('username'), $this->Session->GetProperty('password'), $special); + + if ($candidate_id !== false) { + $this->Session->SetField('user_id', $candidate_id); + $this->Session->Update(); + $this->Session->AfterLogin(); + + $this->parser->register_prefix('m'); + $template = array_shift($params); + if ($template == '') $template = 'index'; + $location = $this->parser->do_process_tag('m', 't', Array($template)); + header("Location: $location"); + exit; + } + elseif ($this->Session->GetProperty('username') != '') { + $this->Session->SetProperty('login_error', 'Incorrect username or password'); + } + } + */ + +} + +global $suite; +if (isset($suite)) { + class TestMainProcessor extends TestCase { + + function testParam_Equals() + { + global $application; + $mp =& new MainProcessor($application, 'm'); + $mp->Application->Parser->SetParams( Array('test' => 1)); + $this->assertTrue($mp->Param_Equals( Array('param' => 'test', 'value' => 1 ))); + $this->assertFalse($mp->Param_Equals( Array('param' => 'test', 'value' => 2 ))); + $this->assertFalse($mp->Param_Equals( Array('param' => 'test1', 'value' => 2 ))); + } + + function testParam() + { + global $application; + $mp =& new MainProcessor($application, 'm'); + $mp->Application->Parser->SetParams( Array('test' => 2)); + $this->assertEquals(2, $mp->Param( Array('name' => 'test'))); + $this->assertEquals(5, $mp->Param( Array('name' => 'test', 'plus' => 3 ))); + $this->assertEquals(1, $mp->Param( Array('name' => 'test', 'plus' => -1 ))); + } + + function testSetGet() + { + global $application; + $mp =& new MainProcessor($application, 'm'); + $mp->Set( Array('test_var' => 7, 'another_var' => 'abc') ); + $this->assertEquals(7, $mp->Get( Array('param' => 'test_var'))); + $this->assertEquals('abc', $mp->Get( Array('param' => 'another_var'))); + } + + function testConfig() + { + global $application; + $mp =& new MainProcessor($application, 'm'); + $application->Session->Config->SetOption('test_config_var', '1'); + $this->assertEquals(true, $mp->Config_Equals( Array('test_config_var' => '1'))); + } + + function testOddEven() + { + global $application; + $mp =& new MainProcessor($application, 'm');; + $this->assertEquals('odd_value', $mp->Odd_Even(Array('odd' => 'odd_value', 'even' => 'even_value'))); + $this->assertEquals('even_value', $mp->Odd_Even(Array('odd' => 'odd_value', 'even' => 'even_value'))); + $this->assertEquals('odd_value', $mp->Odd_Even(Array('odd' => 'odd_value', 'even' => 'even_value'))); + } + + function testApplicationProcessTag() + { + global $application; + $this->assertEquals($application->GetSID(), $application->ProcessTag('m:sid')); + } + + } + $suite->addTest(new TestSuite("TestMainProcessor")); + + + + + + +} + +?> \ No newline at end of file Index: trunk/core/kernel/kbase.php =================================================================== diff -u --- trunk/core/kernel/kbase.php (revision 0) +++ trunk/core/kernel/kbase.php (revision 932) @@ -0,0 +1,206 @@ +Prefix=$prefix[0]; + $this->Special=$special; + } + + /** + * Returns joined prefix + * and special if any + * + * @return string + * @access protected + */ + function getPrefixSpecial() + { + return rtrim($this->Prefix.'.'.$this->Special,'.'); + } + + /** + * Set's application + * + * @return kBase + * @access public + */ + function kBase() + { + $this->Application =& kApplication::Instance(); + } +} + +class kDBBase extends kBase { + /** + * Description + * + * @var DBConnection + * @access public + */ + var $Conn; + + /** + * Description + * + * @var string Name of primary key field for the item + * @access public + */ + var $IDField; + + /** + * Holds SELECT, FROM, JOIN parts of SELECT query + * + * @var string + * @access public + */ + var $SelectClause; + + /** + * Display queries executed by the class + * + * @var bool + * @access public + */ + var $DisplayQueries = false; + + /** + * Object that holds all + * formatters created + * + * @var kItemFormatter + * @access private + */ + var $ItemFormatter; + + /** + * Description + * + * @var string Item' database table name, without prefix + * @access public + */ + var $TableName; + + 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; + } + + /** + * 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() + { + return sprintf($this->SelectClause,$this->TableName); + } + + /** + * 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; + } + + /** + * Returns formatted field value + * + * @param string $field + * @return string + * @access public + */ + function GetField($field) + { + + } + + /** + * 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); + } +} + +?> \ No newline at end of file