Index: trunk/core/kernel/startup.php
===================================================================
diff -u -r932 -r1339
--- trunk/core/kernel/startup.php (.../startup.php) (revision 932)
+++ trunk/core/kernel/startup.php (.../startup.php) (revision 1339)
@@ -1,50 +1,91 @@
',$label,'
',print_r($data,true),'
';
- //echo var_dump($data);
-}
-function safeDefine($const_name, $const_value)
-{
- if(!defined($const_name)) define($const_name,$const_value);
-}
+// global constants
+define('HAVING_FILTER', 1);
+define('WHERE_FILTER', 2);
+define('FLT_TYPE_AND', 'AND');
+define('FLT_TYPE_OR', 'OR');
+
?>
\ No newline at end of file
Index: trunk/core/kernel/db/db_tag_processor.php
===================================================================
diff -u -r938 -r1339
--- trunk/core/kernel/db/db_tag_processor.php (.../db_tag_processor.php) (revision 938)
+++ trunk/core/kernel/db/db_tag_processor.php (.../db_tag_processor.php) (revision 1339)
@@ -3,6 +3,108 @@
class kDBTagProcessor extends TagProcessor {
/**
+ * Description
+ *
+ * @var DBConnection
+ * @access public
+ */
+ var $Conn;
+
+ function kDBTagProcessor()
+ {
+ parent::kBase();
+ $this->Conn =& $this->Application->GetADODBConnection();
+ }
+
+ /**
+ * Returns view menu name for current prefix
+ *
+ * @param Array $params
+ * @return string
+ */
+ function GetItemName($params)
+ {
+ $item_name = $this->Application->getUnitOption($this->Prefix,'ViewMenuPhrase');
+ return $this->Application->Phrase($item_name);
+ }
+
+ /**
+ * Draw filter menu content (for ViewMenu) based on filters defined in config
+ *
+ * @param Array $params
+ * @return string
+ */
+ function DrawFilterMenu($params)
+ {
+ $block_params = $this->prepareTagParams($params);
+ $block_params['name'] = $params['spearator_block'];
+ $separator = $this->Application->ParseBlock($block_params);
+ $filter_menu = $this->Application->getUnitOption($this->Prefix,'FilterMenu');
+
+ // Params: label, filter_action, filter_status
+ $block_params['name'] = $params['item_block'];
+
+ $view_filter = $this->Application->RecallVar($this->getPrefixSpecial().'_view_filter');
+ if($view_filter === false)
+ {
+ $event_params = Array('prefix'=>$this->Prefix,'special'=>$this->Special,'name'=>'OnRemoveFilters');
+ $this->Application->HandleEvent( new kEvent($event_params) );
+ $view_filter = $this->Application->RecallVar($this->getPrefixSpecial().'_view_filter');
+ }
+ $view_filter = unserialize($view_filter);
+
+ $filters = Array();
+ $prefix_special = $this->getPrefixSpecial();
+ foreach($filter_menu['Filters'] as $filter_key => $filter_params)
+ {
+ if(!$filter_params)
+ {
+ $filters[] = $separator;
+ continue;
+ }
+
+ $block_params['label'] = addslashes( $this->Application->Phrase($filter_params['label']) );
+ if( getArrayValue($view_filter,$filter_key) )
+ {
+ $submit = 0;
+ $status = 1;
+ }
+ else
+ {
+ $submit = 1;
+ $status = 0;
+ }
+ $block_params['filter_action'] = 'set_filter("'.$prefix_special.'","'.$filter_key.'","'.$submit.'");';
+ $block_params['filter_status'] = $status;
+ $filters[] = $this->Application->ParseBlock($block_params);
+ }
+ return implode('', $filters);
+ }
+
+ function IterateGridFields($params)
+ {
+ $mode = $params['mode'];
+ $def_block = $params['block'];
+
+ $grids = $this->Application->getUnitOption($this->Prefix,'Grids');
+ $grid_config = $grids[$params['grid']]['Fields'];
+
+ $std_params['pass_params']='true';
+ $std_params['PrefixSpecial']=$this->getPrefixSpecial();
+
+ $o = '';
+ foreach ($grid_config as $field => $options) {
+ $block_params = Array();
+ $block_params['name'] = isset($options[$mode.'_block']) ? $options[$mode.'_block'] : $def_block;
+ $block_params['field'] = $field;
+ $block_params['sort_field'] = isset($options['sort_field']) ? $options['sort_field'] : $field;
+ $block_params = array_merge($std_params, $block_params, $options);
+ $o.= $this->Application->ParseBlock($block_params, 1);
+ }
+ return $o;
+ }
+
+ /**
* Prints list content using block specified
*
* @param Array $params
@@ -13,29 +115,99 @@
{
$list =& $this->Application->recallObject( $this->getPrefixSpecial(), $this->Prefix.'_List',$params);
$id_field = $this->Application->getUnitOption($this->Prefix,'IDField');
- //
+
+ $list->Query();
+ $o = '';
+ $list->GoFirst();
- /*$parser =& $this->Application->recallObject('TemplateParser');
+ $block_params=$this->prepareTagParams($params);
+ $block_params['name']=$params['block'];
+ $block_params['pass_params']='true';
- // 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);*/
+ while (!$list->EOL())
+ {
+ $this->Application->SetVar( $this->getPrefixSpecial().'_id', $list->GetDBField($id_field) ); // for edit/delete links using GET
+ $o.= $this->Application->ParseBlock($block_params, 1);
+ $list->GoNext();
+ }
+ $this->Application->SetVar( $this->getPrefixSpecial().'_id', '');
+ return $o;
+ }
+
+ /**
+ * Prints list content using block specified
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function PrintList2($params)
+ {
+ $prefix_special = $this->getPrefixSpecial();
+ $list =& $this->Application->recallObject( $prefix_special, $this->Prefix.'_List',$params);
+
+ if ( !($list->OriginalParams == $params) ) {
+ $this->Application->removeObject($prefix_special);
+ $list =& $this->Application->recallObject($prefix_special,$this->Prefix.'_List',$params);
+ }
+
+ $id_field = $this->Application->getUnitOption($this->Prefix,'IDField');
+
$list->Query();
$o = '';
+
+ $direction = (isset($params['direction']) && $params['direction']=="H")?"H":"V";
+ $columns = (isset($params['columns']))?$params['columns']:1;
+
+ if ($columns>1 && $direction=="V") {
+ $list->Records = $this->LinearToVertical($list->Records, $columns, $params['per_page']);
+ $list->SelectedCount=count($list->Records);
+ ksort($list->Records);
+ }
+
+
$list->GoFirst();
+
+
$block_params=$this->prepareTagParams($params);
$block_params['name']=$params['block'];
$block_params['pass_params']='true';
+ $block_start_row_params=$this->prepareTagParams($params);
+ $block_start_row_params['name']=$params['row_start_block'];
+
+ $block_end_row_params=$this->prepareTagParams($params);
+ $block_end_row_params['name']=$params['row_end_block'];
+
+ $i=0;
+
+ $backup_id=$this->Application->GetVar($this->Prefix."_id");
+
while (!$list->EOL())
{
- $this->Application->SetVar( $this->getPrefixSpecial().'_id', $list->GetDBField($id_field) );
+ if (!$list->getCurrentRecord()){
+ //$list->GoNext();
+ //continue;
+ $block_params['name']=$params['block_empty_cell'];
+ }else{
+ $block_params['name']=$params['block'];
+ }
+ $this->Application->SetVar( $this->getPrefixSpecial().'_id', $list->GetDBField($id_field) ); // for edit/delete links using GET
+ $this->Application->SetVar( $this->Prefix.'_id', $list->GetDBField($id_field) );
+
+ if ($i%$params['columns'] == 0) $o.= $this->Application->ParseBlock($block_start_row_params, 1);
$o.= $this->Application->ParseBlock($block_params, 1);
+ if (($i+1)%$params['columns'] == 0) $o.= $this->Application->ParseBlock($block_end_row_params, 1);
+
$list->GoNext();
+
+ $i++;
}
+
+ $this->Application->SetVar( $this->Prefix.'_id', $backup_id);
+ $this->Application->SetVar( $this->getPrefixSpecial().'_id', '');
return $o;
}
@@ -58,7 +230,7 @@
}
/**
- * Get's reuested field value
+ * Get's requested field value
*
* @param Array $params
* @return string
@@ -69,13 +241,105 @@
$field = $params['field'];
$object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
- $value = $object->GetField($field);
+ if ( getArrayValue($params, 'db') !== false )
+ {
+ $value = $object->GetDBField($field);
+ }
+ else
+ {
+ $format = getArrayValue($params, 'format');
+ if (!$format) {
+ $format = null;
+ }
+ else {
+ if (preg_match("/_regional_(.*)/", $format, $regs)) {
+ $lang = $this->Application->recallObject('lang');
+ $format = $lang->GetDBField($regs[1]);
+ }
+ }
+ $value = $object->GetField($field, $format);
+ }
- if (isset($params['nl2br'])) $value = nl2br($value);
+ if( getArrayValue($params,'nl2br' ) ) $value = nl2br($value);
+ if( !getArrayValue($params,'no_special') ) $value = htmlspecialchars($value);
+ if( getArrayValue($params,'checked' ) ) $value = ($value == 1) ? 'checked' : '';
+ if( getArrayValue($params,'as_label') ) $value = $this->Application->Phrase($value);
+ $cut_first = getArrayValue($params,'cut_first');
+ if($cut_first)
+ {
+ $needs_cut = strlen($value) > $cut_first;
+ $value = substr($value,0,$cut_first);
+ if($needs_cut) $value .= ' ...';
+ }
+
+ if ($value != '') $this->Application->Parser->DataExists = true;
+
return $value;
}
+ function Error($params)
+ {
+ $field = $params['field'];
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ $msg = $object->GetErrorMsg($field);
+
+ return $msg;
+ }
+
+ function HasError($params)
+ {
+ return $this->Error($params) != '';
+ }
+
+ function IsRequired($params)
+ {
+ $field = $params['field'];
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ $options = $object->GetFieldOptions($field);
+ return getArrayValue($options,'required');
+ }
+
+ function PredefinedOptions($params)
+ {
+ $field = $params['field'];
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ $value = $object->GetDBField($field);
+ $options = $object->GetFieldOptions($field);
+
+ $block_params['name'] = $params['block'];
+ $block_params['pass_params'] = 'true';
+ $selected = $params['selected'];
+
+ $o = '';
+ foreach ($options['options'] as $key => $val) {
+ $block_params['key'] = $key;
+ $block_params['option'] = $val;
+ $block_params[$selected] = ( $key == $value ? ' '.$selected : '');
+ $o .= $this->Application->ParseBlock($block_params, 1);
+ }
+
+ return $o;
+ }
+
+ function Format($params)
+ {
+ $field = $params['field'];
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ $options = $object->GetFieldOptions($field);
+ if (isset($options['formatter']) && (isset($params['human']) || isset($params['edit_size'])) ) {
+ $formatter =& $this->Application->recallObject($options['formatter']);
+ $format = $formatter->HumanFormat($options['format']);
+ return isset($params['edit_size']) ? strlen($format) : $format;
+ }
+
+ return $options['format'];
+ }
+
/**
* Print grid pagination using
* block names specified
@@ -86,37 +350,90 @@
*/
function PrintPages($params)
{
+
$prefix_special=$this->getPrefixSpecial();
$object =& $this->Application->recallObject($prefix_special,$this->Prefix.'_List',$params);
+
+ if ( !($object->OriginalParams == $params) ) {
+ $this->Application->removeObject($prefix_special);
+ $object =& $this->Application->recallObject($prefix_special,$this->Prefix.'_List',$params);
+ }
+
$total = $object->GetTotalPages();
$o = '';
+ // what are these 2 lines for?
$this->Application->SetVar($prefix_special.'_event','');
$this->Application->SetVar($prefix_special.'_id','');
- $current_page = $this->Application->RecallVar($prefix_special.'_page');
+ $current_page = $this->Application->RecallVar($prefix_special.'_Page');
- $block_params=$this->prepareTagParams($params);
+ $block_params = $this->prepareTagParams($params);
- for ($i=1; $i<=$total; $i++)
+ $split = ( isset($params['split'])?$params['split']:10 );
+
+ $split_start = $current_page - ceil($split/2);
+ if ($split_start < 1){
+ $split_start = 1;
+ }
+
+ $split_end = $split_start + $split-1;
+ if ($split_end > $total) {
+ $split_end = $total;
+ $split_start = max($split_end - $split + 1, 1);
+ }
+
+ if ($current_page > 1){
+ $prev_block_params=array();
+
+ if ($total > $split){
+ $prev_block_params['page']=max($current_page-$split, 1);
+ $prev_block_params['name'] = getArrayValue($params, 'prev_page_split_block');
+ if ($prev_block_params['name']){
+ $o .= $this->Application->ParseBlock($prev_block_params, 1);
+ }
+ }
+
+ $prev_block_params['name']="page";
+ $prev_block_params['page']=$current_page-1;
+ $prev_block_params['name'] = getArrayValue($params, 'prev_page_block');
+ if ($prev_block_params['name']){
+ $o .= $this->Application->ParseBlock($prev_block_params, 1);
+ }
+ }
+
+
+ for ($i = $split_start; $i<=$split_end; $i++)
{
- $this->Application->SetVar($prefix_special.'_page',$i);
+ //$this->Application->SetVar($prefix_special.'_Page',$i);
$block = $params[ (($i==$current_page)?'active':'inactive').'_block' ];
$block_params['name']=$block;
$block_params['page']=$i;
$o .= $this->Application->ParseBlock($block_params, 1);
}
+ if ($current_page < $total){
+ $next_block_params=array();
+ $next_block_params['page']=$current_page+1;
+ $next_block_params['name'] = getArrayValue($params, 'next_page_block');
+ if ($next_block_params['name']){
+ $o .= $this->Application->ParseBlock($next_block_params, 1);
+ }
+ if ($total > $split){
+ $next_block_params['page']=min($current_page+$split, $total);
+ $next_block_params['name'] = getArrayValue($params, 'next_page_split_block');
+ if ($next_block_params['name']){
+ $o .= $this->Application->ParseBlock($next_block_params, 1);
+ }
+ }
+ }
+
+
+
+
return $o;
}
-
- /*function MapField($params)
- {
- $object =& $this->Application->recallObject($this->Prefix.'.'.$this->Special);
- $value = $object->GetField($params['field']);
- $this->Application->SetVar($params['var_name'],$value);
- }*/
/**
* Returns input field name to
@@ -131,11 +448,398 @@
{
$prefix_special=$this->getPrefixSpecial();
$item = $this->Application->recallObject($prefix_special);
- return $prefix_special.'['.$item->GetID().']['.$params['field'].']';
+
+ if ( $formatter = getArrayValue($item->Fields, $params['field'], 'formatter') ) {
+ if ( $formatter == 'kMultiLanguage' ) {
+ $formatter =& $this->Application->recallObject($formatter);
+ $params['field'] = $formatter->LangFieldName($params['field']);
+ }
+ }
+
+ if ( $idfield = getArrayValue($params, 'IdField') ) {
+ $id = $item->GetDBField($idfield);
+ }
+ else {
+ $id = $item->GetID();
+ }
+
+ return $prefix_special.'['.$id.']['.$params['field'].']';
}
+
+
+ /**
+ * Returns index where 1st changable sorting field begins
+ *
+ * @return int
+ * @access private
+ */
+ function getUserSortIndex()
+ {
+ $list_sortings = $this->Application->getUnitOption($this->Prefix, 'ListSortings');
+ $sorting_prefix = getArrayValue($list_sortings, $this->Special) ? $this->Special : '';
+
+ $user_sorting_start = 0;
+ if ( $forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting') ) {
+ $user_sorting_start = count($forced_sorting);
+ }
+ return $user_sorting_start;
+ }
+
+ /**
+ * Returns order direction for given field
+ *
+ *
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function Order($params)
+ {
+ $field = $params['field'];
+ $user_sorting_start = $this->getUserSortIndex();
+
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+
+ if ($object->GetOrderField($user_sorting_start) == $field)
+ {
+ return $object->GetOrderDirection($user_sorting_start);
+ }
+ elseif($object->GetOrderField($user_sorting_start+1) == $field)
+ {
+ return '2_'.$object->GetOrderDirection($user_sorting_start+1);
+ }
+ else
+ {
+ return 'no';
+ }
+ }
+ /**
+ * Get's information of sorting field at "pos" position,
+ * like sorting field name (type="field") or sorting direction (type="direction")
+ *
+ * @param Array $params
+ * @return mixed
+ */
+ function OrderInfo($params)
+ {
+ $user_sorting_start = $this->getUserSortIndex() + --$params['pos'];
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+
+ if($params['type'] == 'field') return $object->GetOrderField($user_sorting_start);
+ if($params['type'] == 'direction') return $object->GetOrderDirection($user_sorting_start);
+ }
+ /**
+ * Checks if sorting field/direction matches passed field/direction parameter
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function IsOrder($params)
+ {
+ $params['type'] = isset($params['field']) ? 'field' : 'direction';
+ $value = $this->OrderInfo($params);
+
+ if( isset($params['field']) ) return $params['field'] == $value;
+ if( isset($params['direction']) ) return $params['direction'] == $value;
+ }
+
+ /**
+ * Returns list perpage
+ *
+ * @param Array $params
+ * @return int
+ */
+ function PerPage($params)
+ {
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+ return $object->PerPage;
+ }
+
+ /**
+ * Checks if list perpage matches value specified
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function PerPageEquals($params)
+ {
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+ return $object->PerPage == $params['value'];
+ }
+
+ function SaveEvent($params)
+ {
+ // SaveEvent is set during onbuild, but we may need it before any other tag calls onBuild
+ $prefix_special = $this->getPrefixSpecial();
+ $item = $this->Application->recallObject($prefix_special);
+
+ return $this->Application->GetVar($prefix_special.'_SaveEvent');
+ }
+
+ function NextId($params)
+ {
+ $prefix_special=$this->getPrefixSpecial();
+ $ids = explode(',', $this->Application->RecallVar($prefix_special.'_selected_ids'));
+ $item = $this->Application->recallObject($prefix_special);
+ $cur_id = $item->GetId();
+
+ $i = array_search($cur_id,$ids);
+ if ($i !== false) {
+ return $i < count($ids)-1 ? $ids[$i+1] : '';
+ }
+ return '';
+ }
+
+ function PrevId($params)
+ {
+ $prefix_special=$this->getPrefixSpecial();
+ $ids = explode(',', $this->Application->RecallVar($prefix_special.'_selected_ids'));
+ $item = $this->Application->recallObject($prefix_special);
+ $cur_id = $item->GetId();
+
+ $i = array_search($cur_id,$ids);
+ if ($i !== false) {
+ return $i > 0 ? $ids[$i-1] : '';
+ }
+ return '';
+ }
+
+ function IsSingle($params)
+ {
+ return ($this->NextId($params) === '' && $this->PrevId($params) === '');
+ }
+
+ function IsLast($params)
+ {
+ return ($this->NextId($params) === '');
+ }
+
+ function IsFirst($params)
+ {
+ return ($this->PrevId($params) === '');
+ }
+
+ /**
+ * Checks if field value is equal to proposed one
+ *
+ * @param Array $params
+ * @return bool
+ */
+ function FieldEquals($params)
+ {
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+ $ret = $object->GetDBField($params['field']) == $params['value'];
+ if( getArrayValue($params,'inverse') ) $ret = !$ret;
+ return $ret;
+ }
+
+ function ItemIcon($params)
+ {
+ $object =& $this->Application->recallObject($this->getPrefixSpecial(),$this->Prefix, $params);
+
+ $grids = $this->Application->getUnitOption($this->Prefix,'Grids');
+ $icons =& $grids[ $params['grid'] ]['Icons'];
+
+ $key = '';
+ $status_fields = $this->Application->getUnitOption($this->Prefix,'StatusField');
+ if(!$status_fields) return $icons['default'];
+
+ foreach($status_fields as $status_field)
+ {
+ $key .= $object->GetDBField($status_field).'_';
+ }
+ $key = rtrim($key,'_');
+ $value = ($key !== false) ? $key : 'default';
+
+ return isset($icons[$value]) ? $icons[$value] : $icons['default'];
+ }
+
+ function SectionTitle($params)
+ {
+ $title_presets = $this->Application->getUnitOption($this->Prefix,'TitlePresets');
+ $title_info = getArrayValue($title_presets, $params['title_preset'] );
+ if($title_info === false) return $params['title'];
+
+ if( getArrayValue($title_presets,'default') )
+ {
+ // use default labels + custom labels specified in preset used
+ $title_info = array_merge_recursive2($title_presets['default'], $title_info);
+ }
+
+ $title = $title_info['format'];
+
+ // 1. get objects in use for title construction
+ $objects = Array();
+ $object_status = Array();
+ $status_labels = Array();
+
+ $prefixes = getArrayValue($title_info,'prefixes');
+ if($prefixes)
+ {
+ foreach($prefixes as $prefix_special)
+ {
+ $prefix_data = $this->Application->processPrefix($prefix_special);
+ $prefix_data['prefix_special'] = rtrim($prefix_data['prefix_special'],'.');
+ $objects[ $prefix_data['prefix_special'] ] =& $this->Application->recallObject($prefix_data['prefix_special'], $prefix_data['prefix'], $params);
+ $object_status[ $prefix_data['prefix_special'] ] = $objects[ $prefix_data['prefix_special'] ]->GetID() ? 'edit' : 'new';
+
+ // a. set object's status field (adding item/editing item) for each object in title
+ if( getArrayValue($title_info[ $object_status[ $prefix_data['prefix_special'] ].'_status_labels' ],$prefix_data['prefix_special']) )
+ {
+ $status_labels[ $prefix_data['prefix_special'] ] = $title_info[ $object_status[ $prefix_data['prefix_special'] ].'_status_labels' ][ $prefix_data['prefix_special'] ];
+ $title = str_replace('#'.$prefix_data['prefix_special'].'_status#', $status_labels[ $prefix_data['prefix_special'] ], $title);
+ }
+
+ // b. setting object's titlefield value (in titlebar ONLY) to default in case if object beeing created with no titlefield filled in
+ if( $object_status[ $prefix_data['prefix_special'] ] == 'new' )
+ {
+ $new_value = $this->getInfo( $objects[ $prefix_data['prefix_special'] ], 'titlefield' );
+ if(!$new_value && getArrayValue($title_info['new_titlefield'],$prefix_data['prefix_special']) ) $new_value = $this->Application->Phrase($title_info['new_titlefield'][ $prefix_data['prefix_special'] ]);
+ $title = str_replace('#'.$prefix_data['prefix_special'].'_titlefield#', $new_value, $title);
+ }
+ }
+ }
+
+ // 2. replace phrases if any found in format string
+ $title = $this->Application->ReplaceLanguageTags($title);
+
+ // 3. find and replace any replacement vars
+ preg_match_all('/#(.*_.*)#/Uis',$title,$rets);
+ if($rets[1])
+ {
+ $replacement_vars = array_keys( array_flip($rets[1]) );
+ foreach($replacement_vars as $replacement_var)
+ {
+ $var_info = explode('_',$replacement_var,2);
+ $object =& $objects[ $var_info[0] ];
+ $new_value = $this->getInfo($object,$var_info[1]);
+ $title = str_replace('#'.$replacement_var.'#', $new_value, $title);
+ }
+ }
+
+ return $title;
+ }
+
+ function getInfo(&$object, $info_type)
+ {
+ switch ($info_type)
+ {
+ case 'titlefield':
+ $field = $this->Application->getUnitOption($object->Prefix,'TitleField');
+ return $field !== false ? $object->GetField($field) : 'TitleField Missing';
+ break;
+
+ case 'recordcount':
+ $of_phrase = $this->Application->Phrase('la_of');
+ return $object->NoFilterCount != $object->RecordsCount ? $object->RecordsCount.' '.$of_phrase.' '.$object->NoFilterCount : $object->RecordsCount;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Parses block depending on its element type.
+ * For radio and select elements values are taken from 'value_list_field' in key1=value1,key2=value2
+ * format. key=value can be substituted by SELECT f1 AS OptionName, f2 AS OptionValue... FROM TableName
+ * where prefix is TABLE_PREFIX
+ *
+ * @param Array $params
+ * @return string
+ */
+ function ConfigFormElement($params)
+ {
+ $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
+ $field = $params['field'];
+
+ $helper = $this->Application->recallObject('InpCustomFieldsHelper');
+
+ $element_type = $object->GetDBField($params['element_type_field']);
+
+ if($element_type=='label') $element_type='text';
+ $params['name']= $params['blocks_prefix'] . $element_type;
+
+ switch ($element_type){
+ case 'select':
+ case 'radio':
+ $field_options = $object->GetFieldOptions($field, 'options');
+ $field_options['options'] = $helper->GetValuesHash( $object->GetDBField($params['value_list_field']) );
+ $object->SetFieldOptions($field, $field_options);
+ break;
+
+ case 'textarea':
+ $params['field_params'] = $helper->ParseConfigSQL($object->GetDBField($params['value_list_field']));
+ break;
+
+ case 'password':
+ case 'text':
+ case 'checkbox':
+ default:
+ break;
+ }
+ return $this->Application->ParseBlock($params, 1);
+ }
+
+ /**
+ * Get's requested custom field value
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function CustomField($params)
+ {
+ $prefix = $this->getPrefixSpecial();
+ $object =& $this->Application->recallObject( $prefix );
+
+ $sql = ' SELECT cv.Value FROM '.TABLE_PREFIX.'CustomField cf
+ LEFT JOIN '.TABLE_PREFIX.'CustomMetaData cv
+ ON cf.CustomFieldId = cv.CustomFieldId
+ WHERE cf.Type = '.$this->Application->getUnitOption($prefix, 'ItemType').'
+ AND cv.ResourceId = '.$object->GetDBField('ResourceId').'
+ AND cf.FieldName = "'.$params['field'].'"';
+ return $this->Conn->GetOne($sql);
+ }
+
+ /**
+ * transposes 1-dimensional array elements for vertical alignment according to given columns and per_page parameters
+ *
+ * @param array $arr
+ * @param int $columns
+ * @param int $per_page
+ * @return array
+ */
+ function LinearToVertical(&$arr, $columns, $per_page){
+ $rows=$columns;
+ $cols=min(ceil($per_page/$columns), ceil(sizeof($arr)/$columns));
+ $imatrix=array();
+ for ($row=0; $row<$rows; $row++) {
+ for ($col=0; $col<$cols; $col++){
+ $imatrix[$col*$rows+$row]=$arr[$row*$cols+$col];
+ }
+ }
+ ksort($imatrix);
+ reset($imatrix);
+ return $imatrix;
+ }
+
+ function SaveWarning($params){
+
+ $top_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
+
+ if ( $this->Application->GetVar($top_prefix.'_mode') == 't' && $this->Application->RecallVar($top_prefix."_modified")=="1"){
+ return $this->Application->ParseBlock($params);
+ }else{
+ $this->Application->RemoveVar($top_prefix."_modified");
+ return "";
+ }
+ }
+
}
?>
\ No newline at end of file
Index: trunk/core/kernel/session/session.php
===================================================================
diff -u -r939 -r1339
--- trunk/core/kernel/session/session.php (.../session.php) (revision 939)
+++ trunk/core/kernel/session/session.php (.../session.php) (revision 1339)
@@ -61,52 +61,60 @@
class SessionStorage extends kDBBase {
var $Expiration;
+ var $SessionTimeout=0;
var $OriginalData=Array();
+ var $TimestampField;
+ var $SessionDataTable;
+ var $DataValueField;
+ var $DataVarField;
+
+ function Init($prefix,$special)
+ {
+ parent::Init($prefix,$special);
+ $this->setTableName('sessions');
+ $this->setIDField('sid');
+ $this->TimestampField = 'expire';
+ $this->SessionDataTable = 'SessionData';
+ $this->DataValueField = 'value';
+ $this->DataVarField = 'var';
+ }
+
+ function setSessionTimeout($new_timeout)
+ {
+ $this->SessionTimeout = $new_timeout;
+ }
+
function StoreSession(&$session)
{
- $query = sprintf( "INSERT INTO %sSessions (sid, expire) VALUES (%s, %s)",
- TABLE_PREFIX,
- $session->SID,
- $session->Expiration);
+ $query = ' INSERT INTO '.$this->TableName.' ('.$this->IDField.', '.$this->TimestampField.')'.
+ ' VALUES ('.$this->Conn->qstr($session->SID).', '.$session->Expiration.')';
$this->Conn->Query($query);
}
function DeleteSession(&$session)
{
- $query = sprintf( "DELETE FROM %sSessions WHERE %s = %s",
- TABLE_PREFIX,
- 'sid',
- $session->SID);
+ $query = ' DELETE FROM '.$this->TableName.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
- $query = sprintf( "DELETE FROM %sSessionData WHERE %s = %s",
- TABLE_PREFIX,
- 'sid',
- $session->SID);
+ $query = ' DELETE FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
$this->OriginalData = Array();
}
- function UpdateSession(&$session)
+ function UpdateSession(&$session, $timeout=0)
{
- $query = sprintf( "UPDATE %sSessions SET expire = %s WHERE %s = %s",
- TABLE_PREFIX,
- $session->Expiration,
- 'sid',
- $session->SID);
+ $query = ' UPDATE '.$this->TableName.' SET '.$this->TimestampField.' = '.$session->Expiration.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
}
function LocateSession($sid)
{
- $query = sprintf( "SELECT expire FROM %sSessions WHERE %s = %s",
- TABLE_PREFIX,
- 'sid',
- $sid);
+ $query = ' SELECT '.$this->TimestampField.' FROM '.$this->TableName.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($sid);
$result = $this->Conn->GetOne($query);
+
if($result===false) return false;
$this->Expiration = $result;
@@ -120,16 +128,27 @@
function LoadData(&$session)
{
- $query = sprintf( "SELECT value,name FROM %sSessionData WHERE %s = %s",
- TABLE_PREFIX,
- 'sid',
- $session->SID);
- $this->OriginalData = $this->Conn->GetCol($query,'name');
+ $query = 'SELECT '.$this->DataValueField.','.$this->DataVarField.' FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
+
+ $this->OriginalData = $this->Conn->GetCol($query, $this->DataVarField);
return $this->OriginalData;
}
+ /**
+ * Enter description here...
+ *
+ * @param Session $session
+ * @param string $var_name
+ */
+ function GetField(&$session, $var_name)
+ {
+ return $this->Conn->GetOne('SELECT '.$var_name.' FROM '.$this->TableName.' WHERE `'.$this->IDField.'` = '.$this->Conn->qstr($session->GetID()) );
+ }
+
function SaveData(&$session)
{
+ if(!$session->SID) return false; // can't save without sid
+
$ses_data = $session->Data->GetParams();
$replace = '';
@@ -142,31 +161,46 @@
else
{
$replace .= sprintf("(%s, %s, %s),",
- $session->SID,
+ $this->Conn->qstr($session->SID),
$this->Conn->qstr($key),
$this->Conn->qstr($value));
}
}
$replace = rtrim($replace, ',');
if ($replace != '') {
- $query = sprintf( 'REPLACE INTO %sSessionData (sid, name, value) VALUES %s',
- TABLE_PREFIX,
- $replace);
+ $query = ' REPLACE INTO '.$this->SessionDataTable. ' ('.$this->IDField.', '.$this->DataVarField.', '.$this->DataValueField.') VALUES '.$replace;
$this->Conn->Query($query);
}
}
function RemoveFromData(&$session, $var)
{
- $query = sprintf( "DELETE FROM %sSessionData WHERE %s = %s AND %s = %s",
- TABLE_PREFIX,
- 'sid',
- $session->SID,
- 'name',
- $this->Conn->qstr($var));
+ $query = 'DELETE FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID).
+ ' AND '.$this->DataVarField.' = '.$this->Conn->qstr($var);
$this->Conn->Query($query);
unset($this->OriginalData[$var]);
}
+
+ function GetExpiredSIDs()
+ {
+ $query = ' SELECT '.$this->IDField.' FROM '.$this->TableName.' WHERE '.$this->TimestampField.' > '.time();
+ return $this->Conn->GetCol($query);
+ }
+
+ function DeleteExpired()
+ {
+ $expired_sids = $this->GetExpiredSIDs();
+ if($expired_sids)
+ {
+ $where_clause=' WHERE '.$this->IDField.' IN ("'.implode('","',$expired_sids).'")';
+ $sql = 'DELETE FROM '.$this->SessionDataTable.$where_clause;
+ $this->Conn->Query($sql);
+
+ $sql = 'DELETE FROM '.$this->TableName.$where_clause;
+ $this->Conn->Query($sql);
+ }
+ return $expired_sids;
+ }
}
define('smAUTO', 1);
@@ -231,7 +265,8 @@
function InitStorage()
{
- $this->Storage =& new SessionStorage();
+ $this->Storage =& $this->Application->recallObject('SessionStorage');
+ $this->Storage->setSessionTimeout($this->SessionTimeout);
}
function Init($prefix,$special)
@@ -242,6 +277,19 @@
$this->Checkers = Array();
$this->InitStorage();
$this->Data =& new Params();
+
+ $tmp_sid = $this->GetPassedSIDValue();
+ $expired_sids = $this->DeleteExpired();
+ if( ( $expired_sids && in_array($tmp_sid,$expired_sids) ) || ( $tmp_sid && !$this->Check() ) )
+ {
+ $event = new kEvent();
+ $event->Init('login','');
+ $event->Name = 'OnSessionExpire';
+ $this->SID='';
+ $this->SetSessionCookie();
+ $this->Application->HandleEvent($event);
+ }
+
if ($this->Check()) {
$this->SID = $this->GetPassedSIDValue();
$this->Refresh();
@@ -260,13 +308,14 @@
function CheckIfCookiesAreOn()
{
- if ($this->Mode == smGET_ONLY) {
+ if ($this->Mode == smGET_ONLY || (defined('INPORTAL_ENV')&&INPORTAL_ENV && defined('ADMIN')&&ADMIN) )
+ {
//we don't need to bother checking if we would not use it
$this->CookiesEnabled = false;
return;
}
$http_query =& $this->Application->recallObject('HTTPQuery');
- $cookies_on = $http_query->Cookie['cookies_on']; // not good here
+ $cookies_on = isset($http_query->Cookie['cookies_on']); // not good here
if (!$cookies_on) {
//If referer is our server, but we don't have our cookies_on, it's definetly off
@@ -313,7 +362,7 @@
function LoadSession($sid)
{
- if ($this->Storage->LocateSession($sid)) {
+ if( $this->Storage->LocateSession($sid) ) {
//if we have session with such SID - get its expiration
$this->Expiration = $this->Storage->GetExpiration();
@@ -336,7 +385,7 @@
switch ($this->Mode) {
case smAUTO:
//Cookies has the priority - we ignore everything else
- $sid=$this->CookiesEnabled?$http_query->Cookie[$this->CookieName]:$get_sid;
+ $sid=$this->CookiesEnabled ? getArrayValue($http_query->Cookie,$this->CookieName) : $get_sid;
break;
case smCOOKIES_ONLY:
$sid = $http_query->Cookie[$this->CookieName];
@@ -487,8 +536,34 @@
$this->Data->AddParams($this->Storage->LoadData($this));
}
+ function PrintSession($comment='')
+ {
+ if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_SHOW_SESSIONDATA') )
+ {
+ global $debugger;
+ $debugger->appendHTML('SessionStorage ('.$comment.'):');
+ $session_data = $this->Data->GetParams();
+ ksort($session_data);
+ foreach($session_data as $session_key => $session_value)
+ {
+ if( preg_match('/a:([\d]+):{/',$session_value) )
+ {
+ $session_data[$session_key] = unserialize($session_value);
+ }
+ }
+ $debugger->dumpVars($session_data);
+
+ // to insert after HTTPQuery if it's visible
+ $new_row = dbg_ConstOn('DBG_SHOW_HTTPQUERY') ? 4 : 2;
+
+ //$debugger->moveAfterRow($new_row,2);
+ }
+ }
+
function SaveData()
{
+ $this->StoreVar('last_template', basename($_SERVER['PHP_SELF']).'|'.substr($this->Application->BuildEnv($this->Application->GetVar('t'), Array('m_opener' => 'u'), 'all', true), strlen(ENV_VAR_NAME)+1 ));
+ $this->PrintSession('after save');
$this->Storage->SaveData($this);
}
@@ -497,17 +572,43 @@
$this->Data->Set($name, $value);
}
+ function StoreVarDefault($name, $value)
+ {
+ $tmp = $this->RecallVar($name);
+ if($tmp === false || $tmp == '')
+ {
+ $this->StoreVar($name, $value);
+ }
+ }
+
function RecallVar($name,$default=false)
{
- $ret=$this->Data->Get($name);
- return ($ret===false)?$default:$ret;
+ $ret = $this->Data->Get($name);
+ return ($ret===false) ? $default : $ret;
}
function RemoveVar($name)
{
$this->Storage->RemoveFromData($this, $name);
$this->Data->Remove($name);
}
+
+ function GetField($var_name)
+ {
+ return $this->Storage->GetField($this, $var_name);
+ }
+
+ /**
+ * Deletes expired sessions
+ *
+ * @return Array expired sids if any
+ * @access private
+ */
+ function DeleteExpired()
+ {
+ return $this->Storage->DeleteExpired();
+ }
+
}
?>
\ No newline at end of file
Index: trunk/core/kernel/utility/http_query.php
===================================================================
diff -u -r939 -r1339
--- trunk/core/kernel/utility/http_query.php (.../http_query.php) (revision 939)
+++ trunk/core/kernel/utility/http_query.php (.../http_query.php) (revision 1339)
@@ -57,6 +57,8 @@
*/
var $Files;
+ var $specialsToRemove = Array();
+
/**
* Loads info from $_POST, $_GET and
* related arrays into common place
@@ -70,10 +72,34 @@
parent::Params();
$this->Order = $order;
$this->AddAllVars();
- $this->processQueryString();
- ini_set("magic_quotes_gpc", 0);
+
+ $this->specialsToRemove = $this->Get('remove_specials');
+ if($this->specialsToRemove)
+ {
+ $this->_Params = $this->removeSpecials($this->_Params);
+ }
+ ini_set('magic_quotes_gpc', 0);
}
+ function removeSpecials($array)
+ {
+ $ret = Array();
+ $removed = false;
+ foreach($this->specialsToRemove as $prefix_special => $flag)
+ {
+ if($flag)
+ {
+ $removed = true;
+ list($prefix,$special) = explode('.',$prefix_special);
+ foreach ($array as $key => $val) {
+ $new_key = preg_match("/^".$prefix."[._]{1}".$special."(.*)/", $key, $regs) ? $prefix.$regs[1] : $key;
+ $ret[$new_key] = is_array($val) ? $this->removeSpecials($val) : $val;
+ }
+ }
+ }
+ return $removed ? $ret : $array;
+ }
+
/**
* All all requested vars to
* common storage place
@@ -88,10 +114,12 @@
switch ($current) {
case 'G':
$this->Get =$this->AddVars($_GET);
+ $this->processQueryString();
break;
case 'P':
- $my_post = $this->post_convert($_POST); // needed ?
+ //$my_post = $this->post_convert($_POST); // needed ?
$this->Post = $this->AddVars($_POST);
+ $this->convertPostEvents();
break;
case 'C':
$this->Cookie = $this->AddVars($_COOKIE);
@@ -103,11 +131,106 @@
$this->Server = $this->AddVars($_SERVER);
break;
case 'F';
- $this->Files = $this->AddVars($_FILES);
+ $this->convertFiles();
+ $this->Files = $this->MergeVars($_FILES, false); //do not strip slashes!
break;
}
}
}
+
+ function convertFiles()
+ {
+ if (!$_FILES)
+ {
+ return false;
+ }
+
+ $file_keys = Array('error','name','size','tmp_name','type');
+
+ foreach($_FILES as $file_name => $file_info)
+ {
+ if( is_array($file_info['error']) )
+ {
+ $tmp[$file_name] = $this->getArrayLevel( $file_info['error'], $file_name );
+ }
+ else
+ {
+ $normal_files[$file_name] = $file_info;
+ }
+ }
+
+ $files = $_FILES;
+ $_FILES = Array();
+
+ foreach($tmp as $prefix => $prefix_files)
+ {
+ $anchor =& $_FILES;
+ foreach($prefix_files['keys'] as $key)
+ {
+ $anchor =& $anchor[$key];
+ }
+ foreach($prefix_files['value'] as $field_name)
+ {
+ unset($inner_anchor);
+ unset($copy);
+ $work_copy = $prefix_files['keys'];
+ foreach($file_keys as $file_key)
+ {
+ $inner_anchor =& $files[$prefix][$file_key];
+ if (isset($copy))
+ {
+ $work_copy = $copy;
+ }
+ else
+ {
+ $copy = $work_copy;
+ }
+ array_shift($work_copy);
+ foreach($work_copy as $prefix_file_key)
+ {
+ $inner_anchor =& $inner_anchor[$prefix_file_key];
+ }
+ $anchor[$field_name][$file_key] = $inner_anchor[$field_name];
+ }
+ }
+ }
+
+ // keys: img_temp, 0, values: LocalPath, ThumbPath
+ }
+
+ function getArrayLevel(&$level, $prefix='')
+ {
+ $ret['keys'] = $prefix ? Array($prefix) : Array();
+ $ret['value'] = Array();
+
+ foreach($level as $level_key => $level_value)
+ {
+ if( is_array($level_value) )
+ {
+ $ret['keys'][] = $level_key;
+ $tmp = $this->getArrayLevel($level_value);
+
+ $ret['keys'] = array_merge($ret['keys'], $tmp['keys']);
+ $ret['value'] = array_merge($ret['value'], $tmp['value']);
+ }
+ else
+ {
+ $ret['value'][] = $level_key;
+ }
+ }
+
+ return $ret;
+ }
+
+ function convertPostEvents()
+ {
+ $events = $this->Get('events');
+ if (is_array($events)) {
+ foreach ($events as $prefix_special => $event) {
+ $this->Set($prefix_special.'_event', $event);
+ }
+ }
+ }
/**
* Process QueryString only, create
@@ -120,39 +243,84 @@
function processQueryString()
{
// env=SID:TEMPLATE:m-1-1-1-1:l0-0-0:n-0-0-0:bb-0-0-1-1-1-0
-
+
$env_var =& $this->Get(ENV_VAR_NAME);
if($env_var)
{
+ $env_var = str_replace('\:','_&+$$+&_',$env_var); // replace escaped "=" with spec-chars :)
+
$parts=explode(':',$env_var);
- // Save Session ID
- $sid=array_shift($parts);
- if($sid) $this->Set('sid',$sid);
+ if (defined('INPORTAL_ENV')) {
+ $sub_parts = array_shift($parts);
+
+ list($sid, $t) = explode('-', $sub_parts, 2);
+
+
+ // Save Session ID
+ if($sid) $this->Set('sid',$sid);
+
+ // Save Template Name
+ $t=$this->getTemplateName( $t );
+ if(!$t) $t='index';
+ $this->Set('t',$t);
+ }
+ else {
+ // Save Session ID
+ $sid=array_shift($parts);
+ if($sid) $this->Set('sid',$sid);
+
+ // Save Template Name
+ $t=$this->getTemplateName( array_shift($parts) );
+ if(!$t) $t='index';
+ $this->Set('t',$t);
+ }
- // Save Template Name
- $t=$this->getTemplateName( array_shift($parts) );
- if(!$t) $t='index';
- $this->Set('t',$t);
-
if($parts)
{
$query_maps=Array();
$event_manger =& $this->Application->recallObject('EventManager');
+ $passed = Array();
+
foreach($parts as $mixed_part)
{
- $mixed_part=explode('-',$mixed_part);
+ //In-portal old style env conversion - adds '-' between prefix and first var
+ $mixed_part = str_replace('_&+$$+&_',':',$mixed_part);
+ $mixed_part = preg_replace("/^([a-zA-Z]+)([0-9]+)-(.*)/", "$1-$2-$3", $mixed_part);
+
+ $escaped_part = str_replace('\-', '_&+$$+&_', $mixed_part);
+ $escaped_part = explode('-', $escaped_part);
+
+ $mixed_part = array();
+ foreach ($escaped_part as $escaped_val) {
+ $mixed_part[] = str_replace('_&+$$+&_', '-', $escaped_val);
+ }
+
$prefix_special=array_shift($mixed_part); // l.pick, l
list($prefix)=explode('.',$prefix_special);
-
+
$query_maps[$prefix_special]=$this->Application->getUnitOption($prefix,'QueryString');
- foreach($query_maps[$prefix_special] as $index => $var_name)
+
+ // if config is not defined for prefix in QueryString, then don't process it
+ if( $query_maps[$prefix_special] )
{
- // l_id, l_page, l_bla-bla-bla
- $this->Set($prefix_special.'_'.$var_name,$mixed_part[$index-1]);
+ array_push($passed, $prefix);
+ foreach($query_maps[$prefix_special] as $index => $var_name)
+ {
+ // l_id, l_page, l_bla-bla-bla
+ $val = $mixed_part[$index-1];
+ if ($val == '') $val = false;
+ $this->Set($prefix_special.'_'.$var_name, $val);
+ }
}
+ else
+ {
+ unset($query_maps[$prefix_special]);
+ }
+
}
+ $this->Set('passed', implode(',', $passed));
$event_manger->setQueryMaps($query_maps);
}
}
@@ -173,8 +341,15 @@
*/
function getTemplateName($querystring_template)
{
- $t_from_post=$this->Get('t');
- $t=$t_from_post?$t_from_post:$querystring_template;
+ $t_from_post = $this->Get('t');
+ $t= $t_from_post ? $t_from_post : $querystring_template;
+
+ if ( is_numeric($t) ) {
+ $t = $this->Application->DB->GetOne('SELECT CONCAT(FilePath, \'/\', FileName) FROM '.TABLE_PREFIX.'ThemeFiles
+ WHERE FileId = '.$t);
+ }
+ $t = preg_replace("/\.tpl$/", '', $t);
+
return $t;
}
@@ -200,40 +375,34 @@
*/
function AddVars($array)
{
- foreach ($array as $key => $val) {
- if (get_magic_quotes_gpc())
- {
-
- if ( is_array($val) )
- {
- foreach ($val as $key_array => $val_array)
- {
- if( is_array($val_array) )
- {
- $array[$key][$key_array] = $this->AddVars($val_array);
- }
- else
- {
- $array[$key][$key_array] = stripslashes($val_array);
- }
-
- }
- $this->Set($key, $array[$key]);
- }
- else {
- $array[$key] = stripslashes($val);
- $this->Set($key, $array[$key]);
- }
-
-
- }
- else {
- $this->Set($key, $val);
- }
+ $array = $this->StripSlashes($array);
+ foreach($array as $key => $value)
+ {
+ $this->Set($key,$value);
}
return $array;
}
+ function MergeVars($array, $strip_slashes=true)
+ {
+ if ($strip_slashes) $array = $this->StripSlashes($array);
+ foreach($array as $key => $value)
+ {
+ $this->_Params = array_merge_recursive2($this->_Params, Array($key=>$value));
+ }
+ return $array;
+ }
+
+ function StripSlashes($array)
+ {
+ if( !get_magic_quotes_gpc() ) return $array;
+ foreach($array as $key=>$value)
+ {
+ $array[$key]=is_array($value)?$this->StripSlashes($value):stripslashes($value);
+ }
+ return $array;
+ }
+
/**
* Returns the hash of http params
* matching the mask with values
Index: trunk/core/kernel/parser/template_parser.php
===================================================================
diff -u -r932 -r1339
--- trunk/core/kernel/parser/template_parser.php (.../template_parser.php) (revision 932)
+++ trunk/core/kernel/parser/template_parser.php (.../template_parser.php) (revision 1339)
@@ -1,6 +1,6 @@
Ses =& $this->Application->recallObject('Session');
+
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $conn =& $this->Application->GetADODBConnection();
+ if (isset($this->Application->PreParsedBlocks) && is_array($this->Application->PreParsedBlocks)) return;
+ $data = $conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "blocks_cache"');
+ if ($data && $data['Cached'] > (time() - 3600) ) {
+ $blocks = unserialize($data['Data']);
+ foreach ($blocks as $name => $f_body) {
+ $func = create_function('$params', $f_body);
+ $this->Application->PreParsedBlocks[$name] = $func;
+ }
+ $cached = $data['Cached'];
+ }
+ else {
+ $cached = 0;
+ }
+ }
}
function AddParam($pattern, $value, $dont_sort=0)
@@ -57,22 +80,20 @@
if (!is_array($params)) $params = Array();
$this->Params = $params;
foreach ($params as $key => $val) {
- $this->AddParam('/\$'.$key.'/', $val, 1); //Do not sort every time
+ $this->AddParam('/[{]{0,1}\$'.$key.'[}]{0,1}/i', $val, 1); //Do not sort every time
}
$this->SortParams(); //Sort once after adding is done
}
function GetParam($name)
{
- if (isset($this->Params[$name]))
- return $this->Params[$name];
- else
- return false;
+ //return isset($this->Params[strtolower($name)]) ? $this->Params[strtolower($name)] : false;
+ return isset($this->Params[$name]) ? $this->Params[$name] : false;
}
function SetParam($name, $value)
{
- $this->Params[$name] = $value;
+ $this->Params[strtolower($name)] = $value;
}
function SetBuffer($body)
@@ -85,20 +106,82 @@
return $this->Buffers[$this->RecursionIndex];
}
+ function GetCode()
+ {
+ return $this->Code[$this->RecursionIndex];
+ }
+
function AppendBuffer($append)
{
$this->Buffers[$this->RecursionIndex] .= $append;
+ $this->AppendCode( $this->ConvertToCode($append) );
}
- function AppendOutput($append)
+ function AppendOutput($append, $append_code=false)
{
- if ($this->SkipMode == parse)
+ if ($this->SkipMode == parse) {
$this->Output .= $append; //append to Ouput only if we are parsing
+ if ($append_code) $this->AppendCompiledHTML($append);
+ }
elseif ($this->SkipMode == skip_tags) {
$this->AppendBuffer($append); //append to buffer if we are skipping tags
}
}
+ function ConvertToCode($data)
+ {
+ $code = '$o .= \''. str_replace("'", "\'", $data) .'\';';
+ $code = explode("\n", $code);
+ return $code;
+ }
+
+ function AppendCode($code)
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ if (!isset($this->Code[$this->RecursionIndex])) {
+ $this->Code[$this->RecursionIndex] = Array();
+ }
+ if (is_array($code)) {
+ foreach ($code as $line) {
+ $this->Code[$this->RecursionIndex][] = rtrim($line, "\n")."\n";
+ }
+ }
+ else {
+ $this->Code[$this->RecursionIndex][] .= rtrim($code, "\n")."\n";
+ }
+ }
+ }
+
+ function AppendCompiledFunction($f_name, $f_body)
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->CompiledBuffer .= 'function '.$f_name.'($params)'."\n{\n";
+ $this->CompiledBuffer .= $f_body;
+ $this->CompiledBuffer .= "}\n\n";
+ }
+ }
+
+ function AppendCompiledCode($code)
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->CompiledBuffer .= $code;
+ }
+ }
+
+ function AppendCompiledHTML($append)
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->CompiledBuffer .= '?'.'>'."\n";
+ $this->CompiledBuffer .= $append;
+ $this->CompiledBuffer .= '<'.'?php'."\n";
+ }
+ }
+
+ function ResetCode()
+ {
+ $this->Code[$this->RecursionIndex] = Array();
+ }
+
function FindTag()
{
$tagOpen = strpos($this->Template, '<%', $this->Position); //Finding tag start
@@ -128,57 +211,77 @@
return $tag;
}
- function Parse($template)
+ function CurrentLineNumber()
{
+ return substr_count(substr($this->Template, 0, $this->Position), "\n")+1;
+ }
+
+ function SkipModeName()
+ {
+ switch ($this->SkipMode) {
+ case skip: return 'skip';
+ case skip_tags: return 'skip_tags';
+ case parse: return 'parse';
+ }
+ }
+
+ function Parse($template, $name='unknown')
+ {
$this->Template = $template;
+ $this->TemplateName = $name;
$this->Position = 0;
$this->Output = '';
+ $this->CompiledBuffer .= '<'.'?php'."\n";
//While we have more tags
while ($tag_data = $this->FindTag())
{
//Create tag object from passed tag data
+ if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_SHOW_TAGS') )
+ {
+ global $debugger;
+ $debugger->appendHTML('mode: '.$this->SkipModeName().' tag '.$debugger->highlightString($tag_data).' in '.$debugger->getFileLink($debugger->getLocalFile(DOC_ROOT.BASE_PATH.TEMPLATES_PATH.'/'.$this->TemplateName).'.tpl', $this->CurrentLineNumber(), '', true));
+ }
$tag =& new Tag($tag_data, $this);
if (!$this->CheckRecursion($tag)) //we do NOT process closing tags
{
$tag->Process();
}
}
+ $this->CompiledBuffer .= '?'.'>'."\n";
return $this->Output;
}
- function ParseBlock($params, $force_pass_params=0)
+ function ParseBlock($params, $force_pass_params=0, $as_template=false)
{
- $BlockParser =& $this->Application->Factory->makeClass('TemplateParser');
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ if (isset($this->Application->PreParsedBlocks[$params['name']]) ) {
+ $f = $this->Application->PreParsedBlocks[$params['name']];
+ //$this->SetParams($params);
+ return $f($params);
+ }
+ }
+
+ $BlockParser =& $this->Application->makeClass('TemplateParser');
if (isset($params['pass_params']) || $force_pass_params) {
$BlockParser->SetParams(array_merge($this->Params, $params));
}
else
$BlockParser->SetParams($params);
$this->Application->Parser =& $BlockParser;
- if (!isset($params['name'])) die("***Error: Block name not passed to ParseBlock
");
+ if (!isset($params['name'])) trigger_error('***Error: Block name not passed to ParseBlock', E_USER_ERROR);
$templates_cache =& $this->Application->recallObject('TemplatesCache');
+
+ $template_name = $as_template ? $params['name'] : $templates_cache->GetTemplateFileName($params['name']) . '-block:'.$params['name'];
+
$o = $BlockParser->Parse(
- $templates_cache->GetTemplateBody($params['name'])
+ $templates_cache->GetTemplateBody($params['name']),
+ $template_name
);
$this->Application->Parser =& $this;
return $o;
}
- function ParseXML($template, $params)
- {
- $templates_cache =& $this->Application->recallObject('TemplatesCache');
- $xml = $templates_cache->GetTemplateBody($template);
-
- $PreParser =& new TemplateParser();
- $PreParser->SetParams($params);
- $this->Application->Parser =& $PreParser;
- $xml = $PreParser->Parse($xml);
- $this->Application->Parser =& $this;
- $XMLParser =& new XMLParser($params);
- $this->AppendOutput($XMLParser->Parse($xml));
- }
-
function Recurve(&$tag)
{
$this->Recursion[++$this->RecursionIndex] =& $tag;
@@ -201,32 +304,4 @@
}
}
-// ################### 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 -r932 -r1339
--- trunk/core/kernel/db/dbitem.php (.../dbitem.php) (revision 932)
+++ trunk/core/kernel/db/dbitem.php (.../dbitem.php) (revision 1339)
@@ -15,6 +15,11 @@
*/
var $FieldValues;
+
+ var $FieldErrors;
+
+ var $ErrorMsgs = Array();
+
/**
* Holds item' primary key value
*
@@ -23,34 +28,34 @@
*/
var $ID;
- /**
- * Fields allowed to be set (from table + virtual)
- *
- * @var Array
- * @access private
- */
- var $Fields=Array();
+ function kDBItem()
+ {
+ parent::kDBBase();
+ $this->ErrorMsgs['required'] = 'Field is required';
+ $this->ErrorMsgs['unique'] = 'Field value must be unique';
+ $this->ErrorMsgs['value_out_of_range'] = 'Field is out of range, possible values from %s to %s';
+ $this->ErrorMsgs['length_out_of_range'] = 'Field is out of range';
+ $this->ErrorMsgs['bad_type'] = 'Incorrect data format, please use %s';
+ $this->ErrorMsgs['bad_date_format'] = 'Incorrect date format, please use (%s) ex. (%s)';
+ }
/**
- * All virtual field names
+ * Set's default values for all fields
*
- * @var Array
- * @access private
- */
- var $VirtualFields=Array();
-
- /**
- * Set's field names from table
- * from config
- *
- * @param Array $fields
* @access public
*/
- function setConfigFields($fields)
+ function SetDefaultValues()
{
- $this->Fields=$fields;
+ foreach ($this->Fields as $field => $params) {
+ if ( isset($params['default']) ) {
+ $this->SetDBField($field, $params['default']);
+ }
+ else {
+ $this->SetDBField($field, NULL);
+ }
+ }
}
-
+
/**
* Sets current item field value
* (applies formatting)
@@ -62,7 +67,15 @@
*/
function SetField($name,$value)
{
- $this->SetDBField($name,$value);
+ $options = $this->GetFieldOptions($name);
+ $parsed = $value;
+ if ($value == '') $parsed = NULL;
+ if (isset($options['formatter'])) {
+ $formatter =& $this->Application->recallObject($options['formatter']);
+// $parsed = $formatter->Parse($value, $options, $err);
+ $parsed = $formatter->Parse($value, $name, $this);
+ }
+ $this->SetDBField($name,$parsed);
}
/**
@@ -79,22 +92,8 @@
$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
@@ -106,6 +105,16 @@
return $this->FieldValues[$name];
}
+ function HasField($name)
+ {
+ return isset($this->FieldValues[$name]);
+ }
+
+ function GetFieldValues()
+ {
+ return $this->FieldValues;
+ }
+
/**
* Sets item' fields corresponding to elements in passed $hash values.
*
@@ -114,17 +123,29 @@
*
* @access public
* @param Array $hash
+ * @param Array $set_fields Optional param, field names in target object to set, other fields will be skipped
* @return void
*/
- function SetFieldsFromHash($hash)
+ function SetFieldsFromHash($hash, $set_fields=null)
{
foreach ($hash as $field_name => $field_value)
{
- if( eregi("^[0-9]+$", $field_name) || !in_array($field_name,$this->Fields) ) continue;
+ if( eregi("^[0-9]+$", $field_name) || !array_key_exists($field_name,$this->Fields) ) continue;
+ if ( is_array($set_fields) && !in_array($field_name, $set_fields) ) continue;
$this->SetField($field_name,$field_value);
}
}
+ function SetDBFieldsFromHash($hash, $set_fields=null)
+ {
+ foreach ($hash as $field_name => $field_value)
+ {
+ if( eregi("^[0-9]+$", $field_name) || !array_key_exists($field_name,$this->Fields) ) continue;
+ if ( is_array($set_fields) && !in_array($field_name, $set_fields) ) continue;
+ $this->SetDBField($field_name,$field_value);
+ }
+ }
+
/**
* Returns part of SQL WHERE clause identifing the record, ex. id = 25
*
@@ -137,7 +158,7 @@
*/
function GetKeyClause($method=null)
{
- return $this->IDField.' = '.$this->Conn->qstr($this->ID);
+ return '`'.$this->TableName.'`.'.$this->IDField.' = '.$this->Conn->qstr($this->ID);
}
/**
@@ -150,36 +171,94 @@
*/
function Load($id, $id_field_name=null)
{
+ if (is_array($id)) {
+ $keys = $id;
+ foreach ($keys as $field => $value) {
+ $sqls[] = '`'.$this->TableName.'`.'.$field.' = '.$this->Conn->qstr($value);
+ }
+ $keys_sql = '('.implode(') AND (', $sqls).')';
+ }
+
if (isset($id_field_name)) $this->SetIDField($id_field_name);
+ if (!isset($id) && !isset($keys_sql)) return false;
- if (!isset($id)) return false;
+ if( !$this->raiseEvent('OnBeforeItemLoad',$id) ) return false;
$this->ID = $id;
- $q = $this->GetSelectSQL().' WHERE '.$this->GetKeyClause('load');
+ $q = $this->GetSelectSQL().' WHERE '.(isset($keys_sql) ? $keys_sql : $this->GetKeyClause('load'));
if ($this->DisplayQueries) {
echo get_class($this)." Load SQL: $q
";
}
- $this->FieldValues = $this->Conn->GetRow($q);
-
+ $this->FieldValues = array_merge_recursive2( $this->FieldValues, $this->Conn->GetRow($q) );
+
if ($this->FieldValues === false) {
//Error handling could be here
return false;
}
- $this->setID($id);
+ if (isset($keys_sql)) {
+ $this->setID($this->FieldValues[$this->IDField]);
+ }
+ else {
+ $this->setID($id);
+ }
+
+ $this->UpdateFormattersSubFields(); // used for updating separate virtual date/time fields from DB timestamp (for example)
+
+ $this->raiseEvent('OnAfterItemLoad');
return true;
}
+
+ /**
+ * Builds select sql, SELECT ... FROM parts only
+ *
+ * @access public
+ * @return string
+ */
+ function GetSelectSQL()
+ {
+ $sql = $this->addCalculatedFields($this->SelectClause);
+ return parent::GetSelectSQL($sql);
+ }
+ function UpdateFormattersMasterFields()
+ {
+ foreach ($this->Fields as $field => $options) {
+ if (isset($options['formatter'])) {
+ $formatter =& $this->Application->recallObject($options['formatter']);
+ $formatter->UpdateMasterFields($field, $this->GetDBField($field), $options, $this);
+ }
+ }
+ }
+
+ function SkipField($field_name, $force_id=false)
+ {
+ $skip = false;
+ $skip = $skip || ( isset($this->VirtualFields[$field_name]) ); //skipping 'virtual' field
+ $skip = $skip || ( !getArrayValue($this->FieldValues, $field_name) && getArrayValue($this->Fields[$field_name], 'skip_empty') ); //skipping 'virtual' field
+ $skip = $skip || ($field_name == $this->IDField && !$force_id); //skipping Primary Key
+
+// $table_name = preg_replace("/^(.*)\./", "$1", $field_name);
+// $skip = $skip || ($table_name && ($table_name != $this->TableName)); //skipping field from other tables
+
+ $skip = $skip || ( !isset($this->Fields[$field_name]) ); //skipping field not in Fields (nor virtual, nor real)
+
+ return $skip;
+ }
+
/**
* Updates previously loaded record with current item' values
*
* @access public
* @param int Primery Key Id to update
- * @return void
+ * @return bool
*/
- function Update($id=null)
+ function Update($id=null, $system_update=false)
{
- if( isset($id) ) $this->ID=$id;
+ if( isset($id) ) $this->setID($id);
+
+ if( !$this->raiseEvent('OnBeforeItemUpdate') ) return false;
+
if( !isset($this->ID) ) return false;
// Validate before updating
@@ -191,13 +270,22 @@
$sql = sprintf('UPDATE %s SET ',$this->TableName);
foreach ($this->FieldValues as $field_name => $field_value)
{
- if ( isset($this->VirtualFields[$field_name]) ) continue; //skipping 'virtual' field
- if ($field_name == $this->IDField) continue; //skipping Primary Key
+ if ($this->SkipField($field_name)) continue;
$real_field_name = eregi_replace("^.*\.", '',$field_name); //removing table names from field names
//Adding part of SET clause for current field, escaping data with ADODB' qstr
- $sql.= sprintf('%s=%s, ',$real_field_name,$this->Conn->qstr($this->FieldValues[$field_name], 0));
+ if (is_null( $this->FieldValues[$field_name] )) {
+ if (isset($this->Fields[$field_name]['not_null']) && $this->Fields[$field_name]['not_null']) {
+ $sql .= '`'.$real_field_name.'` = '.$this->Conn->qstr($this->Fields[$field_name]['default']).', ';
+ }
+ else {
+ $sql .= '`'.$real_field_name.'` = NULL, ';
+ }
+ }
+ else {
+ $sql.= sprintf('`%s`=%s, ', $real_field_name, $this->Conn->qstr($this->FieldValues[$field_name], 0));
+ }
}
$sql = ereg_replace(", $", '', $sql); //Removing last comma and space
@@ -212,34 +300,256 @@
}
return false;
}
+
+ $affected = $this->Conn->getAffectedRows();
+ if (!$system_update && $affected == 1){
+ $this->setModifiedFlag();
+ }
+ $this->raiseEvent('OnAfterItemUpdate');
return true;
}
+ /**
+ * Validate all item fields based on
+ * constraints set in each field options
+ * in config
+ *
+ * @return bool
+ * @access private
+ */
function Validate()
{
- return true;
+ $this->UpdateFormattersMasterFields(); //order is critical - should be called BEFORE checking errors
+ $global_res = true;
+ foreach ($this->Fields as $field => $params) {
+ $res = true;
+ $res = $res && $this->ValidateRequired($field, $params);
+ $res = $res && $this->ValidateType($field, $params);
+ $res = $res && $this->ValidateRange($field, $params);
+ $res = $res && $this->ValidateUnique($field, $params);
+
+ // If Formatter has set some error messages during values parsing
+ if (isset($this->FieldErrors[$field]['pseudo']) && $this->FieldErrors[$field] != '') {
+ $global_res = false;
+ }
+
+ $global_res = $global_res && $res;
+ }
+
+ if (!$global_res && $this->Application->isDebugMode() )
+ {
+ global $debugger;
+ $error_msg = "Validation failed in prefix ".$this->Prefix.", FieldErrors follow (look at items with 'pseudo' key set)
+ You may ignore this notice if submitted data really has a validation error ";
+ trigger_error( $error_msg, E_USER_NOTICE);
+ $debugger->dumpVars($this->FieldErrors);
+ }
+
+ return $global_res;
}
/**
+ * Check if value in field matches field type specified in config
+ *
+ * @param string $field field name
+ * @param Array $params field options from config
+ * @return bool
+ */
+ function ValidateType($field, $params)
+ {
+ $res = true;
+ $val = $this->FieldValues[$field];
+ if ( $val != '' &&
+ isset($params['type']) &&
+ preg_match("#int|integer|double|float|real|numeric|string#", $params['type'])
+ ) {
+ $res = is_numeric($val);
+ if($params['type']=='string' || $res)
+ {
+ $f = 'is_'.$params['type'];
+ settype($val, $params['type']);
+ $res = $f($val) && ($val==$this->FieldValues[$field]);
+ }
+ if (!$res)
+ {
+ $this->FieldErrors[$field]['pseudo'] = 'bad_type';
+ $this->FieldErrors[$field]['params'] = $params['type'];
+ }
+ }
+ return $res;
+ }
+
+ /**
+ * Check if value is set for required field
+ *
+ * @param string $field field name
+ * @param Array $params field options from config
+ * @return bool
+ * @access private
+ */
+ function ValidateRequired($field, $params)
+ {
+ $res = true;
+ if ( getArrayValue($params,'required') )
+ {
+ $res = ( (string) $this->FieldValues[$field] != '');
+ }
+ if (!$res) $this->FieldErrors[$field]['pseudo'] = 'required';
+ return $res;
+ }
+
+ /**
+ * Validates that current record has unique field combination among other table records
+ *
+ * @param string $field field name
+ * @param Array $params field options from config
+ * @return bool
+ * @access private
+ */
+ function ValidateUnique($field, $params)
+ {
+ $res = true;
+ $unique_fields = getArrayValue($params,'unique');
+ if($unique_fields !== false)
+ {
+ $where = Array();
+ array_push($unique_fields,$field);
+ foreach($unique_fields as $unique_field)
+ {
+ $where[] = '`'.$unique_field.'` = '.$this->Conn->qstr( $this->GetDBField($unique_field) );
+ }
+
+ $sql = 'SELECT COUNT(*) FROM %s WHERE ('.implode(') AND (',$where).') AND ('.$this->IDField.' <> '.(int)$this->ID.')';
+
+ $res_temp = $this->Conn->GetOne( sprintf($sql, $this->TableName ) );
+ $res_live = $this->Conn->GetOne( sprintf($sql, kTempTablesHandler::GetLiveName($this->TableName) ) );
+ $res = ($res_temp == 0) && ($res_live == 0);
+
+ if(!$res) $this->FieldErrors[$field]['pseudo'] = 'unique';
+ }
+ return $res;
+ }
+
+ /**
+ * Check if field value is in range specified in config
+ *
+ * @param string $field field name
+ * @param Array $params field options from config
+ * @return bool
+ * @access private
+ */
+ function ValidateRange($field, $params)
+ {
+ $res = true;
+ $val = $this->FieldValues[$field];
+ if ( isset($params['type']) && preg_match("#int|integer|double|float|real#", $params['type']) && strlen($val) > 0 ) {
+ if ( isset($params['max_value_inc'])) {
+ $res = $res && $val <= $params['max_value_inc'];
+ $max_val = $params['max_value_inc'].' (inclusive)';
+ }
+ if ( isset($params['min_value_inc'])) {
+ $res = $res && $val >= $params['min_value_inc'];
+ $min_val = $params['min_value_inc'].' (inclusive)';
+ }
+ if ( isset($params['max_value_exc'])) {
+ $res = $res && $val < $params['max_value_exc'];
+ $max_val = $params['max_value_exc'].' (exclusive)';
+ }
+ if ( isset($params['min_value_exc'])) {
+ $res = $res && $val > $params['min_value_exc'];
+ $min_val = $params['min_value_exc'].' (exclusive)';
+ }
+ }
+ if (!$res) {
+ $this->FieldErrors[$field]['pseudo'] = 'value_out_of_range';
+
+ if ( !isset($min_val) ) $min_val = '-∞';
+ if ( !isset($max_val) ) $max_val = '∞';
+
+ $this->FieldErrors[$field]['params'] = Array( $min_val, $max_val );
+ return $res;
+ }
+ if ( isset($params['max_len'])) {
+ $res = $res && strlen($val) <= $params['max_len'];
+ }
+ if ( isset($params['min_len'])) {
+ $res = $res && strlen($val) >= $params['min_len'];
+ }
+ if (!$res) {
+ $this->FieldErrors[$field]['pseudo'] = 'length_out_of_range';
+ $this->FieldErrors[$field]['params'] = Array($params['min_len'], $params['max_len']);
+ return $res;
+ }
+ return $res;
+ }
+
+ /**
+ * Return error message for field
+ *
+ * @param string $field
+ * @return string
+ * @access public
+ */
+ function GetErrorMsg($field)
+ {
+ if( !isset($this->FieldErrors[$field]) ) return '';
+
+ $err = getArrayValue($this->FieldErrors[$field], 'pseudo');
+ if( isset($this->Fields[$field]['error_msgs'][$err]) )
+ {
+ $msg = $this->Fields[$field]['error_msgs'][$err];
+ }
+ else
+ {
+ if( !isset($this->ErrorMsgs[$err]) ) return $err;
+ $msg = $this->ErrorMsgs[$err];
+ }
+
+ if ( isset($this->FieldErrors[$field]['params']) )
+ {
+ return vsprintf($msg, $this->FieldErrors[$field]['params']);
+ }
+ return $msg;
+ }
+
+ /**
* Creates a record in the database table with current item' values
*
+ * @param mixed $force_id Set to TRUE to force creating of item's own ID or to value to force creating of passed id. Do not pass 1 for true, pass exactly TRUE!
* @access public
- * @return void
+ * @return bool
*/
- function Create()
+ function Create($force_id=false, $system_create=false)
{
+ if( !$this->raiseEvent('OnBeforeItemCreate') ) return false;
+
if(!$this->Validate()) //Validating fields before attempting to create record
return false;
+ if (is_int($force_id)) {
+ $this->FieldValues[$this->IDField] = $force_id;
+ }
+
$fields_sql = '';
$values_sql = '';
foreach ($this->FieldValues as $field_name => $field_value)
{
- if ( isset($this->VirtualFields[$field_name]) ) continue; //skipping 'virtual' field
+ if ($this->SkipField($field_name, $force_id)) continue;
$fields_sql .= sprintf('%s, ',$field_name); //Adding field name to fields block of Insert statement
//Adding field' value to Values block of Insert statement, escaping it with ADODB' qstr
- $values_sql .= sprintf('%s, ',$this->Conn->qstr($this->FieldValues[$field_name], 0));
+ if (is_null( $this->FieldValues[$field_name] )) {
+ if (isset($this->Fields[$field_name]['not_null']) && $this->Fields[$field_name]['not_null']) {
+ $values_sql .= $this->Conn->qstr($this->Fields[$field_name]['default']).', ';
+ }
+ else {
+ $values_sql .= 'NULL, ';
+ }
+ }
+ else {
+ $values_sql .= sprintf('%s, ',$this->Conn->qstr($this->FieldValues[$field_name], 0));
+ }
+
}
//Cutting last commas and spaces
$fields_sql = ereg_replace(", $", '', $fields_sql);
@@ -256,27 +566,100 @@
return false;
}
$this->setID( $this->Conn->getInsertID() );
- //$this->SetInsertID(); //Setting Primary Key ($this->id) for futher using the object
+
+ if (!$system_create){
+ $this->setModifiedFlag();
+ }
+
+ $this->raiseEvent('OnAfterItemCreate');
return true;
}
/**
* Deletes the record from databse
*
* @access public
- * @return void
+ * @return bool
*/
- function Delete()
+ function Delete($id=null)
{
+ if( isset($id) ) {
+ $this->setID($id);
+ }
+
+ if( !$this->raiseEvent('OnBeforeItemDelete') ) return false;
+
$q = 'DELETE FROM '.$this->TableName.' WHERE '.$this->GetKeyClause('Delete');
if ($this->DisplayQueries)
{
echo get_class($this).' Delete SQL: '.$q.'
';
}
- return $this->Conn->ChangeQuery($q);
+ $ret = $this->Conn->ChangeQuery($q);
+
+ $this->setModifiedFlag();
+
+ $this->raiseEvent('OnAfterItemDelete');
+
+ return $ret;
}
/**
+ * Sets new name for item in case if it is beeing copied
+ * in same table
+ *
+ * @param array $master Table data from TempHandler
+ * @param int $foreign_key ForeignKey value to filter name check query by
+ * @access private
+ */
+ function NameCopy($master=null, $foreign_key=null)
+ {
+ $title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
+ if (!$title_field) return;
+
+ $new_name = $this->GetDBField($title_field);
+ $original_checked = false;
+ do {
+ if ( preg_match("/Copy ([0-9]*)[ ]*of(.*)/", $new_name, $regs) ) {
+ $new_name = 'Copy '.($regs[1]+1).' of '.$regs[2];
+ }
+ elseif ($original_checked) {
+ $new_name = 'Copy of '.$new_name;
+ }
+
+ // if we are cloning in temp table this will look for names in temp table,
+ // since object' TableName contains correct TableName (for temp also!)
+ // if we are cloning live - look in live
+ $query = 'SELECT '.$title_field.' FROM '.$this->TableName.'
+ WHERE '.$title_field.' = '.$this->Conn->qstr($new_name);
+
+ if (getArrayValue($master, 'ForeignKey') && isset($foreign_key)) {
+ $query .= ' AND '.$master['ForeignKey'].' = '.$foreign_key;
+ }
+
+ $res = $this->Conn->GetOne($query);
+
+ /*// if not found in live table, check in temp table if applicable
+ if ($res === false && $object->Special == 'temp') {
+ $query = 'SELECT '.$name_field.' FROM '.$this->GetTempName($master['TableName']).'
+ WHERE '.$name_field.' = '.$this->Conn->qstr($new_name);
+ $res = $this->Conn->GetOne($query);
+ }*/
+
+ $original_checked = true;
+ } while ($res !== false);
+ $this->SetDBField($title_field, $new_name);
+ }
+
+ function raiseEvent($name, $id=null)
+ {
+ if( !isset($id) ) $id = $this->GetID();
+ $event = new kEvent( Array('name'=>$name,'prefix'=>$this->Prefix,'special'=>$this->Special) );
+ $event->setEventParam('id', $id);
+ $this->Application->HandleEvent($event);
+ return $event->status == erSUCCESS ? true : false;
+ }
+
+ /**
* Set's new ID for item
*
* @param int $new_id
@@ -287,6 +670,26 @@
$this->ID=$new_id;
$this->SetDBField($this->IDField,$new_id);
}
+
+ /**
+ * Generate and set new temporary id
+ *
+ * @access private
+ */
+ function setTempID()
+ {
+ $new_id = (int)$this->Conn->GetOne('SELECT MIN('.$this->IDField.') FROM '.$this->TableName);
+ if($new_id > 0) $new_id = 0;
+ --$new_id;
+
+ $this->Conn->Query('UPDATE '.$this->TableName.' SET `'.$this->IDField.'` = '.$new_id.' WHERE `'.$this->IDField.'` = '.$this->GetID());
+ $this->SetID($new_id);
+ }
+
+ function setModifiedFlag(){
+
+ $this->Application->StoreVar($this->Application->GetTopmostPrefix($this->Prefix).'_modified', "1");
+ }
}
Index: trunk/core/kernel/event_handler.php
===================================================================
diff -u -r958 -r1339
--- trunk/core/kernel/event_handler.php (.../event_handler.php) (revision 958)
+++ trunk/core/kernel/event_handler.php (.../event_handler.php) (revision 1339)
@@ -27,21 +27,54 @@
class kEventHandler extends kBase {
/**
+ * In case if event should be handled with mehod,
+ * which name differs from event name, then it
+ * should be specified here.
+ * key - event name, value - event method
+ *
+ * @var Array
+ * @access protected
+ */
+ var $eventMethods=Array();
+
+ /**
+ * Define alternative event processing method names
+ *
+ * @see $eventMethods
+ * @access protected
+ */
+ function mapEvents()
+ {
+
+ }
+
+ /**
+ * Set's prefix and special
+ *
+ * @param string $prefix
+ * @param string $special
+ * @access public
+ */
+ function Init($prefix,$special)
+ {
+ parent::Init($prefix,$special);
+ $this->mapEvents();
+ }
+
+ /**
* Process Event
*
* @param kEvent $event
* @access public
*/
function processEvent(&$event)
{
- if( method_exists($this,$event->Name) )
+ $event_name=$event->Name;
+ if( isset($this->eventMethods[$event_name]) ) $event_name=$this->eventMethods[$event_name];
+
+ if( method_exists($this,$event_name) )
{
- $event_name = $event->Name;
- $this->$event_name(&$event);
- if($event->status==erSUCCESS && $event->redirect && strlen($event->redirect) > 0 )
- {
- $this->Application->Redirect($event->redirect);
- }
+ $this->$event_name($event);
}
else
{
@@ -82,13 +115,14 @@
* @param kEvent $event
* @access protected
*/
- function &inheritEvent(&$event)
+ function &inheritEvent(&$event, $name=null)
{
$child_event = new kEvent();
$child_event->MasterEvent =& $event;
$child_event->Prefix=$event->Prefix;
$child_event->Special=$event->Special;
$child_event->Prefix_Special=$event->Prefix_Special;
+ $child_event->Name = $name;
return $child_event;
}
}
Index: trunk/core/kernel/utility/factory.php
===================================================================
diff -u -r932 -r1339
--- trunk/core/kernel/utility/factory.php (.../factory.php) (revision 932)
+++ trunk/core/kernel/utility/factory.php (.../factory.php) (revision 1339)
@@ -1,8 +1,5 @@
$regs[1].$regs[3].$regs[4], 'special'=>$regs[2]);
+
$tmp=explode('_',$prefix_special,2);
$tmp[0]=explode('.',$tmp[0]);
$prefix=$tmp[0][0];
+ $prefix_special=$prefix; // new1
if( isset($tmp[1]) )
{
$prefix.='_'.$tmp[1];
}
- $special=isset($tmp[0][1])?$tmp[0][1]:'';
-
- return Array('prefix'=>$prefix,'special'=>$special);
+ $special= isset($tmp[0][1]) ? $tmp[0][1] : '';
+ $prefix_special.='.'.$special; // new2
+ return Array('prefix'=>$prefix,'special'=>$special,'prefix_special'=>$prefix_special);
}
@@ -74,7 +76,7 @@
// $name = 'l.pick', $pseudo_class = 'l'
//echo 'N: '.$name.' - P: '.$pseudo_class."\n";
$ret=$this->processPrefix($name);
- if(!$pseudo_class)$pseudo_class=$ret['prefix'];
+ if (!$pseudo_class) $pseudo_class = $ret['prefix'];
$name=rtrim($name,'.');
if( isset($this->Storage[$name]) ) return $this->Storage[$name];
@@ -83,9 +85,12 @@
$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']);
+ $funs_args = func_get_args();
+ array_splice($funs_args, 0, 3, Array($pseudo_class) );
+ $this->Storage[$name] =& call_user_func_array( Array(&$this,'makeClass'), $funs_args);
+ $this->Storage[$name]->Init($ret['prefix'],$ret['special'],$event_params);
+
$prefix=$this->Storage[$name]->Prefix;
$special=$this->Storage[$name]->Special;
@@ -104,7 +109,18 @@
return $this->Storage[$name];
}
+
/**
+ * Removes object from storage, so next time it could be created from scratch
+ *
+ * @param string $name Object's name in the Storage
+ */
+ function DestroyObject($name)
+ {
+ unset($this->Storage[$name]);
+ }
+
+ /**
* Includes file containing class
* definition for real class name
*
@@ -113,15 +129,26 @@
*/
function includeClassFile($real_class)
{
+ if (class_exists($real_class)) return;
+
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]);
+
+ if ( $deps = getArrayValue($this->Dependencies, $real_class) ) {
+ foreach ($deps as $filename) {
+ k4_include_once($filename);
+ }
+ }
+
+ k4_include_once($this->Files[$real_class]);
}
/**
* Get's real class name for pseudo class,
* includes class file and creates class
- * instance
+ * instance.
+ * All parameters except first one are passed to object constuctor
+ * through mediator method makeClass that creates instance of class
*
* @param string $pseudo_class
* @return Object
@@ -131,11 +158,17 @@
{
$real_class=$this->realClasses[$pseudo_class];
$this->includeClassFile($real_class);
- /*if (!class_exists($real_class))
+
+ if( func_num_args() == 1 )
{
- $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();
+ return new $real_class();
+ }
+ else
+ {
+ $func_args = func_get_args();
+ $pseudo_class = array_shift($func_args);
+ return call_user_func_array( Array($real_class,'makeClass'), $func_args );
+ }
}
/**
@@ -150,6 +183,11 @@
{
if(!isset($pseudo_class)) $pseudo_class = $real_class;
if(!isset($this->Files[$real_class])) $this->Files[$real_class]=$file;
+
+ if (getArrayValue($this->realClasses, $pseudo_class)) {
+ $this->Dependencies[$real_class][] = $this->Files[ $this->realClasses[$pseudo_class] ];
+ }
+
$this->realClasses[$pseudo_class]=$real_class;
}
Index: trunk/core/kernel/event_manager.php
===================================================================
diff -u -r939 -r1339
--- trunk/core/kernel/event_manager.php (.../event_manager.php) (revision 939)
+++ trunk/core/kernel/event_manager.php (.../event_manager.php) (revision 1339)
@@ -88,12 +88,23 @@
*/
function HandleEvent(&$event)
{
+ if (!$event->SkipBeforeHooks) {
+ $this->processHooks($event, hBEFORE);
+ if ($event->status == erFATAL) return;
+ }
+
$event_handler =& $this->Application->recallObject($event->Prefix.'_EventHandler');
- $event_handler->processEvent(&$event);
+ $event_handler->processEvent($event);
+ if ($event->status == erFATAL) return;
+ if (!$event->SkipAfterHooks) {
+ $this->processHooks($event, hAFTER);
+ }
}
function ProcessRequest()
{
+ $this->processOpener();
+
// 1. get events from $_POST
$events=$this->Application->GetVar('events');
if($events===false) $events=Array();
@@ -111,7 +122,7 @@
}
}
- //print_pre($events);
+ $passed = explode(',', $this->Application->GetVar('passed'));
foreach($events as $prefix_special => $event_name)
{
if(!$event_name) continue;
@@ -121,27 +132,93 @@
$prefix_special=explode('.',$prefix_special);
$event->Prefix=$prefix_special[0];
+ array_push($passed, $prefix_special[0]);
$event->Special=isset($prefix_special[1])?$prefix_special[1]:'';
- $event->redirect=$this->Application->RecallVar('redirect_to');
- $this->HandleEvent(&$event);
+ $event->redirect_params = Array('opener'=>'s', 'pass'=>'all');
+ $event->redirect = true;
+ $this->HandleEvent($event);
+
+ if($event->status==erSUCCESS && ($event->redirect === true || strlen($event->redirect) > 0) )
+ {
+ $this->Application->Redirect($event->redirect, $event->redirect_params, null, $event->redirect_script);
+ }
}
+ $this->Application->SetVar('passed', implode(',', $passed));
}
- function registerHook($hookto_unit, $hookto_event_name, $mode, $do_unit, $do_event_name)
+ function processOpener()
{
-
-
-
-
+ $opener_action=$this->Application->GetVar('m_opener');
+ $opener_stack=$this->Application->RecallVar('opener_stack');
+ $opener_stack=$opener_stack?unserialize($opener_stack):Array();
+ switch($opener_action)
+ {
+ case 'r': // "reset" opener stack
+ $opener_stack=Array();
+ break;
+
+ case 'd': // "down/push" new template to opener stack, deeplevel++
+ array_push($opener_stack, $this->Application->RecallVar('last_template') );
+ break;
+
+ case 'u': // "up/pop" last template from opener stack, deeplevel--
+ array_pop($opener_stack);
+ break;
+
+ default: // "s/0," stay on same deep level
+ break;
+ }
+ $this->Application->SetVar('m_opener','s');
+ $this->Application->StoreVar('opener_stack',serialize($opener_stack));
}
+ function registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional)
+ {
+ $hookto_prefix_special = rtrim($hookto_prefix.'.'.$hookto_special, '.');
+ if ($mode == hBEFORE) {
+ $this->beforeHooks[strtolower($hookto_prefix_special.'.'.$hookto_event)][] = Array(
+ 'DoPrefix' => $do_prefix,
+ 'DoSpecial' => $do_special,
+ 'DoEvent' => $do_event,
+ 'Conditional' => $conditional,
+ );
+ }
+ elseif ($mode == hAFTER) {
+ $this->afterHooks[strtolower($hookto_prefix_special.'.'.$hookto_event)][] = Array(
+ 'DoPrefix' => $do_prefix,
+ 'DoSpecial' => $do_special,
+ 'DoEvent' => $do_event,
+ 'Conditional' => $conditional,
+ );
+ }
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ * @param int $mode hBEFORE or hAFTER
+ */
function processHooks(&$event, $mode)
{
-
-
-
-
+ if ($mode == hBEFORE) {
+ $mode_hooks =& $this->beforeHooks;
+ }
+ else {
+ $mode_hooks =& $this->afterHooks;
+ }
+ if ( $hooks = getArrayValue($mode_hooks, strtolower($event->Prefix_Special.'.'.$event->Name)) ) {
+ foreach($hooks as $hook)
+ {
+ $prefix_special = rtrim($hook['DoPrefix'].'_'.$hook['DoSpecial'],'_');
+ if( $hook['Conditional'] && !$this->Application->GetVar($prefix_special) ) continue;
+ $hook_event = new kEvent( Array('name'=>$hook['DoEvent'],'prefix'=>$hook['DoPrefix'],'special'=>$hook['DoSpecial']) );
+ $hook_event->MasterEvent =& $event;
+
+ $this->HandleEvent($hook_event);
+ }
+ }
}
/**
Index: trunk/core/kernel/parser/tags.php
===================================================================
diff -u -r932 -r1339
--- trunk/core/kernel/parser/tags.php (.../tags.php) (revision 932)
+++ trunk/core/kernel/parser/tags.php (.../tags.php) (revision 1339)
@@ -1,8 +1,8 @@
Parser->Pattern, $tag_data);
+ $values = $this->Parser->Values;
+ foreach($values as $param_name => $param_value)
+ {
+ $values[$param_name] = $this->EscapeReservedChars($param_value);
+ }
+
if (is_array($this->Parser->Params)) {
- $tag_data = preg_replace($this->Parser->Pattern, $this->Parser->Values, $tag_data);
+ $tag_data = preg_replace($this->Parser->Pattern, $values, $tag_data);
}
//echo "got: $tag_data
";
return $tag_data;
}
+ function PreParseReplaceParams($tag_data)
+ {
+ //print_pre($this->Parser->Pattern, $tag_data);
+ $values = $this->Parser->Values;
+ foreach($values as $param_name => $param_value)
+ {
+ $values[$param_name] = $this->EscapeReservedChars($param_value);
+ }
+
+ /*$patterns = Array();
+ if ( is_array($this->Parser->Args) ) {
+ foreach ($this->Parser->Args as $arg) {
+
+ }
+ }*/
+
+ if ($this->Parser->SkipMode == parse) {
+ if (is_array($this->Parser->Params)) {
+ $tag_data = preg_replace($this->Parser->Pattern, $values, $tag_data);
+ }
+ }
+ //echo "got: $tag_data
";
+ return $tag_data;
+ }
+
function CmpParams($a, $b)
{
$a_len = strlen($a);
@@ -68,32 +119,20 @@
return $a_len > $b_len ? -1 : 1;
}
- function ReplaceLanguageTags($tag_data)
- {
- preg_match_all("(!(la|lu)[^!]+!)", $tag_data, $res, PREG_PATTERN_ORDER);
- $language_tags = $res[0];
- uasort($language_tags, array ("Tag", "CmpParams"));
-
- $values = Array();
- $i = 0;
- foreach ($language_tags as $label) {
- array_push($values, $this->Application->Phrase($label));
- $language_tags[$i] = '/' . $language_tags[$i] . '/';
- $i++;
- }
- $tag_data = preg_replace($language_tags, $values, $tag_data);
- return $tag_data;
- }
-
function ParseTagData($tag_data)
{
- $tag_data = $this->ReplaceParams($tag_data) . ' ';
- $tag_data = $this->ReplaceLanguageTags($tag_data);
+ if (defined('EXPERIMENTAL_PRE_PARSE') ) {
+ $tag_data = $this->PreParseReplaceParams($tag_data) . ' ';
+ }
+ else {
+ $tag_data = $this->ReplaceParams($tag_data) . ' ';
+ $tag_data = $this->Application->ReplaceLanguageTags($tag_data);
+ }
list ($key_data, $params) = explode(' ', $tag_data, 2);
list($this->Processor, $this->Tag) = explode(':', $key_data);
-
+
if ($params != '') $this->ParseNamedParams($params);
}
@@ -132,21 +171,14 @@
$tag->CopyFrom($this);
$tag->Process();
}
- elseif ($this->Tag == 'xml') {
- $tag =& new XMLTag('', $this->Parser);
- $tag->CopyFrom($this);
- $tag->Process();
- }
else {
if ($this->Parser->SkipMode == skip) return;
- //if (!$this->ProcessMainTag()) //other main tags
- $this->ProcessTag();
+ $this->ProcessTag();
}
}
else { //normal tags - processors other than main
if ($this->Parser->SkipMode == skip_tags || $this->Parser->SkipMode == skip) return; //do not parse if we skipping tags
$this->ProcessTag();
- //$this->Parser->AppendOutput(''.$this->Tag.'');
}
}
@@ -166,64 +198,57 @@
}
else
{
- echo "Warning: can't process tag ".$this->Tag."
";
+ trigger_error('can\'t process tag '.$this->Tag,E_USER_WARNING);
}
}
-}
+
+ function GetCode($echo=false)
+ {
+ $pass_params = $this->NP;
+
+ $code = Array();
-
-// ################### TESTS ############################
-
-global $suite;
-if (isset($suite)) {
- class TestTags extends TestCase {
+ $to_pass = 'Array(';
+ foreach ($pass_params as $name => $val) {
+ $to_pass .= '"'.$name.'" => "'.$val.'",';
+ }
+ $to_pass .= ')';
- function testTagParsing()
- {
- global $application;
-
- $tag_data = "m:test param1=\"123\"";
- $tag =& new Tag($tag_data, $application->Parser);
- $this->assertEquals('m', $tag->Processor);
- $this->assertEquals('test', $tag->Tag);
- $this->assertEquals('123', $tag->GetParam('param1'));
-
- $this->assertFalse($tag->GetParam('no_such_param'));
- }
+ if ($echo) $code[] = '$o = '."'';\n";
- function testTagParamEscaping()
- {
- global $application;
+ switch ( $this->Tag ) {
+ case 'param':
+ $code[] = '$o .= $params["'.$this->NP['name'].'"];';
+ return $code;
+ case 'if':
+ $code[] = ' $__tag_processor = "'.$pass_params['prefix'].'".\'_TagProcessor\';'."\n";
+ $code[] = ' $processor =& $application->recallObject($__tag_processor);'."\n";
+ $code[] = ' $if_result = $processor->ProcessParsedTag(\''.$pass_params['function'].'\', '.$to_pass.');'."\n";
+ $code[] = ' if ($if_result) {';
+ return $code;
- $tag_data = "m:test escape1='-\"-' \t\t \n \t\n escape2=\"+\\\"+\" \n escape3='*\'*' escape4='=\='";
- //$tag_data = "m:test escape1='-\"-' escape2=\"+\\\"+\" escape3='*\'*' escape4='=\='";
- $tag =& new Tag($tag_data, $application->Parser);
- $this->assertEquals('-"-', $tag->GetParam('escape1'));
- $this->assertEquals('+"+', $tag->GetParam('escape2'));
- $this->assertEquals("*'*", $tag->GetParam('escape3'));
- $this->assertEquals('=\=', $tag->GetParam('escape4'));
+ case 'endif':
+ $code[] = ' }';
+ return $code;
+
+ case 'else':
+ $code[] = ' }';
+ $code[] = ' else {';
+ return $code;
}
- function testTagParamSubstitution()
- {
- global $application;
-
- $application->Parser->SetParams( Array(
- 'prefix' => 'a_prefix',
- 'tag' => 'a_tag',
- 'param_name' => 'a_param_name',
- 'param_value' => 'a_param_value'
- )
- );
-
- $tag_data = '$prefix:$tag $param_name="$param_value"';
- $tag =& new Tag($tag_data, $application->Parser);
- $this->assertEquals('a_prefix', $tag->Processor);
- $this->assertEquals('a_tag', $tag->Tag);
- $this->assertEquals('a_param_value', $tag->GetParam('a_param_name'));
- }
+ $code[] = ' $__tag_processor = "'.$this->Processor.'".\'_TagProcessor\';'."\n";
+ $code[] = ' $processor =& $application->recallObject($__tag_processor);'."\n";
+ $code[] = ' $o .= $processor->ProcessParsedTag(\''.$this->Tag.'\', '.$to_pass.');'."\n";
+
+ /*$code = ' $processor =& $application->recallObject(\''.$this->Processor.'_TagProcessor\');
+ $o .= $processor->ProcessParsedTag(\''.$this->Tag.'\', unserialize(\''.serialize($this->NP).'\'));';*/
+
+ if ($echo) $code[] = ' echo $o;'."\n";
+
+ return $code;
+ //return '$o .= \'tag:'. $this->Tag .'\'';
}
- $suite->addTest(new TestSuite("TestTags"));
}
?>
\ No newline at end of file
Index: trunk/core/kernel/languages/phrases_cache.php
===================================================================
diff -u -r932 -r1339
--- trunk/core/kernel/languages/phrases_cache.php (.../phrases_cache.php) (revision 932)
+++ trunk/core/kernel/languages/phrases_cache.php (.../phrases_cache.php) (revision 1339)
@@ -3,10 +3,13 @@
class PhrasesCache extends kDBBase {
var $Phrases = Array();
- var $Ids;
+ var $Ids = Array();
+ var $OriginalIds = Array(); //for comparing cache
var $LanguageId = 1;
+ var $fromTag = false;
+
function PhrasesCache($LanguageId=1)
{
parent::kDBBase();
@@ -18,7 +21,7 @@
function GetCachedIds()
{
$query = sprintf("SELECT PhraseList FROM %s WHERE Template = %s",
- 'PhraseCache',
+ TABLE_PREFIX.'PhraseCache',
$this->Conn->Qstr($this->Application->GetVar('t')));
$phrases_ids = $this->Conn->GetOne($query);
if ($phrases_ids === false) return Array();
@@ -27,9 +30,9 @@
function LoadPhrases($ids)
{
- if (!is_array($ids) || count($ids) == 0) return;
+ if ( !is_array($ids) || !implode('', $ids) ) return;
$query = sprintf("SELECT Translation,Phrase FROM %s WHERE LanguageId = %s AND PhraseId IN (%s)",
- 'Phrase',
+ TABLE_PREFIX.'Phrase',
$this->LanguageId,
join(',', $ids));
$phrases = $this->Conn->GetCol($query,'Phrase');
@@ -38,6 +41,7 @@
$this->AddCachedPhrase(strtoupper($phrase), $tanslation);
}
$this->Ids = $ids;
+ $this->OriginalIds = $ids;
}
function AddCachedPhrase($label, $value)
@@ -48,10 +52,11 @@
function UpdateCache()
{
- if (!is_array($this->Ids) || count($Ids) == 0) return;
+ if (!is_array($this->Ids) || count($this->Ids) == 0) return;
+ if ($this->Ids == $this->OriginalIds) return; //nothing changed
$query = sprintf("REPLACE %s (PhraseList, CacheDate, Template)
VALUES (%s, %s, %s)",
- 'PhraseCache',
+ TABLE_PREFIX.'PhraseCache',
$this->Conn->Qstr(join(',', $this->Ids)),
mktime(),
$this->Conn->Qstr($this->Application->GetVar('t')));
@@ -60,31 +65,99 @@
function GetPhrase($label)
{
+ if (ereg("^!.+!$", $label) > 0) {
+ $label = substr($label, 1, -1); //cut exclamation marks
+ }
+
+ $original_label = $label;
$label = strtoupper($label);
- if (array_key_exists($label, $this->Phrases))
- return $this->Phrases[$label];
+ if( isset($this->Phrases[$label]) ) return $this->Phrases[$label];
- $this->LoadPhraseByLabel($label);
+ $this->LoadPhraseByLabel($label, $original_label);
return $this->GetPhrase($label);
}
- function LoadPhraseByLabel($label)
+ function LoadPhraseByLabel($label, $original_label)
{
$query = sprintf("SELECT PhraseId, Translation FROM %s WHERE LanguageId = %s AND UPPER(Phrase) = UPPER(%s)",
- Phrase,
+ TABLE_PREFIX.'Phrase',
$this->LanguageId,
$this->Conn->qstr($label));
$res = $this->Conn->GetRow($query);
- if ($res === false || count($res) == 0) {
- $this->AddCachedPhrase($label, '!'.$label.'!'); //add it as already cached, as long as we dont need to cache not found phrase
+ if ($res === false || count($res) == 0)
+ {
+ $translation = '!'.$label.'!';
+ if( defined('DEBUG_MODE') && defined('ADMIN') && ADMIN && dbg_ConstOn('DBG_PHRASES'))
+ {
+ $edit_url = $this->Application->HREF('in-commerce/regional/phrases_edit','',Array('m_opener'=>'d','phrases_label'=>$original_label,'phrases_event'=>'OnNew', 'pass'=>'all,phrases','index_file'=>'index4.php') );
+ $translation = '!'.$label.'!';
+ if($this->fromTag) $translation = $this->escapeTagReserved($translation);
+ }
+ $this->AddCachedPhrase($label, $translation); //add it as already cached, as long as we dont need to cache not found phrase
return false;
}
$this->Phrases[$label] = $res['Translation'];
array_push($this->Ids, $res['PhraseId']);
- $this->Ids = array_unique ( $this->Ids ); //just to make sure
+ $this->Ids = array_unique($this->Ids); //just to make sure
return true;
}
+
+ /**
+ * Sort params by name and then by length
+ *
+ * @param string $a
+ * @param string $b
+ * @return int
+ * @access private
+ */
+ function CmpParams($a, $b)
+ {
+ $a_len = strlen($a);
+ $b_len = strlen($b);
+ if ($a_len == $b_len) return 0;
+ return $a_len > $b_len ? -1 : 1;
+ }
+
+ /**
+ * Replace language tags in exclamation marks found in text
+ *
+ * @param string $text
+ * @return string
+ * @access public
+ */
+ function ReplaceLanguageTags($text)
+ {
+ $this->fromTag = true;
+ preg_match_all("(!(la|lu)[^!]+!)", $text, $res, PREG_PATTERN_ORDER);
+ $language_tags = $res[0];
+ uasort($language_tags, Array(&$this, 'CmpParams') );
+
+ $values = Array();
+ $i = 0;
+ foreach ($language_tags as $label) {
+ array_push($values, $this->GetPhrase($label) );
+ //array_push($values, $this->Application->Phrase($label) );
+ $language_tags[$i] = '/' . $language_tags[$i] . '/';
+ $i++;
+ }
+ $this->fromTag = false;
+ return preg_replace($language_tags, $values, $text);
+ }
+
+ /**
+ * Escape chars in phrase translation, that could harm parser to process tag
+ *
+ * @param string $text
+ * @return string
+ * @access private
+ */
+ function escapeTagReserved($text)
+ {
+ $reserved = Array('"',"'"); // =
+ $replacement = Array('\"',"\'"); // \=
+ return str_replace($reserved,$replacement,$text);
+ }
}
Index: trunk/core/kernel/parser/template.php
===================================================================
diff -u -r932 -r1339
--- trunk/core/kernel/parser/template.php (.../template.php) (revision 932)
+++ trunk/core/kernel/parser/template.php (.../template.php) (revision 1339)
@@ -5,12 +5,12 @@
var $BasePath = '';
var $Filename = '';
- function Template($base_path=null, $filename=null)
+ function Template($base_path=null, $filename=null, $silent=0)
{
if ($this->SetBasePath($base_path)) {
if (isset($filename)) {
$this->Filename = $filename;
- $this->LoadTemplate();
+ $this->LoadTemplate($silent);
}
}
}
@@ -34,14 +34,18 @@
{
$filename = $this->GetFullPath();
if(file_exists($filename)) {
+ if (filesize ($filename) == 0) {
+ trigger_error("Template file size is 0: $filename", ($silent ? E_USER_NOTICE : E_USER_ERROR) );
+ }
+
$handle = fopen ($filename, "r");
$contents = fread ($handle, filesize ($filename));
$this->SetBody($contents);
fclose ($handle);
return true;
}
else {
- if (!$silent) echo "File or block not found: $filename ($filename)
";
+ trigger_error("File or block not found: $filename", ($silent ? E_USER_NOTICE : E_USER_ERROR) );
return false;
}
}
@@ -60,39 +64,92 @@
class TemplatesCache extends kBase {
var $Templates = Array();
var $BasePath;
+ var $FileNames = Array();
+ var $ModulesCache = Array();
+
function TemplatesCache()
{
parent::kBase();
$this->BasePath = DOC_ROOT.BASE_PATH.THEMES_PATH;
+
+ $conn =& $this->Application->GetADODBConnection();
+ $this->ModulesCache = $conn->GetCol('SELECT LOWER(Name) FROM '.TABLE_PREFIX.'Modules');
}
- function LoadTemplate($filename, $title=NULL)
+ function LoadTemplate($filename, $title=NULL, $silent=0)
{
- $template =& new Template($this->BasePath, $filename);
+ if (preg_match('#^[\/]{0,1}([^\/]*)\/(.*)#', $filename, $regs)) {
+ $module_filename = $regs[2];
+ $first_dir = $regs[1];
+ }
+ else {
+ $first_dir = '';
+ $module_filename = $filename;
+ }
+
+ if ( defined('ADMIN') && ADMIN && in_array(strtolower($first_dir), $this->ModulesCache)) {
+ $path = MODULES_PATH.'/'.strtolower($first_dir).'/admin_templates';
+ }
+ else {
+ $path = $this->BasePath;
+ $module_filename = $first_dir.'/'.$module_filename;
+ }
+
+ $template =& new Template($path, $module_filename, $silent);
if (!isset($title)) $title = $filename;
$this->SetTemplate($title, $template);
}
- function SetTemplate($title, &$template)
+ function GetRealFilename($filename) {
+ if (preg_match('#^[\/]{0,1}([^\/]*)\/(.*)#', $filename, $regs)) {
+ $module_filename = $regs[2];
+ $first_dir = $regs[1];
+ }
+ else {
+ $first_dir = '';
+ $module_filename = $filename;
+ }
+
+ if ( defined('ADMIN') && ADMIN && in_array(strtolower($first_dir), $this->ModulesCache)) {
+ $path = MODULES_PATH.'/'.strtolower($first_dir).'/admin_templates';
+ }
+ else {
+ $path = $this->BasePath;
+ $module_filename = $first_dir.'/'.$module_filename;
+ }
+ return $path.'/'.$module_filename;
+ }
+
+ function SetTemplate($title, &$template, $filename=null)
{
+ if (!isset($filename)) $filename=$title;
$this->Templates[$title] = $template;
+ $this->FileNames[$title] = $filename;
}
- function &GetTemplate($title)
+ function &GetTemplate($title, $silent=0)
{
if (!isset($this->Templates[$title])) {
- $this->LoadTemplate($title);
+ $this->LoadTemplate($title, null, $silent);
}
return $this->Templates[$title];
}
- function GetTemplateBody($title)
+ function GetTemplateBody($title, $silent=0)
{
- $template =& $this->GetTemplate($title);
+ $template =& $this->GetTemplate($title, $silent);
+ if ( !is_object($template) ) {
+ return '';
+ }
return $template->GetBody();
}
+ function GetTemplateFileName($title)
+ {
+ return $this->FileNames[$title];
+ }
+
function SetTemplateBody($title, $body)
{
$template =& new Template();
Index: trunk/core/kernel/db/dblist.php
===================================================================
diff -u -r932 -r1339
--- trunk/core/kernel/db/dblist.php (.../dblist.php) (revision 932)
+++ trunk/core/kernel/db/dblist.php (.../dblist.php) (revision 1339)
@@ -1,5 +1,29 @@
null, FLT_NORMAL => null, FLT_SEARCH => null, FLT_VIEW => null);
+
+ /**
+ * Holds list HAVING filter object
+ *
+ * @var kMultipleFilter
+ * @access private
+ */
+ var $HavingFilter = Array(FLT_SYSTEM => null, FLT_NORMAL => null, FLT_SEARCH => null, FLT_VIEW => null);
+
+ /**
* Creates kDBList
*
* @return kDBList
*/
function kDBList() {
parent::kDBBase();
$this->OrderFields = Array();
+
+ $this->WhereFilter[FLT_SYSTEM] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
+ $this->WhereFilter[FLT_NORMAL] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
+
+ $this->WhereFilter[FLT_SEARCH] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
+ $this->WhereFilter[FLT_SEARCH]->setType(FLT_TYPE_OR);
+
+ $this->WhereFilter[FLT_VIEW] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
+
+ $this->HavingFilter[FLT_SYSTEM] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
+ $this->HavingFilter[FLT_NORMAL] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
+
+ $this->HavingFilter[FLT_SEARCH] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_OR);
+ $this->HavingFilter[FLT_SEARCH]->setType(FLT_TYPE_OR);
+
+ $this->HavingFilter[FLT_VIEW] =& $this->Application->makeClass('kMultipleFilter', FLT_TYPE_AND);
+
$this->PerPage = -1;
}
/**
- * Sets counted part of SELECT query used in grouped queries
- *
- * When using queries containing GROUP BY clause, the SELECT part may contain aggregate functions such as SUM(), COUNT() etc.
- * the part of the query with this functions should be set as 'counted SQL' for {@link dDBList::CountRecs()} to build the correct
- * count query.
- * Example:
- *
- * ...
- * $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)
+ * Adds new or replaces old filter with same name
+ *
+ * @param string $name filter name (for internal use)
+ * @param string $clause where/having clause part (no OR/AND allowed)
+ * @param int $filter_type is filter having filter or where filter
+ * @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW
+ * @access public
+ */
+ function addFilter($name, $clause, $filter_type = WHERE_FILTER, $filter_scope = FLT_SYSTEM)
{
- $this->CountedSQL = $sql;
+ $filter_name = ($filter_type == WHERE_FILTER) ? 'WhereFilter' : 'HavingFilter';
+
+ $filter =& $this->$filter_name;
+ $filter =& $filter[$filter_scope];
+ $filter->addFilter($name,$clause);
}
/**
+ * Removes specified filter from filters list
+ *
+ * @param string $name filter name (for internal use)
+ * @param int $filter_type is filter having filter or where filter
+ * @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW
+ * @access public
+ */
+ function removeFilter($name, $filter_type = WHERE_FILTER, $filter_scope = FLT_SYSTEM)
+ {
+ $filter_name = ($filter_type == WHERE_FILTER) ? 'WhereFilter' : 'HavingFilter';
+
+ $filter =& $this->$filter_name;
+ $filter =& $filter[$filter_scope];
+ $filter->removeFilter($name);
+ }
+
+ /**
+ * Clear list filters
+ *
+ * @param bool $user clear user filters
+ * @param bool $system clear system filters
+ */
+ function clearFilters($user=true,$system=true,$search=true,$view=true)
+ {
+ if($system)
+ {
+ $this->WhereFilter[FLT_SYSTEM]->clearFilters();
+ $this->HavingFilter[FLT_SYSTEM]->clearFilters();
+ }
+ if($user)
+ {
+ $this->WhereFilter[FLT_NORMAL]->clearFilters();
+ $this->HavingFilter[FLT_NORMAL]->clearFilters();
+ }
+ if($search)
+ {
+ $this->WhereFilter[FLT_SEARCH]->clearFilters();
+ $this->HavingFilter[FLT_SEARCH]->clearFilters();
+ }
+ if($view)
+ {
+ $this->WhereFilter[FLT_VIEW]->clearFilters();
+ $this->HavingFilter[FLT_VIEW]->clearFilters();
+ }
+ }
+
+ /**
* Counts the total number of records base on the query resulted from {@link kDBList::GetSelectSQL()}
*
* The method modifies the query to substitude SELECT part (fields listing) with COUNT(*).
@@ -134,24 +245,25 @@
*/
function CountRecs()
{
- $q = $this->GetSelectSQL();
- $counted_sql = '';
- if ($this->hasCounted) {
- $counted_sql = $this->GetCountedSQL();
- $counted_sql = ", $counted_sql";
+ $sql = $this->GetSelectSQL(true,false);
+ $sql = $this->getCountSQL($sql);
+ $this->RecordsCount = (int)$this->Conn->GetOne($sql);
+
+ $sql = $this->GetSelectSQL(true,true);
+ $sql = $this->getCountSQL($sql);
+ $this->NoFilterCount = (int)$this->Conn->GetOne($sql);
+ }
+
+ function getCountSQL($sql)
+ {
+ if ( preg_match("/DISTINCT(.*?)FROM(?!_)/is",$sql,$regs ) )
+ {
+ return preg_replace("/^.*SELECT DISTINCT(.*?)FROM(?!_)/is", "SELECT COUNT(DISTINCT ".$regs[1].") AS count FROM", $sql);
}
-
- 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
";
+ {
+ return preg_replace("/^.*SELECT(.*?)FROM(?!_)/is", "SELECT COUNT(*) AS count FROM ", $sql);
}
-
- $this->RecordsCount = (int)$this->Conn->GetOne($q);
- $this->hasCounted=true;
}
/**
@@ -174,7 +286,7 @@
$sql = $q.' '.$this->Conn->getLimitClause($this->Offset,$this->PerPage);
$this->Records = $this->Conn->Query($sql);
- $this->SelectedCount=count($this->Records);
+ $this->SelectedCount = count($this->Records);
if ($this->Records === false) {
//handle errors here
@@ -189,43 +301,107 @@
* @access public
* @return string
*/
- function GetSelectSQL()
+ function GetSelectSQL($for_counting=false,$system_filters_only=false)
{
- $q = parent::GetSelectSQL();
+ $q = parent::GetSelectSQL($this->SelectClause);
+ if(!$for_counting) $q = $this->addCalculatedFields($q);
- $where = $this->GetWhereClause();
- $having = $this->GetHavingClause();
+ $where = $this->GetWhereClause($for_counting,$system_filters_only);
+ $having = $this->GetHavingClause($for_counting,$system_filters_only);
$order = $this->GetOrderClause();
$group = $this->GetGroupClause();
if (!empty($where)) $q .= ' WHERE ' . $where;
- if (!empty($having)) $q .= ' HAVING ' . $having;
if (!empty($group)) $q .= ' GROUP BY ' . $group;
- if (!empty($order)) $q .= ' ORDER BY ' . $order;
+ if (!empty($having)) $q .= ' HAVING ' . $having;
+ if ( !$for_counting && !empty($order) ) $q .= ' ORDER BY ' . $order;
- return $q;
+ return str_replace('%1$s',$this->TableName,$q);
}
+ function extractCalculatedFields($clause)
+ {
+ if ( is_array($this->CalculatedFields) ) {
+ foreach($this->CalculatedFields as $field_name => $field_expression)
+ {
+ $clause = preg_replace('/`'.$field_name.'`/', $field_expression, $clause);
+ }
+ }
+ return $clause;
+ }
+
/**
* Returns WHERE clause of the query
*
* @access public
+ * @param bool $for_counting merge where filters with having filters + replace field names for having fields with their values
* @return string
*/
- function GetWhereClause()
+ function GetWhereClause($for_counting=false,$system_filters_only=false)
{
- return '';
+ $where =& $this->Application->makeClass('kMultipleFilter');
+
+ $where->addFilter('system_where', $this->WhereFilter[FLT_SYSTEM] );
+
+ if (!$system_filters_only) {
+ $where->addFilter('view_where', $this->WhereFilter[FLT_VIEW] );
+ $search_w = $this->WhereFilter[FLT_SEARCH]->getSQL();
+ if( $search_w || $for_counting ) // move search_having to search_where in case search_where isset or we are counting
+ {
+ $search_h = $this->extractCalculatedFields( $this->HavingFilter[FLT_SEARCH]->getSQL() );
+ $search_w = ($search_w && $search_h) ? $search_w.' OR '.$search_h : $search_w.$search_h;
+ $where->addFilter('search_where', $search_w );
+ }
+ }
+
+ if( $for_counting ) // add system_having and view_having to where
+ {
+ $where->addFilter('system_having', $this->extractCalculatedFields( $this->HavingFilter[FLT_SYSTEM]->getSQL() ) );
+ if (!$system_filters_only) $where->addFilter('view_having', $this->extractCalculatedFields( $this->HavingFilter[FLT_VIEW]->getSQL() ) );
+ }
+
+ return $where->getSQL();
}
/**
+ * Depricated method
+ *
+ * @param string $clause
+ * @todo REMOVE
+ */
+ function SetWhereClause($clause)
+ {
+ if( $this->Application->isDebugMode() )
+ {
+ global $debugger;
+ $debugger->appendTrace();
+ }
+ trigger_error('Depricated method kDBList->SetWhereClause. Use kDBList->addFilter instead.', E_USER_ERROR);
+ }
+
+ /**
* Returns HAVING clause of the query
*
- * @access public
+ * @param bool $for_counting don't return having filter in case if this is counting sql
* @return string
+ * @access public
*/
- function GetHavingClause()
+ function GetHavingClause($for_counting=false, $system_filters_only=false)
{
- return '';
+ if( $for_counting ) return '';
+
+ $having =& $this->Application->makeClass('kMultipleFilter');
+
+ $having->addFilter('system_having', $this->HavingFilter[FLT_SYSTEM] );
+ if (!$system_filters_only) {
+ $having->addFilter('view_having', $this->HavingFilter[FLT_VIEW] );
+ $search_w = $this->WhereFilter[FLT_SEARCH]->getSQL();
+ if (!$search_w) {
+ $having->addFilter('search_having', $this->HavingFilter[FLT_SEARCH] );
+ }
+ }
+
+ return $having->getSQL();
}
/**
@@ -275,30 +451,55 @@
{
$ret = '';
foreach ($this->OrderFields as $field) {
- $ret .= $field[0] . ' ' . $field[1] . ',';
+
+ $name = $field[0];
+ $ret .= isset($this->Fields[$name]) && !isset($this->VirtualFields[$name]) ? '`'.$this->TableName.'`.' : '';
+ $ret .= '`'.$field[0] . '` ' . $field[1] . ',';
}
$ret = rtrim($ret, ',');
return $ret;
}
+ function GetOrderField($pos=NULL)
+ {
+ if(!(isset($this->OrderFields[$pos]) && $this->OrderFields[$pos]) )
+ {
+ $pos = 0;
+ }
+ return isset($this->OrderFields[$pos][0]) ? $this->OrderFields[$pos][0] : '';
+ }
+
+ function GetOrderDirection($pos=NULL)
+ {
+ if(!$this->OrderFields[$pos])
+ $pos = 0;
+
+ return $this->OrderFields[$pos][1];
+ }
+
/**
- * Description
+ * Return unformatted field value
*
- * @access public
* @param string
- * @return void
+ * @return mixed
+ * @access public
*/
function GetDBField($name)
{
$row =& $this->getCurrentRecord();
return $row[$name];
}
- function GetField($name)
+ function HasField($name)
{
- return $this->GetDBField($name);
+ $row =& $this->getCurrentRecord();
+ return isset($row[$name]);
}
+ function GetFieldValues()
+ {
+ return $this->getCurrentRecord();
+ }
function &getCurrentRecord()
{
@@ -314,7 +515,7 @@
*/
function GoFirst()
{
- $this->CurrentIndex=0;
+ $this->CurrentIndex = 0;
}
/**
@@ -332,6 +533,18 @@
* Description
*
* @access public
+ * @return void
+ */
+ function GoPrev()
+ {
+ if ($this->CurrentIndex>0)
+ $this->CurrentIndex--;
+ }
+
+ /**
+ * Description
+ *
+ * @access public
* @return bool
*/
function EOL()
@@ -388,6 +601,41 @@
}
//$this->GoFirst();
}
+
+ /**
+ * Sets current item field value
+ * (doesn't apply formatting)
+ *
+ * @access public
+ * @param string $name Name of the field
+ * @param mixed $value Value to set the field to
+ * @return void
+ */
+ function SetDBField($name,$value)
+ {
+ $this->Records[$this->CurrentIndex][$name] = $value;
+ }
+
+ /**
+ * Apply where clause, that links this object ti it's parent item
+ *
+ * @param string $special
+ * @access public
+ */
+ function linkToParent($special)
+ {
+ $parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix');
+ if($parent_prefix)
+ {
+ $parent_table_key = $this->Application->getUnitOption($this->Prefix, 'ParentTableKey');
+ $foreign_key_field = $this->Application->getUnitOption($this->Prefix, 'ForeignKey');
+
+ $parent_object =& $this->Application->recallObject($parent_prefix.'.'.$special);
+ $parent_id = $parent_object->GetDBField($parent_table_key);
+
+ $this->addFilter('parent_filter', $foreign_key_field.' = '.$parent_id); // only for list in this case
+ }
+ }
}
?>
\ No newline at end of file
Index: trunk/core/kernel/processors/tag_processor.php
===================================================================
diff -u -r932 -r1339
--- trunk/core/kernel/processors/tag_processor.php (.../tag_processor.php) (revision 932)
+++ trunk/core/kernel/processors/tag_processor.php (.../tag_processor.php) (revision 1339)
@@ -19,10 +19,45 @@
}
else
{
+ if ($this->Application->hasObject('TagsAggregator')) {
+ $aggregator = $this->Application->recallObject('TagsAggregator');
+ $tag_mapping = $aggregator->GetArrayValue($tag->Prefix, $Method);
+ if ($tag_mapping) {
+
+ $mapped_tag =& new MyTag('', $this->Application->Parser);
+ $mapped_tag->CopyFrom($tag);
+ $mapped_tag->Processor = $tag_mapping[0];
+ $mapped_tag->Tag = $tag_mapping[1];
+ $mapped_tag->NP['PrefixSpecial'] = $tag->getPrefixSpecial();
+ $mapped_tag->RebuildTagData();
+ return $mapped_tag->DoProcessTag();
+ }
+ }
$this->Application->trigerError('Tag Undefined:
'.$tag->RebuildTagData().'');
return false;
}
}
+
+ function ProcessParsedTag($tag, $params)
+ {
+ $Method=$tag;
+ if(method_exists($this, $Method))
+ {
+ if( $this->Application->isDebugMode() && dbg_ConstOn('DBG_SHOW_TAGS') )
+ {
+ global $debugger;
+ $debugger->appendHTML('Processing PreParsed Tag '.$Method.' in '.$this->Prefix);
+ }
+
+ //echo htmlspecialchars($tag->GetFullTag()).'
';
+ return $this->$Method($params);
+ }
+ else
+ {
+ $this->Application->trigerError('Tag Undefined:
'.$tag.'');
+ return false;
+ }
+ }
}
/*class ProcessorsPool {
Index: trunk/core/kernel/application.php
===================================================================
diff -u -r966 -r1339
--- trunk/core/kernel/application.php (.../application.php) (revision 966)
+++ trunk/core/kernel/application.php (.../application.php) (revision 1339)
@@ -1,29 +1,5 @@
DB = new DBConnection(SQL_TYPE, Array(&$this,'handleSQLError') );
+ $this->DB = new kDBConnection(SQL_TYPE, Array(&$this,'handleSQLError') );
$this->DB->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB);
$this->DB->debugMode = $this->isDebugMode();
$this->SetDefaultConstants();
- setcookie('CookiesOn', 1, time()+600);
-
$this->Factory = new kFactory();
-
+
$this->registerDefaultClasses();
// 1. to read configs before doing any recallObject
$config_reader =& $this->recallObject('kUnitConfigReader');
- $this->Phrases = new PhrasesCache( $this->RecallVar('LanguageId', DEFAULT_LANGUAGE_ID) );
+ if (!$this->GetVar('m_lang')) $this->SetVar('m_lang', $this->GetDefaultLanguageId());
+ $this->Phrases = new PhrasesCache( $this->GetVar('m_lang') );
+ $language =& $this->recallObject('lang');
+ $language->Load($this->GetVar('m_lang'));
+
$this->ValidateLogin(); // TODO: write that method
+
+ if (defined('DEBUG_MODE')) {
+ global $debugger;
+ $debugger->profileFinish('kernel4_startup');
+ }
+
}
+ function GetDefaultLanguageId()
+ {
+ return 1;
+ }
+
/**
* Registers default classes such as ItemController, GridController and LoginController
*
@@ -182,18 +171,33 @@
//$this->registerClass('Utilites',KERNEL_PATH.'/utility/utilities.php');
$this->registerClass('HTTPQuery',KERNEL_PATH.'/utility/http_query.php');
$this->registerClass('Session',KERNEL_PATH.'/session/session.php');
+ $this->registerClass('SessionStorage',KERNEL_PATH.'/session/session.php');
+ $this->registerClass('LoginEventHandler',KERNEL_PATH.'/session/login_event_handler.php','login_EventHandler');
$this->registerClass('kEventManager',KERNEL_PATH.'/event_manager.php','EventManager');
$this->registerClass('kUnitConfigReader',KERNEL_PATH.'/utility/unit_config_reader.php');
+
$this->registerClass('Params',KERNEL_PATH.'/utility/params.php','kActions');
+ $this->registerClass('kArray',KERNEL_PATH.'/utility/params.php','kArray');
+ $this->registerClass('kFormatter', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kOptionsFormatter', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kPictureFormatter', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kDateFormatter', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kLEFTFormatter', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kMultiLanguage', KERNEL_PATH.'/utility/formatters.php');
+ $this->registerClass('kTempTablesHandler', KERNEL_PATH.'/utility/temp_handler.php');
+
+ $event_manager =& $this->recallObject('EventManager');
+ $event_manager->registerBuildEvent('kTempTablesHandler','OnTempHandlerBuild');
//$this->registerClass('Configuration',KERNEL_PATH.'/utility/configuration.php');
$this->registerClass('TemplatesCache',KERNEL_PATH.'/parser/template.php');
$this->registerClass('TemplateParser',KERNEL_PATH.'/parser/template_parser.php');
$this->registerClass('MainProcessor', KERNEL_PATH.'/processors/main_processor.php','m_TagProcessor');
+ $this->registerClass('kMultipleFilter', KERNEL_PATH.'/utility/filters.php');
$this->registerClass('kDBList', KERNEL_PATH.'/db/dblist.php');
$this->registerClass('kDBItem', KERNEL_PATH.'/db/dbitem.php');
$this->registerClass('kDBEventHandler', KERNEL_PATH.'/db/db_event_handler.php');
@@ -233,12 +237,21 @@
function Run()
{
$event_manager =& $this->recallObject('EventManager');
+
+ if( $this->isDebugMode() && dbg_ConstOn('DBG_SHOW_HTTPQUERY') )
+ {
+ global $debugger;
+ $http_query =& $this->recallObject('HTTPQuery');
+ $debugger->appendHTML('HTTPQuery:');
+ $debugger->dumpVars($http_query->_Params);
+ }
+
$event_manager->ProcessRequest();
$this->Parser =& $this->recallObject('TemplateParser');
$template_cache =& $this->recallObject('TemplatesCache');
$t = $this->GetVar('t');
- $this->HTML = $this->Parser->Parse( $template_cache->GetTemplateBody($t) );
+ $this->HTML = $this->Parser->Parse( $template_cache->GetTemplateBody($t), $t );
}
/**
@@ -256,8 +269,18 @@
$session =& $this->recallObject('Session');
$session->SaveData();
+ //$this->SaveBlocksCache();
}
+ function SaveBlocksCache()
+ {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $data = serialize($this->PreParsedCache);
+
+ $this->DB->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("blocks_cache", '.$this->DB->qstr($data).', '.time().')');
+ }
+ }
+
// Facade
/**
@@ -326,8 +349,20 @@
$session =& $this->recallObject('Session');
return $session->RemoveVar($var);
}
-
+
/**
+ * Deletes HTTPQuery variable
+ *
+ * @param string $var
+ * @todo think about method name
+ */
+ function DeleteVar($var)
+ {
+ $http_query =& $this->recallObject('HTTPQuery');
+ return $http_query->Remove($var);
+ }
+
+ /**
* Returns session variable value
*
* Return value of $var variable stored in Session. An optional default value could be passed as second parameter.
@@ -338,7 +373,7 @@
* @param mixed $default Default value to return if no $var variable found in session
* @return mixed
*/
- function RecallVar($var,$default='')
+ function RecallVar($var,$default=false)
{
$session =& $this->recallObject('Session');
return $session->RecallVar($var,$default);
@@ -382,11 +417,14 @@
function LinkVar($var, $ses_var=null, $default='')
{
if (!isset($ses_var)) $ses_var = $var;
- if ($this->GetVar($var) !== false) {
+ if ($this->GetVar($var) !== false)
+ {
$this->StoreVar($ses_var, $this->GetVar($var));
}
else
+ {
$this->SetVar($var, $this->RecallVar($ses_var, $default));
+ }
}
/**
@@ -471,6 +509,15 @@
return $a_tag->DoProcessTag();
}
+ function ProcessParsedTag($prefix, $tag, $params)
+ {
+ $a_tag = new Tag('',$this->Parser);
+ $a_tag->Tag = $tag;
+ $a_tag->Processor = $prefix.'_TagProcessor';
+ $a_tag->NamedParams = $params;
+ return $a_tag->DoProcessTag();
+ }
+
/*function &GetProcessor($prefix)
{
$this->KernelDie('GetProcessor is DEPRICATED, use recallObject');
@@ -545,9 +592,9 @@
return $this->DB;
}
- function ParseBlock($params,$pass_params=0)
+ function ParseBlock($params,$pass_params=0,$as_template=false)
{
- return $this->Parser->ParseBlock($params,$pass_params);
+ return $this->Parser->ParseBlock($params, $pass_params, $as_template);
}
function &GetXMLFactory()
@@ -562,47 +609,94 @@
* @param string $t Template path
* @var string $prefix index.php prefix - could be blank, 'admin'
*/
- function HREF($t, $prefix='')
+ function HREF($t, $prefix='', $params=null, $index_file=null)
{
global $HTTP_SERVER_VARS;
if (defined('ADMIN') && $prefix == '') $prefix='/admin';
if (defined('ADMIN') && $prefix == '_FRONT_END_') $prefix = '';
- $index_file = defined('INDEX_FILE') ? INDEX_FILE : 'index.php';
- $t_path = !empty($t) ? 't='.$t : '';
+ $index_file = isset($index_file) ? $index_file : (defined('INDEX_FILE') ? INDEX_FILE : basename($_SERVER['PHP_SELF']));
+ if( isset($params['index_file']) ) $index_file = $params['index_file'];
+
+ if (getArrayValue($params, 'opener') == 'u') {
+ $opener_stack=$this->RecallVar('opener_stack');
+ if($opener_stack) {
+ $opener_stack=unserialize($opener_stack);
+ list($index_file, $env) = explode('|', $opener_stack[count($opener_stack)-1]);
+ $ret = $this->BaseURL($prefix).$index_file.'?'.ENV_VAR_NAME.'='.$env;
+ return $ret;
+ }
+ }
+
+ $pass = isset($params['pass']) ? $params['pass'] : '';
+ $pass_events = isset($params['pass_events']) ? $params['pass_events'] : false; // pass events with url
+
+ $ret = $this->BaseURL($prefix).$index_file.'?'.$this->BuildEnv($t, $params, $pass, $pass_events);
+
+ return $ret;
+ }
+
+ function BuildEnv($t, $params, $pass='all', $pass_events=false)
+ {
$session =& $this->recallObject('Session');
$sid = $session->NeedQueryString()?$this->GetSID():'';
+ if (defined('INPORTAL_ENV')) {
+ $ret = ENV_VAR_NAME.'='.$sid.'-'.$t;
+ }
+ else {
+ $ret = ENV_VAR_NAME.'='.$sid.':'.$t;
+ }
- $ret = $this->BaseURL($prefix).$index_file.'?'.ENV_VAR_NAME.'='.$sid.':'.$t;
+ $pass = str_replace('all', trim($this->GetVar('passed'), ','), $pass);
- $t_pass=$this->GetVar('t_pass');
- $t_pass_events=$this->GetVar('t_pass_events'); // pass events with url
-
- if($t_pass)
+ if(strlen($pass) > 0)
{
- $pass_info=explode(',',$t_pass); // array( prefix[.special], prefix[.special] ...
+ $pass_info = array_unique( explode(',',$pass) ); // array( prefix[.special], prefix[.special] ...
foreach($pass_info as $pass_element)
{
$ret.=':';
list($prefix)=explode('.',$pass_element);
$query_vars = $this->getUnitOption($prefix,'QueryString');
- if(!$t_pass_events) $this->SetVar($pass_element.'_event',''); // remove event from url if requested
+ //if pass events is off and event is not implicity passed
+ if(!$pass_events && !isset($params[$pass_element.'_event'])) {
+ $params[$pass_element.'_event'] = ''; // remove event from url if requested
+ //otherwise it will use value from get_var
+ }
if($query_vars)
{
$tmp_string=Array(0=>$pass_element);
foreach($query_vars as $index => $var_name)
{
- $tmp_string[$index]=$this->GetVar($pass_element.'_'.$var_name);
+ //if value passed in params use it, otherwise use current from application
+ $tmp_string[$index] = isset( $params[$pass_element.'_'.$var_name] ) ? $params[$pass_element.'_'.$var_name] : $this->GetVar($pass_element.'_'.$var_name);
+ if ( isset($params[$pass_element.'_'.$var_name]) ) {
+ unset( $params[$pass_element.'_'.$var_name] );
+ }
}
- $ret.=implode('-',$tmp_string);
+ $escaped = array();
+ foreach ($tmp_string as $tmp_val) {
+ $escaped[] = str_replace(Array('-',':'), Array('\-','\:'), $tmp_val);
+ }
+
+ if ($this->getUnitOption($prefix, 'PortalStyleEnv') == true) {
+ $ret.= array_shift($escaped).array_shift($escaped).'-'.implode('-',$escaped);
+ }
+ else {
+ $ret.=implode('-',$escaped);
+ }
}
}
}
- $this->SetVar('t_pass',''); // don't pass any prefixes_specials in url by default
- $this->SetVar('t_pass_events',0); // don't pass events in url by default
+ unset($params['pass']);
+ unset($params['opener']);
+ unset($params['m_event']);
+ foreach ($params as $param => $value) {
+ $ret .= '&'.$param.'='.$value;
+ }
+ if( getArrayValue($params,'escape') ) $ret = addslashes($ret);
return $ret;
}
@@ -611,40 +705,28 @@
return PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').BASE_PATH.$prefix.'/';
}
- /**
- * Build enviroment variable based on
- * data submitted from previous template
- *
- * @access public
- */
- function ReBuildENV()
+ function Redirect($t='', $params=null, $prefix='', $index_file=null)
{
- $event_manager =& $this->recallObject('EventManager');
- $prefix_specials = array_keys($event_manager->queryMaps);
- $this->SetVar('t_pass', implode(',',$prefix_specials) );
- }
-
- function Redirect($t='', $params='', $prefix='')
- {
- if ($t == '') $t = $this->GetVar('t');
+ if ($t == '' || $t === true) $t = $this->GetVar('t');
// pass prefixes and special from previous url
- $this->ReBuildENV();
+ if (!isset($params['pass'])) $params['pass'] = 'all';
- $location = $this->HREF($t, $prefix);
+ $location = $this->HREF($t, $prefix, $params, $index_file);
$a_location = $location;
- $location = sprintf("Location: %s".($params ? "&" : '')."%s",$location, $params);
+ $location = "Location: $location";
//echo " location : $location
";
-
- if (headers_sent() != '') {
+ if (headers_sent() != '' || ($this->isDebugMode() && dbg_ConstOn('DBG_REDIRECT')) ) {
echo "Debug output above!!! Proceed to redirect: $a_location
";
}
- else
+ else {
header("$location");
-
+ }
+
$session =& $this->recallObject('Session');
$session->SaveData();
+ $this->SaveBlocksCache();
exit;
}
@@ -656,13 +738,22 @@
function Phrase($label)
{
- if (ereg("^!.+!$", $label) > 0) {
- $label = substr($label, 1, -1); //cut exclamation marks
- }
return $this->Phrases->GetPhrase($label);
}
/**
+ * Replace language tags in exclamation marks found in text
+ *
+ * @param string $text
+ * @return string
+ * @access public
+ */
+ function ReplaceLanguageTags($text)
+ {
+ return $this->Phrases->ReplaceLanguageTags($text);
+ }
+
+ /**
* Validtates user in session if required
*
*/
@@ -700,7 +791,7 @@
function HandleEvent(&$event)
{
$event_manager =& $this->recallObject('EventManager');
- $event_manager->HandleEvent(&$event);
+ $event_manager->HandleEvent($event);
}
/**
@@ -716,6 +807,18 @@
$this->Factory->registerClass($real_class,$file,$pseudo_class);
}
+ function registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional)
+ {
+ $event_manager =& $this->recallObject('EventManager');
+ $event_manager->registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional);
+ }
+
+ function registerAggregateTag($tag_info)
+ {
+ $aggregator =& $this->recallObject('TagsAggregator', 'kArray');
+ $aggregator->SetArrayValue($tag_info['AggregateTo'], $tag_info['AggregatedTagName'], Array($tag_info['LocalPrefix'], $tag_info['LocalTagName']));
+ }
+
/**
* Returns object using params specified,
* creates it if is required
@@ -727,10 +830,48 @@
*/
function &recallObject($name,$pseudo_class=null,$event_params=Array())
{
- return $this->Factory->getObject($name,$pseudo_class,$event_params);
+ $o1 =& $this->Factory->getObject($name,$pseudo_class,$event_params);
+ //$o1->param1 = 'one';
+
+ /*$func_args = func_get_args();
+ $factory =& $this->Factory;
+ $o2 =& call_user_func_array( Array(&$factory, 'getObject'), $func_args );*/
+
+ //$o2->param1 = 'two';
+ return $o1;
}
+ function &hasObject($name)
+ {
+ return isset($this->Factory->Storage[$name]);
+ }
+
/**
+ * Removes object from storage by given name
+ *
+ * @param string $name Object's name in the Storage
+ */
+ function removeObject($name)
+ {
+ return $this->Factory->DestroyObject($name);
+ }
+
+ /**
+ * Get's real class name for pseudo class,
+ * includes class file and creates class
+ * instance
+ *
+ * @param string $pseudo_class
+ * @return Object
+ * @access private
+ */
+ function &makeClass($pseudo_class)
+ {
+ $func_args = func_get_args();
+ return call_user_func_array( Array(&$this->Factory, 'makeClass'), $func_args);
+ }
+
+ /**
* Checks if application is in debug mode
*
* @return bool
@@ -771,6 +912,19 @@
}
/**
+ * Read all unit with $prefix options
+ *
+ * @param string $prefix
+ * @return Array
+ * @access public
+ */
+ function getUnitOptions($prefix)
+ {
+ $unit_config_reader =& $this->recallObject('kUnitConfigReader');
+ return $unit_config_reader->getUnitOptions($prefix);
+ }
+
+ /**
* Splits any mixing of prefix and
* special into correct ones
*
@@ -812,7 +966,7 @@
global $debugger;
if($debugger)
{
- $errorLevel=defined('DBG_SQL_FAILURE')&&DBG_SQL_FAILURE?E_USER_ERROR:E_USER_WARNING;
+ $errorLevel=defined('DBG_SQL_FAILURE') && DBG_SQL_FAILURE ? E_USER_ERROR : E_USER_WARNING;
$debugger->dumpVars($_REQUEST);
$debugger->appendTrace();
@@ -828,6 +982,23 @@
return false;
}
}
+
+ function NextResourceId()
+ {
+ $this->DB->Query('LOCK TABLES '.TABLE_PREFIX.'IdGenerator WRITE');
+ $this->DB->Query('UPDATE '.TABLE_PREFIX.'IdGenerator SET lastid = lastid+1');
+ $id = $this->DB->GetOne("SELECT lastid FROM ".TABLE_PREFIX."IdGenerator");
+ $this->DB->Query('UNLOCK TABLES');
+ return $id;
+ }
+
+ function GetTopmostPrefix($current_prefix)
+ {
+ while ( $parent_prefix = $this->getUnitOption($current_prefix, 'ParentPrefix') ) {
+ $current_prefix = $parent_prefix;
+ }
+ return $current_prefix;
+ }
}
?>
\ No newline at end of file
Index: trunk/core/kernel/utility/temp_handler.php
===================================================================
diff -u
--- trunk/core/kernel/utility/temp_handler.php (revision 0)
+++ trunk/core/kernel/utility/temp_handler.php (revision 1339)
@@ -0,0 +1,546 @@
+Conn =& $this->Application->GetADODBConnection();
+ }
+
+ function SetTables($tables)
+ {
+ // set tablename as key for tables array
+ $ret = Array();
+ $this->Tables = $tables;
+ $this->MasterTable = $tables['TableName'];
+ }
+
+ /**
+ * Get temp table name
+ *
+ * @param string $table
+ * @return string
+ */
+ function GetTempName($table)
+ {
+ return TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_'.$table;
+ }
+
+ /**
+ * Return live table name based on temp table name
+ *
+ * @param string $temp_table
+ * @return string
+ */
+ function GetLiveName($temp_table)
+ {
+ if( preg_match('/'.TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_(.*)/',$temp_table,$rets) )
+ {
+ return $rets[1];
+ }
+ else
+ {
+ return $temp_table;
+ }
+ }
+
+ function IsTempTable($table)
+ {
+ return strpos($table, TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_edit_') !== false;
+ }
+
+ /**
+ * Return temporary table name for master table
+ *
+ * @return string
+ * @access public
+ */
+ function GetMasterTempName()
+ {
+ return $this->GetTempName($this->MasterTable);
+ }
+
+ function CreateTempTable($table)
+ {
+ $query = sprintf("CREATE TABLE %s SELECT * FROM %s WHERE 0",
+ $this->GetTempName($table),
+ $table);
+ $this->Conn->Query($query);
+ }
+
+ function BuildTables($prefix, $ids)
+ {
+ $tables = Array(
+ 'TableName' => $this->Application->getUnitOption($prefix,'TableName'),
+ 'IdField' => $this->Application->getUnitOption($prefix,'IDField'),
+ 'IDs' => $ids,
+ 'Prefix' => $prefix,
+ );
+
+ $SubItems = $this->Application->getUnitOption($prefix,'SubItems');
+ if (is_array($SubItems)) {
+ foreach ($SubItems as $prefix) {
+ $this->AddTables($prefix, $tables);
+ }
+ }
+ $this->SetTables($tables);
+ }
+
+ function AddTables($prefix, &$tables)
+ {
+ $tmp = Array(
+ 'TableName' => $this->Application->getUnitOption($prefix,'TableName'),
+ 'IdField' => $this->Application->getUnitOption($prefix,'IDField'),
+ 'ForeignKey' => $this->Application->getUnitOption($prefix,'ForeignKey'),
+ 'ParentTableKey' => $this->Application->getUnitOption($prefix,'ParentTableKey'),
+ 'Prefix' => $prefix,
+ 'AutoClone' => $this->Application->getUnitOption($prefix,'AutoClone'),
+ 'AutoDelete' => $this->Application->getUnitOption($prefix,'AutoDelete'),
+ );
+
+ $SubItems = $this->Application->getUnitOption($prefix,'SubItems');
+ if (is_array($SubItems)) {
+ foreach ($SubItems as $prefix) {
+ $this->AddTables($prefix, $tmp);
+ }
+ }
+
+ if ( !is_array(getArrayValue($tables, 'SubTables')) ) {
+ $tables['SubTables'] = array();
+ }
+
+ $tables['SubTables'][] = $tmp;
+ }
+
+ function CloneItems($prefix, $special, $ids, $master=null, $foreign_key=null, $parent_prefix=null)
+ {
+ if (!isset($master)) $master = $this->Tables;
+ $prefix_special = rtrim($prefix.'.'.$special, '.');
+
+ //recalling by different name, because we may get kDBList, if we recall just by prefix
+ $recall_prefix = $prefix_special.($special ? '' : '.').'-item';
+ $object =& $this->Application->recallObject($recall_prefix, $prefix);
+
+ foreach ($ids as $id)
+ {
+ $mode = 'create';
+ if ( $cloned_ids = getArrayValue($this->AlreadyProcessed, $master['TableName']) ) {
+ // if we have already cloned the id, replace it with cloned id and set mode to update
+ // update mode is needed to update second ForeignKey for items cloned by first ForeignKey
+ if ( getArrayValue($cloned_ids, $id) ) {
+ $id = $cloned_ids[$id];
+ $mode = 'update';
+ }
+ }
+
+ $object->Load($id);
+ $original_values = $object->FieldValues;
+
+ $object->NameCopy($master, $foreign_key);
+
+ if (isset($foreign_key)) {
+ $master_foreign_key_field = is_array($master['ForeignKey']) ? $master['ForeignKey'][$parent_prefix] : $master['ForeignKey'];
+ $object->SetDBField($master_foreign_key_field, $foreign_key);
+ }
+
+ if ($mode == 'create') {
+ $this->RaiseEvent('OnBeforeClone', $master['Prefix'], Array($object->GetId()) );
+ }
+
+ $res = $mode == 'update' ? $object->Update() : $object->Create();
+
+ if( $res )
+ {
+ if ( $mode == 'create' && is_array( getArrayValue($master, 'ForeignKey')) ) {
+ // remember original => clone mapping for dual ForeignKey updating
+ $this->AlreadyProcessed[$master['TableName']][$id] = $object->GetId();
+ }
+ if($object->mode == 't') $object->setTempID();
+ if ($mode == 'create') {
+ $this->RaiseEvent('OnAfterClone', $master['Prefix'], Array($object->GetId()) );
+ }
+
+ if ( is_array(getArrayValue($master, 'SubTables')) ) {
+ foreach($master['SubTables'] as $sub_table) {
+ if (!getArrayValue($sub_table, 'AutoClone')) continue;
+ $sub_TableName = ($object->mode == 't') ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
+
+ $foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
+ $parent_key_field = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
+
+ $query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
+ WHERE '.$foreign_key_field.' = '.$original_values[$parent_key_field];
+
+ $sub_ids = $this->Conn->GetCol($query);
+
+ if ( is_array(getArrayValue($sub_table, 'ForeignKey')) ) {
+ // $sub_ids could containt newly cloned items, we need to remove it here
+ // to escape double cloning
+
+ $cloned_ids = getArrayValue($this->AlreadyProcessed, $sub_table['TableName']);
+ if ( !$cloned_ids ) $cloned_ids = Array();
+ $new_ids = array_values($cloned_ids);
+ $sub_ids = array_diff($sub_ids, $new_ids);
+ }
+
+ $parent_key = $object->GetDBField($parent_key_field);
+
+ $this->CloneItems($sub_table['Prefix'], '', $sub_ids, $sub_table, $parent_key, $master['Prefix']);
+ }
+ }
+ }
+ }
+ }
+
+ function DeleteItems($prefix, $special, $ids, $master=null, $foreign_key=null)
+ {
+ if (!isset($master)) $master = $this->Tables;
+ $prefix_special = rtrim($prefix.'.'.$special, '.');
+
+ //recalling by different name, because we may get kDBList, if we recall just by prefix
+ $recall_prefix = $prefix_special.($special ? '' : '.').'-item';
+ $this->Application->setUnitOption($prefix,'AutoLoad',false);
+ $object =& $this->Application->recallObject($recall_prefix, $prefix);
+
+ foreach ($ids as $id)
+ {
+ $object->Load($id);
+ $original_values = $object->FieldValues;
+ $object->Delete($id);
+
+ if ( is_array(getArrayValue($master, 'SubTables')) ) {
+ foreach($master['SubTables'] as $sub_table) {
+ if (!getArrayValue($sub_table, 'AutoDelete')) continue;
+ $sub_TableName = ($object->mode == 't') ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
+
+ $foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
+ $parent_key_field = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
+
+ $query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
+ WHERE '.$foreign_key_field.' = '.$original_values[$parent_key_field];
+
+ $sub_ids = $this->Conn->GetCol($query);
+
+ $parent_key = $object->GetDBField($sub_table['ParentTableKey']);
+
+ $this->DeleteItems($sub_table['Prefix'], '', $sub_ids, $sub_table, $parent_key);
+ }
+ }
+
+ }
+ }
+
+ function DoCopyLiveToTemp($master, $ids, $parent_prefix=null)
+ {
+ // when two tables refers the same table as sub-sub-table, and ForeignKey and ParentTableKey are arrays
+ // the table will be first copied by first sub-table, then dropped and copied over by last ForeignKey in the array
+ // this should not do any problems :)
+ $this->DropTempTable($master['TableName']);
+ $this->CreateTempTable($master['TableName']);
+
+ if (is_array($ids)) {
+ $ids = join(',', $ids);
+ }
+
+ if ($ids != '') {
+ if ( getArrayValue($master, 'ForeignKey') ) {
+ if ( is_array($master['ForeignKey']) ) {
+ $key_field = $master['ForeignKey'][$parent_prefix];
+ }
+ else {
+ $key_field = $master['ForeignKey'];
+ }
+ }
+ else {
+ $key_field = $master['IdField'];
+ }
+
+ $query = 'INSERT INTO '.$this->GetTempName($master['TableName']).'
+ SELECT * FROM '.$master['TableName'].'
+ WHERE '.$key_field.' IN ('.$ids.')';
+ $this->Conn->Query($query);
+
+ $query = 'SELECT '.$master['IdField'].' FROM '.$master['TableName'].'
+ WHERE '.$key_field.' IN ('.$ids.')';
+
+ $this->RaiseEvent( 'OnAfterCopyToTemp', $master['Prefix'], $this->Conn->GetCol($query) );
+ }
+
+ if ( getArrayValue($master, 'SubTables') ) {
+ foreach ($master['SubTables'] as $sub_table) {
+
+ $parent_key = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
+
+ if ( $ids != '' && $parent_key != $key_field ) {
+ $query = 'SELECT '.$parent_key.' FROM '.$master['TableName'].'
+ WHERE '.$key_field.' IN ('.$ids.')';
+ $sub_foreign_keys = join(',', $this->Conn->GetCol($query));
+ }
+ else {
+ $sub_foreign_keys = $ids;
+ }
+ $this->DoCopyLiveToTemp($sub_table, $sub_foreign_keys, $master['Prefix']);
+ }
+ }
+ }
+
+ function GetForeignKeys($master, $sub_table, $live_id, $temp_id=null)
+ {
+ $mode = 1; //multi
+ if (!is_array($live_id)) {
+ $live_id = Array($live_id);
+ $mode = 2; //single
+ }
+ if (isset($temp_id) && !is_array($temp_id)) $temp_id = Array($temp_id);
+
+ if ( isset($sub_table['ParentTableKey']) ) {
+ if ( is_array($sub_table['ParentTableKey']) ) {
+ $parent_key_field = $sub_table['ParentTableKey'][$master['Prefix']];
+ }
+ else {
+ $parent_key_field = $sub_table['ParentTableKey'];
+ }
+ }
+ else {
+ $parent_key_field = $master['IdField'];
+ }
+
+ if ( $cached = getArrayValue($this->FKeysCache, $master['TableName'].'.'.$parent_key_field) ) {
+ if ( array_key_exists(serialize($live_id), $cached) ) {
+ list($live_foreign_key, $temp_foreign_key) = $cached[serialize($live_id)];
+ if ($mode == 1) {
+ return $live_foreign_key;
+ }
+ else {
+ return Array($live_foreign_key[0], $temp_foreign_key[0]);
+ }
+ }
+ }
+
+ if ($parent_key_field != $master['IdField']) {
+ $query = 'SELECT '.$parent_key_field.' FROM '.$master['TableName'].'
+ WHERE '.$master['IdField'].' IN ('.join(',', $live_id).')';
+ $live_foreign_key = $this->Conn->GetCol($query);
+
+ if (isset($temp_id)) {
+ $query = 'SELECT '.$parent_key_field.' FROM '.$this->GetTempName($master['TableName']).'
+ WHERE '.$master['IdField'].' IN ('.join(',', $temp_id).')';
+ $temp_foreign_key = $this->Conn->GetCol($query);
+ }
+ else {
+ $temp_foreign_key = Array();
+ }
+ }
+ else {
+ $live_foreign_key = $live_id;
+ $temp_foreign_key = $temp_id;
+ }
+
+ $this->FKeysCache[$master['TableName'].'.'.$parent_key_field][serialize($live_id)] = Array($live_foreign_key, $temp_foreign_key);
+
+ if ($mode == 1) {
+ return $live_foreign_key;
+ }
+ else {
+ return Array($live_foreign_key[0], $temp_foreign_key[0]);
+ }
+ }
+
+ function DoCopyTempToOriginal($master, $parent_prefix=null)
+ {
+ $query = 'SELECT '.$master['IdField'].' FROM '.$this->GetTempName($master['TableName']);
+ $current_ids = $this->Conn->GetCol($query);
+
+ if ($current_ids) {
+ // delete all ids from live table - for MasterTable ONLY!
+ // because items from Sub Tables get deteleted in CopySubTablesToLive !BY ForeignKey!
+ if ($master['TableName'] == $this->MasterTable) {
+ $this->RaiseEvent( 'OnBeforeDeleteFromLive', $master['Prefix'], $current_ids );
+
+ $query = 'DELETE FROM '.$master['TableName'].' WHERE '.$master['IdField'].' IN ('.join(',', $current_ids).')';
+ $this->Conn->Query($query);
+ }
+
+ if ( getArrayValue($master, 'SubTables') ) {
+ foreach ($current_ids AS $id) {
+ $this->RaiseEvent( 'OnBeforeCopyToLive', $master['Prefix'], Array($id) );
+
+ //reset negative ids to 0, so autoincrement in live table works fine
+ if ($id < 0) {
+ $query = 'UPDATE '.$this->GetTempName($master['TableName']).'
+ SET '.$master['IdField'].' = 0
+ WHERE '.$master['IdField'].' = '.$id;
+ $this->Conn->Query($query);
+ $id_to_copy = 0;
+ }
+ else {
+ $id_to_copy = $id;
+ }
+
+ //copy current id_to_copy (0 for new or real id) to live table
+ $query = 'INSERT INTO '.$master['TableName'].'
+ SELECT * FROM '.$this->GetTempName($master['TableName']).'
+ WHERE '.$master['IdField'].' = '.$id_to_copy;
+ $this->Conn->Query($query);
+ $insert_id = $id_to_copy == 0 ? $this->Conn->getInsertID() : $id_to_copy;
+
+ $this->RaiseEvent( 'OnAfterCopyToLive', $master['Prefix'], Array($insert_id) );
+
+ $this->UpdateForeignKeys($master, $insert_id, $id);
+
+ //delete already copied record from master temp table
+ $query = 'DELETE FROM '.$this->GetTempName($master['TableName']).'
+ WHERE '.$master['IdField'].' = '.$id_to_copy;
+ $this->Conn->Query($query);
+ }
+ // when all of ids in current master has been processed, copy all sub-tables data
+ $this->CopySubTablesToLive($master, $current_ids);
+ }
+ else { //If current master doesn't have sub-tables - we could use mass operations
+ // We don't need to delete items from live here, as it get deleted in the beggining of the method for MasterTable
+ // or in parent table processing for sub-tables
+
+ $this->RaiseEvent('OnBeforeCopyToLive', $master['Prefix'], $current_ids);
+
+ // reset ALL negative IDs to 0 so it get inserted into live table with autoincrement
+ $query = 'UPDATE '.$this->GetTempName($master['TableName']).'
+ SET '.$master['IdField'].' = 0
+ WHERE '.$master['IdField'].' < 0';
+ $this->Conn->Query($query);
+
+ // copy ALL records to live table
+ $query = 'INSERT INTO '.$master['TableName'].'
+ SELECT * FROM '.$this->GetTempName($master['TableName']);
+ $this->Conn->Query($query);
+
+ /*
+
+ !!! WE NEED TO FIND A WAY TO DETERMINE IF OnAfterCopyToLive is not an empty method, and do on-by-one insert
+ and pass Ids to OnAfterCopyToLive, otherwise it's not smart to do on-by-one insert for any object
+ OR WE COULD FIND A WAY TO GET ALL INSERTED IDS as an array and iterate them !!!
+
+ $this->RaiseEvent('OnAfterCopyToLive', IDS ??? );
+
+ */
+
+ // no need to clear temp table - it will be dropped by next statement
+ }
+ }
+ if ( is_array(getArrayValue($master, 'ForeignKey')) ) { //if multiple ForeignKeys
+ if ( $master['ForeignKey'][$parent_prefix] != end($master['ForeignKey']) ) {
+ return; // Do not delete temp table if not all ForeignKeys have been processed (current is not the last)
+ }
+ }
+ $this->DropTempTable($master['TableName']);
+ }
+
+ function UpdateForeignKeys($master, $live_id, $temp_id) {
+ foreach ($master['SubTables'] as $sub_table) {
+ list ($live_foreign_key, $temp_foreign_key) = $this->GetForeignKeys($master, $sub_table, $live_id, $temp_id);
+
+ $foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
+
+ //Update ForeignKey in sub TEMP table
+ if ($live_foreign_key != $temp_foreign_key) {
+ $query = 'UPDATE '.$this->GetTempName($sub_table['TableName']).'
+ SET '.$foreign_key_field.' = '.$live_foreign_key.'
+ WHERE '.$foreign_key_field.' = '.$temp_foreign_key;
+ $this->Conn->Query($query);
+ }
+ }
+ }
+
+ function CopySubTablesToLive($master, $current_ids) {
+ foreach ($master['SubTables'] as $sub_table) {
+
+ // delete records from live table by foreign key, so that records deleted from temp table
+ // get deleted from live
+ if (count($current_ids) > 0) {
+ $foreign_keys = $this->GetForeignKeys($master, $sub_table, $current_ids);
+ $foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
+ if (count($foreign_keys) > 0) {
+ $query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_table['TableName'].'
+ WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
+
+ $this->RaiseEvent( 'OnBeforeDeleteFromLive', $sub_table['Prefix'], $this->Conn->GetCol($query) );
+
+ $query = 'DELETE FROM '.$sub_table['TableName'].'
+ WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
+ $this->Conn->Query($query);
+ }
+ }
+
+ //sub_table passed here becomes master in the method, and recursively updated and copy its sub tables
+ $this->DoCopyTempToOriginal($sub_table, $master['Prefix']);
+ }
+ }
+
+ function RaiseEvent($name, $prefix, $ids)
+ {
+ if ( !is_array($ids) ) return;
+ foreach ($ids as $id) {
+ $event = new kEvent( Array('name'=>$name, 'prefix'=>$prefix, 'special'=>'') );
+ $event->setEventParam('id', $id);
+ $this->Application->HandleEvent($event);
+ }
+ }
+
+ function DropTempTable($table)
+ {
+ $query = sprintf("DROP TABLE IF EXISTS %s",
+ $this->GetTempName($table)
+ );
+ $this->Conn->Query($query);
+ }
+
+ function PrepareEdit()
+ {
+ $this->DoCopyLiveToTemp($this->Tables, $this->Tables['IDs']);
+ }
+
+ function SaveEdit($skip_master=0)
+ {
+ $this->DoCopyTempToOriginal($this->Tables);
+ }
+
+ function CancelEdit($master=null)
+ {
+ if (!isset($master)) $master = $this->Tables;
+ $this->DropTempTable($master['TableName']);
+ if ( getArrayValue($master, 'SubTables') ) {
+ foreach ($master['SubTables'] as $sub_table) {
+ $this->CancelEdit($sub_table);
+ }
+ }
+ }
+}
+
+?>
\ No newline at end of file
Index: trunk/core/kernel/globals.php
===================================================================
diff -u
--- trunk/core/kernel/globals.php (revision 0)
+++ trunk/core/kernel/globals.php (revision 1339)
@@ -0,0 +1,189 @@
+ $sValue2)
+ {
+ $paArray1[$sKey2] = array_merge_recursive2( getArrayValue($paArray1,$sKey2), $sValue2);
+ }
+ return $paArray1;
+ }
+
+ if (!function_exists('print_pre')) {
+ /**
+ * Same as print_r, budet designed for viewing in web page
+ *
+ * @param Array $data
+ * @param string $label
+ */
+ function print_pre($data, $label='')
+ {
+ if( defined('DEBUG_MODE') && DEBUG_MODE )
+ {
+ global $debugger;
+ if($label) $debugger->appendHTML(''.$label.'');
+ $debugger->dumpVars($data);
+ }
+ else
+ {
+ if($label) echo '',$label,'
';
+ echo '',print_r($data,true),'
';
+ }
+ }
+ }
+
+ if (!function_exists('getArrayValue')) {
+ /**
+ * Returns array value if key exists
+ *
+ * @param Array $array
+ * @param int $key
+ * @return string
+ * @access public
+ */
+ function getArrayValue(&$array,$key)
+ {
+ $ret = isset($array[$key]) ? $array[$key] : false;
+ if ($ret && func_num_args() > 2) {
+ for ($i = 2; $i < func_num_args(); $i++) {
+ $cur_key = func_get_arg($i);
+ $ret = getArrayValue( $ret, $cur_key );
+ if ($ret === false) break;
+ }
+ }
+ return $ret;
+ }
+ }
+
+ /**
+ * Rename key in associative array, maintaining keys order
+ *
+ * @param Array $array Associative Array
+ * @param mixed $old Old key name
+ * @param mixed $new New key name
+ * @access public
+ */
+ function array_rename_key(&$array, $old, $new)
+ {
+ foreach ($array as $key => $val)
+ {
+ $new_array[ $key == $old ? $new : $key] = $val;
+ }
+ $array = $new_array;
+ }
+
+ /**
+ * Define constant if it was not already defined before
+ *
+ * @param string $const_name
+ * @param string $const_value
+ * @access public
+ */
+ function safeDefine($const_name, $const_value)
+ {
+ if(!defined($const_name)) define($const_name,$const_value);
+ }
+
+
+if (!function_exists('parse_portal_ini')) {
+ function parse_portal_ini($file, $parse_section = false) {
+ if(!file_exists($file) && !is_readable($file))
+ die('Could Not Open Ini File');
+
+ $contents = file($file);
+
+ $retval = array();
+
+ $section = '';
+ $ln = 1;
+ $resave = false;
+ foreach($contents as $line) {
+ if ($ln == 1 && $line != '<'.'?'.'php die() ?'.">\n") {
+ $resave = true;
+ }
+ $ln++;
+ $line = trim($line);
+ $line = eregi_replace(';[.]*','',$line);
+ if(strlen($line) > 0) {
+ //echo $line . " - ";
+ if(eregi('^[[a-z]+]$',str_replace(' ', '', $line))) {
+ //echo 'section';
+ $section = substr($line,1,(strlen($line)-2));
+ if ($parse_section) {
+ $retval[$section] = array();
+ }
+ continue;
+ } elseif(eregi('=',$line)) {
+ //echo 'main element';
+ list($key,$val) = explode(' = ',$line);
+ if (!$parse_section) {
+ $retval[trim($key)] = str_replace('"', '', $val);
+ }
+ else {
+ $retval[$section][trim($key)] = str_replace('"', '', $val);
+ }
+ } //end if
+ //echo '
';
+ } //end if
+ } //end foreach
+ if ($resave) {
+ $fp = fopen($file, "w");
+ reset($contents);
+ fwrite($fp,'<'.'?'.'php die() ?'.">\n\n");
+ foreach($contents as $line) fwrite($fp,"$line");
+ fclose($fp);
+ }
+
+ return $retval;
+ }
+
+if (!function_exists( 'getmicrotime' ) ) {
+ function getmicrotime()
+ {
+ list($usec, $sec) = explode(" ",microtime());
+ return ((float)$usec + (float)$sec);
+ }
+}
+
+ function k4_include_once($file)
+ {
+ if ( defined('DEBUG_MODE') && dbg_ConstOn('DBG_PROFILE_INCLUDES')) {
+
+ if ( in_array($file, get_required_files()) ) return;
+ global $debugger;
+
+ $debugger->IncludeLevel++;
+ $before_time = getmicrotime();
+ $before_mem = memory_get_usage();
+ include_once($file);
+ $used_time = getmicrotime() - $before_time;
+ $used_mem = memory_get_usage() - $before_mem;
+
+ $debugger->IncludeLevel--;
+ $debugger->IncludesData['file'][] = str_replace(DOC_ROOT.BASE_PATH, '', $file);
+ $debugger->IncludesData['mem'][] = $used_mem;
+ $debugger->IncludesData['time'][] = $used_time;
+ $debugger->IncludesData['level'][] = $debugger->IncludeLevel;
+
+
+ }
+ else {
+ include_once($file);
+ }
+ }
+}
+
+?>
\ No newline at end of file
Index: trunk/core/kernel/parser/construct_tags.php
===================================================================
diff -u -r932 -r1339
--- trunk/core/kernel/parser/construct_tags.php (.../construct_tags.php) (revision 932)
+++ trunk/core/kernel/parser/construct_tags.php (.../construct_tags.php) (revision 1339)
@@ -1,7 +1,7 @@
CheckEndRecursion($tag)) {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ if ($tag->Tag == 'endif') {
+ $this->Parser->AppendCompiledCode('}');
+ }
+ }
$this->RestoreSkipMode(); //Restoring original SkipMode
return true;
}
+ else {
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $this->Parser->AppendCode($tag->GetCode());
+ $this->Parser->AppendCompiledCode(join("\n", $tag->GetCode()));
+ }
+ }
return false;
}
@@ -131,6 +142,9 @@
$this->Parser->Recurve($this); //Saving current tag in parser recursion array
$this->Parser->SetBuffer('');
$this->BlockName = $this->NP['name']; //Stroing BlockName
+ if (isset($this->NP['args']) ) {
+ $this->Parser->Args = explode(',', $this->NP['args']);
+ }
$this->StoreSkipMode();
$this->SuggestSkipMode(skip_tags); //We need to skip tags from now
break;
@@ -141,128 +155,72 @@
{
if (parent::CheckRecursion($tag)) { //if endtag matches (SkipMode would be restored then)
//Creating template from buffer
+
+ if (defined('EXPERIMENTAL_PRE_PARSE') && isset($this->Application->PreParsedBlocks[$this->BlockName])) return true;
+
$template = new Template();
$template->SetBody($this->Parser->GetBuffer());
$templates_cache =& $this->Application->recallObject('TemplatesCache');
//Adding template to application' cache
- $templates_cache->SetTemplate($this->BlockName,$template);
+ $templates_cache->SetTemplate($this->BlockName, $template, $this->Parser->TemplateName);
+
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ $code = $this->Parser->GetCode();
+ array_unshift($code, '$o = \'\';');
+ array_unshift($code, '$application =& kApplication::Instance();');
+ array_unshift($code, 'extract($params);');
+
+ $code[] = 'return $o;';
+
+ global $debugger;
+
+ $dbg_functions = $this->Application->isDebugMode() && dbg_ConstOn('DBG_PRINT_PREPARSED');
+
+ $f_body = '';
+ //echo "";
+ $l = 0;
+ if ($dbg_functions) echo "function ".$this->BlockName." {
";
+ foreach ($code as $line) {
+ $l++;
+ if ($dbg_functions) {
+ echo $l.' '.$debugger->highlightString(trim($line)."\n", true);
+ }
+ $f_body .= rtrim($line, "\n")."\n";
+ }
+ if ($dbg_functions) echo "} // function ".$this->BlockName." end
";
+ //echo "
";
+
+ //caching func body
+ $this->Application->PreParsedCache[$this->BlockName] = $f_body;
+
+ $func = create_function('$params', $f_body);
+ $this->Application->PreParsedBlocks[$this->BlockName] = $func;
+ $this->Parser->Args = null;
+ $this->Parser->ResetCode();
+
+ $this->Parser->AppendCompiledFunction($this->BlockName, $f_body);
+ }
return true;
}
else {
// append the tag itself to the block - while in block, we check every tag to be 'blockend'
// if it is not - we need to append the tag to the buffer, which we'll parse later in 'parse_block'
if ($tag->Tag != 'block') {
- $this->Parser->AppendOutput($tag->GetFullTag());
+ if (defined('EXPERIMENTAL_PRE_PARSE') && isset($this->Application->PreParsedBlocks[$this->BlockName])) {
+ return;
+ }
+ if (defined('EXPERIMENTAL_PRE_PARSE')) {
+ // $this->Parser->AppendCode($tag->GetCode());
+ }
+ else {
+ $this->Parser->AppendOutput($tag->GetFullTag());
+ }
}
return false;
}
}
}
-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/debugger.php
===================================================================
diff -u -r1088 -r1339
--- trunk/core/kernel/utility/debugger.php (.../debugger.php) (revision 1088)
+++ trunk/core/kernel/utility/debugger.php (.../debugger.php) (revision 1339)
@@ -1,798 +1,893 @@
'c:\Program Files\UltraEdit\uedit32.exe', 'params' => '%F/%L');
- $dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-4.0Beta\bin\ZDE.exe', 'params' => '%F');
- define('WINDOWS_EDITOR',$dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']);
- unset($dbg_editors,$dbg_editor);
- }
-
- class Debugger
- {
- /**
- * Debugger data for building report
- *
- * @var Array
- */
- var $Data = Array();
- var $ProfilerData = Array();
- var $RecursionStack = Array(); // prevent recursion when processing debug_backtrace() function results
-
- var $TraceNextError=false;
-
- var $Options = 0;
- var $OptionsMap = Array('shutdown_func' => 1, 'error_handler' => 2,
- 'output_buffer' => 4, 'highlight_output' => 8);
-
-
- var $longErrors=Array();
-
- /**
- * Amount of memory used by debugger itself
- *
- * @var Array
- * @access private
- */
- var $memoryUsage=Array();
-
- function Debugger()
+ function dbg_ConstOn($const_name)
{
- $this->memoryUsage['error_handling']=0; // memory amount used by error handler
- $this->appendRequest();
+ return defined($const_name)&&constant($const_name);
}
- function initOptions()
+ function dbg_safeDefine($const_name,$const_value)
{
-
+ if(!defined($const_name)) define($const_name,$const_value);
}
- function mapLongError($msg)
- {
- $key=$this->generateID();
- $this->longErrors[$key]=$msg;
- return $key;
- }
+ unset($_REQUEST['debug_host']); // this var messed up whole detection stuff :(
- function setOption($name,$value)
+ // Detect fact, that this session beeing debugged by Zend Studio
+ foreach($_REQUEST as $rq_name=>$rq_value)
{
- if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']
');
- if($value)
+ if( substr($rq_name,0,6)=='debug_' )
{
- $this->Options|=$this->OptionsMap[$name];
- }
- else
- {
- $this->Options=$this->Options&~$this->OptionsMap[$name];
- }
+ define('DBG_ZEND_PRESENT',1);
+ break;
+ }
}
- function getOption($name)
- {
- if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']
');
- return ($this->Options & $this->OptionsMap[$name]) == $this->OptionsMap[$name];
- }
+ dbg_safeDefine('DBG_ZEND_PRESENT',0);
- /**
- * Set's flag, that next error that occurs will
- * be prepended by backtrace results
- *
- */
- function traceNext()
+ // set default values for debugger constants
+ $dbg_constMap=Array('DBG_OPTIONS'=>0,
+ 'DBG_USE_HIGHLIGHT'=>1,
+ 'DBG_USE_SHUTDOWN_FUNC'=>DBG_ZEND_PRESENT?0:1,
+ 'DBG_HANDLE_ERRORS'=>DBG_ZEND_PRESENT?0:1,
+ 'DBG_SHOW_MEMORY_USAGE'=>1,
+ 'DBG_IGNORE_STRICT_ERRORS'=>1,
+ 'DOC_ROOT'=>$_SERVER['DOCUMENT_ROOT'],
+ 'DBG_LOCAL_BASE_PATH'=>'w:');
+
+ foreach($dbg_constMap as $dbg_constName=>$dbg_constValue)
{
- $this->TraceNextError=true;
+ dbg_safeDefine($dbg_constName,$dbg_constValue);
}
- function dumpVars()
+ // only for IE, in case if no windows php script editor defined
+ /*if(!defined('WINDOWS_EDITOR'))
{
- $dumpVars = func_get_args();
- foreach($dumpVars as $varValue)
+ $dbg_editor = 0;
+ $dbg_editors[0] = Array('editor' => 'c:\Program Files\UltraEdit\uedit32.exe', 'params' => '%F/%L');
+ $dbg_editors[1] = Array('editor' => 'c:\Program Files\Zend\ZendStudio-4.0Beta\bin\ZDE.exe', 'params' => '%F');
+ define('WINDOWS_EDITOR',$dbg_editors[$dbg_editor]['editor'].' '.$dbg_editors[$dbg_editor]['params']);
+ unset($dbg_editors,$dbg_editor);
+ }*/
+
+ class Debugger
+ {
+ /**
+ * Debugger data for building report
+ *
+ * @var Array
+ */
+ var $Data = Array();
+ var $ProfilerData = Array();
+ var $RecursionStack = Array(); // prevent recursion when processing debug_backtrace() function results
+
+ var $TraceNextError=false;
+
+ var $Options = 0;
+ var $OptionsMap = Array('shutdown_func' => 1, 'error_handler' => 2,
+ 'output_buffer' => 4, 'highlight_output' => 8);
+
+
+ var $longErrors=Array();
+
+ /**
+ * Amount of memory used by debugger itself
+ *
+ * @var Array
+ * @access private
+ */
+ var $memoryUsage=Array();
+
+ var $IncludesData=Array();
+ var $IncludeLevel=0;
+
+ function Debugger()
{
- $this->Data[] = Array('value' => $varValue, 'debug_type' => 'var_dump');
+ $this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4');
+ ini_set('display_errors',dbg_ConstOn('DBG_ZEND_PRESENT')?0:1);
+ $this->memoryUsage['error_handling']=0; // memory amount used by error handler
+ $this->appendRequest();
}
- }
-
- function prepareHTML($dataIndex)
- {
- $Data =& $this->Data[$dataIndex];
- if($Data['debug_type'] == 'html') return $Data['html'];
- switch($Data['debug_type'])
+ function initOptions()
{
- case 'error':
- $fileLink = $this->getFileLink($Data['file'],$Data['line']);
- $ret = ''.$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;
+ }
+
+ function mapLongError($msg)
+ {
+ $key=$this->generateID();
+ $this->longErrors[$key]=$msg;
+ return $key;
+ }
+
+ function setOption($name,$value)
+ {
+ if( !isset($this->OptionsMap[$name]) ) die('undefined debugger option: ['.$name.']
');
+ 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 'trace':
- ini_set('memory_limit','500M');
- $trace =& $Data['trace'];
+ case 'var_dump':
+ return $this->highlightString( print_r($Data['value'], true) );
+ break;
+
+ case 'trace':
+ ini_set('memory_limit','500M');
+ $trace =& $Data['trace'];
+
+ //return 'sorry';
+ //return $this->highlightString(print_r($trace,true));
+
+
+ $i = 0; $traceCount = count($trace);
+ $ret = '';
+ while($i < $traceCount)
+ {
+ $traceRec =& $trace[$i];
+ $argsID = 'trace_args_'.$dataIndex.'_'.$i;
+ if(isset($traceRec['file']))
+ {
+ $func_name=isset($traceRec['class'])?$traceRec['class'].$traceRec['type'].$traceRec['function']:$traceRec['function'];
+ $ret .= 'Function: '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name);
+ $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 .= ''.$args.'
';
+ $i++;
+ }
+ return $ret;
+ break;
- //return 'sorry';
- //return $this->highlightString(print_r($trace,true));
-
-
- $i = 0; $traceCount = count($trace);
- $ret = '';
- while($i < $traceCount)
+ 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)
+ {
+ if(!$traceArgs) return '';
+ foreach ($traceArgs as $argID => $argValue)
+ {
+ if( is_array($argValue) || is_object($argValue) )
{
- $traceRec =& $trace[$i];
- $argsID = 'trace_args_'.$dataIndex.'_'.$i;
- if(isset($traceRec['file']))
+ 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) )
{
- $func_name=isset($traceRec['class'])?$traceRec['class'].$traceRec['type'].$traceRec['function']:$traceRec['function'];
- $ret .= 'Function: '.$this->getFileLink($traceRec['file'],$traceRec['line'],$func_name);
- $ret .= ' in '.basename($traceRec['file']).' on line '.$traceRec['line'].'
';
+ // object & in stack - recursion
+ $traceArgs[$argID] = '**** RECURSION ***';
}
- else
+ else
{
- $ret .= 'no file information available';
+ // normal array here
+ $this->processTraceArguments($argValue);
}
-
- // ensure parameter value is not longer then 200 symbols
- $this->processTraceArguments($traceRec['args']);
- $args = $this->highlightString(print_r($traceRec['args'], true));
- $ret .= ''.$args.'
';
- $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)
- {
- if(!$traceArgs) return '';
- foreach ($traceArgs as $argID => $argValue)
- {
- if( is_array($argValue) || is_object($argValue) )
- {
- if(is_object($argValue) && !in_array(get_class($argValue),$this->RecursionStack) )
- {
- // object & not in stack - ok
- array_push($this->RecursionStack, get_class($argValue));
- settype($argValue,'array');
- $this->processTraceArguments($argValue);
- array_pop($this->RecursionStack);
- }
- elseif(is_object($argValue) && in_array(get_class($argValue),$this->RecursionStack) )
- {
- // object & in stack - recursion
- $traceArgs[$argID] = '**** RECURSION ***';
- }
else
{
- // normal array here
- $this->processTraceArguments($argValue);
+ $traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]);
}
}
+ }
+
+ function cutStringForHTML($string)
+ {
+ if( strlen($string) > 200 ) $string = substr($string,0,50).' ...';
+ return $string;
+ }
+
+ /**
+ * Format SQL Query using predefined formatting
+ * and highlighting techniques
+ *
+ * @param string $sql
+ * @return string
+ */
+ function formatSQL($sql)
+ {
+ $sql = preg_replace('/(\n|\t| )+/is',' ',$sql);
+ $sql = preg_replace('/(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY) /is', "\n\t$1 ",$sql);
+ return $this->highlightString($sql);
+ }
+
+ function highlightString($string)
+ {
+ if( dbg_ConstOn('DBG_USE_HIGHLIGHT') )
+ {
+ $string = str_replace('\\','_no_match_string_',$string);
+ $string = highlight_string('', true);
+ $string = str_replace('_no_match_string_','\\',$string);
+ return preg_replace('/<\?(.*)php (.*)\?>/s','$2',$string);
+ }
else
{
- $traceArgs[$argID] = $this->cutStringForHTML($traceArgs[$argID]);
+ return $string;
}
}
- }
-
- function cutStringForHTML($string)
- {
- if( strlen($string) > 200 ) $string = substr($string,0,50).' ...';
- return $string;
- }
-
- /**
- * Format SQL Query using predefined formatting
- * and highlighting techniques
- *
- * @param string $sql
- * @return string
- */
- function formatSQL($sql)
- {
- $sql = preg_replace('/(\n|\t| )+/is',' ',$sql);
- $sql = preg_replace('/(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY) /is', "\n\t$1 ",$sql);
- return $this->highlightString($sql);
- }
-
- function highlightString($string)
- {
- if( defined('DBG_USE_HIGHLIGHT')&&DBG_USE_HIGHLIGHT )
+
+ function getFileLink($file, $lineno = 1, $title = '')
{
- $string = highlight_string('', true);
- return preg_replace('/<\?(.*)php (.*)\?>/s','$2',$string);
+ if(!$title) $title = $file;
+ $is_mozilla=strpos(strtolower($_SERVER['HTTP_USER_AGENT']),'firefox')!==false?true:false;
+ if($is_mozilla)
+ {
+ return ''.$title.'';
+ }
+ else
+ {
+ return ''.$title.'';
+ }
+
}
- else
+
+ function getLocalFile($remoteFile)
{
- return $string;
+ return str_replace(DOC_ROOT, DBG_LOCAL_BASE_PATH, $remoteFile);
}
- }
-
- function getFileLink($file, $lineno = 1, $title = '')
- {
- if(!$title) $title = $file;
- $is_mozilla=strpos(strtolower($_SERVER['HTTP_USER_AGENT']),'firefox')!==false?true:false;
- if($is_mozilla)
+
+ function appendTrace()
{
- return ''.$title.'';
+ $trace = debug_backtrace();
+ array_shift($trace);
+ $this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace');
}
- else
+
+ function appendHTML($html)
{
- return ''.$title.'';
+ $this->Data[] = Array('html' => $html,'debug_type' => 'html');
}
- }
-
- 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' )
+ /**
+ * 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')
{
- return false;
+ 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;
}
- switch ($type)
+ /**
+ * Move $debugLineCount lines of input from debug output
+ * end to beginning.
+ *
+ * @param int $debugLineCount
+ */
+ function moveToBegin($debugLineCount)
{
- 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;
+ $lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
+ $this->Data = array_merge($lines,$this->Data);
}
- 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();
- ?>
-
-
- Src | Name | Value |
-
- $value)
- {
- if( !is_array($value) && trim($value) == '' )
+
+ function moveAfterRow($new_row, $debugLineCount)
+ {
+ $lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
+ $rows_before = array_splice($this->Data,0,$new_row,$lines);
+ $this->Data = array_merge($rows_before,$this->Data);
+ }
+
+ function appendRequest()
+ {
+ $script = $_SERVER['PATH_TRANSLATED'];
+ $this->appendHTML('ScriptName: '.$this->getFileLink($script,1,basename($script)).' ('.dirname($script).')');
+ ob_start();
+ ?>
+
+
+ Src | Name | Value |
+
+ $value)
{
- $value = 'no 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 ''.$src.' | '.$key.' | '.$value.' |
';
}
- else
- {
- $value = htmlspecialchars(print_r($value, true));
- }
- $src = isset($_GET[$key]) ? 'GE' : (isset($_POST[$key]) ? 'PO' : (isset($_COOKIE[$key]) ? 'CO' : '?') );
- echo ''.$src.' | '.$key.' | '.$value.' |
';
- }
- ?>
-
- appendHTML( ob_get_contents() );
- ob_end_clean();
- }
-
- function appendSession()
- {
- if( isset($_SESSION)&&$_SESSION )
+ ?>
+
+ appendHTML( ob_get_contents() );
+ ob_end_clean();
+ }
+
+ function appendSession()
{
- $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;
+ if( isset($_SESSION)&&$_SESSION )
+ {
+ $this->appendHTML('PHP Session: ['.ini_get('session.name').']');
+ $this->dumpVars($_SESSION);
+ $this->moveToBegin(2);
+ }
}
- return $id_part_1.$id_part_2.$id_part_3;
- }
-
-
- function getErrorNameByCode($errorCode)
- {
- switch($errorCode)
+
+ function profileStart($key, $description)
{
- 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;
+ $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');
}
- }
-
- /**
- * Generates report
- *
- */
- function printReport($returnResult = false)
- {
- $this->memoryUsage['debugger_start']=memory_get_usage();
- // show php session if any
- $this->appendSession();
+ function profileFinish($key)
+ {
+ $this->ProfilerData[$key]['ends'] = $this->getMoment();
+ }
- // ensure, that 1st line of debug output always is this one:
- $this->appendHTML('Hide Debugger');
- $this->moveToBegin(1);
+ function getMoment()
+ {
+ list($usec, $sec) = explode(' ', microtime());
+ return ((float)$usec + (float)$sec);
+ }
- $i = 0; $lineCount = count($this->Data);
- ob_start();
- ?>
-
-
-
-
- '.$this->prepareHTML($i).' | ';
- $i++;
- }
- ?>
-
-
-
-
- memoryUsage['debugger_finish']=memory_get_usage();
- $this->memoryUsage['print_report']=$this->memoryUsage['debugger_finish']-$this->memoryUsage['debugger_start'];
- $this->memoryUsage['total']=$this->memoryUsage['print_report']+$this->memoryUsage['error_handling'];
- $this->memoryUsage['application']=memory_get_usage()-$this->memoryUsage['total'];
- if($returnResult)
- {
- $ret = ob_get_contents();
- ob_clean();
- if( ConstOn('DBG_SHOW_MEMORY_USAGE') ) $ret.=$this->getMemoryUsageReport();
- return $ret;
+
+
+ document.onkeydown = keyProcessor;
+ window.onresize = resizeDebugLayer;
+ window.onscroll = resizeDebugLayer;
+ window.focus();
+ if( typeof($isFatalError) != 'undefined' && $isFatalError == 1 || )
+ {
+ toggleDebugLayer();
+ }
+ if( typeof($isFatalError) != 'undefined' && $isFatalError == 1)
+ {
+ document.getElementById('debug_layer').scrollTop = 10000000;
+ }
+
+ memoryUsage['debugger_finish']=memory_get_usage();
+ $this->memoryUsage['print_report']=$this->memoryUsage['debugger_finish']-$this->memoryUsage['debugger_start'];
+ $this->memoryUsage['total']=$this->memoryUsage['print_report']+$this->memoryUsage['error_handling'];
+ $this->memoryUsage['application']=memory_get_usage()-$this->memoryUsage['total'];
+ if($returnResult)
+ {
+ $ret = ob_get_contents();
+ ob_clean();
+ if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) $ret.=$this->getMemoryUsageReport();
+ return $ret;
+ }
+ else
+ {
+ ob_end_flush();
+ if( dbg_ConstOn('DBG_SHOW_MEMORY_USAGE') ) echo $this->getMemoryUsageReport();
+ }
}
- else
+
+ /**
+ * Format's memory usage report by debugger
+ *
+ * @return string
+ * @access private
+ */
+ function getMemoryUsageReport()
{
- ob_end_flush();
- if( ConstOn('DBG_SHOW_MEMORY_USAGE') ) echo $this->getMemoryUsageReport();
+ $info=Array('printReport'=>'print_report',
+ 'saveError'=>'error_handling',
+ 'Total'=>'total',
+ 'Application'=>'application');
+ $ret=Array();
+ foreach($info as $title => $value_key)
+ {
+ $ret[]=''.$title.': | '.$this->formatSize($this->memoryUsage[$value_key]).' |
';
+ }
+ return '';
}
- }
-
- /**
- * Format's memory usage report by debugger
- *
- * @return string
- * @access private
- */
- function getMemoryUsageReport()
- {
- $info=Array('printReport'=>'print_report',
- 'saveError'=>'error_handling',
- 'Total'=>'total',
- 'Application'=>'application');
- $ret=Array();
- foreach($info as $title => $value_key)
- {
- $ret[]=$title.': '.$this->formatSize($this->memoryUsage[$value_key]).'';
- }
- return implode('
',$ret);
- }
-
-
- /**
- * User-defined error handler
- *
- * @param int $errno
- * @param string $errstr
- * @param string $errfile
- * @param int $errline
- * @param array $errcontext
- */
- function saveError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
- {
- $memory_used=Array();
- $memory_used['begin']=memory_get_usage();
- $errorType = $this->getErrorNameByCode($errno);
- if(!$errorType)
+
+ /**
+ * User-defined error handler
+ *
+ * @param int $errno
+ * @param string $errstr
+ * @param string $errfile
+ * @param int $errline
+ * @param array $errcontext
+ */
+ function saveError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
{
- trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR);
- return false;
+ $memory_used=Array();
+ $memory_used['begin']=memory_get_usage();
+
+ $errorType = $this->getErrorNameByCode($errno);
+ if(!$errorType)
+ {
+ trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR);
+ return false;
+ }
+
+ if( dbg_ConstOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT) ) return;
+
+ $long_id_pos=strrpos($errstr,'#');
+ if($long_id_pos!==false)
+ {
+ // replace short message with long one (due triger_error limitations on message size)
+ $long_id=substr($errstr,$long_id_pos+1,strlen($errstr));
+ $errstr=$this->longErrors[$long_id];
+ unset($this->longErrors[$long_id]);
+ }
+
+
+ /*in /www/kostja/in-commerce4/kernel/kernel4/parser/construct_tags.php(177) : runtime-created function on line
+
+ [PRE-PARSED block, $line 13]: Undefined variable: IdField*/
+
+ if( strpos($errfile,'runtime-created') !== false ) {
+ $errfile = ' PRE-PARSED block '.$this->CurrentPreParsedBlock.' ';
+ }
+
+ 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');
+ $memory_used['end']=memory_get_usage();
+ $this->memoryUsage['error_handling']+=$memory_used['end']-$memory_used['begin'];
+ if( substr($errorType,0,5) == 'Fatal')
+ {
+ echo '';
+ exit;
+ }
}
- $long_id_pos=strrpos($errstr,'#');
- if($long_id_pos!==false)
+ function saveToFile($msg)
{
- // replace short message with long one (due triger_error limitations on message size)
- $long_id=substr($errstr,$long_id_pos+1,strlen($errstr));
- $errstr=$this->longErrors[$long_id];
- unset($this->longErrors[$long_id]);
+ $fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a');
+ fwrite($fp,$msg."\n");
+ fclose($fp);
}
- if( strpos($errfile,'eval()\'d code') !== false )
+ /**
+ * Formats file/memory size in nice way
+ *
+ * @param int $bytes
+ * @return string
+ * @access public
+ */
+ function formatSize($bytes)
{
- $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 ($bytes >= 1099511627776) {
+ $return = round($bytes / 1024 / 1024 / 1024 / 1024, 2);
+ $suffix = "TB";
+ } elseif ($bytes >= 1073741824) {
+ $return = round($bytes / 1024 / 1024 / 1024, 2);
+ $suffix = "GB";
+ } elseif ($bytes >= 1048576) {
+ $return = round($bytes / 1024 / 1024, 2);
+ $suffix = "MB";
+ } elseif ($bytes >= 1024) {
+ $return = round($bytes / 1024, 2);
+ $suffix = "KB";
+ } else {
+ $return = $bytes;
+ $suffix = "Byte";
+ }
+ $return .= ' '.$suffix;
+ return $return;
}
- if($this->TraceNextError)
- {
- $this->appendTrace();
- $this->TraceNextError=false;
- }
- $this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error');
- $memory_used['end']=memory_get_usage();
- $this->memoryUsage['error_handling']+=$memory_used['end']-$memory_used['begin'];
- if( substr($errorType,0,5) == 'Fatal')
- {
- echo '';
- exit;
- }
+
}
-
- function saveToFile($msg)
+
+ if( !function_exists('memory_get_usage') )
{
- $fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a');
- fwrite($fp,$msg."\n");
- fclose($fp);
+ function memory_get_usage(){ return -1; }
}
- /**
- * Formats file/memory size in nice way
- *
- * @param int $bytes
- * @return string
- * @access public
- */
- function formatSize($bytes)
- {
- if ($bytes >= 1099511627776) {
- $return = round($bytes / 1024 / 1024 / 1024 / 1024, 2);
- $suffix = "TB";
- } elseif ($bytes >= 1073741824) {
- $return = round($bytes / 1024 / 1024 / 1024, 2);
- $suffix = "GB";
- } elseif ($bytes >= 1048576) {
- $return = round($bytes / 1024 / 1024, 2);
- $suffix = "MB";
- } elseif ($bytes >= 1024) {
- $return = round($bytes / 1024, 2);
- $suffix = "KB";
- } else {
- $return = $bytes;
- $suffix = "Byte";
- }
- $return .= ' '.$suffix;
- return $return;
+ $debugger = new Debugger();
+ if(dbg_ConstOn('DBG_HANDLE_ERRORS')) set_error_handler( array(&$debugger,'saveError') );
+ if(dbg_ConstOn('DBG_USE_SHUTDOWN_FUNC')) {
+ register_shutdown_function( array(&$debugger,'printReport') );
}
-
}
-
- if( !function_exists('memory_get_usage') )
- {
- function memory_get_usage(){ return -1; }
- }
-
- function ConstOn($const_name)
- {
- return defined($const_name)&&constant($const_name);
- }
-
- $debugger = new Debugger();
- if(ConstOn('DBG_HANDLE_ERRORS')) set_error_handler( array(&$debugger,'saveError') );
- if(ConstOn('DBG_USE_SHUTDOWN_FUNC')) register_shutdown_function( array(&$debugger,'printReport') );
-
-
?>
\ No newline at end of file
Index: trunk/core/kernel/db/db_event_handler.php
===================================================================
diff -u -r958 -r1339
--- trunk/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 958)
+++ trunk/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 1339)
@@ -1,5 +1,8 @@
Conn =& $this->Application->GetADODBConnection();
+ }
+
+ function mapEvents()
+ {
+ $events_map = Array('OnRemoveFilters' => 'FilterAction',
+ 'OnApplyFilters' => 'FilterAction');
+
+ $this->eventMethods = array_merge($this->eventMethods, $events_map);
+ }
+
+ /**
+ * Returns ID of current item to be edited
+ * by checking ID passed in get/post as prefix_id
+ * or by looking at first from selected ids, stored.
+ * Returned id is also stored in Session in case
+ * it was explicitly passed as get/post
+ *
* @param kEvent $event
* @return int
*/
function getPassedID(&$event)
{
- $ret=$this->Application->GetVar($event->getPrefixSpecial().'_id');
- if($ret===false)
- {
- $ids=$this->Application->GetVar($event->getPrefixSpecial().'_selected_ids');
+ //$ret = $this->Application->GetLinkedVar($event->getPrefixSpecial(true).'_id', $event->getPrefixSpecial().'_id');
+
+ // ?? We don't need to store selected id in session, as long as we have pass=all by default, which
+ // means that main item id will be passed to all sub-item screens by default
+ // another prove of that is that sub-items relay on main item '_mode' = 't' for switching to temp tables
+ // Also having id in session raised problems with the id of deleted item stuck in session
+ $ret = $this->Application->GetVar($event->getPrefixSpecial(true).'_id');
+ if ($ret) return $ret; // if id was passed explicity as prefix[_special]_id use it, and store it in session
+
+ // recall selected ids array and use the first one
+ $ids=$this->Application->GetVar($event->getPrefixSpecial().'_selected_ids');
+ if ($ids != '') {
$ids=explode(',',$ids);
if($ids) $ret=array_shift($ids);
}
+ else { // if selected ids are not yet stored
+ $this->StoreSelectedIDs($event);
+ return $this->Application->GetVar($event->getPrefixSpecial(true).'_id'); // StoreSelectedIDs sets this variable
+ }
return $ret;
}
/**
+ * Prepares and stores selected_ids string
+ * in Session and Application Variables
+ * by getting all checked ids from grid plus
+ * id passed in get/post as prefix_id
+ *
+ * @param kEvent $event
+ */
+ function StoreSelectedIDs(&$event)
+ {
+ $ret = Array();
+
+ // May be we don't need this part: ?
+ $passed = $this->Application->GetVar($event->getPrefixSpecial(true).'_id');
+ if($passed !== false && $passed != '')
+ {
+ array_push($ret, $passed);
+ }
+
+ $ids = Array();
+
+ // get selected ids from post & save them to session
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if($items_info)
+ {
+ $id_field = $this->Application->getUnitOption($event->Prefix,'IDField');
+ foreach($items_info as $id => $field_values)
+ {
+ if( getArrayValue($field_values,$id_field) ) array_push($ids,$id);
+ }
+ //$ids=array_keys($items_info);
+ }
+
+ $ret = array_unique(array_merge($ret, $ids));
+
+ $this->Application->SetVar($event->getPrefixSpecial().'_selected_ids',implode(',',$ret));
+ $this->Application->LinkVar($event->getPrefixSpecial().'_selected_ids');
+
+ // This is critical - otherwise getPassedID will return last ID stored in session! (not exactly true)
+ // this smells... needs to be refactored
+ $first_id = getArrayValue($ret,0);
+ if($first_id === false) trigger_error('Requested ID for prefix '.$event->getPrefixSpecial().' not passed',E_USER_NOTICE);
+ $this->Application->SetVar($event->getPrefixSpecial(true).'_id', $first_id);
+ }
+
+ /**
+ * Returns stored selected ids as an array
+ *
+ * @param kEvent $event
+ * @return array
+ */
+ function getSelectedIDs(&$event)
+ {
+ return explode(',', $this->Application->GetVar($event->getPrefixSpecial().'_selected_ids'));
+ }
+
+ /**
+ * Returs associative array of submitted fields for current item
+ * Could be used while creating/editing single item -
+ * meaning on any edit form, except grid edit
+ *
+ * @param kEvent $event
+ */
+ function getSubmittedFields(&$event)
+ {
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ $field_values = $items_info ? array_shift($items_info) : Array();
+ return $field_values;
+ }
+
+ /**
+ * Removes any information about current/selected ids
+ * from Application variables and Session
+ *
+ * @param kEvent $event
+ */
+ function clearSelectedIDs(&$event)
+ {
+ $prefix_special = $event->getPrefixSpecial();
+ $this->Application->RemoveVar($prefix_special.'_selected_ids');
+ $this->Application->SetVar($prefix_special.'_selected_ids', '');
+ $this->Application->RemoveVar($prefix_special.'_id'); // not needed anymore ??
+ $this->Application->SetVar($prefix_special.'_id', '');
+ //$this->Application->RemoveVar($prefix_special.'_modified');
+ }
+
+ /*function SetSaveEvent(&$event)
+ {
+ $this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnUpdate');
+ $this->Application->LinkVar($event->Prefix_Special.'_SaveEvent');
+ }*/
+
+ /**
+ * Common builder part for Item & List
+ *
+ * @param kDBBase $object
+ * @param kEvent $event
+ * @access private
+ */
+ function dbBuild(&$object,&$event)
+ {
+ $object->Configure();
+
+ if( $this->UseTempTables($event) )
+ {
+ $object->SwitchToTemp();
+ }
+
+ // This strange constuction creates hidden field for storing event name in form submit
+ // It pass SaveEvent to next screen, otherwise after unsuccsefull create it will try to update rather than create
+ $current_event = $this->Application->GetVar($event->Prefix_Special.'_event');
+ $this->Application->setEvent($event->Prefix_Special, $current_event);
+
+ $save_event = $this->UseTempTables($event) && $this->Application->GetTopmostPrefix($event->Prefix) == $event->Prefix ? 'OnSave' : 'OnUpdate';
+ $this->Application->SetVar($event->Prefix_Special.'_SaveEvent',$save_event);
+ }
+
+ /**
* Builds item (loads if needed)
*
* @param kEvent $event
* @access protected
*/
function OnItemBuild(&$event)
{
- $object =& $event->createObject();
- $this->dbBuild(&$object,&$event);
+ $object =& $event->getObject();
+ $this->dbBuild($object,$event);
- $sql=$this->getSelectSQL($event,'OnItemPrepareQuery');
+ $sql = $this->ItemPrepareQuery($event);
+ $sql = $this->Application->ReplaceLanguageTags($sql);
$object->setSelectSQL($sql);
- // 1. set from config what needed
- $fields = $this->Application->getUnitOption($event->Prefix,'Fields');
- $object->setConfigFields( array_keys($fields) );
-
// 2. loads if allowed
$auto_load = $this->Application->getUnitOption($event->Prefix,'AutoLoad');
- if($auto_load)
- {
- $id = $this->getPassedID(&$event);
- $object->Load($id);
+ if($auto_load) $this->LoadItem($event);
+
+ $actions =& $this->Application->recallObject('kActions');
+ $actions->Set($event->Prefix_Special.'_GoTab', '');
+
+ $actions->Set($event->Prefix_Special.'_GoId', '');
+ }
+
+ /**
+ * Build subtables array from configs
+ *
+ * @param kEvent $event
+ */
+ function OnTempHandlerBuild(&$event)
+ {
+ $object =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $object->BuildTables( $event->Prefix, $this->getSelectedIDs($event) );
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ * @return unknown
+ */
+ function UseTempTables(&$event)
+ {
+ $object = &$event->getObject();
+ $top_prefix = $this->Application->GetTopmostPrefix($event->Prefix);
+ return $this->Application->GetVar($top_prefix.'_mode') == 't';
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param kEvent $event
+ * @return unknown
+ */
+ function __GetTopmostPrefix(&$event)
+ {
+ $current_prefix = $event->Prefix;
+ while ( $parent_prefix = $this->Application->getUnitOption($current_prefix, 'ParentPrefix') ) {
+ $current_prefix = $parent_prefix;
}
- $this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnUpdate');
+ return $current_prefix;
}
+ function LoadItem(&$event)
+ {
+ $object =& $event->getObject();
+ if ( $event->getEventParam('ByParent') ) {
+ $parent_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
+ $parent_table_key = $this->Application->getUnitOption($event->Prefix, 'ParentTableKey');
+ $parent_object =& $this->Application->recallObject($parent_prefix);
+ $id = $parent_object->GetDBField($parent_table_key);
+ $id_field = $this->Application->getUnitOption($event->Prefix, 'ForeignKey');
+ }
+ else {
+ $id = $this->getPassedID($event);
+ $id_field = null;
+ }
+ $object->Load($id, $id_field);
+
+ $actions =& $this->Application->recallObject('kActions');
+ $actions->Set($event->Prefix_Special.'_id', $object->GetId());
+ }
+
/**
* Builds list
*
@@ -83,22 +301,53 @@
*/
function OnListBuild(&$event)
{
- $event->setPseudoClass('_List');
- $object =& $event->createObject();
+ //$event->setPseudoClass('_List');
+ $object =& $event->getObject();
- $this->dbBuild(&$object,&$event);
+ $this->dbBuild($object,$event);
- $sql=$this->getSelectSQL($event,'OnListPrepareQuery');
+ $sql = $this->ListPrepareQuery($event);
+ $sql = $this->Application->ReplaceLanguageTags($sql);
$object->setSelectSQL($sql);
- $t=$this->Application->GetVar('t');
- $this->Application->StoreVar('redirect_to',$t);
+ $object->linkToParent('');
- $this->SetPagination(&$event);
- $this->SetSorting(&$event);
+ $this->AddFilters($event);
+ $this->SetCustomQuery($event); // new!, use this for dynamic queries based on specials for ex.
+ $this->SetPagination($event);
+ $this->SetSorting($event);
+
+ $actions =& $this->Application->recallObject('kActions');
+ $actions->Set('remove_specials['.$event->Prefix_Special.']', '0');
+ $actions->Set($event->Prefix_Special.'_GoTab', '');
}
+
+
/**
+ * Apply any custom changes to list's sql query
+ *
+ * @param kEvent $event
+ * @access protected
+ * @see OnListBuild
+ */
+ function SetCustomQuery(&$event)
+ {
+
+ }
+
+ /**
+ * Set's new perpage for grid
+ *
+ * @param kEvent $event
+ */
+ function OnSetPerPage(&$event)
+ {
+ $per_page = $this->Application->GetVar($event->getPrefixSpecial(true).'_PerPage');
+ $this->Application->StoreVar( $event->getPrefixSpecial().'_PerPage', $per_page );
+ }
+
+ /**
* Set's correct page for list
* based on data provided with event
*
@@ -108,22 +357,40 @@
*/
function SetPagination(&$event)
{
+ // get PerPage (forced -> session -> config -> 10)
$per_page = $event->getEventParam('per_page');
if(!$per_page)
{
- $per_page=$this->Application->RecallVar($event->Prefix_Special.'_PerPage');
+ $per_page_var = $event->getPrefixSpecial().'_PerPage';
+
+ $per_page = $this->Application->RecallVar($per_page_var);
if(!$per_page)
{
- $per_page=10;
+ $per_page = $this->Application->ConfigValue($per_page_var);
+ if(!$per_page) $per_page = 10;
}
}
- $event->setPseudoClass('_List');
- $object =& $event->createObject();
+ $object =& $event->getObject();
$object->SetPerPage($per_page);
- $object->CountRecs();
-
- $object->SetPage( $this->Application->GetLinkedVar( $event->Prefix_Special.'_Page' ) );
+
+ if( !$event->getEventParam('skip_counting') )
+ {
+ $object->CountRecs();
+
+ $this->Application->StoreVarDefault($event->getPrefixSpecial().'_Page', 1);
+
+ $page = $this->Application->GetLinkedVar($event->getPrefixSpecial(true).'_Page', $event->getPrefixSpecial().'_Page');
+ $pages = $object->GetTotalPages();
+
+ if($page > $pages)
+ {
+ $this->Application->StoreVar($event->getPrefixSpecial().'_Page', 1);
+ $page = 1;
+ }
+
+ $object->SetPage($page);
+ }
}
/**
@@ -137,20 +404,35 @@
function SetSorting(&$event)
{
$event->setPseudoClass('_List');
- $object =& $event->createObject();
+ $object =& $event->getObject();
$cur_sort1 = $this->Application->RecallVar($event->Prefix_Special.'_Sort1');
$cur_sort1_dir = $this->Application->RecallVar($event->Prefix_Special.'_Sort1_Dir');
$cur_sort2 = $this->Application->RecallVar($event->Prefix_Special.'_Sort2');
$cur_sort2_dir = $this->Application->RecallVar($event->Prefix_Special.'_Sort2_Dir');
- //Use default if not specified
- /*if ( $cur_sort1 === false || $cur_sort1_dir == false ) {
- $cur_sort1 = $this->Application->ConfigOption($event->Prefix_Special.'_Sort1');
- $cur_sort1_dir = $this->Application->ConfigOption($event->Prefix_Special.'_Sort1_Dir');
- $cur_sort2 = $this->Application->ConfigOption($event->Prefix_Special.'_Sort2');
- $cur_sort2_dir = $this->Application->ConfigOption($event->Prefix_Special.'_Sort2_Dir');
- }*/
+ $list_sortings = $this->Application->getUnitOption($event->Prefix, 'ListSortings');
+ $sorting_prefix = getArrayValue($list_sortings, $event->Special) ? $event->Special : '';
+
+ // Use default if not specified
+ if ( !$cur_sort1 || !$cur_sort1_dir)
+ {
+ if ( $sorting = getArrayValue($list_sortings, $sorting_prefix, 'Sorting') ) {
+ reset($sorting);
+ $cur_sort1 = key($sorting);
+ $cur_sort1_dir = current($sorting);
+ if (next($sorting)) {
+ $cur_sort2 = key($sorting);
+ $cur_sort2_dir = current($sorting);
+ }
+ }
+ }
+
+ if ( $forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting') ) {
+ foreach ($forced_sorting as $field => $dir) {
+ $object->AddOrderField($field, $dir);
+ }
+ }
if($cur_sort1 != '' && $cur_sort1_dir != '')
{
@@ -162,14 +444,53 @@
}
}
+
/**
- * Some kind of filter processing stuff.
- * Not in use by now
+ * Add filters found in session
*
+ * @param kEvent $event
*/
- function AddFilters()
+ function AddFilters(&$event)
{
-
+ $object =& $event->getObject();
+
+ $search_filter = $this->Application->RecallVar($event->getPrefixSpecial().'_search_filter');
+ if($search_filter)
+ {
+ $search_filter = unserialize($search_filter);
+ foreach($search_filter as $search_field => $filter_params)
+ {
+ $filter_type = ($filter_params['type'] == 'having') ? HAVING_FILTER : WHERE_FILTER;
+ $object->addFilter($search_field, $filter_params['value'], $filter_type, FLT_SEARCH);
+ }
+ }
+
+ $view_filter = $this->Application->RecallVar($event->getPrefixSpecial().'_view_filter');
+ if($view_filter)
+ {
+ $view_filter = unserialize($view_filter);
+ $temp_filter =& $this->Application->makeClass('kMultipleFilter');
+ $filter_menu = $this->Application->getUnitOption($event->Prefix,'FilterMenu');
+
+ $group_key = 0; $group_count = count($filter_menu['Groups']);
+ while($group_key < $group_count)
+ {
+ $group_info = $filter_menu['Groups'][$group_key];
+
+ $temp_filter->setType( constant('FLT_TYPE_'.$group_info['mode']) );
+ $temp_filter->clearFilters();
+ foreach ($group_info['filters'] as $flt_id)
+ {
+ $sql_key = getArrayValue($view_filter,$flt_id) ? 'on_sql' : 'off_sql';
+ if ($filter_menu['Filters'][$flt_id][$sql_key] != '')
+ {
+ $temp_filter->addFilter('view_filter_'.$flt_id, $filter_menu['Filters'][$flt_id][$sql_key]);
+ }
+ }
+ $object->addFilter('view_group_'.$group_key, $temp_filter, $group_info['type'] , FLT_VIEW);
+ $group_key++;
+ }
+ }
}
/**
@@ -180,56 +501,51 @@
*/
function OnSetSorting(&$event)
{
- $this->Application->LinkVar($event->getPrefixSpecial(true).'_Sort1',$event->Prefix_Special.'_Sort1');
- $this->Application->LinkVar($event->getPrefixSpecial(true).'_Sort1_Dir',$event->Prefix_Special.'_Sort1_Dir');
+ $cur_sort1 = $this->Application->RecallVar($event->Prefix_Special.'_Sort1');
+ $cur_sort1_dir = $this->Application->RecallVar($event->Prefix_Special.'_Sort1_Dir');
+ $cur_sort2 = $this->Application->RecallVar($event->Prefix_Special.'_Sort2');
+ $cur_sort2_dir = $this->Application->RecallVar($event->Prefix_Special.'_Sort2_Dir');
- //$event->setPseudoClass('_List');
- //$object =& $event->createObject();
+ $passed_sort1 = $this->Application->GetVar($event->getPrefixSpecial(true).'_Sort1');
+ if ($cur_sort1 == $passed_sort1) {
+ $cur_sort1_dir = $cur_sort1_dir == 'asc' ? 'desc' : 'asc';
+ }
+ else {
+ $cur_sort2 = $cur_sort1;
+ $cur_sort2_dir = $cur_sort1_dir;
+ $cur_sort1 = $passed_sort1;
+ $cur_sort1_dir = 'asc';
+ }
+
+ $this->Application->StoreVar($event->Prefix_Special.'_Sort1', $cur_sort1);
+ $this->Application->StoreVar($event->Prefix_Special.'_Sort1_Dir', $cur_sort1_dir);
+ $this->Application->StoreVar($event->Prefix_Special.'_Sort2', $cur_sort2);
+ $this->Application->StoreVar($event->Prefix_Special.'_Sort2_Dir', $cur_sort2_dir);
}
/**
- * Common builder part for Item & List
+ * Set sorting directly to session
*
- * @param Object $object
- * @access private
+ * @param kEvent $event
*/
- function dbBuild(&$object,&$event)
+ function OnSetSortingDirect(&$event)
{
- // set Item & List common parameters from config
- $table = $this->Application->getUnitOption($event->Prefix,'TableName');
- $object->setTableName($table);
-
- $id_field = $this->Application->getUnitOption($event->Prefix,'IDField');
- $object->setIDField($id_field);
-
- // get selected ids from post & save them to session
- $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
- if($items_info)
- {
- $ids=array_keys($items_info);
- $this->Application->SetVar($event->getPrefixSpecial().'_selected_ids',implode(',',$ids));
- }
- $this->Application->LinkVar($event->getPrefixSpecial().'_selected_ids');
-
- // set's any possible hidden fields needed for both Item & List
- $current_event = $this->Application->GetVar($event->Prefix_Special.'_event');
- $this->Application->setEvent($event->Prefix_Special,$current_event);
+ $field_pos = $this->Application->GetVar($event->getPrefixSpecial(true).'_SortPos');
+ $this->Application->LinkVar( $event->getPrefixSpecial(true).'_Sort'.$field_pos, $event->Prefix_Special.'_Sort'.$field_pos);
+ $this->Application->LinkVar( $event->getPrefixSpecial(true).'_Sort'.$field_pos.'_Dir', $event->Prefix_Special.'_Sort'.$field_pos.'_Dir');
}
/**
- * Returns select query for loading item/list
+ * Reset grid sorting to default (from config)
*
* @param kEvent $event
- * @param string $event_name
- * @return string
- * @access protected
*/
- function getSelectSQL(&$event,$event_name)
+ function OnResetSorting(&$event)
{
- $new_event =& $this->inheritEvent(&$event);
- $new_event->Name=$event_name;
- $this->Application->HandleEvent(&$new_event);
- return $event->getEventParam('SQLQuery');
+ $this->Application->RemoveVar($event->Prefix_Special.'_Sort1');
+ $this->Application->RemoveVar($event->Prefix_Special.'_Sort1_Dir');
+ $this->Application->RemoveVar($event->Prefix_Special.'_Sort2');
+ $this->Application->RemoveVar($event->Prefix_Special.'_Sort2_Dir');
}
/**
@@ -241,11 +557,10 @@
* @param kEvent $event
* @access protected
*/
- function OnItemPrepareQuery(&$event)
+ function ItemPrepareQuery(&$event)
{
$sqls = $this->Application->getUnitOption($event->Prefix,'ItemSQLs');
- $sql = isset($sqls[$event->Special])?$sqls[$event->Special]:$sqls[''];
- $event->MasterEvent->setEventParam('SQLQuery',$sql);
+ return isset($sqls[$event->Special]) ? $sqls[$event->Special] : $sqls[''];
}
/**
@@ -257,11 +572,10 @@
* @param kEvent $event
* @access protected
*/
- function OnListPrepareQuery(&$event)
+ function ListPrepareQuery(&$event)
{
$sqls = $this->Application->getUnitOption($event->Prefix,'ListSQLs');
- $sql = isset($sqls[$event->Special])?$sqls[$event->Special]:$sqls[''];
- $event->MasterEvent->setEventParam('SQLQuery',$sql);
+ return isset( $sqls[$event->Special] ) ? $sqls[$event->Special] : $sqls[''];
}
/**
@@ -272,22 +586,29 @@
*/
function OnCreate(&$event)
{
- $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false);
- $object =& $event->createObject();
- $this->prepareObject(&$object,&$event);
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if($items_info) $field_values = array_shift($items_info);
$object->SetFieldsFromHash($field_values);
- if( $object->Create() )
+ $this->customProcessing($event,'before');
+
+ //look at kDBItem' Create for ForceCreateId description, it's rarely used and is NOT set by default
+ if( $object->Create($event->getEventParam('ForceCreateId')) )
{
+ if ($this->UseTempTables($event)) $object->setTempID();
+ $this->customProcessing($event,'after');
$event->status=erSUCCESS;
+ $event->redirect_params = Array('opener'=>'u');
}
else
{
- $event->status=erFATAL;
+ $event->status=erFAIL;
$event->redirect=false;
+ $this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
+ $object->setID(0);
}
}
@@ -299,30 +620,31 @@
*/
function OnUpdate(&$event)
{
- $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false);
- $object =& $event->createObject();
- $this->prepareObject(&$object,&$event);
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if($items_info)
{
foreach($items_info as $id => $field_values)
{
- //$object->Load($id);
+ $object->Load($id);
$object->SetFieldsFromHash($field_values);
+ $this->customProcessing($event, 'before');
if( $object->Update($id) )
{
+ $this->customProcessing($event, 'after');
$event->status=erSUCCESS;
}
else
{
- $event->status=erFATAL;
+ $event->status=erFAIL;
$event->redirect=false;
break;
}
}
}
-
+ $event->redirect_params = Array('opener'=>'u');
}
/**
@@ -333,18 +655,17 @@
*/
function OnDelete(&$event)
{
- $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false);
- $object =& $event->createObject();
- $object->ID=$this->Application->GetVar($event->Prefix_Special.'_id');
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
+ $object->ID = $this->getPassedID($event);
if( $object->Delete() )
{
- $event->status=erSUCCESS;
+ $event->status = erSUCCESS;
}
else
{
- $event->status=erFATAL;
- $event->redirect=false;
- break;
+ $event->status = erFAIL;
+ $event->redirect = false;
}
}
@@ -356,11 +677,14 @@
*/
function OnNew(&$event)
{
- $this->Application->setUnitOption($this->getPrefixSpecial(),'AutoLoad',false);
- $object =& $event->createObject();
- $this->prepareObject(&$object,&$event);
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
$object->setID(0);
$this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
+
+ $table_info = $object->getLinkedInfo();
+ $object->SetDBField($table_info['ForeignKey'], $table_info['ParentId']);
+
$event->redirect=false;
}
@@ -372,9 +696,605 @@
*/
function OnCancel(&$event)
{
+ $event->redirect_params = Array('opener'=>'u');
+ }
+
+
+ /**
+ * Deletes all selected items.
+ * Automatically recurse into sub-items using temp handler, and deletes sub-items
+ * by calling its Delete method if sub-item has AutoDelete set to true in its config file
+ *
+ * @param kEvent $event
+ */
+ function OnMassDelete(&$event)
+ {
+ $event->status=erSUCCESS;
+ $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $this->StoreSelectedIDs($event);
+
+ $event->setEventParam('ids', $this->getSelectedIDs($event) );
+ $this->customProcessing($event, 'before');
+ $ids = $event->getEventParam('ids');
+
+ if($ids)
+ {
+ $temp->DeleteItems($event->Prefix, $event->Special, $ids);
+ }
+ $this->clearSelectedIDs($event);
}
+
+ /**
+ * Prepare temp tables and populate it
+ * with items selected in the grid
+ *
+ * @param kEvent $event
+ */
+ function OnEdit(&$event)
+ {
+ $this->StoreSelectedIDs($event);
+
+ $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $temp->PrepareEdit();
+
+ $event->redirect=false;
+ }
+
+ /**
+ * Saves content of temp table into live and
+ * redirects to event' default redirect (normally grid template)
+ *
+ * @param kEvent $event
+ */
+ function OnSave(&$event)
+ {
+ $event->CallSubEvent('OnPreSave');
+ if ($event->status==erSUCCESS) {
+ $skip_master=false;
+ $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+
+ // newly created item
+ /*if($this->getPassedID($event) == 0)
+ {
+ $master_id = $temp->CopyMasterToOriginal();
+ $temp->UpdateForeignKeys($master_id); // save linked field values
+ $skip_master = true; //we've already copied master table to get the id
+ }*/
+
+ $temp->SaveEdit($skip_master);
+ $this->clearSelectedIDs($event);
+
+ $event->redirect_params = Array('opener'=>'u');
+ $this->Application->RemoveVar($event->getPrefixSpecial().'_modified');
+ }
+ }
+
+ /**
+ * Cancels edit
+ * Removes all temp tables and clears selected ids
+ *
+ * @param kEvent $event
+ */
+ function OnCancelEdit(&$event)
+ {
+ $temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $temp->CancelEdit();
+
+ $this->clearSelectedIDs($event);
+ $event->redirect_params = Array('opener'=>'u');
+ $this->Application->RemoveVar($event->getPrefixSpecial().'_modified');
+ }
+
+ /**
+ * Saves edited item into temp table
+ * If there is no id, new item is created in temp table
+ *
+ * @param kEvent $event
+ */
+ function OnPreSave(&$event)
+ {
+ //$event->redirect = false;
+ // if there is no id - it means we need to create an item
+ $item_id = $this->getPassedID($event);
+ if ($item_id == '') {
+ $event->CallSubEvent('OnPreSaveCreated');
+ return;
+ }
+
+ $object =& $event->getObject();
+
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if($items_info)
+ {
+ foreach($items_info as $id => $field_values)
+ {
+ $object->SetDefaultValues();
+ $object->Load($id);
+ $object->SetFieldsFromHash($field_values);
+ if( $object->Update($id) )
+ {
+ $event->status=erSUCCESS;
+ }
+ else
+ {
+ $event->status=erFAIL;
+ $event->redirect=false;
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Saves edited item in temp table and loads
+ * item with passed id in current template
+ * Used in Prev/Next buttons
+ *
+ * @param kEvent $event
+ */
+ function OnPreSaveAndGo(&$event)
+ {
+ $event->CallSubEvent('OnPreSave');
+ if ($event->status==erSUCCESS) {
+ $event->redirect_params[$event->getPrefixSpecial(true).'_id'] = $this->Application->GetVar($event->Prefix_Special.'_GoId');
+ }
+ }
+
+ /**
+ * Saves edited item in temp table and goes
+ * to passed tabs, by redirecting to it with OnPreSave event
+ *
+ * @param kEvent $event
+ */
+ function OnPreSaveAndGoToTab(&$event)
+ {
+ $event->CallSubEvent('OnPreSave');
+ if ($event->status==erSUCCESS) {
+ $event->redirect=$this->Application->GetVar($event->getPrefixSpecial(true).'_GoTab');
+ }
+ }
+
+ /**
+ * Saves editable list and goes to passed tab,
+ * by redirecting to it with empty event
+ *
+ * @param kEvent $event
+ */
+ function OnUpdateAndGoToTab(&$event)
+ {
+ $event->setPseudoClass('_List');
+ $event->CallSubEvent('OnUpdate');
+ if ($event->status==erSUCCESS) {
+ $event->redirect=$this->Application->GetVar($event->getPrefixSpecial(true).'_GoTab');
+ }
+ }
+
+ /**
+ * Prepare temp tables for creating new item
+ * but does not create it. Actual create is
+ * done in OnPreSaveCreated
+ *
+ * @param kEvent $event
+ */
+ function OnPreCreate(&$event)
+ {
+ $this->clearSelectedIDs($event);
+
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+ $object =& $event->getObject();
+
+ $temp =& $this->Application->recallObject($event->Prefix.'_TempHandler', 'kTempTablesHandler');
+ $temp->PrepareEdit();
+
+ $object->setID(0);
+
+ $event->redirect=false;
+ }
+
+ /**
+ * Apply custom processing to item
+ *
+ * @param kEvent $event
+ */
+ function customProcessing(&$event, $type)
+ {
+
+ }
+
+ /**
+ * Creates a new item in temp table and
+ * stores item id in App vars and Session on succsess
+ *
+ * @param kEvent $event
+ */
+ function OnPreSaveCreated(&$event)
+ {
+ $this->Application->setUnitOption($event->Prefix,'AutoLoad',false);
+
+ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
+ if($items_info) $field_values = array_shift($items_info);
+
+ $object =& $event->getObject();
+ $object->SetFieldsFromHash($field_values);
+
+ $this->customProcessing($event, 'before');
+
+ if( $object->Create() )
+ {
+ $this->customProcessing($event, 'after');
+ $event->redirect_params[$event->getPrefixSpecial(true).'_id'] = $object->GetId();
+ $event->status=erSUCCESS;
+ }
+ else
+ {
+ $event->status=erFAIL;
+ $event->redirect=false;
+ $object->setID(0);
+ }
+
+ }
+
+ // III. Events that allow to put some code before and after Update,Load,Create and Delete methods of item
+
+ /**
+ * Occurse before loading item, 'id' parameter
+ * allows to get id of item beeing loaded
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnBeforeItemLoad(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse after loading item, 'id' parameter
+ * allows to get id of item that was loaded
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnAfterItemLoad(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse before creating item
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnBeforeItemCreate(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse after creating item
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnAfterItemCreate(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse before updating item
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnBeforeItemUpdate(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse after updating item
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnAfterItemUpdate(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse before deleting item, id of item beeing
+ * deleted is stored as 'id' event param
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnBeforeItemDelete(&$event)
+ {
+
+ }
+
+ /**
+ * Occurse after deleting item, id of deleted item
+ * is stored as 'id' param of event
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function OnAfterItemDelete(&$event)
+ {
+
+ }
+
+
+ /**
+ * Occures after an item has been copied to temp
+ * Id of copied item is passed as event' 'id' param
+ *
+ * @param kEvent $event
+ */
+ function OnAfterCopyToTemp(&$event)
+ {
+
+ }
+
+ /**
+ * Occures before an item is deleted from live table when copying from temp
+ * (temp handler deleted all items from live and then copy over all items from temp)
+ * Id of item being deleted is passed as event' 'id' param
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeDeleteFromLive(&$event)
+ {
+
+ }
+
+ /**
+ * Occures before an item is copied to live table (after all foreign keys have been updated)
+ * Id of item being copied is passed as event' 'id' param
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeCopyToLive(&$event)
+ {
+
+ }
+
+ /**
+ * !!! NOT FULLY IMPLEMENTED - SEE TEMP HANDLER COMMENTS (search by event name)!!!
+ * Occures after an item has been copied to live table
+ * Id of copied item is passed as event' 'id' param
+ *
+ * @param kEvent $event
+ */
+ function OnAfterCopyToLive(&$event)
+ {
+
+ }
+
+ /**
+ * Occures before an item is cloneded
+ * Id of ORIGINAL item is passed as event' 'id' param
+ * Do not call object' Update method in this event, just set needed fields!
+ *
+ * @param kEvent $event
+ */
+ function OnBeforeClone(&$event)
+ {
+
+ }
+
+ /**
+ * Occures after an item has been cloned
+ * Id of newly created item is passed as event' 'id' param
+ *
+ * @param kEvent $event
+ */
+ function OnAfterClone(&$event)
+ {
+
+ }
+
+ /**
+ * Ensures that popup will be closed automatically
+ * and parent window will be refreshed with template
+ * passed
+ *
+ * @param kEvent $event
+ * @access public
+ */
+ function finalizePopup(&$event, $main_prefix, $t)
+ {
+ $event->redirect = 'incs/close_popup';
+
+ // 2. substitute opener
+ $opener_stack = $this->Application->RecallVar('opener_stack');
+ $opener_stack = $opener_stack ? unserialize($opener_stack) : Array();
+ //array_pop($opener_stack);
+
+ $new_level = 'index4.php|'.ltrim($this->Application->BuildEnv($t, Array('m_opener' => 'u'), 'all'), ENV_VAR_NAME.'=');
+ array_push($opener_stack,$new_level);
+ $this->Application->StoreVar('opener_stack',serialize($opener_stack));
+ }
+
+ /**
+ * Create search filters based on search query
+ *
+ * @param kEvent $event
+ * @access protected
+ */
+ function OnSearch(&$event)
+ {
+ $event->setPseudoClass('_List');
+ $object =& $event->getObject();
+
+ $keyword = $this->Application->GetVar( $event->getPrefixSpecial(true).'_search_keyword');
+ $this->Application->StoreVar( $event->getPrefixSpecial().'_search_keyword', $keyword);
+
+ if(!$keyword)
+ {
+ $this->OnSearchReset($event);
+ return true;
+ }
+
+ $grid_name = $this->Application->GetVar('grid_name');
+ $grids = $this->Application->getUnitOption($event->Prefix,'Grids');
+ $search_fields = array_keys($grids[$grid_name]['Fields']);
+
+ $search_filter = Array();
+
+ foreach($search_fields as $search_field)
+ {
+ $filter_type = isset($object->VirtualFields[$search_field]) ? 'having' : 'where';
+ $field_type = getArrayValue($object->Fields[$search_field],'type');
+ if(!$field_type) $field_type = 'string'; // default LIKE filter for all fields without type
+ $keyword = trim($keyword);
+ $filter_value = '';
+ $table_name = ($filter_type == 'where') ? '`'.$object->TableName.'`.' : '';
+
+ // get field clause by formatter name and/or parameters
+ $formatter = getArrayValue($object->Fields[$search_field],'formatter');
+ switch ($formatter)
+ {
+ case 'kOptionsFormatter':
+ $search_keys = Array();
+ $use_phrases = getArrayValue($object->Fields[$search_field], 'use_phrases');
+ foreach($object->Fields[$search_field]['options'] as $key => $val)
+ {
+ $pattern = '#'.$keyword.'#i';
+ if ( preg_match($pattern, $use_phrases ? $this->Application->Phrase($val) : $val) ) {
+ array_push($search_keys, $key);
+ }
+ }
+ if (count($search_keys) > 0) {
+ $filter_value = $table_name.'`'.$search_field.'` IN ('.implode(',', $search_keys).')';
+ }
+
+ $field_processed = true;
+ break;
+
+ default:
+ $field_processed = false;
+ break;
+ }
+
+ // if not already processed by formatter, then get clause by field type
+
+ if(!$field_processed)
+ {
+ switch($field_type)
+ {
+ case 'int':
+ case 'integer':
+ case 'numeric':
+ if( !is_numeric($keyword) ) break;
+ $filter_value = $table_name.'`'.$search_field.'` = \''.$keyword.'\'';
+ break;
+
+ case 'double':
+ case 'float':
+ case 'real':
+ if( !is_numeric($keyword) ) break;
+ $filter_value = 'ABS('.$table_name.'`'.$search_field.'` - \''.str_replace(',','.',$keyword).'\') <= 0.0001';
+ break;
+
+ case 'string':
+ $keywords = explode(' ',$keyword);
+ foreach($keywords as $keyword_pos => $keyword_value)
+ {
+ $keywords[$keyword_pos] = $table_name.'`'.$search_field.'` LIKE \'%'.trim($keyword_value).'%\'';
+ }
+ $filter_value = '('.implode(') OR (',$keywords).')';
+ break;
+ }
+ }
+ if($filter_value) $search_filter[$search_field] = Array('type' => $filter_type, 'value' => $filter_value);
+ }
+
+ $this->Application->StoreVar($event->getPrefixSpecial().'_search_filter', serialize($search_filter) );
+ }
+
+ /**
+ * Clear search keywords
+ *
+ * @param kEvent $event
+ * @access protected
+ */
+ function OnSearchReset(&$event)
+ {
+ $this->Application->RemoveVar($event->getPrefixSpecial().'_search_filter');
+ $this->Application->RemoveVar($event->getPrefixSpecial().'_search_keyword');
+ }
+
+ /**
+ * Set's new filter value (filter_id meaning from config)
+ *
+ * @param kEvent $event
+ */
+ function OnSetFilter(&$event)
+ {
+ $filter_id = $this->Application->GetVar('filter_id');
+ $filter_value = $this->Application->GetVar('filter_value');
+
+ $view_filter = $this->Application->RecallVar($event->getPrefixSpecial().'_view_filter');
+ $view_filter = $view_filter ? unserialize($view_filter) : Array();
+
+ $view_filter[$filter_id] = $filter_value;
+
+ $this->Application->StoreVar( $event->getPrefixSpecial().'_view_filter', serialize($view_filter) );
+ }
+
+ /**
+ * Add/Remove all filters applied to list from "View" menu
+ *
+ * @param kEvent $event
+ */
+ function FilterAction(&$event)
+ {
+ $view_filter = Array();
+ $filter_menu = $this->Application->getUnitOption($event->Prefix,'FilterMenu');
+ switch ($event->Name)
+ {
+ case 'OnRemoveFilters':
+ $filter_value = 1;
+ break;
+
+ case 'OnApplyFilters':
+ $filter_value = 0;
+ break;
+ }
+
+ foreach($filter_menu['Filters'] as $filter_key => $filter_params)
+ {
+ if(!$filter_params) continue;
+ $view_filter[$filter_key] = $filter_value;
+ }
+ $this->Application->StoreVar( $event->getPrefixSpecial().'_view_filter', serialize($view_filter) );
+ }
+
+ function OnPreSaveAndOpenTranslator(&$event)
+ {
+ $this->Application->SetVar('allow_translation', true);
+ $event->CallSubEvent('OnPreSave');
+ $wnd_name = $this->Application->GetVar('translator_wnd_name');
+ if ($event->status == erSUCCESS) {
+ $t = $this->Application->GetVar('translator_t');
+ $object = $this->Application->recallObject($event->getPrefixSpecial());
+ $url = $this->Application->HREF($t, '', Array('pass'=>'all', $event->getPrefixSpecial(true).'_id' => $object->GetId()));
+ $field = $this->Application->GetVar('translator_field');
+ $after_script = "openTranslator('".$event->getPrefixSpecial()."', '".$field."', '".$url."', '".$wnd_name."')";
+ }
+ else {
+ $after_script = "wnd = window.open('', '".$wnd_name."'); wnd.close()";
+ }
+ $this->Application->SetVar('after_script', $after_script);
+ $event->redirect = false;
+ }
}
Index: trunk/core/kernel/session/login_event_handler.php
===================================================================
diff -u
--- trunk/core/kernel/session/login_event_handler.php (revision 0)
+++ trunk/core/kernel/session/login_event_handler.php (revision 1339)
@@ -0,0 +1,12 @@
+Application->Redirect('logout');
+ }
+ }
+
+
+?>
\ No newline at end of file
Index: trunk/core/kernel/utility/unit_config_reader.php
===================================================================
diff -u -r932 -r1339
--- trunk/core/kernel/utility/unit_config_reader.php (.../unit_config_reader.php) (revision 932)
+++ trunk/core/kernel/utility/unit_config_reader.php (.../unit_config_reader.php) (revision 1339)
@@ -9,7 +9,10 @@
* @access private
*/
var $configData=Array();
+ var $configFiles=Array();
+ var $CacheExpired = false;
+
/**
* Module names found during
* config reading
@@ -37,37 +40,170 @@
* @param string $folderPath
* @access public
*/
- function processFolder($folderPath)
+ function processFolder($folderPath, $cached)
{
$fh=opendir($folderPath);
while(($sub_folder=readdir($fh)))
{
$full_path=$folderPath.'/'.$sub_folder;
if( $this->isDir($full_path) && file_exists($this->getConfigName($full_path)) )
{
- include_once $this->getConfigName($full_path);
- $prefix=$config['Prefix'];
- $config['BasePath']=$full_path;
- $this->configData[$prefix] = $config;
- $this->parseConfig($prefix);
+ if (filemtime($full_path) > $cached) {
+ $this->CacheExpired = true;
+
+ $file = $this->getConfigName($full_path);
+ if ( defined('DEBUG_MODE') && dbg_ConstOn('DBG_PROFILE_INCLUDES')) {
+
+ if ( in_array($file, get_required_files()) ) return;
+ global $debugger;
+ $debugger->IncludeLevel++;
+ $before_time = getmicrotime();
+ $before_mem = memory_get_usage();
+ include_once($file);
+ $used_time = getmicrotime() - $before_time;
+ $used_mem = memory_get_usage() - $before_mem;
+ $debugger->IncludeLevel--;
+ $debugger->IncludesData['file'][] = str_replace(DOC_ROOT.BASE_PATH, '', $file);
+ $debugger->IncludesData['mem'][] = $used_mem;
+ $debugger->IncludesData['time'][] = $used_time;
+ $debugger->IncludesData['level'][] = -1;
+ }
+ else {
+ include_once($file);
+ }
+
+ $prefix=$config['Prefix'];
+ $config['BasePath']=$full_path;
+ $this->configData[$prefix] = $config;
+ }
}
}
}
+ function ParseConfigs()
+ {
+ foreach ($this->configData as $prefix => $config)
+ {
+ $this->parseConfig($prefix);
+ }
+ }
- function scanModules($folderPath)
+ function findConfigFiles($folderPath)
{
$fh=opendir($folderPath);
while(($sub_folder=readdir($fh)))
{
$full_path=$folderPath.'/'.$sub_folder;
- if( $this->isDir($full_path) )
+ if( $this->isDir($full_path))
{
- $this->processFolder($full_path);
+ if ( file_exists($this->getConfigName($full_path)) ) {
+ $this->configFiles[] = $this->getConfigName($full_path);
+ }
+ $this->findConfigFiles($full_path);
+
+// if (filemtime($full_path) > $cached) { }
+
}
}
}
+ function includeConfigFiles()
+ {
+ foreach ($this->configFiles as $filename) {
+ if ( defined('DEBUG_MODE') && dbg_ConstOn('DBG_PROFILE_INCLUDES')) {
+
+ if ( in_array($filename, get_required_files()) ) return;
+ global $debugger;
+ $debugger->IncludeLevel++;
+ $before_time = getmicrotime();
+ $before_mem = memory_get_usage();
+ include_once($filename);
+ $used_time = getmicrotime() - $before_time;
+ $used_mem = memory_get_usage() - $before_mem;
+ $debugger->IncludeLevel--;
+ $debugger->IncludesData['file'][] = str_replace(DOC_ROOT.BASE_PATH, '', $filename);
+ $debugger->IncludesData['mem'][] = $used_mem;
+ $debugger->IncludesData['time'][] = $used_time;
+ $debugger->IncludesData['level'][] = -1;
+ }
+ else {
+ include_once($filename);
+ }
+
+ $prefix=$config['Prefix'];
+ $config['BasePath']=dirname($filename);
+ $this->configData[$prefix] = $config;
+
+ }
+ }
+
+ function scanModules($folderPath)
+ {
+ global $debugger;
+
+ if (defined('CACHE_CONFIGS_FILES')) {
+ $conn =& $this->Application->GetADODBConnection();
+ $data = $conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "config_files"');
+ if ($data && $data['Cached'] > (time() - 3600) ) {
+ $this->configFiles = unserialize($data['Data']);
+ $files_cached = $data['Cached'];
+ }
+ else {
+ $files_cached = 0;
+ }
+ }
+ else {
+ $files_cached = 0;
+ }
+
+
+ if (defined('CACHE_CONFIGS_DATA')) {
+ $conn =& $this->Application->GetADODBConnection();
+ $data = $conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "config_data"');
+ if ($data && $data['Cached'] > (time() - 3600) ) {
+ $this->configData = unserialize($data['Data']);
+ $data_cached = $data['Cached'];
+ }
+ else {
+ $data_cached = 0;
+ }
+ }
+ else {
+ $data_cached = 0;
+ }
+
+ if ( !defined('CACHE_CONFIGS_FILES') || $files_cached == 0 ) {
+ $this->findConfigFiles($folderPath);
+ }
+
+ if ( !defined('CACHE_CONFIGS_DATA') || $data_cached == 0) {
+ $this->includeConfigFiles();
+ }
+
+ /*// && (time() - $cached) > 600) - to skip checking files modified dates
+ if ( !defined('CACHE_CONFIGS') ) {
+ $fh=opendir($folderPath);
+ while(($sub_folder=readdir($fh)))
+ {
+ $full_path=$folderPath.'/'.$sub_folder.'/units';
+ if( $this->isDir($full_path) )
+ {
+ $this->processFolder($full_path, $cached);
+ }
+ }
+ }*/
+ $this->ParseConfigs();
+
+ if (defined('CACHE_CONFIGS_FILES') && $files_cached == 0) {
+ $conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("config_files", '.$conn->qstr(serialize($this->configFiles)).', '.time().')');
+ }
+
+ if (defined('CACHE_CONFIGS_DATA') && $data_cached == 0) {
+ $conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("config_data", '.$conn->qstr(serialize($this->configData)).', '.time().')');
+ }
+
+ }
+
/**
* Register nessasary classes
*
@@ -81,13 +217,70 @@
$class_params=Array('ItemClass','ListClass','EventHandlerClass','TagProcessorClass');
foreach($class_params as $param_name)
{
+ if ( !(isset($config[$param_name]) ) ) continue;
$class_info =& $config[$param_name];
$pseudo_class = $this->getPrefixByParamName($param_name,$prefix);
$this->Application->registerClass( $class_info['class'],
$config['BasePath'].'/'.$class_info['file'],
$pseudo_class);
$event_manager->registerBuildEvent($pseudo_class,$class_info['build_event']);
}
+
+ if ( is_array(getArrayValue($config, 'Hooks')) ) {
+ foreach ($config['Hooks'] as $hook) {
+ $do_prefix = $hook['DoPrefix'] == '' ? $config['Prefix'] : $hook['DoPrefix'];
+
+ if ( !is_array($hook['HookToEvent']) ) {
+ $hook_events = Array( $hook['HookToEvent'] );
+ }
+ else {
+ $hook_events = $hook['HookToEvent'];
+ }
+ foreach ($hook_events as $hook_event) {
+ $this->Application->registerHook($hook['HookToPrefix'], $hook['HookToSpecial'], $hook_event, $hook['Mode'], $do_prefix, $hook['DoSpecial'], $hook['DoEvent'], $hook['Conditional']);
+ }
+ }
+ }
+
+ if ( is_array(getArrayValue($config, 'AggregateTags')) ) {
+ foreach ($config['AggregateTags'] as $aggregate_tag) {
+ $aggregate_tag['LocalPrefix'] = $config['Prefix'];
+ $this->Application->registerAggregateTag($aggregate_tag);
+ }
+ }
+
+ if ( $this->Application->isDebugMode() && dbg_ConstOn('DBG_VALIDATE_CONFIGS') && isset($config['TableName']) )
+ {
+ global $debugger;
+ $tablename = $config['TableName'];
+
+ $conn =& $this->Application->GetADODBConnection();
+ $res = $conn->Query("DESCRIBE $tablename");
+
+ foreach ($res as $field) {
+ $f_name = $field['Field'];
+ if (getArrayValue($config, 'Fields')) {
+ if ( !array_key_exists ($f_name, $config['Fields']) ) {
+ $debugger->appendHTML("Config Warning: Field $f_name exists in the database, but is not defined in config file for prefix ".$config['Prefix']."!");
+ safeDefine('DBG_RAISE_ON_WARNINGS', 1);
+ }
+ else {
+ $options = $config['Fields'][$f_name];
+ if ($field['Null'] == '') {
+ if ( $f_name != $config['IDField'] && !isset($options['not_null']) && !isset($options['required']) ) {
+ $debugger->appendHTML("Config Error: Field $f_name in config for prefix ".$config['Prefix']." is NOT NULL in the database, but is not configured as not_null or required!");
+ safeDefine('DBG_RAISE_ON_WARNINGS', 1);
+ }
+ if ( isset($options['not_null']) && !isset($options['default']) ) {
+ $debugger->appendHTML("Config Error: Field $f_name in config for prefix ".$config['Prefix']." is described as NOT NULL, but does not have DEFAULT value!");
+ safeDefine('DBG_RAISE_ON_WARNINGS', 1);
+ }
+ }
+
+ }
+ }
+ }
+ }
}
/**
@@ -101,10 +294,22 @@
*/
function getUnitOption($prefix,$name)
{
- return $this->configData[$prefix][$name];
+ return isset($this->configData[$prefix][$name])?$this->configData[$prefix][$name]:false;
}
/**
+ * Read all unit with $prefix options
+ *
+ * @param string $prefix
+ * @return Array
+ * @access public
+ */
+ function getUnitOptions($prefix)
+ {
+ return isset($this->configData[$prefix])?$this->configData[$prefix]:false;
+ }
+
+ /**
* Set's new unit option value
*
* @param string $prefix
Index: trunk/core/kernel/utility/event.php
===================================================================
diff -u -r958 -r1339
--- trunk/core/kernel/utility/event.php (.../event.php) (revision 958)
+++ trunk/core/kernel/utility/event.php (.../event.php) (revision 1339)
@@ -1,7 +1,20 @@
Init($prefix,$special);
+ $this->Name = getArrayValue($params,'name');
+ }
+ }
+
function setEventParam($name,$value)
{
$this->specificParams[$name]=$value;
}
function getEventParam($name)
{
- return isset($this->specificParams[$name])?$this->specificParams[$name]:false;
+ return getArrayValue($this->specificParams, $name);
}
function getPrefixSpecial($from_submit=false)
@@ -123,7 +181,7 @@
$this->pseudoClass=$this->Prefix.$appendix;
}
- function Init($prefix,$special)
+ function Init($prefix,$special='')
{
$this->Prefix=$prefix;
$this->pseudoClass=$prefix; // default value
@@ -135,12 +193,45 @@
* Returns object used in event
*
* @access public
+ * @return kDBBase
*/
- function &createObject()
+ function &getObject()
{
- return $this->Application->recallObject($this->Prefix_Special,$this->pseudoClass);
+ return $this->Application->recallObject($this->Prefix_Special,$this->pseudoClass);
}
+ /**
+ * Calls passed event by name in current prefix/special environment
+ * Called event gets this event as MasterEvent,
+ * but its results (status and redirect* properties are copied back to current event)
+ *
+ * @param string $name EventName to call
+ */
+ function CallSubEvent($name)
+ {
+ $child_event = new kEvent();
+ $child_event->MasterEvent =& $this;
+ $child_event->Prefix = $this->Prefix;
+ $child_event->Special = $this->Special;
+ $child_event->Prefix_Special = $this->Prefix_Special;
+ $child_event->redirect = $this->redirect;
+ $child_event->redirect_params = $this->redirect_params;
+ $child_event->redirect_script = $this->redirect_script;
+ $child_event->Name = $name;
+
+ $this->Application->HandleEvent( $child_event );
+
+ $this->status = $child_event->status;
+ $this->redirect = $child_event->redirect;
+ $this->redirect_params = $child_event->redirect_params;
+ $this->redirect_script = $child_event->redirect_script;
+ }
+
+ function SetRedirectParam($name, $value)
+ {
+ $this->redirect_params = array_merge_recursive2( $this->redirect_params, Array($name => $value) );
+ }
+
}
?>
\ No newline at end of file
Index: trunk/core/kernel/utility/params.php
===================================================================
diff -u -r939 -r1339
--- trunk/core/kernel/utility/params.php (.../params.php) (revision 939)
+++ trunk/core/kernel/utility/params.php (.../params.php) (revision 1339)
@@ -39,7 +39,8 @@
function Set($name, $val)
{
//echo "sessing params: [$name] = [$val] (class: ".get_class($this).")
";
- $this->_Params[strtolower($name)] = $val;
+// $this->_Params[strtolower($name)] = $val;
+ $this->_Params[$name] = $val;
}
/**
@@ -64,7 +65,7 @@
function Get($name, $mode=FALSE_ON_NULL)
{
// echo " name : '$name' || mode : $mode
";
- $name = strtolower($name);
+ //$name = strtolower($name);
if (array_key_exists($name, $this->_Params))
return $this->_Params[$name];
else
@@ -85,7 +86,8 @@
}
else {*/
foreach ($params as $name => $val)
- $this->Set(strtolower($name), $val);
+// $this->Set(strtolower($name), $val);
+ $this->Set($name, $val);
//}
}
@@ -101,6 +103,39 @@
}
}
+class kArray extends kBase {
+ var $_Array;
+
+ /**
+ * Returns array value with any deep key
+ *
+ * @return mixed
+ * @todo array_unshift doesn't accept parameters by reference, fix it's usage in this method
+ */
+ function GetArrayValue()
+ {
+ $args = func_get_args();
+ array_unshift($args, &$this->_Array);
+ return call_user_func_array('getArrayValue', $args);
+ }
+
+ function SetArrayValue()
+ {
+ $args = func_get_args();
+ $value = array_pop($args);
+
+ $arr =& $this->_Array;
+ for ($i=0; $isetType($type);
+ }
+
+ /**
+ * Enter description here...
+ *
+ * @param unknown_type $new_type
+ */
+ function setType($new_type)
+ {
+ $this->type = $new_type;
+ }
+
+ /**
+ * Adds new or replaces old filter with same name
+ *
+ * @param string $name
+ * @param mixed $clause kMultipleFilter object or where clause ifself
+ * @access public
+ */
+ function addFilter($name, $clause)
+ {
+ if( is_object($clause) && $clause->hasFilters() )
+ {
+ $this->filters[$name] = $clause->getSQL();
+ }
+ elseif( !is_object($clause) && $clause )
+ {
+ $this->filters[$name] = $clause;
+ }
+ }
+
+ /**
+ * Removes specified filter from filters list
+ *
+ * @param string $name
+ * @access public
+ */
+ function removeFilter($name)
+ {
+ unset($this->filters[$name]);
+ }
+
+ /**
+ * Remove all added filters
+ *
+ * @access public
+ */
+ function clearFilters()
+ {
+ $this->filters = Array();
+ }
+
+ /**
+ * Build where clause based on added filters and multiple filter type
+ *
+ * @return string
+ * @access public
+ */
+ function getSQL()
+ {
+ $filter_count = count($this->filters);
+ if(!$filter_count) return '';
+
+ return '('.implode(') '.$this->type.' (',$this->filters).')';
+ }
+
+ /**
+ * Allows to check if some filters are added to multiple filter
+ *
+ * @return bool
+ * @access public
+ */
+ function hasFilters()
+ {
+ return $this->filters ? true : false;
+ }
+ }
+?>
\ No newline at end of file
Index: trunk/core/kernel/processors/main_processor.php
===================================================================
diff -u -r950 -r1339
--- trunk/core/kernel/processors/main_processor.php (.../main_processor.php) (revision 950)
+++ trunk/core/kernel/processors/main_processor.php (.../main_processor.php) (revision 1339)
@@ -9,6 +9,8 @@
$actions =& $this->Application->recallObject('kActions');
$actions->Set('t', $this->Application->GetVar('t'));
$actions->Set('sid', $this->Application->GetSID());
+ $actions->Set('m_opener', $this->Application->GetVar('m_opener') );
+
}
/**
@@ -34,18 +36,33 @@
*/
function Base_Ref($params)
{
- $templates_path = substr(THEMES_PATH,1);
- return "";
+ $url = $this->Application->BaseURL().substr(THEMES_PATH,1).'/';
+ return '';
}
- /*function Base_URL($params)
+ /**
+ * Returns base url for web-site
+ *
+ * @return string
+ * @access public
+ */
+ function BaseURL()
{
- $templates_path = substr(THEMES_PATH,1);
- return $this->Application->BaseURL().$templates_path;
+ return $this->Application->BaseURL();
}
- function Base($params)
+ function TemplatesBase($params)
{
+ return $this->Application->BaseURL().THEMES_PATH;
+ }
+
+ function ProjectBase($params)
+ {
+ return $this->Application->BaseURL();
+ }
+
+ /*function Base($params)
+ {
return $this->Application->BaseURL().$params['add'];
}*/
@@ -61,17 +78,20 @@
*/
function T($params)
{
- $t=isset($params['t'])&&$params['t']?$params['t']:$this->Application->GetVar('t'); unset($params['t']);
- $prefix=isset($params['prefix'])?$params['prefix']:''; unset($params['prefix']);
+ //by default link to current template
+ $t=isset($params['t'])&&$params['t'] ? $params['t'] : $this->Application->GetVar('t'); unset($params['t']);
+ $prefix=isset($params['prefix']) ? $params['prefix'] : ''; unset($params['prefix']);
+ $index_file = isset($params['index_file']) ? $params['index_file'] : null; unset($params['index_file']);
- $pass=isset($params['pass'])?$params['pass']:$this->Application->GetVar('t_pass'); unset($params['pass']);
- $this->Application->SetVar('t_pass',$pass);
+ /*$pass=isset($params['pass']) ? $params['pass'] : $this->Application->GetVar('t_pass'); unset($params['pass']);
+ $this->Application->SetVar('t_pass', $pass);
- $pass_events=isset($params['pass_events'])&&$params['pass_events']?1:0; unset($params['pass_events']);
- $this->Application->SetVar('t_pass_events',$pass_events);
+ $pass_events = isset($params['pass_events']) && $params['pass_events'] ? 1 : 0; unset($params['pass_events']);
+ $this->Application->SetVar('t_pass_events', $pass_events);*/
- $this->Set($params); // set other params as application vars
- return $this->Application->HREF($t,$prefix);
+ //Use only implicit params passing, do not set into APP
+// $this->Set($params); // set other params as application vars
+ return $this->Application->HREF($t,$prefix,$params,$index_file);
}
/*// NEEDS TEST
@@ -146,7 +166,7 @@
* @return bool
* @access public
*/
- function Param_Equals($params)
+ function ParamEquals($params)
{
//$parser =& $this->Application->recallObject('TemplateParser');
$name = $this->SelectParam($params, 'name,var,param');
@@ -243,6 +263,19 @@
return $this->Application->GetVar($this->SelectParam($params, 'name,var,param'), EMPTY_ON_NULL);
}
+ /**
+ * Retrieves application constant
+ * value by name
+ *
+ * @param Array $params
+ * @return string
+ * @access public
+ */
+ function GetConst($params)
+ {
+ return defined($this->SelectParam($params, 'name,const')) ? constant($this->SelectParam($params, 'name,const,param')) : '';
+ }
+
/*function Config_Equals($params)
{
foreach ($params as $name => $val) {
@@ -274,20 +307,20 @@
return $o;
}
- /*function Odd_Even($params)
+ function Odd_Even($params)
{
$odd = $params['odd'];
$even = $params['even'];
- if ($this->Session->GetProperty('odd_even') == 'even') {
- $this->Session->SetProperty('odd_even', 'odd');
+ if ($this->Application->GetVar('odd_even') == 'even') {
+ $this->Application->SetVar('odd_even', 'odd');
return $even;
}
else {
- $this->Session->SetProperty('odd_even', 'even');
+ $this->Application->SetVar('odd_even', 'even');
return $odd;
}
- }*/
+ }
/**
* Returns phrase translation by name
@@ -307,13 +340,15 @@
function is_active($params)
{
$test_templ = $params["templ"];
- if (!$params['allow_empty']) {
- $if_true = $params["true"] != '' ? $params["true"] : 1;
- $if_false = $params["false"] != '' ? $params["false"] : 0;
+ if ( !getArrayValue($params,'allow_empty') )
+ {
+ $if_true=getArrayValue($params,'true')?$params['true']:1;
+ $if_false=getArrayValue($params,'false')?$params['false']:0;
}
- else {
- $if_true = $params["true"];
- $if_false = $params["false"];
+ else
+ {
+ $if_true=$params['true'];
+ $if_false=$params['false'];
}
if ( eregi("^$test_templ", $this->Application->GetVar('t')))
@@ -336,7 +371,7 @@
* @return string
* @access public
*/
- function Recall_Equals($params)
+ function RecallEquals($params)
{
$name = $params['var'];
$value = $params['value'];
@@ -352,7 +387,7 @@
* @return bool
* @access public
*/
- function Get_Equals($params)
+ function GetEquals($params)
{
$name = $this->SelectParam($params, 'var,name,param');
$value = $params['value'];
@@ -372,7 +407,7 @@
*/
function MyInclude($params)
{
- $BlockParser =& $this->Application->Factory->makeClass('TemplateParser');
+ $BlockParser =& $this->Application->makeClass('TemplateParser');
$BlockParser->SetParams($params);
$parser =& $this->Application->Parser;
@@ -381,7 +416,7 @@
$templates_cache =& $this->Application->recallObject('TemplatesCache');
- $res = $BlockParser->Parse( $templates_cache->GetTemplateBody($t) );
+ $res = $BlockParser->Parse( $templates_cache->GetTemplateBody($t), $t );
$this->Application->Parser =& $parser;
return $res;
@@ -461,17 +496,67 @@
}
/**
- * Find out what object were in link
- * used to move here and copy them to
- * form submit url
+ * Checks if debug mode is on
*
- * @param unknown_type $params
+ * @return bool
+ * @access public
*/
- function PrepareSubmitURL($params)
+ function IsDebugMode()
{
- $this->Application->ReBuildENV();
+ return $this->Application->isDebugMode();
}
+
+ function MassParse($params)
+ {
+ $qty = $params['qty'];
+ $block = $params['block'];
+ $mode = $params['mode'];
+
+ $o = '';
+ if ($mode == 'func') {
+ $func = create_function('$params', '
+ $o = \'\';
+ $o.= \'a\'.$params[\'param1\'].\' | \';
+ $o.= \'a\'.$params[\'param2\'].\' | \';
+ $o.= \'a\'.$params[\'param3\'].\' | \';
+ $o.= \'a\'.$params[\'param4\'].\' | \';
+ $o.= \'
\';
+ return $o;
+ ');
+ for ($i=1; $i<$qty; $i++) {
+ $block_params['param1'] = rand(1, 10000);
+ $block_params['param2'] = rand(1, 10000);
+ $block_params['param3'] = rand(1, 10000);
+ $block_params['param4'] = rand(1, 10000);
+ $o .= $func($block_params);
+ }
+ return $o;
+ }
+ $block_params['name'] = $block;
+
+ for ($i=0; $i<$qty; $i++) {
+ $block_params['param1'] = rand(1, 10000);
+ $block_params['param2'] = rand(1, 10000);
+ $block_params['param3'] = rand(1, 10000);
+ $block_params['param4'] = rand(1, 10000);
+ $block_params['passed'] = $params['passed'];
+ $block_params['prefix'] = 'm';
+
+ $o.= $this->Application->ParseBlock($block_params, 1);
+ }
+ return $o;
+ }
+
+ function AfterScript($params)
+ {
+ $after_script = $this->Application->GetVar('after_script');
+ if ( $after_script ) {
+ return '';
+ }
+ return '';
+ }
+
/*
function Login($params)
{
Index: trunk/core/kernel/utility/formatters.php
===================================================================
diff -u
--- trunk/core/kernel/utility/formatters.php (revision 0)
+++ trunk/core/kernel/utility/formatters.php (revision 1339)
@@ -0,0 +1,758 @@
+GetFieldOptions($field_name);
+ if ( isset($format) ) $options['format'] = $format;
+ $tc_value = $this->TypeCast($value,$options);
+ if( ($tc_value === false) || ($tc_value != $value) ) return $value; // for leaving badly formatted date on the form
+
+ if (isset($options['format'])) return sprintf($options['format'], $tc_value);
+
+ return $tc_value;
+ }
+
+//function Parse($value, $options, &$errors)
+ function Parse($value, $field_name, &$object)
+ {
+ if ($value == '') return NULL;
+
+ $options = $object->GetFieldOptions($field_name);
+ $tc_value = $this->TypeCast($value,$options);
+ if($tc_value === false) return $value; // for leaving badly formatted date on the form
+
+ if( isset($options['type']) )
+ {
+ if( preg_match('#double|float|real|numeric#', $options['type']) ) $tc_value = str_replace(',', '.', $tc_value);
+ }
+ return $tc_value;
+ }
+
+ function HumanFormat($format)
+ {
+ return $format;
+ }
+
+
+ /**
+ * The method is supposed to alter config options or cofigure object in some way based on its usage of formatters
+ * The methods is called for every field with formatter defined when configuring item.
+ * Could be used for adding additional VirtualFields to an object required by some special Formatter
+ *
+ * @param string $field_name
+ * @param array $field_options
+ * @param kDBBase $object
+ */
+ function PrepareOptions($field_name, &$field_options, &$object)
+ {
+
+ }
+
+ /**
+ * Used for split fields like timestamp -> date, time
+ * Called from DBItem to update sub fields values after loading item
+ *
+ * @param unknown_type $field
+ * @param unknown_type $value
+ * @param unknown_type $options
+ * @param unknown_type $object
+ */
+ function UpdateSubFields($field, $value, &$options, &$object)
+ {
+
+ }
+
+ /**
+ * Used for split fields like timestamp -> date, time
+ * Called from DBItem Validate (before validation) to get back master field value from its sub_fields
+ *
+ * @param unknown_type $field
+ * @param unknown_type $value
+ * @param unknown_type $options
+ * @param unknown_type $object
+ */
+ function UpdateMasterFields($field, $value, &$options, &$object)
+ {
+
+ }
+
+/* function GetErrorMsg($pseudo_error, $options)
+ {
+ if ( isset($options['error_msgs'][$pseudo_error]) ) {
+ return $options['error_msgs'][$pseudo_error];
+ }
+ else {
+ return $this->ErrorMsgs[$pseudo_error];
+ }
+ }*/
+
+}
+
+class kOptionsFormatter extends kFormatter {
+
+//function Format($value, $options, &$errors)
+ function Format($value, $field_name, &$object, $format=null)
+ {
+ if ( is_null($value) ) return '';
+
+ $options = $object->GetFieldOptions($field_name);
+ if ( isset($format) ) $options['format'] = $format;
+
+ $label = $options['options'][$value];
+ if( getArrayValue($options,'use_phrases') )
+ {
+ return $this->Application->Phrase($label);
+ }
+ else
+ {
+ return $label;
+ }
+ }
+
+}
+
+/**
+ * Replacement for kOptionsFormatter in case if options
+ * should be selected from database. Use this formatter
+ * only in case if formatter attached field is in edit form.
+ *
+ * For usage in grid just use LEFT JOIN clause to table
+ * where requested options are located.
+ */
+class kLEFTFormatter extends kFormatter {
+
+//function Format($value, $options, &$errors)
+ function Format($value, $field_name, &$object, $format=null)
+ {
+ if ( is_null($value) ) return '';
+
+ $options = $object->GetFieldOptions($field_name);
+ if ( isset($format) ) $options['format'] = $format;
+
+ if( !isset($options['options'][$value]) )
+ {
+ // required option is not defined in config => query for it
+ $db =& $this->Application->GetADODBConnection();
+ $sql = sprintf($options['left_sql'],$options['left_title_field'],$options['left_key_field'],$value);
+ $options['options'][$value] = $db->GetOne($sql);
+ }
+ return $options['options'][$value];
+ }
+
+//function Parse($value, $options, &$errors)
+ function Parse($value, $field_name, &$object)
+ {
+ if ($value == '') return NULL;
+
+ $options = $object->GetFieldOptions($field_name);
+ if( !array_search($value,$options['options']) )
+ {
+ // required option is not defined in config => query for it
+ $db =& $this->Application->GetADODBConnection();
+ $sql = sprintf($options['left_sql'],$options['left_key_field'],$options['left_title_field'],$value);
+ $found = $db->GetOne($sql);
+ if($found !== false) $options['options'][$found] = $value;
+ }
+ else
+ {
+ $found = array_search($value,$options['options']);
+ }
+ if($found === false) $found = $options['default'];
+ return $found;
+ }
+}
+
+
+class kDateFormatter extends kFormatter {
+
+/* function kDateFormatter()
+ {
+ parent::kFormatter();
+ $this->ErrorMsgs['bad_dformat'] = 'Please use correct date format (%s) ex. (%s)';
+ }
+ */
+
+ function PrepareOptions($field_name, &$field_options, &$object)
+ {
+ $date_format = getArrayValue($field_options, 'date_format');
+ $time_format = getArrayValue($field_options, 'time_format');
+
+ $language = $this->Application->recallObject('lang');
+
+ if ($date_format === false) $date_format = $language->GetDBField('DateFormat');
+ if ($time_format === false) $time_format = $language->GetDBField('TimeFormat');
+
+ if (!isset($field_options['date_time_separator'])) $field_options['date_time_separator'] = ' ';
+ $field_options['format'] = $date_format.$field_options['date_time_separator'].$time_format;
+ $field_options['sub_fields'] = Array('date' => $field_name.'_date', 'time' => $field_name.'_time');
+
+ $add_fields = Array();
+
+ $opts = Array('master_field' => $field_name, 'formatter'=>'kDateFormatter', 'format'=>$date_format);
+ if ( isset($field_options['default']) ) $opts['default'] = $field_options['default'];
+ if ( isset($field_options['required']) ) $opts['required'] = $field_options['required'];
+
+ $add_fields[$field_name.'_date'] = $opts;
+ $opts['format'] = $time_format;
+ $add_fields[$field_name.'_time'] = $opts;
+
+ if ( !isset($object->VirtualFields[$field_name]) ) {
+ // adding caluclated field to format date directly in the query
+ if ( !isset($object->CalculatedFields) || !is_array($object->CalculatedFields) ) {
+ $object->CalculatedFields = Array();
+ }
+ $object->CalculatedFields[$field_name.'_formatted'] = 'FROM_UNIXTIME('.'`%1$s`.'.$field_name.', \''.$this->SQLFormat($field_options['format']).'\')';
+ $opts['format'] = $field_options['format'];
+ $opts['required'] = 0;
+ unset($opts['master_field']);
+ $add_fields[$field_name.'_formatted'] = $opts;
+ }
+
+ $add_fields = array_merge_recursive2($add_fields, $object->VirtualFields);
+ $object->setVirtualFields($add_fields);
+ }
+
+ function UpdateSubFields($field, $value, &$options, &$object)
+ {
+ if ( $sub_fields = getArrayValue($options, 'sub_fields') ) {
+ if( isset($value) && $value )
+ {
+ $object->SetDBField( $sub_fields['date'], $value );
+ $object->SetDBField( $sub_fields['time'], $value );
+ }
+ }
+ }
+
+ function UpdateMasterFields($field, $value, &$options, &$object)
+ {
+ // when in master field - set own value from sub_fields
+ if ( $sub_fields = getArrayValue($options, 'sub_fields') ) {
+ // if date is not empty, but time is empty - set time to 0, otherwise master field fomratter will complain
+ // when we have only date field on form, we need time hidden field always empty, don't ask me why!
+ if ( $object->GetDBField($sub_fields['date']) != '' && $object->GetDBField($sub_fields['time']) == '' ) {
+ $object->SetDBField($sub_fields['time'], mktime(0, 0, 0));
+ }
+ $object->SetField($field, $object->GetField($sub_fields['date']).$options['date_time_separator'].$object->GetField($sub_fields['time']));
+ }
+ // when in one of sub_fields - call update for master_field to update its value from sub_fields [are you following ? :) ]
+ elseif ($master_field = getArrayValue($options, 'master_field') ) {
+ $this->UpdateMasterFields($master_field, null, $object->GetFieldOptions($master_field), $object);
+ }
+ }
+
+//function Format($value, $options, &$errors)
+ function Format($value, $field_name, &$object, $format=null)
+ {
+ if ( is_null($value) ) return '';
+ if ( !is_numeric($value) ) return $value; // for leaving badly formatted date on the form
+ settype($value, 'int');
+ if ( !is_int($value) ) return $value;
+
+ $options = $object->GetFieldOptions($field_name);
+ if ( isset($format) ) $options['format'] = $format;
+
+ return date($options['format'], $value);
+ }
+
+ function HumanFormat($format)
+ {
+ $patterns = Array('/m/',
+ '/n/',
+ '/d/',
+ '/j/',
+ '/y/',
+ '/Y/',
+ '/h|H/',
+ '/g|G/',
+ '/i/',
+ '/s/',
+ '/a|A/');
+ $replace = Array( 'mm',
+ 'm',
+ 'dd',
+ 'd',
+ 'yy',
+ 'yyyy',
+ 'hh',
+ 'h',
+ 'mm',
+ 'ss',
+ 'AM');
+ $res = preg_replace($patterns, $replace, $format);
+ return $res;
+ }
+
+ function SQLFormat($format)
+ {
+ $mapping = Array(
+ '/%/' => '%%',
+ '/(? '%p', // Lowercase Ante meridiem and Post meridiem => MySQL provides only uppercase
+ '/(? '%p', // Uppercase Ante meridiem and Post meridiem
+ '/(? '%d', // Day of the month, 2 digits with leading zeros
+ '/(? '%a', // A textual representation of a day, three letters
+ '/(? '%M', // A full textual representation of a month, such as January or March
+ '/(? '%l', // 12-hour format of an hour without leading zeros
+ '/(? '%k', // 24-hour format of an hour without leading zeros
+ '/(? '%h', // 12-hour format of an hour with leading zeros
+ '/(? '%H', // 24-hour format of an hour with leading zeros
+ '/(? '%i', // Minutes with leading zeros
+ '/(? 'N/A', // Whether or not the date is in daylights savings time
+
+ '/(? 'N/A', // English ordinal suffix for the day of the month, 2 characters, see below
+ '/jS/' => '%D', // MySQL can't return separate suffix, but could return date with suffix
+ '/(? '%e', // Day of the month without leading zeros
+ '/(? '%W', // A full textual representation of the day of the week
+ '/(? 'N/A', // Whether it's a leap year
+ '/(? '%m', // Numeric representation of a month, with leading zeros
+ '/(? '%b', // A short textual representation of a month, three letters
+ '/(? '%c', // Numeric representation of a month, without leading zeros
+ '/(? 'N/A', // Difference to Greenwich time (GMT) in hours
+ '/(? 'N/A', // RFC 2822 formatted date
+ '/(? '%s', // Seconds, with leading zeros
+ // S and jS moved before j - see above
+ '/(? 'N/A', // Number of days in the given month
+ '/(? 'N/A', // Timezone setting of this machine
+ '/(? 'N/A', // Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
+ '/(? '%w', // Numeric representation of the day of the week
+ '/(? '%v', // ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0)
+ '/(? '%Y', // A full numeric representation of a year, 4 digits
+ '/(? '%y', // A two digit representation of a year
+ '/(? 'N/A', // The day of the year (starting from 0) => MySQL starts from 1
+ '/(? 'N/A', // Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive.
+ );
+
+ $patterns = array_keys($mapping);
+ $replacements = array_values($mapping);
+
+ $res = preg_replace($patterns, $replacements, $format);
+ return $res;
+ }
+
+//function Parse($value, $options, &$errors)
+ function Parse($value, $field_name, &$object)
+ {
+ $options = $object->GetFieldOptions($field_name);
+
+ $dt_separator = getArrayValue($options,'date_time_separator');
+ if($dt_separator) $value = trim($value, $dt_separator);
+ if($value == '') return NULL;
+ //return strtotime($value);
+
+ $format = $options['format'];
+ if($dt_separator) $format = trim($format, $dt_separator);
+
+ $object->FieldErrors[$field_name]['params'] = Array( $this->HumanFormat($format), date($format) );
+ $object->FieldErrors[$field_name]['value'] = $value;
+
+ $hour = 0;
+ $minute = 0;
+ $second = 0;
+ $month = 1;
+ $day = 1;
+ $year = 1970;
+
+ $patterns['n'] = '([0-9]{1,2})';
+ $patterns['m'] = '([0-9]{1,2})';
+ $patterns['d'] = '([0-9]{1,2})';
+ $patterns['j'] = '([0-9]{1,2})';
+ $patterns['Y'] = '([0-9]{4})';
+ $patterns['y'] = '([0-9]{2})';
+ $patterns['G'] = '([0-9]{1,2})';
+ $patterns['g'] = '([0-9]{1,2})';
+ $patterns['H'] = '([0-9]{2})';
+ $patterns['h'] = '([0-9]{2})';
+ $patterns['i'] = '([0-9]{2})';
+ $patterns['s'] = '([0-9]{2})';
+ $patterns['a'] = '(am|pm)';
+ $patterns['A'] = '(AM|PM)';
+
+ $holders_mask = eregi_replace('[a-zA-Z]{1}', '([a-zA-Z]{1})', $format);
+ if (!ereg($holders_mask, $format, $holders)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ $values_mask = '/^'.$format.'$/';
+ foreach ($patterns as $key => $val) {
+ $values_mask = ereg_replace($key, $val, $values_mask);
+ }
+ // echo " values_mask : $values_mask
";
+
+ if (!preg_match($values_mask, $value, $values)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ for ($i = 1; $i < count($holders); $i++) {
+ switch ($holders[$i]) {
+ case 'n':
+ case 'm':
+ $month = $values[$i];
+ $month = ereg_replace("^0{1}", '', $month);
+ break;
+ case 'd':
+ $day = $values[$i];
+ $day = ereg_replace("^0{1}", '', $day);
+ break;
+ case 'Y':
+ $year = $values[$i];
+ break;
+ case 'y':
+ $year = $values[$i] >= 70 ? 1900 + $values[$i] : 2000 + $values[$i];
+ break;
+ case 'H':
+ case 'h':
+ case 'G':
+ case 'g':
+ $hour = $values[$i];
+ $hour = ereg_replace("^0{1}", '', $hour);
+ break;
+ case 'i':
+ $minute = $values[$i];
+ $minute = ereg_replace("^0{1}", '', $minute);
+ break;
+ case 's':
+ $second = $values[$i];
+ $second = ereg_replace("^0{1}", '', $second);
+ break;
+ case 'a':
+ case 'A':
+ if ($hour <= 12) { // if AM/PM used with 24-hour - could happen :)
+ if ($values[$i] == 'pm' || $values[$i] == 'PM') {
+ $hour += 12;
+ if ($hour == 24) $hour = 12;
+ }
+ elseif ($values[$i] == 'am' || $values[$i] == 'AM') {
+ if ($hour == 12) $hour = 0;
+ }
+ }
+ break;
+ }
+ }
+
+ //echo "day: $day, month: $month, year: $year, hour: $hour, minute: $minute
";
+
+ if (!($year >= 1970 && $year <= 2037)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ if (!($month >= 1 && $month <= 12)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ $months_days = Array ( 1 => 31,2 => 28, 3 => 31, 4 => 30,5 => 31,6 => 30, 7 => 31, 8 => 31,9 => 30,10 => 31,11 => 30,12 => 31);
+ if ($year % 4 == 0) $months_days[2] = 29;
+
+ if (!($day >=1 && $day <= $months_days[$month])) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ if (!($hour >=0 && $hour <= 23)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ if (!($minute >=0 && $minute <= 59)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+
+ if (!($second >=0 && $second <= 59)) {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_date_format';
+ return $value;
+ }
+ // echo "day: $day, month: $month, year: $year, hour: $hour, minute: $minute
";
+ return (mktime($hour, $minute, $second, $month, $day, $year));
+ }
+}
+
+class kUploadFormatter extends kFormatter
+{
+ var $DestinationPath;
+ var $FullPath;
+
+ function kUploadFormatter()
+ {
+ if ($this->DestinationPath)
+ {
+ $this->FullPath = DOC_ROOT.BASE_PATH.$this->DestinationPath;
+ }
+ parent::kBase();
+ }
+
+
+//function Parse($value, $options, &$errors)
+ function Parse($value, $field_name, &$object)
+ {
+ $ret = '';
+ $options = $object->GetFieldOptions($field_name);
+
+ if (getArrayValue($value, 'upload') && getArrayValue($value, 'error') == UPLOAD_ERR_NO_FILE)
+ {
+ return getArrayValue($value, 'upload');
+ }
+
+ if ( is_array($value) && $value['size'] )
+ {
+ if ( is_array($value) && $value['error'] === UPLOAD_ERR_OK )
+ {
+ if ( !in_array($value['type'], $options['allowed_types']) )
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_file_format';
+ }
+ elseif ( $value['size'] > ($options['max_size'] ? $options['max_size'] : MAX_UPLOAD_SIZE) )
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'bad_file_size';
+ }
+ elseif ( !is_writable($this->FullPath) )
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'cant_save_file';
+ }
+ else
+ {
+ $real_name = $this->ValidateFileName($this->FullPath, $value['name']);
+ $file_name = $this->FullPath.$real_name;
+ if ( !move_uploaded_file($value['tmp_name'], $file_name) )
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'cant_save_file';
+ }
+ else
+ {
+ $ret = $this->DestinationPath.$real_name;
+ }
+ }
+ }
+ else
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'cant_save_file';
+ }
+ }
+
+ if ($value['error'] && !( $value['error'] == UPLOAD_ERR_NO_FILE ) && !$object->FieldErrors[$field_name]['pseudo'])
+ {
+ $object->FieldErrors[$field_name]['pseudo'] = 'cant_save_file';
+ }
+
+ return $ret;
+ }
+
+ function ValidateFileName($path, $name)
+ {
+ $parts = pathinfo($name);
+ $ext = '.'.$parts['extension'];
+ $filename = substr($parts['basename'], 0, -strlen($ext));
+ $new_name = $filename.$ext;
+ while ( file_exists($path.'/'.$new_name) )
+ {
+ if ( preg_match("/({$filename}_)([0-9]*)($ext)/", $new_name, $regs) ) {
+ $new_name = $regs[1].($regs[2]+1).$regs[3];
+ }
+ else {
+ $new_name = $filename.'_1'.$ext;
+ }
+ }
+ return $new_name;
+ }
+
+}
+
+class kPictureFormatter extends kUploadFormatter
+{
+
+ function kPictureFormatter()
+ {
+ $this->NakeLookupPath = IMAGES_PATH;
+ $this->DestinationPath = IMAGES_PENDING_PATH;
+ parent::kUploadFormatter();
+ }
+
+}
+
+
+class kMultiLanguage extends kFormatter
+{
+
+ function LangFieldName($field_name)
+ {
+ $lang = $this->Application->GetVar('m_lang');
+ return 'l'.$lang.'_'.$field_name;
+ }
+
+ function PrepareOptions($field_name, &$field_options, &$object)
+ {
+ if (getArrayValue($object->Fields, $field_name, 'master_field')) return;
+
+ $lang_field_name = $this->LangFieldName($field_name);
+
+ //substitude title field
+ $title_field = $this->Application->getUnitOption($object->Prefix, 'TitleField');
+ if ($title_field = $field_name) {
+ $this->Application->setUnitOption($object->Prefix, 'TitleField', $lang_field_name);
+ }
+
+ //substitude fields
+ $fields = $this->Application->getUnitOption($object->Prefix, 'Fields');
+ if ( isset($fields[$field_name]) ) {
+
+ $fields[$lang_field_name] = $fields[$field_name];
+ $fields[$lang_field_name]['master_field'] = $field_name;
+ $object->Fields[$lang_field_name] = $fields[$lang_field_name];
+ $fields[$field_name]['required'] = false;
+ $object->Fields[$field_name]['required'] = false;
+ $object->VirtualFields[$field_name] = $object->Fields[$field_name];
+ }
+ $this->Application->setUnitOption($object->Prefix, 'Fields', $fields);
+
+ //substitude virtual fields
+ $virtual_fields = $this->Application->getUnitOption($object->Prefix, 'VirtualFields');
+ if ( isset($virtual_fields[$field_name]) ) {
+ $virtual_fields[$lang_field_name] = $virtual_fields[$field_name];
+ $virtual_fields[$lang_field_name]['master_field'] = $field_name;
+ $object->VirtualFields[$lang_field_name] = $virtual_fields[$lang_field_name];
+ $virtual_fields[$field_name]['required'] = false;
+ $object->VirtualFields[$field_name]['required'] = false;
+ }
+ $this->Application->setUnitOption($object->Prefix, 'VirtualFields', $virtual_fields);
+
+ //substitude grid fields
+ $grids = $this->Application->getUnitOption($object->Prefix, 'Grids');
+ foreach ($grids as $name => $grid) {
+ if ( getArrayValue($grid, 'Fields', $field_name) ) {
+ array_rename_key($grids[$name]['Fields'], $field_name, $lang_field_name);
+ }
+ }
+ $this->Application->setUnitOption($object->Prefix, 'Grids', $grids);
+
+ //substitude default sortings
+ $sortings = $this->Application->getUnitOption($object->Prefix, 'ListSortings');
+ foreach ($sortings as $special => $the_sortings) {
+ if (isset($the_sortings['ForcedSorting'])) {
+ array_rename_key($sortings[$special]['ForcedSorting'], $field_name, $lang_field_name);
+ }
+ if (isset($the_sortings['Sorting'])) {
+ array_rename_key($sortings[$special]['Sorting'], $field_name, $lang_field_name);
+ }
+ }
+ $this->Application->setUnitOption($object->Prefix, 'ListSortings', $sortings);
+
+ //TODO: substitude possible language-fields sortings after changing language
+ }
+
+ function UpdateSubFields($field, $value, &$options, &$object)
+ {
+ /*if ( $sub_fields = getArrayValue($options, 'sub_fields') ) {
+ if( isset($value) && $value )
+ {
+ $object->SetDBField( $sub_fields['date'], $value );
+ $object->SetDBField( $sub_fields['time'], $value );
+ }
+ }*/
+ }
+
+ function UpdateMasterFields($field, $value, &$options, &$object)
+ {
+ /*if ( $master_field = getArrayValue($object->Fields, $field, 'master_field') ) // this is Language field
+ {
+ $object->FieldErrors[$master_field] = $object->FieldErrors[$field]; // copy possible errors to master field
+ }
+ else { // THIS is master field
+ // do nothing
+ }*/
+
+
+ /*// when in master field - set own value from sub_fields
+ if ( $sub_fields = getArrayValue($options, 'sub_fields') ) {
+ // if date is not empty, but time is empty - set time to 0, otherwise master field fomratter will complain
+ // when we have only date field on form, we need time hidden field always empty, don't ask me why!
+ if ( $object->GetDBField($sub_fields['date']) != '' && $object->GetDBField($sub_fields['time']) == '' ) {
+ $object->SetDBField($sub_fields['time'], mktime(0, 0, 0));
+ }
+ $object->SetField($field, $object->GetField($sub_fields['date']).$options['date_time_separator'].$object->GetField($sub_fields['time']));
+ }
+ // when in one of sub_fields - call update for master_field to update its value from sub_fields [are you following ? :) ]
+ elseif ($master_field = getArrayValue($options, 'master_field') ) {
+ $this->UpdateMasterFields($master_field, null, $object->GetFieldOptions($master_field), $object);
+ }*/
+ }
+
+ function Format($value, $field_name, &$object, $format=null)
+ {
+ $master_field = getArrayValue($object->Fields, $field_name, 'master_field');
+ if (!$master_field) { // if THIS field is master it does NOT have reference to it's master_field
+ $lang = $this->Application->GetVar('m_lang');
+ $value = $object->GetDBField('l'.$lang.'_'.$field_name); //getting value of current language
+ $master_field = $field_name; // THIS is master_field
+ }
+ if ( $value == '' && $format != 'no_default') { // try to get default language value
+ $def_lang_value = $object->GetDBField('l'.$this->Application->GetDefaultLanguageId().'_'.$master_field);
+ if ($def_lang_value == '') return NULL;
+ return $def_lang_value; //return value from default language
+ }
+ return $value;
+ }
+
+ function Parse($value, $field_name, &$object)
+ {
+ $lang = $this->Application->GetVar('m_lang');
+ $def_lang = $this->Application->GetDefaultLanguageId();
+ $master_field = getArrayValue($object->Fields, $field_name, 'master_field');
+
+ if ( getArrayValue($object->Fields, $field_name, 'required') && ( (string) $value == '' ) ) {
+ $object->FieldErrors[$master_field]['pseudo'] = 'required';
+ };
+
+ if (!$this->Application->GetVar('allow_translation') && $lang != $def_lang && getArrayValue($object->Fields, $field_name, 'required')) {
+ $def_lang_field = 'l'.$def_lang.'_'.$master_field;
+ if ( !$object->ValidateRequired($def_lang_field, $object->Fields[$field_name]) ) {
+ $object->FieldErrors[$master_field]['pseudo'] = 'primary_lang_required';
+ }
+ }
+
+ if ($value == '') return NULL;
+ return $value;
+ }
+
+}
+
+?>
\ No newline at end of file
Index: trunk/core/kernel/kbase.php
===================================================================
diff -u -r932 -r1339
--- trunk/core/kernel/kbase.php (.../kbase.php) (revision 932)
+++ trunk/core/kernel/kbase.php (.../kbase.php) (revision 1339)
@@ -31,18 +31,42 @@
*/
var $Special='';
+ var $OriginalParams;
+
/**
+ * Set's application
+ *
+ * @return kBase
+ * @access public
+ */
+ function kBase()
+ {
+ $this->Application =& kApplication::Instance();
+ }
+
+ /**
+ * Create new instance of object
+ *
+ * @return kBase
+ */
+ function &makeClass()
+ {
+ return new kBase();
+ }
+
+ /**
* Set's prefix and special
*
* @param string $prefix
* @param string $special
* @access public
*/
- function Init($prefix,$special)
+ function Init($prefix,$special,$event_params=null)
{
$prefix=explode('_',$prefix,2);
$this->Prefix=$prefix[0];
$this->Special=$special;
+ $this->OriginalParams = $event_params;
}
/**
@@ -57,16 +81,15 @@
return rtrim($this->Prefix.'.'.$this->Special,'.');
}
- /**
- * Set's application
- *
- * @return kBase
- * @access public
- */
- function kBase()
+ function &getProperty($property_name)
{
- $this->Application =& kApplication::Instance();
+ return $this->$property_name;
}
+
+ function setProperty($property_name, &$property_value)
+ {
+ $this->$property_name =& $property_value;
+ }
}
class kDBBase extends kBase {
@@ -103,22 +126,45 @@
var $DisplayQueries = false;
/**
- * Object that holds all
- * formatters created
+ * Fields allowed to be set (from table + virtual)
+ *
+ * @var Array
+ * @access private
+ */
+ var $Fields=Array();
+
+ /**
+ * All virtual field names
*
- * @var kItemFormatter
+ * @var Array
* @access private
*/
- var $ItemFormatter;
+ var $VirtualFields=Array();
/**
+ * Fields that need to be queried using custom expression, e.g. IF(...) AS value
+ *
+ * @var Array
+ * @access private
+ */
+ var $CalculatedFields = Array();
+
+ /**
* Description
*
* @var string Item' database table name, without prefix
* @access public
*/
var $TableName;
+ /**
+ * Allows to determine object's table status ('temp' - temp table, '' - live table)
+ *
+ * @var string
+ * @access public
+ */
+ var $mode='';
+
function kDBBase()
{
parent::kBase();
@@ -138,6 +184,28 @@
}
/**
+ * Set object' TableName to Live table from config
+ *
+ * @access public
+ */
+ function SwitchToLive()
+ {
+ $this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName');
+ }
+
+ /**
+ * Set object' TableName to Temp table from config
+ *
+ * @access public
+ */
+ function SwitchToTemp()
+ {
+ $this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName');
+ $this->SetTableName( kTempTablesHandler::GetTempName($this->TableName) );
+ $this->mode = 't';
+ }
+
+ /**
* Sets SELECT part of list' query
*
* @access public
@@ -149,12 +217,38 @@
$this->SelectClause = $sql;
}
- function GetSelectSQL()
+ function GetSelectSQL($base_query=null)
{
- return sprintf($this->SelectClause,$this->TableName);
+ if( !isset($base_query) ) $base_query = $this->SelectClause;
+ return $q = str_replace( Array('%1$s','%s'), $this->TableName, $base_query);
}
/**
+ * Insert calculated fields sql into query in place of %2$s,
+ * return processed query.
+ *
+ * @param string $query
+ * @return string
+ */
+ function addCalculatedFields($query)
+ {
+ if($this->CalculatedFields)
+ {
+ $sql = Array();
+ foreach($this->CalculatedFields as $field_name => $field_expression)
+ {
+ $sql[] = '('.$field_expression.') AS '.$field_name;
+ }
+ $sql = implode(',',$sql);
+ return $this->Application->ReplaceLanguageTags( str_replace('%2$s', ','.$sql, $query) );
+ }
+ else
+ {
+ return str_replace('%2$s', '', $query);
+ }
+ }
+
+ /**
* Sets ID Field name used as primary key for loading items
*
* @access public
@@ -167,18 +261,123 @@
$this->IDField = $field_name;
}
+ function Configure()
+ {
+ $this->setTableName( $this->Application->getUnitOption($this->Prefix, 'TableName') );
+ $this->setIDField( $this->Application->getUnitOption($this->Prefix, 'IDField') );
+ $this->setConfigFields( $this->Application->getUnitOption($this->Prefix, 'Fields') );
+ $this->setVirtualFields( $this->Application->getUnitOption($this->Prefix, 'VirtualFields') );
+ $this->setCalculatedFields( $this->Application->getUnitOption($this->Prefix, 'CalculatedFields') );
+ $this->prepareConfigOptions(); // this should go last, but before setDefaultValues, order is significant!
+ $this->SetDefaultValues();
+ }
+
+ function setCalculatedFields($fields)
+ {
+ $this->CalculatedFields = isset($fields[$this->Special]) ? $fields[$this->Special] : (isset($fields['']) ? $fields[''] : false);
+ }
+
/**
+ * Set's field names from table
+ * from config
+ *
+ * @param Array $fields
+ * @access public
+ */
+ function setConfigFields($fields)
+ {
+ $this->Fields=$fields;
+ }
+
+ /**
+ * Set fields (+options) for fields that physically doesn't exist in database
+ *
+ * @param Array $fields
+ * @access public
+ */
+ function setVirtualFields($fields)
+ {
+ if($fields)
+ {
+ $this->VirtualFields = $fields;
+ $this->Fields = array_merge_recursive2($this->VirtualFields, $this->Fields);
+ }
+ }
+
+ function SetDefaultValues()
+ {
+
+ }
+
+ function SetFieldOptions($field, $options)
+ {
+ $this->Fields[$field] = $options;
+ }
+
+ function GetFieldOptions($field)
+ {
+ return isset($this->Fields[$field]) ? $this->Fields[$field] : Array();
+ }
+
+ /**
* Returns formatted field value
*
* @param string $field
* @return string
* @access public
*/
- function GetField($field)
+ function GetField($name, $format=null)
{
+ $options = $this->GetFieldOptions($name);
+ $val = $this->GetDBField($name);
+ $res = $val;
+ if (isset($options['formatter'])) {
+ $formatter =& $this->Application->recallObject($options['formatter']);
+ $res = $formatter->Format($val, $name, $this, $format );
+ }
+ return $res;
+ }
+
+ function HasField($name)
+ {
+
+ }
+
+ function GetFieldValues()
+ {
}
+ function UpdateFormattersSubFields()
+ {
+ foreach ($this->Fields as $field => $options) {
+ if (isset($options['formatter'])) {
+ $formatter =& $this->Application->recallObject($options['formatter']);
+ $formatter->UpdateSubFields($field, $this->GetDBField($field), $options, $this);
+ }
+ }
+ }
+
+ function prepareConfigOptions()
+ {
+ foreach (array_keys($this->Fields) as $field_name)
+ {
+ $field_options =& $this->Fields[$field_name];
+ if( isset($field_options['options_sql']) )
+ {
+ // replace with query result
+ $select_clause = $field_options['option_title_field'].','.$field_options['option_key_field'];
+ $sql = sprintf($field_options['options_sql'], $select_clause);
+ $field_options['options'] = $this->Conn->GetCol($sql, $field_options['option_key_field']);
+ unset($field_options['options_sql']);
+ }
+ if ( $formatter_class = getArrayValue($field_options, 'formatter') ) {
+ $formatter =& $this->Application->recallObject($formatter_class);
+ $formatter->PrepareOptions($field_name, $field_options, $this);
+ }
+ }
+ }
+
/**
* Returns unformatted field value
*
@@ -201,6 +400,33 @@
{
return $this->GetDBField($this->IDField);
}
+
+ /**
+ * Returns parent table information
+ *
+ * @param bool $from_temp load parent item from temp table
+ * @return Array
+ */
+ function getLinkedInfo()
+ {
+ $parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix');
+ if ( $parent_prefix )
+ {
+ // if this is linked table, then set id from main table
+ $table_info = Array(
+ 'TableName' => $this->Application->getUnitOption($this->Prefix,'TableName'),
+ 'IdField' => $this->Application->getUnitOption($this->Prefix,'IDField'),
+ 'ForeignKey' => $this->Application->getUnitOption($this->Prefix,'ForeignKey'),
+ 'ParentTableKey' => $this->Application->getUnitOption($this->Prefix,'ParentTableKey'),
+ 'ParentPrefix' => $parent_prefix
+ );
+
+ $main_object = $this->Application->recallObject($parent_prefix);
+ return array_merge($table_info, Array('ParentId'=> $main_object->GetDBField( $table_info['ParentTableKey'] ) ) );
+ }
+ return false;
+ }
+
}
?>
\ No newline at end of file
Index: trunk/core/kernel/db/db_connection.php
===================================================================
diff -u -r944 -r1339
--- trunk/core/kernel/db/db_connection.php (.../db_connection.php) (revision 944)
+++ trunk/core/kernel/db/db_connection.php (.../db_connection.php) (revision 1339)
@@ -4,7 +4,7 @@
* Multi database connection class
*
*/
- class DBConnection {
+ class kDBConnection {
/**
* Current database type
@@ -75,7 +75,7 @@
* @return DBConnection
* @access public
*/
- function DBConnection($dbType, $errorHandler = '')
+ function kDBConnection($dbType, $errorHandler = '')
{
$this->dbType = $dbType;
$this->initMetaFunctions();
@@ -168,17 +168,24 @@
* @param string $db
* @access public
*/
- function Connect($host,$user,$pass,$db)
+ function Connect($host,$user,$pass,$db,$force_new=false)
{
$func = $this->getMetaFunction('connect');
- $this->connectionID = $func($host,$user,$pass) or die('Can\'t connect to db');
+ $this->connectionID = $func($host,$user,$pass,$force_new) or die('Can\'t connect to db');
if($this->connectionID)
{
$this->setDB($db);
$this->showError();
}
}
+ function ReConnect($host,$user,$pass,$db)
+ {
+ $func = $this->getMetaFunction('close');
+ $func($this->connectionID);
+ $this->Connect($host,$user,$pass,$db);
+ }
+
/**
* Shows error message from previous operation
* if it failed
@@ -269,7 +276,7 @@
{
$sql .= ' '.$this->getLimitClause(0,1);
$ret = $this->Query($sql);
- if(!$ret) return $ret;
+ if(!$ret) return false;
return array_shift($ret);
}
@@ -482,18 +489,32 @@
*/
function qstr($s,$magic_quotes=false)
{
- $replace_quote = "\\'";
+ $replaceQuote = "\\'";
if (!$magic_quotes)
{
- return "'".str_replace("'",$replace_quote,$s)."'";
+ if ($replaceQuote[0] == '\\')
+ {
+ // only since php 4.0.5
+ $s = str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+ //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
+ }
+ return "'".str_replace("'",$replaceQuote,$s)."'";
}
// undo magic quotes for "
$s = str_replace('\\"','"',$s);
- return "'$s'";
+
+ if($replaceQuote == "\\'") // ' already quoted, no need to change anything
+ {
+ return "'$s'";
+ }
+ else // change \' to '' for sybase/mssql
+ {
+ $s = str_replace('\\\\','\\',$s);
+ return "'".str_replace("\\'",$replaceQuote,$s)."'";
+ }
}
-
/**
* Returns last error message
*