Index: branches/5.3.x/core/kernel/db/db_tag_processor.php =================================================================== --- branches/5.3.x/core/kernel/db/db_tag_processor.php (revision 16221) +++ branches/5.3.x/core/kernel/db/db_tag_processor.php (revision 16222) @@ -1,3110 +1,3109 @@ getObject($params); return $object->GetID() <= 0; } /** * Returns view menu name for current prefix * * @param Array $params * @return string */ function GetItemName($params) { $item_name = $this->getUnitConfig()->getViewMenuPhrase(); return $this->Application->Phrase($item_name); } function ViewMenu($params) { $block_params = $params; unset($block_params['block']); $block_params['name'] = $params['block']; $list =& $this->GetList($params); $block_params['PrefixSpecial'] = $list->getPrefixSpecial(); return $this->Application->ParseBlock($block_params); } function SearchKeyword($params) { $list =& $this->GetList($params); return $this->Application->RecallVar($list->getPrefixSpecial() . '_search_keyword'); } /** * Draw filter menu content (for ViewMenu) based on filters defined in config * * @param Array $params * @return string */ function DrawFilterMenu($params) { $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['spearator_block']; $separator = $this->Application->ParseBlock($block_params); $filter_menu = $this->getUnitConfig()->getFilterMenu(); if ( !$filter_menu ) { trigger_error('no filters defined for prefix ' . $this->Prefix . ', but DrawFilterMenu tag used', E_USER_NOTICE); return ''; } // 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)); + $this->Application->HandleEvent(new kEvent($this->getPrefixSpecial() . ':OnRemoveFilters')); $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) { $group_params = isset($filter_params['group_id']) ? $filter_menu['Groups'][$filter_params['group_id']] : Array (); if ( !isset($group_params['element_type']) ) { $group_params['element_type'] = 'checkbox'; } if ( !$filter_params ) { $filters[] = $separator; continue; } $block_params['label'] = $filter_params['label']; if ( getArrayValue($view_filter, $filter_key) ) { $submit = 0; if ( isset($params['old_style']) ) { $status = $group_params['element_type'] == 'checkbox' ? 1 : 2; } else { $status = $group_params['element_type'] == 'checkbox' ? '[\'img/check_on.gif\']' : '[\'img/menu_dot.gif\']'; } } else { $submit = 1; $status = 'null'; } $block_params['filter_action'] = 'set_filter("' . $prefix_special . '","' . $filter_key . '","' . $submit . '",' . $params['ajax'] . ');'; $block_params['filter_status'] = $status; // 1 - checkbox, 2 - radio, 0 - no image $filters[] = $this->Application->ParseBlock($block_params); } return implode('', $filters); } /** * Draws auto-refresh submenu in View Menu. * * @param Array $params * @return string */ function DrawAutoRefreshMenu($params) { $refresh_intervals = $this->Application->ConfigValue('AutoRefreshIntervals'); if (!$refresh_intervals) { trigger_error('no refresh intervals defined for prefix '.$this->Prefix.', but DrawAutoRefreshMenu tag used', E_USER_NOTICE); return ''; } $refresh_intervals = explode(',', $refresh_intervals); $view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view'); $current_refresh_interval = $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_refresh_interval.'.$view_name); if ($current_refresh_interval === false) { // if no interval was selected before, then choose 1st interval $current_refresh_interval = $refresh_intervals[0]; } $ret = ''; $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['render_as']; foreach ($refresh_intervals as $refresh_interval) { $block_params['label'] = $this->_formatInterval($refresh_interval); $block_params['refresh_interval'] = $refresh_interval; $block_params['selected'] = $current_refresh_interval == $refresh_interval; $ret .= $this->Application->ParseBlock($block_params); } return $ret; } /** * Tells, that current grid is using auto refresh * * @param Array $params * @return bool */ function UseAutoRefresh($params) { $view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view'); return $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_auto_refresh.'.$view_name); } /** * Returns current grid refresh interval * * @param Array $params * @return bool */ function AutoRefreshInterval($params) { $view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view'); return $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_refresh_interval.'.$view_name); } /** * Formats time interval using given text for hours and minutes * * @param int $interval minutes * @param string $hour_text Text for hours * @param string $min_text Text for minutes * @return string */ function _formatInterval($interval, $hour_text = 'h', $min_text = 'min') { // 65 $minutes = $interval % 60; $hours = ($interval - $minutes) / 60; $ret = ''; if ($hours) { $ret .= $hours.$hour_text.' '; } if ($minutes) { $ret .= $minutes.$min_text; } return $ret; } function IterateGridFields($params) { $mode = $params['mode']; $def_block = isset($params['block']) ? $params['block'] : ''; $force_block = isset($params['force_block']) ? $params['force_block'] : false; $grid = $this->getUnitConfig()->getGridByName($params['grid']); $grid_config = $grid['Fields']; $picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']); $grid_config = $picker_helper->apply($grid_config); if ( $mode == 'fields' ) { return "'" . join("','", array_keys($grid_config)) . "'"; } $object =& $this->GetList($params); $o = ''; $i = 0; foreach ($grid_config as $field => $options) { $i++; $block_params = $this->prepareTagParams($params); $block_params = array_merge($block_params, $options); $block_params['block_name'] = array_key_exists($mode . '_block', $block_params) ? $block_params[$mode . '_block'] : $def_block; $block_params['name'] = $force_block ? $force_block : $block_params['block_name']; $block_params['field'] = $field; $block_params['sort_field'] = isset($options['sort_field']) ? $options['sort_field'] : $field; $block_params['filter_field'] = isset($options['filter_field']) ? $options['filter_field'] : $field; $w = $picker_helper->getWidth($field); if ( $w ) { // column picker width overrides width from unit config $block_params['width'] = $w; } $field_options = $object->GetFieldOptions($field); if ( array_key_exists('use_phrases', $field_options) ) { $block_params['use_phrases'] = $field_options['use_phrases']; } $block_params['is_last'] = ($i == count($grid_config)); $o .= $this->Application->ParseBlock($block_params, 1); } return $o; } function PickerCRC($params) { $picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']); return $picker_helper->getData()->getChecksum(); } function FreezerPosition($params) { $picker_helper = new kColumnPickerHelper($this->getPrefixSpecial(), $params['grid']); $data = $picker_helper->getData(); $freezer_pos = $data->getOrder('__FREEZER__'); return $freezer_pos === false || $data->isHidden('__FREEZER__') ? 1 : ++$freezer_pos; } function GridFieldsCount($params) { $grid = $this->getUnitConfig()->getGridByName($params['grid']); return count($grid['Fields']); } /** * Prints list content using block specified * * @param Array $params * @return string * @access public */ function PrintList($params) { $params['no_table'] = 1; return $this->PrintList2($params); } function InitList($params) { $list_name = isset($params['list_name']) ? $params['list_name'] : ''; $names_mapping = $this->Application->GetVar('NamesToSpecialMapping', Array ()); if ( getArrayValue($names_mapping, $this->Prefix, $list_name) === false ) { $list =& $this->GetList($params); } } function BuildListSpecial($params) { return $this->Special; } /** * Returns key, that identifies each list on template (used internally, not tag) * * @param Array $params * @return string */ function getUniqueListKey($params) { $types = array_key_exists('types', $params) ? $params['types'] : ''; $except = array_key_exists('except', $params) ? $params['except'] : ''; $list_name = array_key_exists('list_name', $params) ? $params['list_name'] : ''; if (!$list_name) { $list_name = $this->Application->Parser->GetParam('list_name'); } return $types . $except . $list_name; } /** * Enter description here... * * @param Array $params * @return kDBList */ function &GetList($params) { $list_name = $this->SelectParam($params, 'list_name,name'); if ( !$list_name ) { $list_name = $this->Application->Parser->GetParam('list_name'); } $requery = isset($params['requery']) && $params['requery']; $main_list = array_key_exists('main_list', $params) && $params['main_list']; $names_mapping = $this->Application->GetVar('NamesToSpecialMapping', Array ()); if ( !array_key_exists($this->Prefix, $names_mapping) ) { // create prefix-based array to special mapping storage $names_mapping[$this->Prefix] = Array (); } if ( $list_name && !$requery ) { // list with "list_name" parameter if ( !array_key_exists($list_name, $names_mapping[$this->Prefix]) ) { // special missing -> generate one $special = $main_list ? $this->Special : $this->BuildListSpecial($params); } else { // get special, formed during list initialization $special = $names_mapping[$this->Prefix][$list_name]; } } else { // list without "list_name" parameter $special = $main_list ? $this->Special : $this->BuildListSpecial($params); } $prefix_special = rtrim($this->Prefix . '.' . $special, '.'); $params['skip_counting'] = true; $list = $this->Application->recallObject($prefix_special, $this->Prefix . '_List', $params); /* @var $list kDBList */ if ( !array_key_exists('skip_quering', $params) || !$params['skip_quering'] ) { if ( $requery ) { $this->Application->HandleEvent(new kEvent($prefix_special . ':OnListBuild', $params)); } if ( array_key_exists('offset', $params) ) { $list->SetOffset($list->GetOffset() + $params['offset']); // apply custom offset } $list->Query($requery); if ( array_key_exists('offset', $params) ) { $list->SetOffset($list->GetOffset() - $params['offset']); // remove custom offset } } $this->Init($this->Prefix, $special); if ( $list_name ) { $names_mapping[$this->Prefix][$list_name] = $special; $this->Application->SetVar('NamesToSpecialMapping', $names_mapping); } return $list; } function ListMarker($params) { $list =& $this->GetList($params); $ret = $list->getPrefixSpecial(); if (array_key_exists('as_preg', $params) && $params['as_preg']) { $ret = preg_quote($ret, '/'); } return $ret; } function CombinedSortingDropDownName($params) { $list =& $this->GetList($params); return $list->getPrefixSpecial() . '_CombinedSorting'; } /** * Prepares name for field with event in it (used only on front-end) * * @param Array $params * @return string */ function SubmitName($params) { $list =& $this->GetList($params); $prefix_special = $list->getPrefixSpecial(); return 'events[' . $prefix_special . '][' . $params['event'] . ']'; } /** * Prints list content using block specified * * @param Array $params * @return string * @access public */ function PrintList2($params) { $per_page = $this->SelectParam($params, 'per_page,max_items'); if ( $per_page !== false ) { $params['per_page'] = $per_page; } $list =& $this->GetList($params); $o = ''; $direction = (isset($params['direction']) && $params['direction'] == "H") ? "H" : "V"; $columns = (isset($params['columns'])) ? $params['columns'] : 1; $config = $this->getUnitConfig(); $id_field = (isset($params['id_field'])) ? $params['id_field'] : $config->getIDField(); if ( $columns > 1 && $direction == 'V' ) { $records_left = array_splice($list->Records, $list->GetSelectedCount()); // because we have 1 more record for "More..." link detection (don't need to sort it) $list->Records = $this->LinearToVertical($list->Records, $columns, $list->GetPerPage()); $list->Records = array_merge($list->Records, $records_left); } $list->GoFirst(); $block_params = $this->prepareTagParams($params); $block_params['name'] = $this->SelectParam($params, 'render_as,block'); $block_params['pass_params'] = 'true'; $block_params['column_width'] = $params['column_width'] = 100 / $columns; $block_start_row_params = $this->prepareTagParams($params); $block_start_row_params['name'] = $this->SelectParam($params, 'row_start_render_as,block_row_start,row_start_block'); $block_end_row_params = $this->prepareTagParams($params); $block_end_row_params['name'] = $this->SelectParam($params, 'row_end_render_as,block_row_end,row_end_block'); $block_empty_cell_params = $this->prepareTagParams($params); $block_empty_cell_params['name'] = $this->SelectParam($params, 'empty_cell_render_as,block_empty_cell,empty_cell_block'); $i = 0; $backup_id = $this->Application->GetVar($this->Prefix . '_id'); $displayed = Array (); $column_number = 1; $cache_mod_rw = $config->getCacheModRewrite() && $this->Application->RewriteURLs() && !$this->Application->isCachingType(CACHING_TYPE_MEMORY); $limit = isset($params['limit']) ? $params['limit'] : false; while (!$list->EOL() && (!$limit || $i<$limit)) { $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)); $block_params['is_last'] = ($i == $list->GetSelectedCount() - 1); $block_params['last_row'] = ($i + (($i + 1) % $columns) >= $list->GetSelectedCount() - 1); $block_params['not_last'] = !$block_params['is_last']; // for front-end if ( $cache_mod_rw ) { $serial_name = $this->Application->incrementCacheSerial($this->Prefix, $list->GetDBField($id_field), false); if ( $this->Prefix == 'c' ) { // for listing subcategories in category $this->Application->setCache('filenames[%' . $serial_name . '%]', $list->GetDBField('NamedParentPath')); $this->Application->setCache('category_tree[%CIDSerial:' . $list->GetDBField($id_field) . '%]', $list->GetDBField('TreeLeft') . ';' . $list->GetDBField('TreeRight')); } else { // for listing items in category $this->Application->setCache('filenames[%' . $serial_name . '%]', $list->GetDBField('Filename')); $serial_name = $this->Application->incrementCacheSerial('c', $list->GetDBField('CategoryId'), false); $this->Application->setCache('filenames[%' . $serial_name . '%]', $list->GetDBField('CategoryFilename')); } } if ( $i % $columns == 0 ) { // record in this iteration is first in row, then open row $column_number = 1; $o .= $block_start_row_params['name'] ? $this->Application->ParseBlock($block_start_row_params) : (!isset($params['no_table']) ? '' : ''); } else { $column_number++; } $block_params['first_col'] = $column_number == 1 ? 1 : 0; $block_params['last_col'] = $column_number == $columns ? 1 : 0; $block_params['column_number'] = $column_number; $block_params['num'] = ($i + 1); $this->PrepareListElementParams($list, $block_params); // new, no need to rewrite PrintList $o .= $this->Application->ParseBlock($block_params); array_push($displayed, $list->GetDBField($id_field)); if ( $direction == 'V' && $list->GetSelectedCount() % $columns > 0 && $column_number == ($columns - 1) && ceil(($i + 1) / $columns) > $list->GetSelectedCount() % ceil($list->GetSelectedCount() / $columns) ) { // if vertical output, then draw empty cells vertically, not horizontally $o .= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_empty_cell_params) : ' '; $i++; } if ( ($i + 1) % $columns == 0 ) { // record in next iteration is first in row too, then close this row $o .= $block_end_row_params['name'] ? $this->Application->ParseBlock($block_end_row_params) : (!isset($params['no_table']) ? '' : ''); } if ( $this->Special && $this->Application->hasObject($this->Prefix) ) { // object, produced by "kDBList::linkToParent" method, that otherwise would keep it's id $item = $this->Application->recallObject($this->Prefix); /* @var $item kDBBase */ if ( $item instanceof kDBItem ) { $this->Application->removeObject($this->Prefix); } } $list->GoNext(); $i++; } // append empty cells in place of missing cells in last row while ($i % $columns != 0) { // until next cell will be in new row append empty cells $o .= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_empty_cell_params) : ' '; if ( ($i + 1) % $columns == 0 ) { // record in next iteration is first in row too, then close this row $o .= $block_end_row_params['name'] ? $this->Application->ParseBlock($block_end_row_params) : ''; } $i++; } $cur_displayed = $this->Application->GetVar($this->Prefix . '_displayed_ids'); if ( !$cur_displayed ) { $cur_displayed = Array (); } else { $cur_displayed = explode(',', $cur_displayed); } $displayed = array_unique(array_merge($displayed, $cur_displayed)); $this->Application->SetVar($this->Prefix . '_displayed_ids', implode(',', $displayed)); $this->Application->SetVar($this->Prefix . '_id', $backup_id); $this->Application->SetVar($this->getPrefixSpecial() . '_id', ''); if ( isset($params['more_link_render_as']) ) { $block_params = $params; $params['render_as'] = $params['more_link_render_as']; $o .= $this->MoreLink($params); } return $o; } /** * Returns ID of previous record (related to current) in list. * Use only on item detail pages. * * @param Array $params * @return int * @access protected */ protected function PreviousResource($params) { $object = $this->getObject($params); /* @var $object kDBItem */ $list_helper = $this->Application->recallObject('ListHelper'); /* @var $list_helper ListHelper */ $select_clause = $object->getUnitConfig()->getNavigationSelectClause(null); return $list_helper->getNavigationResource($object, $params['list'], false, $select_clause); } /** * Returns ID of next record (related to current) in list. * Use only on item detail pages. * * @param Array $params * @return int * @access protected */ protected function NextResource($params) { $object = $this->getObject($params); /* @var $object kDBItem */ $list_helper = $this->Application->recallObject('ListHelper'); /* @var $list_helper ListHelper */ $select_clause = $object->getUnitConfig()->getNavigationSelectClause(null); return $list_helper->getNavigationResource($object, $params['list'], true, $select_clause); } /** * Allows to modify block params & current list record before PrintList parses record * * @param kDBList $object * @param Array $block_params * @return void * @access protected */ protected function PrepareListElementParams(&$object, &$block_params) { // $fields_hash =& $object->getCurrentRecord(); } /** * Renders given block name, when there there is more data in list, then are displayed right now * * @param Array $params * @return string * @access protected */ protected function MoreLink($params) { $per_page = $this->SelectParam($params, 'per_page,max_items'); if ( $per_page !== false ) { $params['per_page'] = $per_page; } $list =& $this->GetList($params); if ( $list->isCounted() ) { $has_next_page = $list->GetPage() < $list->GetTotalPages(); } else { // selected more, then on the page -> has more $has_next_page = $list->GetPerPage() < $list->GetRecordsCount(); } if ( $has_next_page ) { $block_params = Array ('name' => $this->SelectParam($params, 'render_as,block')); return $this->Application->ParseBlock($block_params); } return ''; } function PageLink($params) { static $default_per_page = Array (); $object =& $this->GetList($params); /* @var $object kDBList */ // process sorting if ($object->isMainList()) { if (!array_key_exists('sort_by', $params)) { $sort_by = $this->Application->GetVar('sort_by'); if ($sort_by !== false) { $params['sort_by'] = $sort_by; } } } $prefix_special = $this->getPrefixSpecial(); // process page $page = array_key_exists('page', $params) ? $params['page'] : $this->Application->GetVar($prefix_special . '_Page'); if (!$page) { // ensure, that page is always present if ($object->isMainList()) { $params[$prefix_special . '_Page'] = $this->Application->GetVar('page', 1); } else { $params[$prefix_special . '_Page'] = 1; } } if (array_key_exists('page', $params)) { $params[$prefix_special . '_Page'] = $params['page']; unset($params['page']); } // process per-page $per_page = array_key_exists('per_page', $params) ? $params['per_page'] : $this->Application->GetVar($prefix_special . '_PerPage'); if (!$per_page) { // ensure, that per-page is always present list ($prefix, ) = explode('.', $prefix_special); if (!array_key_exists($prefix, $default_per_page)) { $list_helper = $this->Application->recallObject('ListHelper'); /* @var $list_helper ListHelper */ $default_per_page[$prefix] = $list_helper->getDefaultPerPage($prefix); } if ($object->isMainList()) { $params[$prefix_special . '_PerPage'] = $this->Application->GetVar('per_page', $default_per_page[$prefix]); } else { $params[$prefix_special . '_PerPage'] = $default_per_page[$prefix]; } } if (array_key_exists('per_page', $params)) { $params[$prefix_special . '_PerPage'] = $params['per_page']; unset($params['per_page']); } if (!array_key_exists('pass', $params)) { $params['pass'] = 'm,' . $prefix_special; } // process template $t = array_key_exists('template', $params) ? $params['template'] : ''; unset($params['template']); if (!$t) { $t = $this->Application->GetVar('t'); } return $this->Application->HREF($t, '', $params); } /** * Deprecated * * @param array $params * @return int * @deprecated Parameter "column_width" of "PrintList" tag does that */ function ColumnWidth($params) { $columns = $this->Application->Parser->GetParam('columns'); return round(100/$columns).'%'; } /** * Append prefix and special to tag * params (get them from tagname) like * they were really passed as params * * @param Array $tag_params * @return Array * @access protected */ function prepareTagParams($tag_params = Array()) { $ret = $tag_params; $ret['Prefix'] = $this->Prefix; $ret['Special'] = $this->Special; $ret['PrefixSpecial'] = $this->getPrefixSpecial(); return $ret; } function GetISO($currency, $field_currency = '') { if ( $currency == 'selected' ) { return $this->Application->RecallVar('curr_iso'); } if ( $currency == 'primary' || $currency == '' ) { return $this->Application->GetPrimaryCurrency(); } // explicit currency return $currency == 'field' && $field_currency ? $field_currency : $currency; } /** * Convert primary currency to selected (if they are the same, converter will just return) * * @param float $value * @param string $target_iso * @param string $source_iso * @return float */ function ConvertCurrency($value, $target_iso, $source_iso = 'PRIMARY') { $converter = $this->Application->recallObject('CurrencyRates'); /* @var $converter CurrencyRates */ return $converter->Convert($value, $source_iso, $target_iso); } function AddCurrencySymbol($value, $iso, $decimal_tag = '') { $converter = $this->Application->recallObject('CurrencyRates'); /* @var $converter CurrencyRates */ return $converter->AddCurrencySymbol($value, $iso, $decimal_tag); } /** * Get's requested field value * * @param Array $params * @return string * @access public */ function Field($params) { $field = $this->SelectParam($params, 'name,field'); if (!$this->Application->isAdmin) { // don't apply kUtil::escape() on any field value on Front-End $params['no_special'] = 'no_special'; } $object = $this->getObject($params); /* @var $object kDBItem */ if (array_key_exists('db', $params) && $params['db']) { $value = $object->GetDBField($field); } else { if (array_key_exists('currency', $params) && $params['currency']) { $source_iso = isset($params['currency_field']) ? $object->GetDBField($params['currency_field']) : 'PRIMARY'; $target_iso = $this->GetISO($params['currency'], $source_iso); $original = $object->GetDBField($field); $value = $this->ConvertCurrency($original, $target_iso, $source_iso); $object->SetDBField($field, $value); $object->SetFieldOption($field, 'converted', true); } $format = array_key_exists('format', $params) ? $params['format'] : false; if (!$format || $format == '$format') { $format = NULL; } $value = $object->GetField($field, $format); if (array_key_exists('negative', $params) && $params['negative']) { if (strpos($value, '-') === 0) { $value = substr($value, 1); } else { $value = '-' . $value; } } if (array_key_exists('currency', $params) && $params['currency']) { $decimal_tag = isset($params['decimal_tag']) ? $params['decimal_tag'] : ''; $value = $this->AddCurrencySymbol($value, $target_iso, $decimal_tag); $params['no_special'] = 1; } } if (!array_key_exists('no_special', $params) || !$params['no_special']) { $value = kUtil::escape($value); } if (array_key_exists('checked', $params) && $params['checked']) { $value = ($value == ( isset($params['value']) ? $params['value'] : 1)) ? 'checked' : ''; } if (array_key_exists('plus_or_as_label', $params) && $params['plus_or_as_label']) { $value = substr($value, 0,1) == '+' ? substr($value, 1) : $this->Application->Phrase($value); } elseif (array_key_exists('as_label', $params) && $params['as_label']) { $value = $this->Application->Phrase($value); } $first_chars = $this->SelectParam($params,'first_chars,cut_first'); if ($first_chars) { $stripped_value = strip_tags($value, $this->SelectParam($params, 'allowed_tags')); if ( mb_strlen($stripped_value) > $first_chars ) { $value = preg_replace('/\s+?(\S+)?$/', '', mb_substr($stripped_value, 0, $first_chars + 1)) . ' ...'; } } if (array_key_exists('nl2br', $params) && $params['nl2br']) { $value = nl2br($value); } if ($value != '') { $this->Application->Parser->DataExists = true; } if (array_key_exists('currency', $params) && $params['currency']) { // restoring value in original currency, for other Field tags to work properly $object->SetDBField($field, $original); } return $value; } function FieldHintLabel($params) { if ( isset($params['direct_label']) && $params['direct_label'] ) { $label = $params['direct_label']; $hint = $this->Application->Phrase($label, false); } else { $label = $params['title_label']; $hint = $this->Application->Phrase('hint:' . $label, false); } return $hint != strtoupper('!' . $label . '!') ? $hint : ''; // $hint } /** * Returns formatted date + time on current language * * @param $params */ function DateField($params) { $field = $this->SelectParam($params, 'name,field'); if ($field) { $object = $this->getObject($params); /* @var $object kDBItem */ $timestamp = $object->GetDBField($field); } else { $timestamp = $params['value']; } $date = $timestamp; // prepare phrase replacements $replacements = Array ( 'l' => 'la_WeekDay', 'D' => 'la_WeekDay', 'M' => 'la_Month', 'F' => 'la_Month', ); // cases allow to append phrase suffix based on requested case (e.g. Genitive) $case_suffixes = array_key_exists('case_suffixes', $params) ? $params['case_suffixes'] : false; if ($case_suffixes) { // apply case suffixes (for russian language only) $case_suffixes = explode(',', $case_suffixes); foreach ($case_suffixes as $case_suffux) { list ($replacement_name, $case_suffix_value) = explode('=', $case_suffux, 2); $replacements[$replacement_name] .= $case_suffix_value; } } $format = array_key_exists('format', $params) ? $params['format'] : false; if (preg_match('/_regional_(.*)/', $format, $regs)) { $language = $this->Application->recallObject('lang.current'); /* @var $language kDBItem */ $format = $language->GetDBField($regs[1]); } elseif (!$format) { $format = null; } // escape formats, that are resolved to words by `date` foreach ($replacements as $format_char => $phrase_prefix) { if (strpos($format, $format_char) === false) { unset($replacements[$format_char]); continue; } $replacements[$format_char] = $this->Application->Phrase($phrase_prefix . date($format_char, $date)); $format = str_replace($format_char, '#' . ord($format_char) . '#', $format); } $date_formatted = date($format, $date); // unescape formats, that are resolved to words by `date` foreach ($replacements as $format_char => $format_replacement) { $date_formatted = str_replace('#' . ord($format_char) . '#', $format_replacement, $date_formatted); } return $date_formatted; } function SetField($params) { // $object = $this->getObject($params); /* @var $object kDBItem */ $dst_field = $this->SelectParam($params, 'name,field'); list($prefix_special, $src_field) = explode(':', $params['src']); $src_object = $this->Application->recallObject($prefix_special); /* @var $src_object kDBItem */ $object->SetDBField($dst_field, $src_object->GetDBField($src_field)); } /** * Depricated * * @param Array $params * @return string * @deprecated parameter "as_label" of "Field" tag does the same */ function PhraseField($params) { $field_label = $this->Field($params); $translation = $this->Application->Phrase( $field_label ); return $translation; } function Error($params) { $object = $this->getObject($params); /* @var $object kDBItem */ $field = $this->SelectParam($params, 'name,field'); return $object->GetErrorMsg($field, false); } function HasError($params) { if ($params['field'] == 'any') { $object = $this->getObject($params); /* @var $object kDBItem */ $skip_fields = array_key_exists('except', $params) ? $params['except'] : false; $skip_fields = $skip_fields ? explode(',', $skip_fields) : Array(); return $object->HasErrors($skip_fields); } else { $res = false; $fields = explode(',', $this->SelectParam($params, 'field,fields')); foreach ($fields as $field) { // call kDBTagProcessor::Error instead of kDBItem::GetErrorPseudo to have ability to override Error tag $params['field'] = $field; $res = $res || ($this->Error($params) != ''); } return $res; } } /** * Renders error message block, when there are errors on a form * * @param Array $params * @return string * @access protected */ protected function ErrorWarning($params) { if ( !isset($params['field']) ) { $params['field'] = 'any'; } if ( $this->HasError($params) ) { $params['prefix'] = $this->getPrefixSpecial(); return $this->Application->ParseBlock($params); } return ''; } function IsRequired($params) { $object = $this->getObject($params); /* @var $object kDBItem */ $field = $params['field']; $formatter_class = $object->GetFieldOption($field, 'formatter'); if ( $formatter_class == 'kMultiLanguage' ) { $formatter = $this->Application->recallObject($formatter_class); /* @var $formatter kMultiLanguage */ $field = $formatter->LangFieldName($field); } return $object->isRequired($field); } function FieldOption($params) { $object = $this->getObject($params);; $options = $object->GetFieldOptions($params['field']); $ret = isset($options[$params['option']]) ? $options[$params['option']] : ''; if (isset($params['as_label']) && $params['as_label']) $ret = $this->Application->ReplaceLanguageTags($ret); return $ret; } /** * Prints list a all possible field options * * @param Array $params * @return string * @access protected */ protected function PredefinedOptions($params) { $object = $this->getObject($params); /* @var $object kDBList */ $field = $params['field']; $value = array_key_exists('value', $params) ? $params['value'] : $object->GetDBField($field); $field_options = $object->GetFieldOptions($field); if (!array_key_exists('options', $field_options) || !is_array($field_options['options'])) { trigger_error('Options not defined for '.$object->Prefix.' field '.$field.'', E_USER_WARNING); return ''; } $options = $field_options['options']; if ( array_key_exists('has_empty', $params) && $params['has_empty'] ) { $empty_value = array_key_exists('empty_value', $params) ? $params['empty_value'] : ''; $empty_label = isset($params['empty_label']) ? $params['empty_label'] : ''; if ( $empty_label ) { if ( mb_substr($empty_label, 0, 1) == '+' ) { // using plain text instead of phrase label $empty_label = mb_substr($empty_label, 1); } else { $empty_label = $this->Application->Phrase($empty_label, false); } } // don't use other array merge function, because they will reset keys !!! $options = kUtil::array_merge_recursive(Array ($empty_value => $empty_label), $options); } $block_params = $this->prepareTagParams($params); $block_params['name'] = $this->SelectParam($params, 'render_as,block'); $block_params['pass_params'] = 'true'; if (method_exists($object, 'EOL') && count($object->Records) == 0) { // for drawing grid column filter $block_params['field_name'] = ''; } else { // deprecated (produces warning when used as grid filter), but used in Front-End (submission create), admin (submission view) $block_params['field_name'] = $this->InputName($params); } $selected_html = isset($params['selected']) ? $params['selected'] : 'selected'; $selected_param_name = array_key_exists('selected_param', $params) ? $params['selected_param'] : false; if (!$selected_param_name) { $selected_param_name = $selected_html; } $o = ''; if (array_key_exists('no_empty', $params) && $params['no_empty'] && !getArrayValue($options, '')) { // removes empty option, when present (needed?) array_shift($options); } $selected_option_keys = $this->getSelectedOptionKeys($value); if ( isset($params['selected_only']) && $params['selected_only'] ) { $options = $this->getSelectedOptions($options, $selected_option_keys); } $column_changed = false; $option_number = $column_number = 1; $option_count = count($options); $column_count = isset($params['columns']) ? $params['columns'] : 1; $options_per_column = ceil($option_count / $column_count); $block_params['option_count'] = $option_count; foreach ( $options as $option_key => $option_title ) { $block_params['key'] = $option_key; $block_params['option'] = $option_title; $block_params[$selected_param_name] = $this->isOptionSelected($option_key, $selected_option_keys) ? ' ' . $selected_html : ''; $block_params['column_number'] = $column_number; $block_params['column_changed'] = $column_changed; $block_params['option_number'] = $option_number; $block_params['is_last'] = $option_number == $option_count; $o .= $this->Application->ParseBlock($block_params); $column_changed = false; $option_number++; if ( $option_number > $column_number * $options_per_column ) { $column_number++; $column_changed = true; } } return $o; } /** * Returns unified representation of selected options based on field value. * * @param mixed $field_value Field value. * * @return array */ protected function getSelectedOptionKeys($field_value) { if ( strpos($field_value, '|') !== false ) { // multiple checkboxes OR multiselect return explode('|', trim($field_value, '|')); } // single selection radio OR checkboxes OR dropdown return array("$field_value"); } /** * Returns only options, that have been selected. * * @param array $options All options. * @param array $selected_option_keys Selected options. * * @return array */ protected function getSelectedOptions(array $options, array $selected_option_keys) { $ret = array(); foreach ( $options as $option_key => $option_title ) { if ( $this->isOptionSelected($option_key, $selected_option_keys) ) { $ret[$option_key] = $option_title; } } return $ret; } /** * Determines if given option is among selected ones. * * @param mixed $option_key Option key. * @param array $selected_option_keys Selected options. * * @return boolean */ protected function isOptionSelected($option_key, array $selected_option_keys) { return in_array("$option_key", $selected_option_keys, true); } function PredefinedSearchOptions($params) { $object =& $this->GetList($params); /* @var $object kDBList */ $params['value'] = $this->SearchField($params); return $this->PredefinedOptions($params); } function Format($params, $object = null) { $field = $this->SelectParam($params, 'name,field'); if ( !isset($object) ) { $object = $this->getObject($params); /* @var $object kDBItem */ } $options = $object->GetFieldOptions($field); $format = $options[$this->SelectParam($params, 'input_format') ? 'input_format' : 'format']; $formatter_class = array_key_exists('formatter', $options) ? $options['formatter'] : false; if ( $formatter_class ) { $formatter = $this->Application->recallObject($formatter_class); /* @var $formatter kFormatter */ $human_format = array_key_exists('human', $params) ? $params['human'] : false; $edit_size = array_key_exists('edit_size', $params) ? $params['edit_size'] : false; $sample = array_key_exists('sample', $params) ? $params['sample'] : false; if ( $sample ) { return $formatter->GetSample($field, $options, $object); } elseif ( $human_format || $edit_size ) { $format = $formatter->HumanFormat($format); return $edit_size ? strlen($format) : $format; } } return $format; } /** * Returns grid padination information * Can return links to pages * * @param Array $params * @return mixed */ function PageInfo($params) { $object =& $this->GetList($params); /* @var $object kDBList */ $type = $params['type']; unset($params['type']); // remove parameters used only by current tag $ret = ''; switch ($type) { case 'current': $ret = $object->GetPage(); break; case 'total': $ret = $object->GetTotalPages(); break; case 'prev': $ret = $object->GetPage() > 1 ? $object->GetPage() - 1 : false; break; case 'next': $ret = $object->GetPage() < $object->GetTotalPages() ? $object->GetPage() + 1 : false; break; } if ($ret && isset($params['as_link']) && $params['as_link']) { unset($params['as_link']); // remove parameters used only by current tag $params['page'] = $ret; $current_page = $object->GetPage(); // backup current page $ret = $this->PageLink($params); $this->Application->SetVar($object->getPrefixSpecial().'_Page', $current_page); // restore page } return $ret; } /** * Print grid pagination using * block names specified * * @param Array $params * @return string * @access public */ function PrintPages($params) { $list =& $this->GetList($params); $prefix_special = $list->getPrefixSpecial(); $total_pages = $list->GetTotalPages(); if ( $total_pages > 1 ) { $this->Application->Parser->DataExists = true; } if ( $total_pages == 0 ) { // display 1st page as selected in case if we have no pages at all $total_pages = 1; } $o = ''; // what are these 2 lines for? $this->Application->SetVar($prefix_special . '_event', ''); $this->Application->SetVar($prefix_special . '_id', ''); $current_page = $list->GetPage(); // $this->Application->RecallVar($prefix_special.'_Page'); $block_params = $this->prepareTagParams($params); $split = (isset($params['split']) ? $params['split'] : 10); $split_start = $current_page - ceil($split / 2); if ( $split_start < 1 ) { $split_start = 1; } $split_end = $split_start + $split - 1; if ( $split_end > $total_pages ) { $split_end = $total_pages; $split_start = max($split_end - $split + 1, 1); } if ( $current_page > 1 ) { $prev_block_params = $this->prepareTagParams($params); if ( $total_pages > $split ) { $prev_block_params['page'] = max($current_page - $split, 1); $prev_block_params['name'] = $this->SelectParam($params, 'prev_page_split_render_as,prev_page_split_block'); if ( $prev_block_params['name'] ) { $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $prev_block_params['page']); $o .= $this->Application->ParseBlock($prev_block_params); } } $prev_block_params['name'] = 'page'; $prev_block_params['page'] = $current_page - 1; $prev_block_params['name'] = $this->SelectParam($params, 'prev_page_render_as,block_prev_page,prev_page_block'); if ( $prev_block_params['name'] ) { $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $prev_block_params['page']); $o .= $this->Application->ParseBlock($prev_block_params); } } else { $no_prev_page_block = $this->SelectParam($params, 'no_prev_page_render_as,block_no_prev_page'); if ( $no_prev_page_block ) { $block_params['name'] = $no_prev_page_block; $o .= $this->Application->ParseBlock($block_params); } } $total_records = $list->GetRecordsCount(); $separator_params['name'] = $this->SelectParam($params, 'separator_render_as,block_separator'); for ($i = $split_start; $i <= $split_end; $i++) { $from_record = ($i - 1) * $list->GetPerPage(); $to_record = $from_record + $list->GetPerPage(); if ( $to_record > $total_records ) { $to_record = $total_records; } $block_params['from_record'] = $from_record + 1; $block_params['to_record'] = $to_record; if ( $i == $current_page ) { $block = $this->SelectParam($params, 'current_render_as,active_render_as,block_current,active_block'); } else { $block = $this->SelectParam($params, 'link_render_as,inactive_render_as,block_link,inactive_block'); } $block_params['name'] = $block; $block_params['page'] = $i; $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $block_params['page']); $o .= $this->Application->ParseBlock($block_params); if ( $this->SelectParam($params, 'separator_render_as,block_separator') && $i < $split_end ) { $o .= $this->Application->ParseBlock($separator_params); } } if ( $current_page < $total_pages ) { $next_block_params = $this->prepareTagParams($params); $next_block_params['page'] = $current_page + 1; $next_block_params['name'] = $this->SelectParam($params, 'next_page_render_as,block_next_page,next_page_block'); if ( $next_block_params['name'] ) { $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $next_block_params['page']); $o .= $this->Application->ParseBlock($next_block_params); } if ( $total_pages > $split ) { $next_block_params['page'] = min($current_page + $split, $total_pages); $next_block_params['name'] = $this->SelectParam($params, 'next_page_split_render_as,next_page_split_block'); if ( $next_block_params['name'] ) { $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $next_block_params['page']); $o .= $this->Application->ParseBlock($next_block_params); } } } else { $no_next_page_block = $this->SelectParam($params, 'no_next_page_render_as,block_no_next_page'); if ( $no_next_page_block ) { $block_params['name'] = $no_next_page_block; $o .= $this->Application->ParseBlock($block_params); } } $this->Application->SetVar($this->getPrefixSpecial() . '_Page', $current_page); return $o; } /** * Print grid pagination using * block names specified * * @param Array $params * @return string * @access public */ function PaginationBar($params) { return $this->PrintPages($params); } function PerPageBar($params) { $object =& $this->GetList($params); $ret = ''; $per_pages = explode(';', $params['per_pages']); $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['render_as']; foreach ($per_pages as $per_page) { $block_params['per_page'] = $per_page; $this->Application->SetVar($this->getPrefixSpecial() . '_PerPage', $per_page); $block_params['selected'] = $per_page == $object->GetPerPage(); $ret .= $this->Application->ParseBlock($block_params, 1); } $this->Application->SetVar($this->getPrefixSpecial() . '_PerPage', $object->GetPerPage()); return $ret; } /** * Returns field name (processed by kMultiLanguage formatter * if required) and item's id from it's IDField or field required * * @param Array $params * @return Array (id,field) * @access private */ function prepareInputName($params) { $object = $this->getObject($params); /* @var $object kDBItem */ $field = $this->SelectParam($params, 'name,field'); $formatter_class = $object->GetFieldOption($field, 'formatter'); if ($formatter_class == 'kMultiLanguage') { $formatter = $this->Application->recallObject($formatter_class); /* @var $formatter kMultiLanguage */ $force_primary = $object->GetFieldOption($field, 'force_primary'); $field = $formatter->LangFieldName($field, $force_primary); } if (array_key_exists('force_id', $params)) { $id = $params['force_id']; } else { $id_field = array_key_exists('IdField', $params) ? $params['IdField'] : false; $id = $id_field ? $object->GetDBField($id_field) : $object->GetID(); } return Array($id, $field); } /** * Returns input field name to * be placed on form (for correct * event processing) * * @param Array $params * @return string * @access public */ function InputName($params) { list($id, $field) = $this->prepareInputName($params); $ret = $this->getPrefixSpecial().'['.$id.']['.$field.']'; if (array_key_exists('as_preg', $params) && $params['as_preg']) { $ret = preg_quote($ret, '/'); } return $ret; } /** * Allows to override various field options through hidden fields with specific names in submit. * This tag generates this special names * * @param Array $params * @return string * @author Alex */ function FieldModifier($params) { list($id, $field) = $this->prepareInputName($params); $ret = 'field_modifiers['.$this->getPrefixSpecial().']['.$field.']['.$params['type'].']'; if (array_key_exists('as_preg', $params) && $params['as_preg']) { $ret = preg_quote($ret, '/'); } if (isset($params['value'])) { $object = $this->getObject($params); $field_modifiers[$field][$params['type']] = $params['value']; $object->ApplyFieldModifiers($field_modifiers); } return $ret; } /** * Returns index where 1st changeable sorting field begins * * @return int * @access private */ function getUserSortIndex() { $list_sortings = $this->getUnitConfig()->getListSortingsBySpecial($this, Array ()); $user_sorting_start = 0; $forced_sorting = getArrayValue($list_sortings, 'ForcedSorting'); return $forced_sorting ? count($forced_sorting) : $user_sorting_start; } /** * Returns order direction for given field * * * * @param Array $params * @return string * @access public */ function Order($params) { $field = $params['field']; $user_sorting_start = $this->getUserSortIndex(); $list =& $this->GetList($params); if ($list->GetOrderField($user_sorting_start) == $field) { return strtolower($list->GetOrderDirection($user_sorting_start)); } elseif($this->Application->ConfigValue('UseDoubleSorting') && $list->GetOrderField($user_sorting_start+1) == $field) { return '2_'.strtolower($list->GetOrderDirection($user_sorting_start+1)); } else { return 'no'; } } /** * Detects, that current sorting is not default * * @param Array $params * @return bool */ function OrderChanged($params) { $list =& $this->GetList($params); $list_helper = $this->Application->recallObject('ListHelper'); /* @var $list_helper ListHelper */ return $list_helper->hasUserSorting($list); } /** * Gets information of sorting field at "pos" position, * like sorting field name (type="field") or sorting direction (type="direction") * * @param Array $params * @return string * @access protected */ protected function OrderInfo($params) { $user_sorting_start = $this->getUserSortIndex() + --$params['pos']; $list =& $this->GetList($params); if ( $params['type'] == 'field' ) { return $list->GetOrderField($user_sorting_start); } if ( $params['type'] == 'direction' ) { return $list->GetOrderDirection($user_sorting_start); } return ''; } /** * Checks if sorting field/direction matches passed field/direction parameter * * @param Array $params * @return bool * @access protected */ protected function IsOrder($params) { $params['type'] = isset($params['field']) ? 'field' : 'direction'; $value = $this->OrderInfo($params); if ( isset($params['field']) ) { return $params['field'] == $value; } elseif ( isset($params['direction']) ) { return $params['direction'] == $value; } return false; } /** * Returns list per-page * * @param Array $params * @return int */ function PerPage($params) { $object =& $this->GetList($params); return $object->GetPerPage(); } /** * Checks if list perpage matches value specified * * @param Array $params * @return bool */ function PerPageEquals($params) { $object =& $this->GetList($params); return $object->GetPerPage() == $params['value']; } function SaveEvent($params) { // SaveEvent is set during OnItemBuild, but we may need it before any other tag calls OnItemBuild $object = $this->getObject($params); return $this->Application->GetVar($this->getPrefixSpecial().'_SaveEvent'); } function NextId($params) { $object = $this->getObject($params); $wid = $this->Application->GetTopmostWid($this->Prefix); $session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_'); $ids = explode(',', $this->Application->RecallVar($session_name)); $cur_id = $object->GetID(); $i = array_search($cur_id, $ids); if ($i !== false) { return $i < count($ids) - 1 ? $ids[$i + 1] : ''; } return ''; } function PrevId($params) { $object = $this->getObject($params); $wid = $this->Application->GetTopmostWid($this->Prefix); $session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_'); $ids = explode(',', $this->Application->RecallVar($session_name)); $cur_id = $object->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 * @deprecated */ function FieldEquals($params) { $object = $this->getObject($params); /* @var $object kDBItem */ return $object->GetDBField( $this->SelectParam($params, 'name,field') ) == $params['value']; } /** * Checks, that grid has icons defined and they should be shown * * @param Array $params * @return bool */ function UseItemIcons($params) { return array_key_exists('Icons', $this->getUnitConfig()->getGridByName($params['grid'])); } /** * Returns corresponding to grid layout selector column width * * @param Array $params * @return int */ function GridSelectorColumnWidth($params) { $width = 0; if ($params['selector']) { $width += $params['selector_width']; } if ($this->UseItemIcons($params)) { $width += $params['icon_width']; } return $width; } /** * Returns grids item selection mode (checkbox, radio, ) * * @param Array $params * @return string */ function GridSelector($params) { $grid = $this->getUnitConfig()->getGridByName($params['grid']); return array_key_exists('Selector', $grid) ? $grid['Selector'] : $params['default']; } function ItemIcon($params) { $config = $this->getUnitConfig(); $grid = $config->getGridByName($params['grid']); if ( !isset($grid['Icons']) ) { return ''; } $icons = $grid['Icons']; if ( isset($params['name']) ) { $icon_name = $params['name']; return isset($icons[$icon_name]) ? $icons[$icon_name] : ''; } $status_fields = $config->getStatusField(false, Array ()); if ( !$status_fields ) { return $icons['default']; } $object = $this->getObject($params); /* @var $object kDBList */ $icon = ''; foreach ($status_fields as $status_field) { $icon .= $object->GetDBField($status_field) . '_'; } $icon = rtrim($icon, '_'); return isset($icons[$icon]) ? $icons[$icon] : $icons['default']; } /** * Generates bluebar title + initializes prefixes used on page * * @param Array $params * @return string */ function SectionTitle($params) { $config = $this->getUnitConfig(); $preset_name = kUtil::replaceModuleSection($params['title_preset']); $title_info = $config->getTitlePresetByName($preset_name); if ( $title_info === false ) { $title = str_replace('#preset_name#', $preset_name, $params['title']); if ( $this->Application->ConfigValue('UseSmallHeader') && isset($params['group_title']) && $params['group_title'] ) { $title .= ' - ' . $params['group_title']; } return $title; } $default_title_preset = $config->getTitlePresetByName('default'); if ( $default_title_preset ) { // use default labels + custom labels specified in preset used $title_info = kUtil::array_merge_recursive($default_title_preset, $title_info); } $title = $title_info['format']; // 1. get objects in use for title construction $objects = Array (); $object_status = Array (); $status_labels = Array (); $prefixes = array_key_exists('prefixes', $title_info) ? $title_info['prefixes'] : false; $all_tag_params = array_key_exists('tag_params', $title_info) ? $title_info['tag_params'] : false; /* @var $prefixes Array */ if ( $prefixes ) { // extract tag_params passed directly to SectionTitle tag for specific prefix foreach ($params as $tp_name => $tp_value) { if ( preg_match('/(.*)\[(.*)\]/', $tp_name, $regs) ) { $all_tag_params[$regs[1]][$regs[2]] = $tp_value; unset($params[$tp_name]); } } $tag_params = Array (); foreach ($prefixes as $prefix_special) { $prefix_data = $this->Application->processPrefix($prefix_special); $prefix_data['prefix_special'] = rtrim($prefix_data['prefix_special'], '.'); if ( $all_tag_params ) { $tag_params = getArrayValue($all_tag_params, $prefix_data['prefix_special']); if ( !$tag_params ) { $tag_params = Array (); } } $tag_params = array_merge($params, $tag_params); $objects[$prefix_data['prefix_special']] = $this->Application->recallObject($prefix_data['prefix_special'], $prefix_data['prefix'], $tag_params); $object_status[$prefix_data['prefix_special']] = $objects[$prefix_data['prefix_special']]->IsNewItem() ? 'new' : 'edit'; // 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); } } } // replace to section title $section = array_key_exists('section', $params) ? $params['section'] : false; if ( $section ) { $sections_helper = $this->Application->recallObject('SectionsHelper'); /* @var $sections_helper kSectionsHelper */ $section_data =& $sections_helper->getSectionData($section); $title = str_replace('#section_label#', '!' . $section_data['label'] . '!', $title); } // 2. replace phrases if any found in format string $title = $this->Application->ReplaceLanguageTags($title, false); // 3. find and replace any replacement vars preg_match_all('/#(.*_.*)#/Uis', $title, $rets); if ( $rets[1] ) { $replacement_vars = array_keys(array_flip($rets[1])); foreach ($replacement_vars as $replacement_var) { $var_info = explode('_', $replacement_var, 2); $object =& $objects[$var_info[0]]; $new_value = $this->getInfo($object, $var_info[1]); $title = str_replace('#' . $replacement_var . '#', $new_value, $title); } } // replace trailing spaces inside title preset + '' occurrences into single space $title = preg_replace('/[ ]*\'\'[ ]*/', ' ', $title); if ( $this->Application->ConfigValue('UseSmallHeader') && isset($params['group_title']) && $params['group_title'] ) { $title .= ' - ' . $params['group_title']; } $first_chars = $this->SelectParam($params, 'first_chars,cut_first'); if ( $first_chars && !preg_match('/(.*)<\/a>/', $title) ) { // don't cut titles, that contain phrase translation links $stripped_title = strip_tags($title, $this->SelectParam($params, 'allowed_tags')); if ( mb_strlen($stripped_title) > $first_chars ) { $title = mb_substr($stripped_title, 0, $first_chars) . ' ...'; } } return $title; } /** * Returns information about list * * @param kDBList $object * @param string $info_type * @return string * @access protected */ protected function getInfo(&$object, $info_type) { switch ( $info_type ) { case 'titlefield': $field = $object->getUnitConfig()->getTitleField(); return $field !== false ? $object->GetField($field) : 'TitleField Missing'; break; case 'recordcount': if ( $object->GetRecordsCount(false) != $object->GetRecordsCount() ) { $of_phrase = $this->Application->Phrase('lc_of'); return $object->GetRecordsCount() . ' ' . $of_phrase . ' ' . $object->GetRecordsCount(false); } return $object->GetRecordsCount(); break; } return $object->GetField($info_type); } function GridInfo($params) { $object =& $this->GetList($params); /* @var $object kDBList */ switch ( $params['type'] ) { case 'filtered': return $object->GetRecordsCount(); case 'total': return $object->GetRecordsCount(false); case 'from': return $object->GetRecordsCount() ? $object->GetOffset() + 1 : 0; //0-based case 'to': $record_count = $object->GetRecordsCount(); return $object->GetPerPage(true) != -1 ? min($object->GetOffset() + $object->GetPerPage(), $record_count) : $record_count; case 'total_pages': return $object->GetTotalPages(); case 'needs_pagination': return ($object->GetPerPage(true) != -1) && (($object->GetRecordsCount() > $object->GetPerPage()) || ($object->GetPage() > 1)); } return false; } /** * 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->getObject($params); /* @var $object kDBItem */ $field = $params['field']; $helper = $this->Application->recallObject('InpCustomFieldsHelper'); /* @var $helper InpCustomFieldsHelper */ $element_type = $object->GetDBField($params['element_type_field']); if ($element_type == 'label') { $element_type = 'text'; } $formatter_class = $object->GetFieldOption($field, 'formatter'); switch ($element_type) { case 'select': case 'multiselect': case 'radio': if ($object->GetDBField('DirectOptions')) { // used for custom fields $options = $object->GetDBField('DirectOptions'); } else { // used for configuration $options = $helper->GetValuesHash( $object->GetDBField($params['value_list_field']) ); } $object->SetFieldOption($field, 'formatter', 'kOptionsFormatter'); $object->SetFieldOption($field, 'options', $options); break; case 'text': case 'textarea': case 'upload': $params['field_params'] = $helper->ParseConfigSQL($object->GetDBField($params['value_list_field'])); break; case 'password': case 'checkbox': default: break; } if (!$element_type) { throw new Exception('Element type missing for "' . $object->GetDBField('VariableName') . '" configuration variable'); } $params['name'] = $params['blocks_prefix'] . $element_type; // use $pass_params to pass 'SourcePrefix' parameter from PrintList to CustomInputName tag $ret = $this->Application->ParseBlock($params, 1); $object->SetFieldOption($field, 'formatter', $formatter_class); return $ret; } /** * Get's requested custom field value * * @param Array $params * @return string * @access public */ function CustomField($params) { $params['name'] = 'cust_'.$this->SelectParam($params, 'name,field'); return $this->Field($params); } function CustomFieldLabel($params) { $object = $this->getObject($params); $field = $this->SelectParam($params, 'name,field'); $sql = 'SELECT FieldLabel FROM ' . $this->Application->getUnitConfig('cf')->getTableName() . ' WHERE FieldName = ' . $this->Conn->qstr($field); return $this->Application->Phrase($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; // in case if after applying per_page limit record count less then // can fill requrested column count, then fill as much as we can $cols = min(ceil($per_page / $columns), ceil(count($arr) / $columns)); $imatrix = array(); for ($row = 0; $row < $rows; $row++) { for ($col = 0; $col < $cols; $col++) { $source_index = $row * $cols + $col; if (!isset($arr[$source_index])) { // in case if source array element count is less then element count in one row continue; } $imatrix[$col * $rows + $row] = $arr[$source_index]; } } ksort($imatrix); return array_values($imatrix); } /** * If data was modified & is in TempTables mode, then parse block with name passed; * remove modification mark if not in TempTables mode * * @param Array $params * @return string * @access protected */ protected function SaveWarning($params) { $main_prefix = array_key_exists('main_prefix', $params) ? $params['main_prefix'] : false; if ( $main_prefix ) { $top_prefix = $main_prefix; } else { $top_prefix = $this->Application->GetTopmostPrefix($this->Prefix); } $temp_tables = substr($this->Application->GetVar($top_prefix . '_mode'), 0, 1) == 't'; $modified = $this->Application->RecallVar($top_prefix . '_modified'); if ( $temp_tables && $modified ) { $block_params = $this->prepareTagParams($params); $block_params['name'] = $this->SelectParam($params, 'render_as,name'); $block_params['edit_mode'] = $temp_tables ? 1 : 0; return $this->Application->ParseBlock($block_params); } $this->Application->RemoveVar($top_prefix . '_modified'); return ''; } /** * Returns list record count queries (on all pages) * * @param Array $params * @return int */ function TotalRecords($params) { $list =& $this->GetList($params); return $list->GetRecordsCount(); } /** * Range filter field name * * @param Array $params * @return string */ function SearchInputName($params) { $field = $this->SelectParam($params, 'field,name'); $ret = 'custom_filters['.$this->getPrefixSpecial().']['.$params['grid'].']['.$field.']['.$params['filter_type'].']'; if (isset($params['type'])) { $ret .= '['.$params['type'].']'; } if (array_key_exists('as_preg', $params) && $params['as_preg']) { $ret = preg_quote($ret, '/'); } return $ret; } /** * Return range filter field value * * @param Array $params * @return string * @access protected */ protected function SearchField($params) // RangeValue { $field = $this->SelectParam($params, 'field,name'); $view_name = $this->Application->RecallVar($this->getPrefixSpecial() . '_current_view'); $custom_filter = $this->Application->RecallPersistentVar($this->getPrefixSpecial() . '_custom_filter.' . $view_name /*, ALLOW_DEFAULT_SETTINGS*/); $custom_filter = $custom_filter ? unserialize($custom_filter) : Array (); if ( isset($custom_filter[$params['grid']][$field]) ) { $ret = $custom_filter[$params['grid']][$field][$params['filter_type']]['submit_value']; if ( isset($params['type']) ) { $ret = $ret[$params['type']]; } if ( array_key_exists('formatted', $params) && $params['formatted'] ) { $object =& $this->GetList($params); $formatter_class = $object->GetFieldOption($field, 'formatter'); if ( $formatter_class ) { $formatter = $this->Application->recallObject($formatter_class); /* @var $formatter kFormatter */ $ret = $formatter->Format($ret, $field, $object); } } if ( !array_key_exists('no_special', $params) || !$params['no_special'] ) { $ret = kUtil::escape($ret); } return $ret; } return ''; } /** * Tells, that at least one of search filters is used by now * * @param Array $params * @return bool */ function SearchActive($params) { if ($this->Application->RecallVar($this->getPrefixSpecial() . '_search_keyword')) { // simple search filter is used return true; } $view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view'); $custom_filter = $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_custom_filter.'.$view_name/*, ALLOW_DEFAULT_SETTINGS*/); $custom_filter = $custom_filter ? unserialize($custom_filter) : Array(); return array_key_exists($params['grid'], $custom_filter); } function SearchFormat($params) { $object =& $this->GetList($params); return $this->Format($params, $object); } /** * Returns error of range field * * @param Array $params * @return string * @access protected */ protected function SearchError($params) { $field = $this->SelectParam($params, 'field,name'); $error_var_name = $this->getPrefixSpecial() . '_' . $field . '_error'; $pseudo = $this->Application->RecallVar($error_var_name); if ( $pseudo ) { $this->Application->RemoveVar($error_var_name); } $object = $this->Application->recallObject($this->Prefix . '.' . $this->Special . '-item', null, Array ('skip_autoload' => true)); /* @var $object kDBItem */ $object->SetError($field, $pseudo); return $object->GetErrorMsg($field, false); } /** * Returns object used in tag processor * * @param Array $params * @access public * @return kDBItem|kDBList */ function getObject($params = Array()) { $object = $this->Application->recallObject($this->getPrefixSpecial(), $this->Prefix, $params); /* @var $object kDBItem */ if ( isset($params['requery']) && $params['requery'] ) { $this->Application->HandleEvent(new kEvent($this->getPrefixSpecial() . ':LoadItem', $params)); } return $object; } /** * Checks if object propery value matches value passed * * @param Array $params * @return bool */ function PropertyEquals($params) { $object = $this->getObject($params); $property_name = $this->SelectParam($params, 'name,var,property'); return $object->$property_name == $params['value']; } function DisplayOriginal($params) { return false; } /*function MultipleEditing($params) { $wid = $this->Application->GetTopmostWid($this->Prefix); $session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_'); $selected_ids = explode(',', $this->Application->RecallVar($session_name)); $ret = ''; if ($selected_ids) { $selected_ids = explode(',', $selected_ids); $object = $this->getObject( kUtil::array_merge_recursive($params, Array('skip_autoload' => true)) ); $params['name'] = $params['render_as']; foreach ($selected_ids as $id) { $object->Load($id); $ret .= $this->Application->ParseBlock($params); } } return $ret; }*/ /** * Returns import/export process percent * * @param Array $params * @return int * @deprecated Please convert to event-model, not tag based */ function ExportStatus($params) { $export_object = $this->Application->recallObject('CatItemExportHelper'); /* @var $export_object kCatDBItemExportHelper */ $event = new kEvent($this->getPrefixSpecial().':OnDummy'); $action_method = 'perform'.ucfirst($this->Special); $field_values = $export_object->$action_method($event); // finish code is done from JS now if ($field_values['start_from'] >= $field_values['total_records']) { if ($this->Special == 'import') { // this is used? $this->Application->StoreVar('PermCache_UpdateRequired', 1); $this->Application->Redirect('categories/cache_updater', Array('m_opener' => 'r', 'pass' => 'm', 'continue' => 1)); } elseif ($this->Special == 'export') { // used for orders export in In-Commerce $finish_t = $this->Application->RecallVar('export_finish_t'); $this->Application->Redirect($finish_t, Array('pass' => 'all')); $this->Application->RemoveVar('export_finish_t'); } } $export_options = $export_object->loadOptions($event); return $export_options['start_from'] * 100 / $export_options['total_records']; } /** * Returns path where exported category items should be saved * * @param Array $params * @return string * @access protected */ protected function ExportPath($params) { $export_options = unserialize($this->Application->RecallVar($this->getPrefixSpecial() . '_options')); $extension = $export_options['ExportFormat'] == 1 ? 'csv' : 'xml'; $filename = preg_replace('/(.*)\.' . $extension . '$/', '\1', $export_options['ExportFilename']) . '.' . $extension; $path = EXPORT_PATH . '/'; if ( array_key_exists('as_url', $params) && $params['as_url'] ) { $path = str_replace(FULL_PATH . '/', $this->Application->BaseURL(), $path); } return $path . $filename; } function FieldTotal($params) { $list =& $this->GetList($params); $field = $this->SelectParam($params, 'field,name'); $total_function = array_key_exists('function', $params) ? $params['function'] : $list->getTotalFunction($field); if (array_key_exists('function_only', $params) && $params['function_only']) { return $total_function; } if (array_key_exists('currency', $params) && $params['currency']) { $iso = $this->GetISO($params['currency']); $original = $list->getTotal($field, $total_function); $value = $this->ConvertCurrency($original, $iso); $list->setTotal($field, $total_function, $value); } $value = $list->GetFormattedTotal($field, $total_function); if (array_key_exists('currency', $params) && $params['currency']) { $value = $this->AddCurrencySymbol($value, $iso); } return $value; } function FCKEditor($params) { $editor_name = array_key_exists('name', $params) ? $params['name'] : $this->InputName($params); $fck_helper = $this->Application->recallObject('FCKHelper'); /* @var $fck_helper fckFCKHelper */ if ( isset($params['mode']) && $params['mode'] == 'inline' ) { return $fck_helper->CKEditorInlineTag($editor_name, $params); } return $fck_helper->CKEditorTag($editor_name, $this->CKEditorValue($params), $params); } /** * Returns value, used by FCKEditor tag * * @param array $params * * @return string */ protected function CKEditorValue($params) { $params['no_special'] = 1; $params['format'] = array_key_exists('format', $params) ? $params['format'] . ';fck_ready' : 'fck_ready'; return $this->Field($params); } function IsNewItem($params) { $object = $this->getObject($params); return $object->IsNewItem(); } /** * Creates link to an item including only it's id * * @param Array $params * @return string * @access protected */ protected function ItemLink($params) { $object = $this->getObject($params); /* @var $object kDBItem */ if ( !isset($params['pass']) ) { $params['pass'] = 'm'; } $params[ $object->getPrefixSpecial() . '_id' ] = $object->GetID(); return $this->Application->ProcessParsedTag('m', 'T', $params); } /** * Creates a button for editing item in Admin Console * * @param Array $params * @return string * @access protected * @throws InvalidArgumentException */ protected function AdminEditButton($params) { if ( EDITING_MODE != EDITING_MODE_CONTENT ) { return ''; } $object = $this->getObject($params); /* @var $object kDBItem */ $item_prefix = isset($params['item_prefix']) ? $params['item_prefix'] : $this->Prefix; if ( isset($params['template']) ) { $template = $params['template']; } else { $item_config = $this->Application->getUnitConfig($item_prefix); $admin_template_prefix = $item_config->getAdminTemplatePrefix(); $template = $item_config->getAdminTemplatePath() . '/' . $admin_template_prefix . 'edit'; if ( !$admin_template_prefix ) { throw new InvalidArgumentException('Automatic admin editing template detection failed because of missing "AdminTemplatePrefix" unit config option in "' . $this->Prefix . '" unit config'); } } $form_name = 'kf_' . str_replace('-', '_', $item_prefix) . '_' . $object->GetID(); $button_icon = isset($params['button_icon']) ? $params['button_icon'] : 'content_mode.png'; $button_class = isset($params['button_class']) ? $params['button_class'] : 'admin-edit-btn'; $button_title = isset($params['button_title']) ? $params['button_title'] : 'la_btn_AdminEditItem'; if ( substr($button_title, 0, 1) == '+' ) { $button_title = substr($button_title, 1); } else { $button_title = $this->Application->Phrase($button_title, false, true); } $icon_url = $this->Application->BaseURL() . 'core/admin_templates/img/top_frame/icons/' . $button_icon; $button_onclick = '$form_name = ' . json_encode($form_name) . '; std_edit_item(' . json_encode($item_prefix) . ', ' . json_encode($template) . ');'; $button_code = ''; if ( !isset($params['pass']) ) { $params['pass'] = 'm,' . $item_prefix; } $params['m_opener'] = 'd'; $params[$item_prefix . '_id'] = $object->GetID(); if ( !isset($params['temp_mode']) || (isset($params['temp_mode']) && $params['temp_mode']) ) { $params[$item_prefix . '_mode'] = 't'; $params[$item_prefix . '_event'] = 'OnEdit'; } $params['front'] = 1; // to make opener stack work properly $params['__NO_REWRITE__'] = 1; // since admin link unset($params['button_icon'], $params['button_class'], $params['button_title'], $params['template'], $params['item_prefix'], $params['temp_mode']); // link from Front-End to Admin, don't remove "index.php" $form_name_escaped = kUtil::escape($form_name, kUtil::ESCAPE_HTML); $edit_url = kUtil::escape($this->Application->HREF($template, ADMIN_DIRECTORY, $params, 'index.php'), kUtil::ESCAPE_HTML); $edit_form = '
'; if ( isset($params['forms_later']) && $params['forms_later'] ) { $all_forms = $this->Application->GetVar('all_forms'); $this->Application->SetVar('all_forms', $all_forms . $edit_form); } else { $button_code .= $edit_form; } return $button_code; } /** * Calls OnNew event from template, when no other event submitted * * @param Array $params */ function PresetFormFields($params) { $prefix = $this->getPrefixSpecial(); if ( !$this->Application->GetVar($prefix . '_event') ) { $this->Application->HandleEvent(new kEvent($prefix . ':OnNew')); } } function PrintSerializedFields($params) { $object = $this->getObject($params); /* @var $object kDBItem */ $field = $this->SelectParam($params, 'field'); $data = unserialize($object->GetDBField($field)); $o = ''; $std_params['name'] = $params['render_as']; $std_params['field'] = $params['field']; $std_params['pass_params'] = true; foreach ($data as $key => $row) { $block_params = array_merge($std_params, $row, array('key'=>$key)); $o .= $this->Application->ParseBlock($block_params); } return $o; } /** * Checks if current prefix is main item * * @param Array $params * @return bool */ function IsTopmostPrefix($params) { return $this->Prefix == $this->Application->GetTopmostPrefix($this->Prefix); } function PermSection($params) { $section = $this->SelectParam($params, 'section,name'); return $this->getUnitConfig()->getPermSectionByName($section, ''); } function PerPageSelected($params) { $list =& $this->GetList($params); return $list->GetPerPage(true) == $params['per_page'] ? $params['selected'] : ''; } /** * Returns prefix + generated sepcial + any word * * @param Array $params * @return string */ function VarName($params) { $list =& $this->GetList($params); return $list->getPrefixSpecial() . '_' . $params['type']; } /** * Returns edit tabs by specified preset name or false in case of error * * @param string $preset_name * @return mixed */ function getEditTabs($preset_name) { $presets = $this->getUnitConfig()->getEditTabPresets(); if ( !$presets || !isset($presets[$preset_name]) || count($presets[$preset_name]) == 0 ) { return false; } return count($presets[$preset_name]) > 1 ? $presets[$preset_name] : false; } /** * Detects if specified preset has tabs in it * * @param Array $params * @return bool */ function HasEditTabs($params) { return $this->getEditTabs($params['preset_name']) ? true : false; } /** * Sorts edit tabs based on their priority * * @param Array $tab_a * @param Array $tab_b * @return int */ function sortEditTabs($tab_a, $tab_b) { if ($tab_a['priority'] == $tab_b['priority']) { return 0; } return $tab_a['priority'] < $tab_b['priority'] ? -1 : 1; } /** * Prints edit tabs based on preset name specified * * @param Array $params * @return string * @access protected */ protected function PrintEditTabs($params) { $edit_tabs = $this->getEditTabs($params['preset_name']); if ( !$edit_tabs ) { return ''; } usort($edit_tabs, Array (&$this, 'sortEditTabs')); $ret = ''; $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['render_as']; foreach ($edit_tabs as $tab_info) { $block_params['title'] = $tab_info['title']; $block_params['template'] = $tab_info['t']; $ret .= $this->Application->ParseBlock($block_params); } return $ret; } /** * Performs image resize to required dimensions and returns resulting url (cached resized image) * * @param Array $params * @return string */ function ImageSrc($params) { $max_width = isset($params['MaxWidth']) ? $params['MaxWidth'] : false; $max_height = isset($params['MaxHeight']) ? $params['MaxHeight'] : false; $logo_filename = isset($params['LogoFilename']) ? $params['LogoFilename'] : false; $logo_h_margin = isset($params['LogoHMargin']) ? $params['LogoHMargin'] : false; $logo_v_margin = isset($params['LogoVMargin']) ? $params['LogoVMargin'] : false; $object = $this->getObject($params); $field = $this->SelectParam($params, 'name,field'); return $object->GetField($field, 'resize:'.$max_width.'x'.$max_height.';wm:'.$logo_filename.'|'.$logo_h_margin.'|'.$logo_v_margin); } /** * Allows to retrieve given setting from unit config * * @param Array $params * @return mixed */ function UnitOption($params) { return $this->getUnitConfig()->getSetting($params['name']); } /** * Returns list of allowed toolbar buttons or false, when all is allowed * * @param Array $params * @return string */ function VisibleToolbarButtons($params) { $preset_name = kUtil::replaceModuleSection($params['title_preset']); $preset_info = $this->getUnitConfig()->getTitlePresetByName($preset_name); if ( !$preset_info ) { trigger_error('Title preset not specified or missing (in tag "' . $this->getPrefixSpecial() . ':' . __METHOD__ . '")', E_USER_NOTICE); return false; } if ( !array_key_exists('toolbar_buttons', $preset_info) || !is_array($preset_info['toolbar_buttons']) ) { return false; } // always add search buttons array_push($preset_info['toolbar_buttons'], 'search', 'search_reset_alt'); $toolbar_buttons = array_values($preset_info['toolbar_buttons']); // reset index return $toolbar_buttons ? trim(json_encode($toolbar_buttons), '[]') : 'false'; } /** * Checks, that "To" part of at least one of range filters is used * * @param Array $params * @return bool */ function RangeFiltersUsed($params) { $search_helper = $this->Application->recallObject('SearchHelper'); /* @var $search_helper kSearchHelper */ return $search_helper->rangeFiltersUsed($this->getPrefixSpecial(), $params['grid']); } /** * This is abstract tag, used to modify unit config data based on template, where it's used. * Tag is called from "combined_header" block in admin only. * * @param Array $params */ function ModifyUnitConfig($params) { } /** * Checks, that field is visible on edit form * * @param Array $params * @return bool */ function FieldVisible($params) { $check_field = $params['field']; $field_options = $this->_getFieldDefinition($check_field); if ( !$field_options ) { $params['field'] = 'Password'; return $check_field == 'VerifyPassword' ? $this->FieldVisible($params) : true; } $show_mode = array_key_exists('show_mode', $field_options) ? $field_options['show_mode'] : true; if ( $show_mode === smDEBUG ) { return defined('DEBUG_MODE') && DEBUG_MODE; } return $show_mode; } /** * Checks, that there area visible fields in given section on edit form * * @param Array $params * @return bool */ function FieldsVisible($params) { if ( !$params['fields'] ) { return true; } $check_fields = explode(',', $params['fields']); foreach ($check_fields as $check_field) { // when at least one field in subsection is visible, then subsection is visible too $field_options = $this->_getFieldDefinition($check_field); if ( $field_options ) { $show_mode = array_key_exists('show_mode', $field_options) ? $field_options['show_mode'] : true; } else { $show_mode = true; } if ( ($show_mode === true) || (($show_mode === smDEBUG) && (defined('DEBUG_MODE') && DEBUG_MODE)) ) { // field is visible return true; } } return false; } /** * Returns field definition * * @param string $field_name * @return Array * @access protected */ protected function _getFieldDefinition($field_name) { $config = $this->getUnitConfig(); $ret = $config->getFieldByName($field_name); if ( !$ret ) { $ret = $config->getVirtualFieldByName($field_name); } return $ret; } /** * Checks, that requested option is checked inside field value * * @param Array $params * @return bool */ function Selected($params) { $object = $this->getObject($params); /* @var $object kDBItem */ $field = $this->SelectParam($params, 'name,field'); $value = $object->GetDBField($field); if (strpos($value, '|') !== false) { $value = explode('|', substr($value, 1, -1)); return in_array($params['value'], $value); } return $value; } /** * Displays option name by it's value * * @param Array $params * @return string * @access protected */ protected function OptionValue($params) { $object = $this->getObject($params); /* @var $object kDBItem */ $value = $params['value']; $field = $this->SelectParam($params, 'name,field'); $field_options = $object->GetFieldOptions($field); if ( isset($field_options['options'][$value]) ) { $value = $field_options['options'][$value]; $use_phrases = isset($field_options['use_phrases']) ? $field_options['use_phrases'] : false; return $use_phrases ? $this->Application->Phrase($value) : $value; } return ''; } /** * Returns/sets form name for current object * * @param Array $params * @return string */ function FormName($params) { $form_name = $this->SelectParam($params, 'name,form,form_name'); if ( $form_name ) { $prefix = $this->getPrefixSpecial(); if ( $this->Application->hasObject( $this->getPrefixSpecial() ) ) { $object = $this->getObject($params); /* @var $object kDBItem */ if ( $object->getFormName() != $form_name ) { trigger_error('Setting form to "' . $form_name . '" failed, since object "' . $this->getPrefixSpecial() . '" is created before FormName tag (e.g. in event or another tag).', E_USER_WARNING); } } else { $forms = $this->Application->GetVar('forms', Array ()); $forms[ $this->getPrefixSpecial() ] = $form_name; $this->Application->SetVar('forms', $forms); } return ''; } $object = $this->getObject($params); /* @var $object kDBItem */ return $object->getFormName(); } /** * Just reloads the object using given parameters * * @param Array $params * @return string * @access protected */ protected function ReloadItem($params) { $params['requery'] = 1; $object = $this->getObject($params); /* @var $object kDBItem */ return ''; } } Index: branches/5.3.x/core/kernel/application.php =================================================================== --- branches/5.3.x/core/kernel/application.php (revision 16221) +++ branches/5.3.x/core/kernel/application.php (revision 16222) @@ -1,3076 +1,3070 @@ * The class encapsulates the main run-cycle of the script, provide access to all other objects in the framework.
*
* The class is a singleton, which means that there could be only one instance of kApplication in the script.
* This could be guaranteed by NOT calling the class constructor directly, but rather calling kApplication::Instance() method, * which returns an instance of the application. The method guarantees that it will return exactly the same instance for any call.
* See singleton pattern by GOF. */ class kApplication implements kiCacheable { /** * Location of module helper class (used in installator too) */ const MODULE_HELPER_PATH = '/../units/helpers/modules_helper.php'; /** * Is true, when Init method was called already, prevents double initialization * * @var bool */ public $InitDone = false; /** * Holds internal NParser object * * @var NParser * @access public */ public $Parser; /** * Holds parser output buffer * * @var string * @access protected */ protected $HTML = ''; /** * The main Factory used to create * almost any class of kernel and * modules * * @var kFactory * @access protected */ protected $Factory; /** * Template names, that will be used instead of regular templates * * @var Array * @access public */ public $ReplacementTemplates = Array (); /** * Registered routers, that are used during url building and parsing. * * @var array */ public $routers = array(); /** * Reference to debugger * * @var Debugger * @access public */ public $Debugger = null; /** * Holds all phrases used * in code and template * * @var kPhraseCache * @access public */ public $Phrases; /** * Modules table content, key - module name * * @var Array * @access public */ public $ModuleInfo = Array (); /** * Holds DBConnection * * @var IDBConnection * @access public */ public $Conn = null; /** * Reference to event log * * @var Array|kLogger * @access public */ protected $_logger = Array (); // performance needs: /** * Holds a reference to httpquery * * @var kHttpQuery * @access public */ public $HttpQuery = null; /** * Holds a reference to UnitConfigReader * * @var kUnitConfigReader * @access public */ public $UnitConfigReader = null; /** * Holds a reference to Session * * @var Session * @access public */ public $Session = null; /** * Holds a ref to kEventManager * * @var kEventManager * @access public */ public $EventManager = null; /** * Holds a ref to kUrlManager * * @var kUrlManager * @access public */ public $UrlManager = null; /** * Ref for TemplatesCache * * @var TemplatesCache * @access public */ public $TemplatesCache = null; /** * Holds current NParser tag while parsing, can be used in error messages to display template file and line * * @var _BlockTag * @access public */ public $CurrentNTag = null; /** * Object of unit caching class * * @var kCacheManager * @access public */ public $cacheManager = null; /** * Tells, that administrator has authenticated in administrative console * Should be used to manipulate data change OR data restrictions! * * @var bool * @access public */ public $isAdminUser = false; /** * Tells, that admin version of "index.php" was used, nothing more! * Should be used to manipulate data display! * * @var bool * @access public */ public $isAdmin = false; /** * Instance of site domain object * * @var kDBItem * @access public * @todo move away into separate module */ public $siteDomain = null; /** * Prevent kApplication class to be created directly, only via Instance method * * @access private */ private function __construct() { } final private function __clone() {} /** * Returns kApplication instance anywhere in the script. * * This method should be used to get single kApplication object instance anywhere in the * Kernel-based application. The method is guaranteed to return the SAME instance of kApplication. * Anywhere in the script you could write: * * $application =& kApplication::Instance(); * * or in an object: * * $this->Application =& kApplication::Instance(); * * to get the instance of kApplication. Note that we call the Instance method as STATIC - directly from the class. * To use descendant of standard kApplication class in your project you would need to define APPLICATION_CLASS constant * BEFORE calling kApplication::Instance() for the first time. If APPLICATION_CLASS is not defined the method would * create and return default KernelApplication instance. * * Pattern: Singleton * * @static * @return kApplication * @access public */ public static function &Instance() { static $instance = false; if ( !$instance ) { $class = defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication'; $instance = new $class(); } return $instance; } /** * Initializes the Application * * @param string $factory_class * @return bool Was Init actually made now or before * @access public * @see kHTTPQuery * @see Session * @see TemplatesCache */ public function Init($factory_class = 'kFactory') { if ( $this->InitDone ) { return false; } if ( preg_match('/utf-8/i', CHARSET) ) { setlocale(LC_ALL, 'en_US.UTF-8'); mb_internal_encoding('UTF-8'); } $this->isAdmin = kUtil::constOn('ADMIN'); if ( !kUtil::constOn('SKIP_OUT_COMPRESSION') ) { ob_start(); // collect any output from method (other then tags) into buffer } if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) { $this->Debugger->appendMemoryUsage('Application before Init:'); } $this->_logger = new kLogger($this->_logger); $this->Factory = new $factory_class(); $this->registerDefaultClasses(); $system_config = new kSystemConfig(true); $vars = $system_config->getData(); $db_class = isset($vars['Databases']) ? 'kDBLoadBalancer' : ($this->isDebugMode() ? 'kDBConnectionDebug' : 'kDBConnection'); $this->Conn = $this->Factory->makeClass($db_class, Array (SQL_TYPE, Array ($this->_logger, 'handleSQLError'))); $this->Conn->setup($vars); $this->cacheManager = $this->makeClass('kCacheManager'); $this->cacheManager->InitCache(); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Before UnitConfigReader'); } // init config reader and all managers $this->UnitConfigReader = $this->makeClass('kUnitConfigReader'); $this->UnitConfigReader->scanModules(MODULES_PATH); // Will also set routers. $this->registerModuleConstants(); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('After UnitConfigReader'); } define('MOD_REWRITE', $this->ConfigValue('UseModRewrite') && !$this->isAdmin ? 1 : 0); // start processing request $this->HttpQuery = $this->recallObject('kHTTPQuery'); $this->HttpQuery->process(); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed HTTPQuery initial'); } $this->Session = $this->recallObject('Session'); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed Session'); } $this->Session->ValidateExpired(); // needs mod_rewrite url already parsed to keep user at proper template after session expiration if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed HTTPQuery AfterInit'); } $this->cacheManager->LoadApplicationCache(); $site_timezone = $this->ConfigValue('Config_Site_Time'); if ( $site_timezone ) { date_default_timezone_set($site_timezone); } if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Loaded cache and phrases'); } $this->ValidateLogin(); // must be called before AfterConfigRead, because current user should be available there $this->UnitConfigReader->AfterConfigRead(); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed AfterConfigRead'); } if ( $this->GetVar('m_cat_id') === false ) { $this->SetVar('m_cat_id', 0); } if ( !$this->RecallVar('curr_iso') ) { $this->StoreVar('curr_iso', $this->GetPrimaryCurrency(), true); // true for optional } $visit_id = $this->RecallVar('visit_id'); if ( $visit_id !== false ) { $this->SetVar('visits_id', $visit_id); } if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->profileFinish('kernel4_startup'); } $this->InitDone = true; $this->HandleEvent(new kEvent('adm:OnStartup')); return true; } /** * Performs initialization of manager classes, that can be overridden from unit configs * * @return void * @access public * @throws Exception */ public function InitManagers() { if ( $this->InitDone ) { throw new Exception('Duplicate call of ' . __METHOD__, E_USER_ERROR); } $this->UrlManager = $this->makeClass('kUrlManager'); $this->EventManager = $this->makeClass('kEventManager'); $this->Phrases = $this->makeClass('kPhraseCache'); $this->RegisterDefaultBuildEvents(); } /** * Returns module information. Searches module by requested field * * @param string $field * @param mixed $value * @param string $return_field field value to returns, if not specified, then return all fields * @return Array */ public function findModule($field, $value, $return_field = null) { $found = $module_info = false; foreach ($this->ModuleInfo as $module_info) { if ( strtolower($module_info[$field]) == strtolower($value) ) { $found = true; break; } } if ( $found ) { return isset($return_field) ? $module_info[$return_field] : $module_info; } return false; } /** * Refreshes information about loaded modules * * @return void * @access public */ public function refreshModuleInfo() { if ( defined('IS_INSTALL') && IS_INSTALL && !$this->TableFound('Modules', true) ) { $this->registerModuleConstants(); $this->Factory->configureAutoloader(); return; } // use makeClass over recallObject, since used before kApplication initialization during installation $modules_helper = $this->makeClass('kModulesHelper'); /* @var $modules_helper kModulesHelper */ $this->Conn->nextQueryCachable = true; $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'Modules WHERE ' . $modules_helper->getWhereClause() . ' ORDER BY LoadOrder'; $this->ModuleInfo = $this->Conn->Query($sql, 'Name'); $this->registerModuleConstants(); $this->Factory->configureAutoloader(); } /** * Checks if passed language id if valid and sets it to primary otherwise * * @return void * @access public */ public function VerifyLanguageId() { /** @var LanguagesItem $lang */ $lang = $this->recallObject('lang.current'); if ( !$lang->isLoaded() || (!$this->isAdmin && !$lang->GetDBField('Enabled')) ) { if ( !defined('IS_INSTALL') ) { $this->ApplicationDie('Unknown or disabled language'); } } } /** * Checks if passed theme id if valid and sets it to primary otherwise * * @return void * @access public */ public function VerifyThemeId() { if ( $this->isAdmin ) { kUtil::safeDefine('THEMES_PATH', '/core/admin_templates'); return; } $path = $this->GetFrontThemePath(); if ( $path === false ) { $this->ApplicationDie('No Primary Theme Selected or Current Theme is Unknown or Disabled'); } kUtil::safeDefine('THEMES_PATH', $path); } /** * Returns relative path to current front-end theme * * @param bool $force * @return string * @access public */ public function GetFrontThemePath($force = false) { static $path = null; if ( !$force && isset($path) ) { return $path; } /** @var ThemeItem $theme */ $theme = $this->recallObject('theme.current'); if ( !$theme->isLoaded() || !$theme->GetDBField('Enabled') ) { return false; } // assign & then return, since it's static variable $path = '/themes/' . $theme->GetDBField('Name'); return $path; } /** * Returns primary front/admin language id * * @param bool $init * @return int * @access public */ public function GetDefaultLanguageId($init = false) { $cache_key = 'primary_language_info[%LangSerial%]'; $language_info = $this->getCache($cache_key); if ( $language_info === false ) { // cache primary language info first $language_config = $this->getUnitConfig('lang'); $table = $language_config->getTableName(); $id_field = $language_config->getIDField(); $this->Conn->nextQueryCachable = true; $sql = 'SELECT ' . $id_field . ', IF(AdminInterfaceLang, "Admin", "Front") AS LanguageKey FROM ' . $table . ' WHERE (AdminInterfaceLang = 1 OR PrimaryLang = 1) AND (Enabled = 1)'; $language_info = $this->Conn->GetCol($sql, 'LanguageKey'); if ( $language_info !== false ) { $this->setCache($cache_key, $language_info); } } $language_key = ($this->isAdmin && $init) || count($language_info) == 1 ? 'Admin' : 'Front'; if ( array_key_exists($language_key, $language_info) && $language_info[$language_key] > 0 ) { // get from cache return $language_info[$language_key]; } $language_id = $language_info && array_key_exists($language_key, $language_info) ? $language_info[$language_key] : false; if ( !$language_id && defined('IS_INSTALL') && IS_INSTALL ) { $language_id = 1; } return $language_id; } /** * Returns front-end primary theme id (even, when called from admin console) * * @param bool $force_front * @return int * @access public */ public function GetDefaultThemeId($force_front = false) { static $theme_id = 0; if ( $theme_id > 0 ) { return $theme_id; } if ( kUtil::constOn('DBG_FORCE_THEME') ) { $theme_id = DBG_FORCE_THEME; } elseif ( !$force_front && $this->isAdmin ) { $theme_id = 999; } else { $cache_key = 'primary_theme[%ThemeSerial%]'; $theme_id = $this->getCache($cache_key); if ( $theme_id === false ) { $this->Conn->nextQueryCachable = true; $theme_config = $this->getUnitConfig('theme'); $sql = 'SELECT ' . $theme_config->getIDField() . ' FROM ' . $theme_config->getTableName() . ' WHERE (PrimaryTheme = 1) AND (Enabled = 1)'; $theme_id = $this->Conn->GetOne($sql); if ( $theme_id !== false ) { $this->setCache($cache_key, $theme_id); } } } return $theme_id; } /** * Returns site primary currency ISO code * * @return string * @access public * @todo Move into In-Commerce */ public function GetPrimaryCurrency() { $cache_key = 'primary_currency[%CurrSerial%][%SiteDomainSerial%]:' . $this->siteDomainField('DomainId'); $currency_iso = $this->getCache($cache_key); if ( $currency_iso === false ) { if ( $this->prefixRegistred('curr') ) { $this->Conn->nextQueryCachable = true; $currency_id = $this->siteDomainField('PrimaryCurrencyId'); $sql = 'SELECT ISO FROM ' . $this->getUnitConfig('curr')->getTableName() . ' WHERE ' . ($currency_id > 0 ? 'CurrencyId = ' . $currency_id : 'IsPrimary = 1'); $currency_iso = $this->Conn->GetOne($sql); } else { $currency_iso = 'USD'; } $this->setCache($cache_key, $currency_iso); } return $currency_iso; } /** * Returns site domain field. When none of site domains are found false is returned. * * @param string $field * @param bool $formatted * @param string $format * @return mixed * @todo Move into separate module */ public function siteDomainField($field, $formatted = false, $format = null) { if ( $this->isAdmin ) { // don't apply any filtering in administrative console return false; } if ( !$this->siteDomain ) { $this->siteDomain = $this->recallObject('site-domain.current', null, Array ('live_table' => true)); /* @var $site_domain kDBItem */ } if ( $this->siteDomain->isLoaded() ) { return $formatted ? $this->siteDomain->GetField($field, $format) : $this->siteDomain->GetDBField($field); } return false; } /** * Registers classes, that are used before unit configs (where class registration usually is done) are read. * * Called automatically while initializing kApplication. * * @return void * @access public */ public function RegisterDefaultClasses() { // Database. $this->registerClass('IDBConnection', KERNEL_PATH . '/db/i_db_connection.php'); $this->registerClass('kDBConnection', KERNEL_PATH . '/db/db_connection.php'); $this->registerClass('kDBConnectionDebug', KERNEL_PATH . '/db/db_connection.php'); $this->registerClass('kDBLoadBalancer', KERNEL_PATH . '/db/db_load_balancer.php'); // Cache. $this->registerClass('kCacheManager', KERNEL_PATH . '/managers/cache_manager.php'); $this->registerClass('kCache', KERNEL_PATH . '/utility/cache.php'); // Unit configs. $this->registerClass('kUnitConfigReader', KERNEL_PATH . '/utility/unit_config_reader.php'); $this->registerClass('kUnitConfigCloner', KERNEL_PATH . '/utility/unit_config_cloner.php'); // Urls. $this->registerClass('kUrlManager', KERNEL_PATH . '/managers/url_manager.php'); $this->registerClass('kUrlProcessor', KERNEL_PATH . '/managers/url_processor.php'); $this->registerClass('kPlainUrlProcessor', KERNEL_PATH . '/managers/plain_url_processor.php'); // $this->registerClass('kRewriteUrlProcessor', KERNEL_PATH . '/managers/rewrite_url_processor.php'); // Events. $this->registerClass('kEventManager', KERNEL_PATH . '/event_manager.php'); $this->registerClass('kHookManager', KERNEL_PATH . '/managers/hook_manager.php'); $this->registerClass('kScheduledTaskManager', KERNEL_PATH . '/managers/scheduled_task_manager.php'); $this->registerClass('kRequestManager', KERNEL_PATH . '/managers/request_manager.php'); // Misc. $this->registerClass('kPhraseCache', KERNEL_PATH . '/languages/phrases_cache.php'); $this->registerClass('kModulesHelper', KERNEL_PATH . self::MODULE_HELPER_PATH); // Aliased. $this->registerClass('Params', KERNEL_PATH . '/utility/params.php', 'kActions'); $this->registerClass('kMainTagProcessor', KERNEL_PATH . '/processors/main_processor.php', 'm_TagProcessor'); $this->registerClass('kEmailSendingHelper', KERNEL_PATH . '/utility/email_send.php', 'EmailSender'); } /** * Registers default build events * * @return void * @access protected */ protected function RegisterDefaultBuildEvents() { $this->EventManager->registerBuildEvent('kTempTablesHandler', 'OnTempHandlerBuild'); } /** * Returns cached category information by given cache name. All given category * information is recached, when at least one of 4 caches is missing. * * @param int $category_id * @param string $name cache name = {filenames, category_designs, category_tree} * @return string * @access public */ public function getCategoryCache($category_id, $name) { return $this->cacheManager->getCategoryCache($category_id, $name); } /** * Returns caching type (none, memory, temporary) * * @param int $caching_type * @return bool * @access public */ public function isCachingType($caching_type) { return $this->cacheManager->isCachingType($caching_type); } /** * Increments serial based on prefix and it's ID (optional) * * @param string $prefix * @param int $id ID (value of IDField) or ForeignKeyField:ID * @param bool $increment * @return string * @access public */ public function incrementCacheSerial($prefix, $id = null, $increment = true) { return $this->cacheManager->incrementCacheSerial($prefix, $id, $increment); } /** * Returns cached $key value from cache named $cache_name * * @param int $key key name from cache * @param bool $store_locally store data locally after retrieved * @param int $max_rebuild_seconds * @return mixed * @access public */ public function getCache($key, $store_locally = true, $max_rebuild_seconds = 0) { return $this->cacheManager->getCache($key, $store_locally, $max_rebuild_seconds); } /** * Stores new $value in cache with $key name * * @param int $key key name to add to cache * @param mixed $value value of cached record * @param int $expiration when value expires (0 - doesn't expire) * @return bool * @access public */ public function setCache($key, $value, $expiration = 0) { return $this->cacheManager->setCache($key, $value, $expiration); } /** * Stores new $value in cache with $key name (only if it's not there) * * @param int $key key name to add to cache * @param mixed $value value of cached record * @param int $expiration when value expires (0 - doesn't expire) * @return bool * @access public */ public function addCache($key, $value, $expiration = 0) { return $this->cacheManager->addCache($key, $value, $expiration); } /** * Sets rebuilding mode for given cache * * @param string $name * @param int $mode * @param int $max_rebuilding_time * @return bool * @access public */ public function rebuildCache($name, $mode = null, $max_rebuilding_time = 0) { return $this->cacheManager->rebuildCache($name, $mode, $max_rebuilding_time); } /** * Deletes key from cache * * @param string $key * @return void * @access public */ public function deleteCache($key) { $this->cacheManager->deleteCache($key); } /** * Reset's all memory cache at once * * @return void * @access public */ public function resetCache() { $this->cacheManager->resetCache(); } /** * Returns value from database cache * * @param string $name key name * @param int $max_rebuild_seconds * @return mixed * @access public */ public function getDBCache($name, $max_rebuild_seconds = 0) { return $this->cacheManager->getDBCache($name, $max_rebuild_seconds); } /** * Sets value to database cache * * @param string $name * @param mixed $value * @param int|bool $expiration * @return void * @access public */ public function setDBCache($name, $value, $expiration = false) { $this->cacheManager->setDBCache($name, $value, $expiration); } /** * Sets rebuilding mode for given cache * * @param string $name * @param int $mode * @param int $max_rebuilding_time * @return bool * @access public */ public function rebuildDBCache($name, $mode = null, $max_rebuilding_time = 0) { return $this->cacheManager->rebuildDBCache($name, $mode, $max_rebuilding_time); } /** * Deletes key from database cache * * @param string $name * @return void * @access public */ public function deleteDBCache($name) { $this->cacheManager->deleteDBCache($name); } /** * Registers each module specific constants if any found * * @return bool * @access protected */ protected function registerModuleConstants() { if ( file_exists(KERNEL_PATH . '/constants.php') ) { kUtil::includeOnce(KERNEL_PATH . '/constants.php'); } if ( !$this->ModuleInfo ) { return false; } foreach ($this->ModuleInfo as $module_info) { $constants_file = FULL_PATH . '/' . $module_info['Path'] . 'constants.php'; if ( file_exists($constants_file) ) { kUtil::includeOnce($constants_file); } } return true; } /** * Performs redirect to hard maintenance template * * @return void * @access public */ public function redirectToMaintenance() { $maintenance_page = WRITEBALE_BASE . '/maintenance.html'; $query_string = ''; // $this->isAdmin ? '' : '?next_template=' . kUtil::escape($_SERVER['REQUEST_URI'], kUtil::ESCAPE_URL); if ( file_exists(FULL_PATH . $maintenance_page) ) { header('Location: ' . BASE_PATH . $maintenance_page . $query_string); exit; } } /** * Actually runs the parser against current template and stores parsing result * * This method gets 't' variable passed to the script, loads the template given in 't' variable and * parses it. The result is store in {@link $this->HTML} property. * * @return void * @access public */ public function Run() { // process maintenance mode redirect: begin $maintenance_mode = $this->getMaintenanceMode(); if ( $maintenance_mode == MaintenanceMode::HARD ) { $this->redirectToMaintenance(); } elseif ( $maintenance_mode == MaintenanceMode::SOFT ) { $maintenance_template = $this->isAdmin ? 'login' : $this->ConfigValue('SoftMaintenanceTemplate'); if ( $this->GetVar('t') != $maintenance_template ) { $redirect_params = Array (); if ( !$this->isAdmin ) { $redirect_params['next_template'] = $_SERVER['REQUEST_URI']; } $this->Redirect($maintenance_template, $redirect_params); } } // process maintenance mode redirect: end if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) { $this->Debugger->appendMemoryUsage('Application before Run:'); } if ( $this->isAdminUser ) { // for permission checking in events & templates $this->LinkVar('module'); // for common configuration templates $this->LinkVar('module_key'); // for common search templates $this->LinkVar('section'); // for common configuration templates if ( $this->GetVar('m_opener') == 'p' ) { $this->LinkVar('main_prefix'); // window prefix, that opened selector $this->LinkVar('dst_field'); // field to set value choosed in selector } if ( $this->GetVar('ajax') == 'yes' && !$this->GetVar('debug_ajax') ) { // hide debug output from ajax requests automatically kUtil::safeDefine('DBG_SKIP_REPORTING', 1); // safeDefine, because debugger also defines it } } elseif ( $this->GetVar('admin') ) { $admin_session = $this->recallObject('Session.admin'); /* @var $admin_session Session */ // store Admin Console User's ID to Front-End's session for cross-session permission checks $this->StoreVar('admin_user_id', (int)$admin_session->RecallVar('user_id')); if ( $this->CheckAdminPermission('CATEGORY.MODIFY', 0, $this->getBaseCategory()) ) { // user can edit cms blocks (when viewing front-end through admin's frame) $editing_mode = $this->GetVar('editing_mode'); define('EDITING_MODE', $editing_mode ? $editing_mode : EDITING_MODE_BROWSE); } } kUtil::safeDefine('EDITING_MODE', ''); // user can't edit anything $this->Phrases->setPhraseEditing(); $this->EventManager->ProcessRequest(); $this->InitParser(); $t = $this->GetVar('render_template', $this->GetVar('t')); if ( !$this->TemplatesCache->TemplateExists($t) && !$this->isAdmin ) { $cms_handler = $this->recallObject('st_EventHandler'); /* @var $cms_handler CategoriesEventHandler */ $t = ltrim($cms_handler->GetDesignTemplate(), '/'); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendHTML('Design Template: ' . $t . '; CategoryID: ' . $this->GetVar('m_cat_id')); } } /*else { $cms_handler->SetCatByTemplate(); }*/ if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) { $this->Debugger->appendMemoryUsage('Application before Parsing:'); } $this->HTML = $this->Parser->Run($t); if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY') ) { $this->Debugger->appendMemoryUsage('Application after Parsing:'); } } /** * Returns console application. * * @return ConsoleApplication */ public function getConsoleApplication() { return $this->makeClass('InPortal\Core\kernel\Console\ConsoleApplication'); } /** * Only renders template * * @see kDBEventHandler::_errorNotFound() */ public function QuickRun() { // discard any half-parsed content ob_clean(); // replace current page content with 404 $this->InitParser(); $this->HTML = $this->Parser->Run($this->GetVar('t')); } /** * Performs template parser/cache initialization * * @param bool|string $theme_name * @return void * @access public */ public function InitParser($theme_name = false) { if ( !is_object($this->Parser) ) { $this->Parser = $this->recallObject('NParser'); $this->TemplatesCache = $this->recallObject('TemplatesCache'); } $this->TemplatesCache->forceThemeName = $theme_name; } /** * Send the parser results to browser * * Actually send everything stored in {@link $this->HTML}, to the browser by echoing it. * * @return void * @access public */ public function Done() { $this->HandleEvent(new kEvent('adm:OnBeforeShutdown')); $debug_mode = defined('DEBUG_MODE') && $this->isDebugMode(); if ( $debug_mode ) { if ( kUtil::constOn('DBG_PROFILE_MEMORY') ) { $this->Debugger->appendMemoryUsage('Application before Done:'); } $this->Session->SaveData(); // adds session data to debugger report $this->HTML = ob_get_clean() . $this->HTML . $this->Debugger->printReport(true); } else { // send "Set-Cookie" header before any output is made $this->Session->SetSession(); $this->HTML = ob_get_clean() . $this->HTML; } $this->_outputPage(); $this->cacheManager->UpdateApplicationCache(); if ( !$debug_mode ) { $this->Session->SaveData(); } $this->EventManager->runScheduledTasks(); if ( defined('DBG_CAPTURE_STATISTICS') && DBG_CAPTURE_STATISTICS && !$this->isAdmin ) { $this->_storeStatistics(); } } /** * Outputs generated page content to end-user * * @return void * @access protected */ protected function _outputPage() { $this->setContentType(); ob_start(); if ( $this->UseOutputCompression() ) { $compression_level = $this->ConfigValue('OutputCompressionLevel'); if ( !$compression_level || $compression_level < 0 || $compression_level > 9 ) { $compression_level = 7; } header('Content-Encoding: gzip'); echo gzencode($this->HTML, $compression_level); } else { // when gzip compression not used connection won't be closed early! echo $this->HTML; } // send headers to tell the browser to close the connection header('Content-Length: ' . ob_get_length()); header('Connection: close'); // flush all output ob_end_flush(); if ( ob_get_level() ) { ob_flush(); } flush(); // close current session if ( session_id() ) { session_write_close(); } } /** * Stores script execution statistics to database * * @return void * @access protected */ protected function _storeStatistics() { global $start; $script_time = microtime(true) - $start; $query_statistics = $this->Conn->getQueryStatistics(); // time & count $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'StatisticsCapture WHERE TemplateName = ' . $this->Conn->qstr($this->GetVar('t')); $data = $this->Conn->GetRow($sql); if ( $data ) { $this->_updateAverageStatistics($data, 'ScriptTime', $script_time); $this->_updateAverageStatistics($data, 'SqlTime', $query_statistics['time']); $this->_updateAverageStatistics($data, 'SqlCount', $query_statistics['count']); $data['Hits']++; $data['LastHit'] = time(); $this->Conn->doUpdate($data, TABLE_PREFIX . 'StatisticsCapture', 'StatisticsId = ' . $data['StatisticsId']); } else { $data['ScriptTimeMin'] = $data['ScriptTimeAvg'] = $data['ScriptTimeMax'] = $script_time; $data['SqlTimeMin'] = $data['SqlTimeAvg'] = $data['SqlTimeMax'] = $query_statistics['time']; $data['SqlCountMin'] = $data['SqlCountAvg'] = $data['SqlCountMax'] = $query_statistics['count']; $data['TemplateName'] = $this->GetVar('t'); $data['Hits'] = 1; $data['LastHit'] = time(); $this->Conn->doInsert($data, TABLE_PREFIX . 'StatisticsCapture'); } } /** * Calculates average time for statistics * * @param Array $data * @param string $field_prefix * @param float $current_value * @return void * @access protected */ protected function _updateAverageStatistics(&$data, $field_prefix, $current_value) { $data[$field_prefix . 'Avg'] = (($data['Hits'] * $data[$field_prefix . 'Avg']) + $current_value) / ($data['Hits'] + 1); if ( $current_value < $data[$field_prefix . 'Min'] ) { $data[$field_prefix . 'Min'] = $current_value; } if ( $current_value > $data[$field_prefix . 'Max'] ) { $data[$field_prefix . 'Max'] = $current_value; } } /** * Remembers slow query SQL and execution time into log * * @param string $slow_sql * @param int $time * @return void * @access public */ public function logSlowQuery($slow_sql, $time) { $query_crc = kUtil::crc32($slow_sql); $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'SlowSqlCapture WHERE QueryCrc = ' . $query_crc; $data = $this->Conn->Query($sql, null, true); if ( $data ) { $this->_updateAverageStatistics($data, 'Time', $time); $template_names = explode(',', $data['TemplateNames']); array_push($template_names, $this->GetVar('t')); $data['TemplateNames'] = implode(',', array_unique($template_names)); $data['Hits']++; $data['LastHit'] = time(); $this->Conn->doUpdate($data, TABLE_PREFIX . 'SlowSqlCapture', 'CaptureId = ' . $data['CaptureId']); } else { $data['TimeMin'] = $data['TimeAvg'] = $data['TimeMax'] = $time; $data['SqlQuery'] = $slow_sql; $data['QueryCrc'] = $query_crc; $data['TemplateNames'] = $this->GetVar('t'); $data['Hits'] = 1; $data['LastHit'] = time(); $this->Conn->doInsert($data, TABLE_PREFIX . 'SlowSqlCapture'); } } /** * Checks if output compression options is available * * @return bool * @access protected */ protected function UseOutputCompression() { if ( kUtil::constOn('IS_INSTALL') || kUtil::constOn('DBG_ZEND_PRESENT') || kUtil::constOn('SKIP_OUT_COMPRESSION') ) { return false; } $accept_encoding = isset($_SERVER['HTTP_ACCEPT_ENCODING']) ? $_SERVER['HTTP_ACCEPT_ENCODING'] : ''; return $this->ConfigValue('UseOutputCompression') && function_exists('gzencode') && strstr($accept_encoding, 'gzip'); } // Facade /** * Returns current session id (SID) * * @return int * @access public */ public function GetSID() { $session = $this->recallObject('Session'); /* @var $session Session */ return $session->GetID(); } /** * Destroys current session * * @return void * @access public * @see UserHelper::logoutUser() */ public function DestroySession() { $session = $this->recallObject('Session'); /* @var $session Session */ $session->Destroy(); } /** * Returns variable passed to the script as GET/POST/COOKIE * * @param string $name Name of variable to retrieve * @param mixed $default default value returned in case if variable not present * @return mixed * @access public */ public function GetVar($name, $default = false) { return isset($this->HttpQuery->_Params[$name]) ? $this->HttpQuery->_Params[$name] : $default; } /** * Removes forceful escaping done to the variable upon Front-End submission. * * @param string|array $value Value. * * @return string|array * @see kHttpQuery::StripSlashes * @todo Temporary method for marking problematic places to take care of, when forceful escaping will be removed. */ public function unescapeRequestVariable($value) { return $this->HttpQuery->unescapeRequestVariable($value); } /** * Returns variable passed to the script as $type * * @param string $name Name of variable to retrieve * @param string $type Get/Post/Cookie * @param mixed $default default value returned in case if variable not present * @return mixed * @access public */ public function GetVarDirect($name, $type, $default = false) { // $type = ucfirst($type); $array = $this->HttpQuery->$type; return isset($array[$name]) ? $array[$name] : $default; } /** * Returns ALL variables passed to the script as GET/POST/COOKIE * * @return Array * @access public * @deprecated */ public function GetVars() { return $this->HttpQuery->GetParams(); } /** * Set the variable 'as it was passed to the script through GET/POST/COOKIE' * * This could be useful to set the variable when you know that * other objects would relay on variable passed from GET/POST/COOKIE * or you could use SetVar() / GetVar() pairs to pass the values between different objects.
* * @param string $var Variable name to set * @param mixed $val Variable value * @return void * @access public */ public function SetVar($var,$val) { $this->HttpQuery->Set($var, $val); } /** * Deletes kHTTPQuery variable * * @param string $var * @return void * @todo Think about method name */ public function DeleteVar($var) { $this->HttpQuery->Remove($var); } /** * Deletes Session variable * * @param string $var * @return void * @access public */ public function RemoveVar($var) { $this->Session->RemoveVar($var); } /** * Removes variable from persistent session * * @param string $var * @return void * @access public */ public function RemovePersistentVar($var) { $this->Session->RemovePersistentVar($var); } /** * Restores Session variable to it's db version * * @param string $var * @return void * @access public */ public function RestoreVar($var) { $this->Session->RestoreVar($var); } /** * Returns session variable value * * Return value of $var variable stored in Session. An optional default value could be passed as second parameter. * * @param string $var Variable name * @param mixed $default Default value to return if no $var variable found in session * @return mixed * @access public * @see Session::RecallVar() */ public function RecallVar($var,$default=false) { return $this->Session->RecallVar($var,$default); } /** * Returns variable value from persistent session * * @param string $var * @param mixed $default * @return mixed * @access public * @see Session::RecallPersistentVar() */ public function RecallPersistentVar($var, $default = false) { return $this->Session->RecallPersistentVar($var, $default); } /** * Stores variable $val in session under name $var * * Use this method to store variable in session. Later this variable could be recalled. * * @param string $var Variable name * @param mixed $val Variable value * @param bool $optional * @return void * @access public * @see kApplication::RecallVar() */ public function StoreVar($var, $val, $optional = false) { $session = $this->recallObject('Session'); /* @var $session Session */ $this->Session->StoreVar($var, $val, $optional); } /** * Stores variable to persistent session * * @param string $var * @param mixed $val * @param bool $optional * @return void * @access public */ public function StorePersistentVar($var, $val, $optional = false) { $this->Session->StorePersistentVar($var, $val, $optional); } /** * Stores default value for session variable * * @param string $var * @param string $val * @param bool $optional * @return void * @access public * @see Session::RecallVar() * @see Session::StoreVar() */ public function StoreVarDefault($var, $val, $optional = false) { $session = $this->recallObject('Session'); /* @var $session Session */ $this->Session->StoreVarDefault($var, $val, $optional); } /** * Links HTTP Query variable with session variable * * If variable $var is passed in HTTP Query it is stored in session for later use. If it's not passed it's recalled from session. * This method could be used for making sure that GetVar will return query or session value for given * variable, when query variable should overwrite session (and be stored there for later use).
* This could be used for passing item's ID into popup with multiple tab - * in popup script you just need to call LinkVar('id', 'current_id') before first use of GetVar('id'). * After that you can be sure that GetVar('id') will return passed id or id passed earlier and stored in session * * @param string $var HTTP Query (GPC) variable name * @param mixed $ses_var Session variable name * @param mixed $default Default variable value * @param bool $optional * @return void * @access public */ public function LinkVar($var, $ses_var = null, $default = '', $optional = false) { if ( !isset($ses_var) ) { $ses_var = $var; } if ( $this->GetVar($var) !== false ) { $this->StoreVar($ses_var, $this->GetVar($var), $optional); } else { $this->SetVar($var, $this->RecallVar($ses_var, $default)); } } /** * Returns variable from HTTP Query, or from session if not passed in HTTP Query * * The same as LinkVar, but also returns the variable value taken from HTTP Query if passed, or from session if not passed. * Returns the default value if variable does not exist in session and was not passed in HTTP Query * * @param string $var HTTP Query (GPC) variable name * @param mixed $ses_var Session variable name * @param mixed $default Default variable value * @return mixed * @access public * @see LinkVar */ public function GetLinkedVar($var, $ses_var = null, $default = '') { $this->LinkVar($var, $ses_var, $default); return $this->GetVar($var); } /** * Renders given tag and returns it's output * * @param string $prefix * @param string $tag * @param Array $params * @return mixed * @access public * @see kApplication::InitParser() */ public function ProcessParsedTag($prefix, $tag, $params) { $processor = $this->Parser->GetProcessor($prefix); /* @var $processor kDBTagProcessor */ return $processor->ProcessParsedTag($tag, $params, $prefix); } /** * Return object of IDBConnection interface * * Return object of IDBConnection interface already connected to the project database, configurable in config.php * * @return IDBConnection * @access public */ public function &GetADODBConnection() { return $this->Conn; } /** * Allows to parse given block name or include template * * @param Array $params Parameters to pass to block. Reserved parameter "name" used to specify block name. * @param bool $pass_params Forces to pass current parser params to this block/template. Use with caution, because you can accidentally pass "block_no_data" parameter. * @param bool $as_template * @return string * @access public */ public function ParseBlock($params, $pass_params = false, $as_template = false) { if ( substr($params['name'], 0, 5) == 'html:' ) { return substr($params['name'], 5); } return $this->Parser->ParseBlock($params, $pass_params, $as_template); } /** * Checks, that we have given block defined * * @param string $name * @return bool * @access public */ public function ParserBlockFound($name) { return $this->Parser->blockFound($name); } /** * Allows to include template with a given name and given parameters * * @param Array $params Parameters to pass to template. Reserved parameter "name" used to specify template name. * @return string * @access public */ public function IncludeTemplate($params) { return $this->Parser->IncludeTemplate($params, isset($params['is_silent']) ? 1 : 0); } /** * Return href for template * * @param string $t Template path * @param string $prefix index.php prefix - could be blank, 'admin' * @param Array $params * @param string $index_file * @return string */ public function HREF($t, $prefix = '', $params = Array (), $index_file = null) { return $this->UrlManager->HREF($t, $prefix, $params, $index_file); } /** * Returns theme template filename and it's corresponding page_id based on given seo template * * @param string $seo_template * @return string * @access public */ public function getPhysicalTemplate($seo_template) { return $this->UrlManager->getPhysicalTemplate($seo_template); } /** * Returns seo template by physical template * * @param string $physical_template * @return string * @access public */ public function getSeoTemplate($physical_template) { return $this->UrlManager->getSeoTemplate($physical_template); } /** * Returns template name, that corresponds with given virtual (not physical) page id * * @param int $page_id * @return string|bool * @access public */ public function getVirtualPageTemplate($page_id) { return $this->UrlManager->getVirtualPageTemplate($page_id); } /** * Returns section template for given physical/virtual template * * @param string $template * @param int $theme_id * @return string * @access public */ public function getSectionTemplate($template, $theme_id = null) { return $this->UrlManager->getSectionTemplate($template, $theme_id); } /** * Returns variables with values that should be passed through with this link + variable list * * @param Array $params * @return Array * @access public */ public function getPassThroughVariables(&$params) { return $this->UrlManager->getPassThroughVariables($params); } /** * Builds url * * @param string $t * @param Array $params * @param string $pass * @param bool $pass_events * @param bool $env_var * @return string * @access public */ public function BuildEnv($t, $params, $pass = 'all', $pass_events = false, $env_var = true) { return $this->UrlManager->plain->build($t, $params, $pass, $pass_events, $env_var); } /** * Process QueryString only, create * events, ids, based on config * set template name and sid in * desired application variables. * * @param string $env_var environment string value * @param string $pass_name * @return Array * @access public */ public function processQueryString($env_var, $pass_name = 'passed') { return $this->UrlManager->plain->parse($env_var, $pass_name); } /** * Parses rewrite url and returns parsed variables * * @param string $url * @param string $pass_name * @return Array * @access public */ public function parseRewriteUrl($url, $pass_name = 'passed') { return $this->UrlManager->rewrite->parse($url, $pass_name); } /** * Returns base part of all urls, build on website * * @param string $domain Domain override. * @param boolean $ssl_redirect Redirect to/from SSL. * * @return string */ public function BaseURL($domain = '', $ssl_redirect = null) { if ( $ssl_redirect === null ) { // stay on same encryption level return PROTOCOL . ($domain ? $domain : SERVER_NAME) . (defined('PORT') ? ':' . PORT : '') . BASE_PATH . '/'; } if ( $ssl_redirect ) { // going from http:// to https:// $protocol = 'https://'; $domain = $this->getSecureDomain(); } else { // going from https:// to http:// $protocol = 'http://'; $domain = $this->siteDomainField('DomainName'); if ( $domain === false ) { $domain = DOMAIN; // not on site domain } } return $protocol . $domain . (defined('PORT') ? ':' . PORT : '') . BASE_PATH . '/'; } /** * Returns secure domain. * * @return string */ public function getSecureDomain() { $ret = $this->isAdmin ? $this->ConfigValue('AdminSSLDomain') : false; if ( !$ret ) { $ssl_domain = $this->siteDomainField('SSLDomainName'); return strlen($ssl_domain) ? $ssl_domain : $this->ConfigValue('SSLDomain'); } return $ret; } /** * Redirects user to url, that's build based on given parameters * * @param string $t * @param Array $params * @param string $prefix * @param string $index_file * @return void * @access public */ public function Redirect($t = '', $params = Array(), $prefix = '', $index_file = null) { $js_redirect = getArrayValue($params, 'js_redirect'); if ( $t == '' || $t === true ) { $t = $this->GetVar('t'); } // pass prefixes and special from previous url if ( array_key_exists('js_redirect', $params) ) { unset($params['js_redirect']); } // allows to send custom responce code along with redirect header if ( array_key_exists('response_code', $params) ) { $response_code = (int)$params['response_code']; unset($params['response_code']); } else { $response_code = 302; // Found } if ( !array_key_exists('pass', $params) ) { $params['pass'] = 'all'; } if ( $this->GetVar('ajax') == 'yes' && $t == $this->GetVar('t') ) { // redirects to the same template as current $params['ajax'] = 'yes'; } $location = $this->HREF($t, $prefix, $params, $index_file); if ( $this->isDebugMode() && (kUtil::constOn('DBG_REDIRECT') || (kUtil::constOn('DBG_RAISE_ON_WARNINGS') && $this->Debugger->WarningCount)) ) { $this->Debugger->appendTrace(); echo 'Debug output above !!!
' . "\n"; if ( array_key_exists('HTTP_REFERER', $_SERVER) ) { echo 'Referer: ' . $_SERVER['HTTP_REFERER'] . '
' . "\n"; } echo "Proceed to redirect:
{$location}
\n"; } else { if ( $js_redirect ) { // show "redirect" template instead of redirecting, // because "Set-Cookie" header won't work, when "Location" // header is used later $this->SetVar('t', 'redirect'); $this->SetVar('redirect_to', $location); // make all additional parameters available on "redirect" template too foreach ($params as $name => $value) { $this->SetVar($name, $value); } return; } else { if ( $this->GetVar('ajax') == 'yes' && ($t != $this->GetVar('t') || !$this->isSOPSafe($location, $t)) ) { // redirection to other then current template during ajax request OR SOP violation kUtil::safeDefine('DBG_SKIP_REPORTING', 1); echo '#redirect#' . $location; } elseif ( headers_sent() != '' ) { // some output occurred -> redirect using javascript echo ''; } else { // no output before -> redirect using HTTP header // header('HTTP/1.1 302 Found'); header('Location: ' . $location, true, $response_code); } } } // session expiration is called from session initialization, // that's why $this->Session may be not defined here $session = $this->recallObject('Session'); /* @var $session Session */ if ( $this->InitDone ) { // if redirect happened in the middle of application initialization don't call event, // that presumes that application was successfully initialized $this->HandleEvent(new kEvent('adm:OnBeforeShutdown')); } $session->SaveData(); ob_end_flush(); exit; } /** * Determines if real redirect should be made within AJAX request. * * @param string $url Location. * @param string $template Template. * * @return boolean * @link http://en.wikipedia.org/wiki/Same-origin_policy */ protected function isSOPSafe($url, $template) { $parsed_url = parse_url($url); if ( $parsed_url['scheme'] . '://' != PROTOCOL ) { return false; } if ( $parsed_url['host'] != SERVER_NAME ) { return false; } if ( defined('PORT') && isset($parsed_url['port']) && $parsed_url['port'] != PORT ) { return false; } return true; } /** * Returns translation of given label * * @param string $label * @param bool $allow_editing return translation link, when translation is missing on current language * @param bool $use_admin use current Admin Console language to translate phrase * @return string * @access public */ public function Phrase($label, $allow_editing = true, $use_admin = false) { return $this->Phrases->GetPhrase($label, $allow_editing, $use_admin); } /** * Replace language tags in exclamation marks found in text * * @param string $text * @param bool $force_escape force escaping, not escaping of resulting string * @return string * @access public */ public function ReplaceLanguageTags($text, $force_escape = null) { return $this->Phrases->ReplaceLanguageTags($text, $force_escape); } /** * Checks if user is logged in, and creates * user object if so. User object can be recalled * later using "u.current" prefix_special. Also you may * get user id by getting "u.current_id" variable. * * @return void * @access protected */ protected function ValidateLogin() { $session = $this->recallObject('Session'); /* @var $session Session */ $user_id = $session->GetField('PortalUserId'); if ( !$user_id && $user_id != USER_ROOT ) { $user_id = USER_GUEST; } $this->SetVar('u.current_id', $user_id); if ( !$this->isAdmin ) { // needed for "profile edit", "registration" forms ON FRONT ONLY $this->SetVar('u_id', $user_id); } $this->StoreVar('user_id', $user_id, $user_id == USER_GUEST); // storing Guest user_id (-2) is optional $this->isAdminUser = $this->isAdmin && $this->LoggedIn(); if ( $this->GetVar('expired') == 1 ) { // this parameter is set only from admin $user = $this->recallObject('u.login-admin', null, Array ('form_name' => 'login')); /* @var $user UsersItem */ $user->SetError('UserLogin', 'session_expired', 'la_text_sess_expired'); } $this->HandleEvent(new kEvent('adm:OnLogHttpRequest')); if ( $user_id != USER_GUEST ) { // normal users + root $this->LoadPersistentVars(); } $user_timezone = $this->Session->GetField('TimeZone'); if ( $user_timezone ) { date_default_timezone_set($user_timezone); } } /** * Loads current user persistent session data * * @return void * @access public */ public function LoadPersistentVars() { $this->Session->LoadPersistentVars(); } /** * Returns configuration option value by name * * @param string $name * @return string * @access public */ public function ConfigValue($name) { return $this->cacheManager->ConfigValue($name); } /** * Changes value of individual configuration variable (+resets cache, when needed) * * @param string $name * @param string $value * @param bool $local_cache_only * @return string * @access public */ public function SetConfigValue($name, $value, $local_cache_only = false) { return $this->cacheManager->SetConfigValue($name, $value, $local_cache_only); } /** - * Allows to process any type of event + * Allows to process any type of event. + * + * @param kEvent $event Event. * - * @param kEvent $event - * @param Array $params - * @param Array $specific_params * @return void - * @access public */ - public function HandleEvent($event, $params = null, $specific_params = null) + public function HandleEvent(kEvent $event) { - if ( isset($params) ) { - $event = new kEvent($params, $specific_params); - } - $this->EventManager->HandleEvent($event); } /** * Notifies event subscribers, that event has occured * * @param kEvent $event * @return void */ public function notifyEventSubscribers(kEvent $event) { $this->EventManager->notifySubscribers($event); } /** * Allows to process any type of event * * @param kEvent $event * @return bool * @access public */ public function eventImplemented(kEvent $event) { return $this->EventManager->eventImplemented($event); } /** * Registers new class in the factory * * @param string $real_class Real name of class as in class declaration * @param string $file Filename in what $real_class is declared * @param string $pseudo_class Name under this class object will be accessed using getObject method * @return void * @access public */ public function registerClass($real_class, $file, $pseudo_class = null) { $this->Factory->registerClass($real_class, $file, $pseudo_class); } /** * Unregisters existing class from factory * * @param string $real_class Real name of class as in class declaration * @param string $pseudo_class Name under this class object is accessed using getObject method * @return void * @access public */ public function unregisterClass($real_class, $pseudo_class = null) { $this->Factory->unregisterClass($real_class, $pseudo_class); } /** * Add new scheduled task * * @param string $short_name name to be used to store last maintenance run info * @param string $event_string * @param int $run_schedule run schedule like for Cron * @param string $module * @param int $status * @access public */ public function registerScheduledTask($short_name, $event_string, $run_schedule, $module, $status = STATUS_ACTIVE) { $this->EventManager->registerScheduledTask($short_name, $event_string, $run_schedule, $module, $status); } /** * Registers Hook from subprefix event to master prefix event * * Pattern: Observer * * @param string $hook_event * @param string $do_event * @param int $mode * @param bool $conditional * @access public */ public function registerHook($hook_event, $do_event, $mode = hAFTER, $conditional = false) { $this->EventManager->registerHook($hook_event, $do_event, $mode, $conditional); } /** * Registers build event for given pseudo class * * @param string $pseudo_class * @param string $event_name * @access public */ public function registerBuildEvent($pseudo_class, $event_name) { $this->EventManager->registerBuildEvent($pseudo_class, $event_name); } /** * Allows one TagProcessor tag act as other TagProcessor tag * * @param Array $tag_info * @return void * @access public */ public function registerAggregateTag($tag_info) { $aggregator = $this->recallObject('TagsAggregator', 'kArray'); /* @var $aggregator kArray */ $tag_data = Array ( $tag_info['LocalPrefix'], $tag_info['LocalTagName'], getArrayValue($tag_info, 'LocalSpecial') ); $aggregator->SetArrayValue($tag_info['AggregateTo'], $tag_info['AggregatedTagName'], $tag_data); } /** * Returns object using params specified, creates it if is required * * @param string $name * @param string $pseudo_class * @param Array $event_params * @param Array $arguments * @return kBase */ public function recallObject($name, $pseudo_class = null, array $event_params = array(), array $arguments = array()) { /*if ( !$this->hasObject($name) && $this->isDebugMode() && ($name == '_prefix_here_') ) { // first time, when object with "_prefix_here_" prefix is accessed $this->Debugger->appendTrace(); }*/ return $this->Factory->getObject($name, $pseudo_class, $event_params, $arguments); } /** * Returns tag processor for prefix specified * * @param string $prefix * @return kDBTagProcessor * @access public */ public function recallTagProcessor($prefix) { $this->InitParser(); // because kDBTagProcesor is in NParser dependencies return $this->recallObject($prefix . '_TagProcessor'); } /** * Checks if object with prefix passes was already created in factory * * @param string $name object pseudo_class, prefix * @return bool * @access public */ public function hasObject($name) { return $this->Factory->hasObject($name); } /** * Removes object from storage by given name * * @param string $name Object's name in the Storage * @return void * @access public */ public function removeObject($name) { $this->Factory->DestroyObject($name); } /** * Get's real class name for pseudo class, includes class file and creates class instance * * Pattern: Factory Method * * @param string $pseudo_class * @param Array $arguments * @return kBase * @access public */ public function makeClass($pseudo_class, array $arguments = array()) { return $this->Factory->makeClass($pseudo_class, $arguments); } /** * Returns sub-classes of given ancestor class. * * @param string $ancestor_class Ancestor class. * @param boolean $concrete_only Return only non-abstract classes. * * @return array */ public function getSubClasses($ancestor_class, $concrete_only = true) { return $this->Factory->getSubClasses($ancestor_class, $concrete_only); } /** * Checks if application is in debug mode * * @param bool $check_debugger check if kApplication debugger is initialized too, not only for defined DEBUG_MODE constant * @return bool * @author Alex * @access public */ public function isDebugMode($check_debugger = true) { $debug_mode = defined('DEBUG_MODE') && DEBUG_MODE; if ($check_debugger) { $debug_mode = $debug_mode && is_object($this->Debugger); } return $debug_mode; } /** * Apply url rewriting used by mod_rewrite or not * * @param bool|null $ssl Force ssl link to be build * @return bool * @access public */ public function RewriteURLs($ssl = false) { // case #1,#4: // we want to create https link from http mode // we want to create https link from https mode // conditions: ($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL') // case #2,#3: // we want to create http link from https mode // we want to create http link from http mode // conditions: !$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://') $allow_rewriting = (!$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://')) // always allow mod_rewrite for http || // or allow rewriting for redirect TO httpS or when already in httpS (($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL')); // but only if it's allowed in config! return kUtil::constOn('MOD_REWRITE') && $allow_rewriting; } /** * Returns unit config for given prefix * * @param string $prefix * @return kUnitConfig * @access public */ public function getUnitConfig($prefix) { return $this->UnitConfigReader->getUnitConfig($prefix); } /** * Returns true if config exists and is allowed for reading * * @param string $prefix * @return bool */ public function prefixRegistred($prefix) { return $this->UnitConfigReader->prefixRegistered($prefix); } /** * Splits any mixing of prefix and * special into correct ones * * @param string $prefix_special * @return Array * @access public */ public function processPrefix($prefix_special) { return $this->Factory->processPrefix($prefix_special); } /** * Set's new event for $prefix_special * passed * * @param string $prefix_special * @param string $event_name * @return void * @access public */ public function setEvent($prefix_special, $event_name) { $this->EventManager->setEvent($prefix_special, $event_name); } /** * SQL Error Handler * * @param int $code * @param string $msg * @param string $sql * @return bool * @access public * @throws Exception * @deprecated */ public function handleSQLError($code, $msg, $sql) { return $this->_logger->handleSQLError($code, $msg, $sql); } /** * Returns & blocks next ResourceId available in system * * @return int * @access public */ public function NextResourceId() { $table_name = TABLE_PREFIX . 'IdGenerator'; $this->Conn->Query('LOCK TABLES ' . $table_name . ' WRITE'); $this->Conn->Query('UPDATE ' . $table_name . ' SET lastid = lastid + 1'); $id = $this->Conn->GetOne('SELECT lastid FROM ' . $table_name); if ( $id === false ) { $this->Conn->Query('INSERT INTO ' . $table_name . ' (lastid) VALUES (2)'); $id = 2; } $this->Conn->Query('UNLOCK TABLES'); return $id - 1; } /** * Returns genealogical main prefix for sub-table prefix passes * OR prefix, that has been found in REQUEST and some how is parent of passed sub-table prefix * * @param string $current_prefix * @param bool $real_top if set to true will return real topmost prefix, regardless of its id is passed or not * @return string * @access public */ public function GetTopmostPrefix($current_prefix, $real_top = false) { // 1. get genealogical tree of $current_prefix $prefixes = Array ($current_prefix); while ($parent_prefix = $this->getUnitConfig($current_prefix)->getParentPrefix()) { if ( !$this->prefixRegistred($parent_prefix) ) { // stop searching, when parent prefix is not registered break; } $current_prefix = $parent_prefix; array_unshift($prefixes, $current_prefix); } if ( $real_top ) { return $current_prefix; } // 2. find what if parent is passed $passed = explode(',', $this->GetVar('all_passed')); foreach ($prefixes as $a_prefix) { if ( in_array($a_prefix, $passed) ) { return $a_prefix; } } return $current_prefix; } /** * Triggers email event of type Admin * * @param string $email_template_name * @param int $to_user_id * @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text * @return kEvent * @access public */ public function emailAdmin($email_template_name, $to_user_id = null, $send_params = Array ()) { return $this->_email($email_template_name, EmailTemplate::TEMPLATE_TYPE_ADMIN, $to_user_id, $send_params); } /** * Triggers email event of type User * * @param string $email_template_name * @param int $to_user_id * @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text * @return kEvent * @access public */ public function emailUser($email_template_name, $to_user_id = null, $send_params = Array ()) { return $this->_email($email_template_name, EmailTemplate::TEMPLATE_TYPE_FRONTEND, $to_user_id, $send_params); } /** * Triggers general email event * * @param string $email_template_name * @param int $email_template_type (0 for User, 1 for Admin) * @param int $to_user_id * @param array $send_params associative array of direct send params, * possible keys: to_email, to_name, from_email, from_name, message, message_text * @return kEvent * @access protected */ protected function _email($email_template_name, $email_template_type, $to_user_id = null, $send_params = Array ()) { $email = $this->makeClass('kEmail'); /* @var $email kEmail */ if ( !$email->findTemplate($email_template_name, $email_template_type) ) { return false; } $email->setParams($send_params); return $email->send($to_user_id); } /** * Allows to check if user in this session is logged in or not * * @return bool * @access public */ public function LoggedIn() { // no session during expiration process return is_null($this->Session) ? false : $this->Session->LoggedIn(); } /** * Check current user permissions based on it's group permissions in specified category * * @param string $name permission name * @param int $cat_id category id, current used if not specified * @param int $type permission type {1 - system, 0 - per category} * @return int * @access public */ public function CheckPermission($name, $type = 1, $cat_id = null) { $perm_helper = $this->recallObject('PermissionsHelper'); /* @var $perm_helper kPermissionsHelper */ return $perm_helper->CheckPermission($name, $type, $cat_id); } /** * Check current admin permissions based on it's group permissions in specified category * * @param string $name permission name * @param int $cat_id category id, current used if not specified * @param int $type permission type {1 - system, 0 - per category} * @return int * @access public */ public function CheckAdminPermission($name, $type = 1, $cat_id = null) { $perm_helper = $this->recallObject('PermissionsHelper'); /* @var $perm_helper kPermissionsHelper */ return $perm_helper->CheckAdminPermission($name, $type, $cat_id); } /** * Set's any field of current visit * * @param string $field * @param mixed $value * @return void * @access public * @todo move to separate module */ public function setVisitField($field, $value) { if ( $this->isAdmin || !$this->ConfigValue('UseVisitorTracking') ) { // admin logins are not registered in visits list return; } $visit = $this->recallObject('visits', null, Array ('raise_warnings' => 0)); /* @var $visit kDBItem */ if ( $visit->isLoaded() ) { $visit->SetDBField($field, $value); $visit->Update(); } } /** * Allows to check if in-portal is installed * * @return bool * @access public */ public function isInstalled() { return $this->InitDone && (count($this->ModuleInfo) > 0); } /** * Allows to determine if module is installed & enabled * * @param string $module_name * @return bool * @access public */ public function isModuleEnabled($module_name) { return $this->findModule('Name', $module_name) !== false; } /** * Returns Window ID of passed prefix main prefix (in edit mode) * * @param string $prefix * @return int * @access public */ public function GetTopmostWid($prefix) { $top_prefix = $this->GetTopmostPrefix($prefix); $mode = $this->GetVar($top_prefix . '_mode'); return $mode != '' ? substr($mode, 1) : ''; } /** * Get temp table name * * @param string $table * @param mixed $wid * @return string * @access public */ public function GetTempName($table, $wid = '') { return $this->GetTempTablePrefix($wid) . $table; } /** * Builds temporary table prefix based on given window id * * @param string $wid * @return string * @access public */ public function GetTempTablePrefix($wid = '') { if ( preg_match('/prefix:(.*)/', $wid, $regs) ) { $wid = $this->GetTopmostWid($regs[1]); } return TABLE_PREFIX . 'ses_' . $this->GetSID() . ($wid ? '_' . $wid : '') . '_edit_'; } /** * Checks if given table is a temporary table * * @param string $table * @return bool * @access public */ public function IsTempTable($table) { static $cache = Array (); if ( !array_key_exists($table, $cache) ) { $cache[$table] = preg_match('/' . TABLE_PREFIX . 'ses_' . $this->GetSID() . '(_[\d]+){0,1}_edit_(.*)/', $table); } return (bool)$cache[$table]; } /** * Checks, that given prefix is in temp mode * * @param string $prefix * @param string $special * @return bool * @access public */ public function IsTempMode($prefix, $special = '') { $top_prefix = $this->GetTopmostPrefix($prefix); $var_names = Array ( $top_prefix, rtrim($top_prefix . '_' . $special, '_'), // from post rtrim($top_prefix . '.' . $special, '.'), // assembled locally ); $var_names = array_unique($var_names); $temp_mode = false; foreach ($var_names as $var_name) { $value = $this->GetVar($var_name . '_mode'); if ( $value && (substr($value, 0, 1) == 't') ) { $temp_mode = true; break; } } return $temp_mode; } /** * Return live table name based on temp table name * * @param string $temp_table * @return string */ public function GetLiveName($temp_table) { if ( preg_match('/' . TABLE_PREFIX . 'ses_' . $this->GetSID() . '(_[\d]+){0,1}_edit_(.*)/', $temp_table, $rets) ) { // cut wid from table end if any return $rets[2]; } else { return $temp_table; } } /** * Stops processing of user request and displays given message * * @param string $message * @access public */ public function ApplicationDie($message = '') { while ( ob_get_level() ) { ob_end_clean(); } if ( $this->isDebugMode() ) { $message .= $this->Debugger->printReport(true); } $this->HTML = $message; $this->_outputPage(); } /** * Returns comma-separated list of groups from given user * * @param int $user_id * @return string */ public function getUserGroups($user_id) { switch ($user_id) { case USER_ROOT: $user_groups = $this->ConfigValue('User_LoggedInGroup'); break; case USER_GUEST: $user_groups = $this->ConfigValue('User_LoggedInGroup') . ',' . $this->ConfigValue('User_GuestGroup'); break; default: $sql = 'SELECT GroupId FROM ' . TABLE_PREFIX . 'UserGroupRelations WHERE PortalUserId = ' . (int)$user_id; $res = $this->Conn->GetCol($sql); $user_groups = Array ($this->ConfigValue('User_LoggedInGroup')); if ( $res ) { $user_groups = array_merge($user_groups, $res); } $user_groups = implode(',', $user_groups); } return $user_groups; } /** * Allows to detect if page is browsed by spider (293 scheduled_tasks supported) * * @return bool * @access public */ /*public function IsSpider() { static $is_spider = null; if ( !isset($is_spider) ) { $user_agent = trim($_SERVER['HTTP_USER_AGENT']); $robots = file(FULL_PATH . '/core/robots_list.txt'); foreach ($robots as $robot_info) { $robot_info = explode("\t", $robot_info, 3); if ( $user_agent == trim($robot_info[2]) ) { $is_spider = true; break; } } } return $is_spider; }*/ /** * Allows to detect table's presence in database * * @param string $table_name * @param bool $force * @return bool * @access public */ public function TableFound($table_name, $force = false) { return $this->Conn->TableFound($table_name, $force); } /** * Returns counter value * * @param string $name counter name * @param Array $params counter parameters * @param string $query_name specify query name directly (don't generate from parameters) * @param bool $multiple_results * @return mixed * @access public */ public function getCounter($name, $params = Array (), $query_name = null, $multiple_results = false) { $count_helper = $this->recallObject('CountHelper'); /* @var $count_helper kCountHelper */ return $count_helper->getCounter($name, $params, $query_name, $multiple_results); } /** * Resets counter, which are affected by one of specified tables * * @param string $tables comma separated tables list used in counting sqls * @return void * @access public */ public function resetCounters($tables) { if ( kUtil::constOn('IS_INSTALL') ) { return; } $count_helper = $this->recallObject('CountHelper'); /* @var $count_helper kCountHelper */ $count_helper->resetCounters($tables); } /** * Sends XML header + optionally displays xml heading * * @param string|bool $xml_version * @return string * @access public * @author Alex */ public function XMLHeader($xml_version = false) { $this->setContentType('text/xml'); return $xml_version ? '' : ''; } /** * Returns category tree * * @param int $category_id * @return Array * @access public */ public function getTreeIndex($category_id) { $tree_index = $this->getCategoryCache($category_id, 'category_tree'); if ( $tree_index ) { $ret = Array (); list ($ret['TreeLeft'], $ret['TreeRight']) = explode(';', $tree_index); return $ret; } return false; } /** * Base category of all categories * Usually replaced category, with ID = 0 in category-related operations. * * @return int * @access public */ public function getBaseCategory() { // same, what $this->findModule('Name', 'Core', 'RootCat') does // don't cache while IS_INSTALL, because of kInstallToolkit::createModuleCategory and upgrade return $this->ModuleInfo['Core']['RootCat']; } /** * Deletes all data, that was cached during unit config parsing (excluding unit config locations) * * @param Array $config_variables * @access public */ public function DeleteUnitCache($config_variables = null) { $this->cacheManager->DeleteUnitCache($config_variables); } /** * Deletes cached section tree, used during permission checking and admin console tree display * * @return void * @access public */ public function DeleteSectionCache() { $this->cacheManager->DeleteSectionCache(); } /** * Sets data from cache to object * * @param Array $data * @access public */ public function setFromCache(&$data) { $this->Factory->setFromCache($data); $this->UnitConfigReader->setFromCache($data); $this->EventManager->setFromCache($data); $this->ReplacementTemplates = $data['Application.ReplacementTemplates']; $this->routers = $data['Application.Routers']; $this->ModuleInfo = $data['Application.ModuleInfo']; } /** * Gets object data for caching * The following caches should be reset based on admin interaction (adjusting config, enabling modules etc) * * @access public * @return Array */ public function getToCache() { return array_merge( $this->Factory->getToCache(), $this->UnitConfigReader->getToCache(), $this->EventManager->getToCache(), Array ( 'Application.ReplacementTemplates' => $this->ReplacementTemplates, 'Application.Routers' => $this->routers, 'Application.ModuleInfo' => $this->ModuleInfo, ) ); } public function delayUnitProcessing($method, $params) { $this->cacheManager->delayUnitProcessing($method, $params); } /** * Returns current maintenance mode state * * @param bool $check_ips * @return int * @access public */ public function getMaintenanceMode($check_ips = true) { $exception_ips = defined('MAINTENANCE_MODE_IPS') ? MAINTENANCE_MODE_IPS : ''; $setting_name = $this->isAdmin ? 'MAINTENANCE_MODE_ADMIN' : 'MAINTENANCE_MODE_FRONT'; if ( defined($setting_name) && constant($setting_name) > MaintenanceMode::NONE ) { $exception_ip = $check_ips ? kUtil::ipMatch($exception_ips) : false; if ( !$exception_ip ) { return constant($setting_name); } } return MaintenanceMode::NONE; } /** * Sets content type of the page * * @param string $content_type * @param bool $include_charset * @return void * @access public */ public function setContentType($content_type = 'text/html', $include_charset = null) { static $already_set = false; if ( $already_set ) { return; } $header = 'Content-type: ' . $content_type; if ( !isset($include_charset) ) { $include_charset = $content_type = 'text/html' || $content_type == 'text/plain' || $content_type = 'text/xml'; } if ( $include_charset ) { $header .= '; charset=' . CHARSET; } $already_set = true; header($header); } /** * Posts message to event log * * @param string $message * @param int $code * @param bool $write_now Allows further customization of log record by returning kLog object * @return bool|int|kLogger * @access public */ public function log($message, $code = null, $write_now = false) { $log = $this->_logger->prepare($message, $code)->addSource($this->_logger->createTrace(null, 1)); if ( $write_now ) { return $log->write(); } return $log; } /** * Deletes log with given id from database or disk, when database isn't available * * @param int $unique_id * @param int $storage_medium * @return void * @access public * @throws InvalidArgumentException */ public function deleteLog($unique_id, $storage_medium = kLogger::LS_AUTOMATIC) { $this->_logger->delete($unique_id, $storage_medium); } /** * Returns the client IP address. * * @return string The client IP address * @access public */ public function getClientIp() { return $this->HttpQuery->getClientIp(); } } Index: branches/5.3.x/core/kernel/utility/event.php =================================================================== --- branches/5.3.x/core/kernel/utility/event.php (revision 16221) +++ branches/5.3.x/core/kernel/utility/event.php (revision 16222) @@ -1,450 +1,453 @@ Init($prefix, $special); - } - - $this->Name = isset($params['name']) ? $params['name'] : ''; - } - elseif ( is_string($params) ) { - if ( preg_match('/([^.:]*)[.]{0,1}([^:]*):(.*)/', $params, $regs) ) { - $prefix = $regs[1]; - $special = $regs[2]; - - if ( $prefix ) { - $this->Init($prefix, $special); - } - - $this->Name = $regs[3]; - } - else { - $error_msg = 'Invalid event string: "' . $params . '". '; - $error_msg .= 'Should be in "prefix[.special]:OnEvent" format'; - throw new InvalidArgumentException($error_msg); - } - } - } + /** + * Event finished working successfully. + */ + const erSUCCESS = 0; + + /** + * Event finished working, but result is unsuccessful. + */ + const erFAIL = -1; + + /** + * Event experienced FATAL error - no hooks should continue! + */ + const erFATAL = -2; + + /** + * Event failed on internal permission checking (user has no permission). + */ + const erPERM_FAIL = -3; + + /** + * Event requested to stop processing (don't parse templates). + */ + const erSTOP = -4; + + /** + * Reference to event, that created given event. + * + * @var self + */ + public $MasterEvent; + + /** + * Event name. + * + * @var string + */ + public $Name; + + /** + * Don't execute hooks, before event processing. + * + * @var boolean + */ + public $SkipBeforeHooks = false; + + /** + * Don't execute hooks, after event processing. + * + * @var boolean + */ + public $SkipAfterHooks = false; + + /** + * Perform redirect after event processing. + * + * Redirect after event processing allows to prevent same event being + * present in resulting url. Also could contain template name, that + * needs to be shown after redirect. + * + * @var mixed + */ + public $redirect = true; + + /** + * Params, used during redirect url building after event successful processing. + * + * @var array + */ + private $_redirectParams = array(); + + /** + * PHP file to redirect to. Defaults to "index.php". + * + * @var string + */ + public $redirectScript = null; + + /** + * Event processing status. + * + * @var integer + */ + public $status = self::erSUCCESS; + + /** + * Event parameters. + * + * Usually indicate, how particular event should be processed. + * + * @var array + */ + private $_specificParams = array(); + + /** + * Pseudo class used, to create object, based on event contents. + * + * @var string + */ + private $_pseudoClass = ''; + + /** + * Creates an event from array. + * + * @param array $params Event string in array format with 'prefix', 'special' (optional) and 'name' keys. + * @param array $specific_params Specific params. + * + * @return self + */ + public static function fromArray(array $params, array $specific_params = array()) + { + $prefix = isset($params['prefix']) ? $params['prefix'] : false; + $special = isset($params['special']) ? $params['special'] : false; + $name = isset($params['name']) ? $params['name'] : ''; - if ( isset($specific_params) ) { - $this->specificParams = $specific_params; - } - } + return new self($prefix . '.' . $special . ':' . $name, $specific_params); + } - /** - * Returns joined prefix and special if any - * - * @param bool $from_submit if true, then joins prefix & special by "_", uses "." otherwise - * @return string - * @access public - */ - public function getPrefixSpecial($from_submit = false) - { - if (!$from_submit) { - return parent::getPrefixSpecial(); - } + /** + * Create event from given prefix, special, name and specific params. + * Parameter $params could be be an an array with following keys: "prefix", "special" (optional), "name". + * Parameter $params could be a string in format: "prefix:name" or "prefix.special:name". + * + * @param mixed $event_string Params. + * @param array $specific_params Event specific params (none by default). + * + * @throws InvalidArgumentException When incorrect event string given. + */ + public function __construct($event_string, array $specific_params = array()) + { + parent::__construct(); + + if ( preg_match('/([^.:]*)[.]{0,1}([^:]*):(.*)/', $event_string, $regs) ) { + $prefix = $regs[1]; + $special = $regs[2]; + + if ( $prefix ) { + $this->Init($prefix, $special); + } + + $this->Name = $regs[3]; + $this->_specificParams = $specific_params; + } + else { + $error_msg = 'Invalid event string: "' . $event_string . '". '; + $error_msg .= 'Should be in "prefix[.special]:OnEvent" format'; + throw new InvalidArgumentException($error_msg); + } + } - return rtrim($this->Prefix . '_' . $this->Special, '_'); + /** + * Returns joined prefix and special if any. + * + * @param boolean $from_submit If true, then joins prefix & special by "_", uses "." otherwise. + * + * @return string + */ + public function getPrefixSpecial($from_submit = false) + { + if ( !$from_submit ) { + return parent::getPrefixSpecial(); } - /** - * Sets event parameter - * - * @param string $name - * @param mixed $value - * @access public - */ - public function setEventParam($name,$value) - { - $this->specificParams[$name] = $value; - } - - /** - * Returns event parameter by name (supports digging) - * - * @param string $name - * @return mixed - * @access public - */ - public function getEventParam($name) - { - $args = func_get_args(); + return rtrim($this->Prefix . '_' . $this->Special, '_'); + } + + /** + * Sets event parameter. + * + * @param string $name Name. + * @param mixed $value Value. + * + * @return void + */ + public function setEventParam($name, $value) + { + $this->_specificParams[$name] = $value; + } - if (count($args) > 1) { - kUtil::array_unshift_ref($args, $this->specificParams); + /** + * Returns event parameter by name (supports digging). + * + * @param string $name Name. + * + * @return mixed + */ + public function getEventParam($name) + { + $args = func_get_args(); - return call_user_func_array('getArrayValue', $args); // getArrayValue($this->specificParams, $name); - } + if ( count($args) > 1 ) { + kUtil::array_unshift_ref($args, $this->_specificParams); - return array_key_exists($name, $this->specificParams) ? $this->specificParams[$name] : false; + return call_user_func_array('getArrayValue', $args); } - /** - * Returns all event parameters - * - * @return Array - * @access public - */ - public function getEventParams() - { - return $this->specificParams; - } - - /** - * Set's pseudo class that differs from - * the one specified in $Prefix - * - * @param string $appendix - * @access public - */ - public function setPseudoClass($appendix) - { - $this->pseudoClass = $this->Prefix . $appendix; - } - - /** - * Performs event initialization - * Also sets pseudo class same $prefix - * - * @param string $prefix - * @param string $special - * @access public - */ - public function Init($prefix, $special) - { - $this->pseudoClass = $prefix; - - parent::Init($prefix, $special); - } - - /** - * Returns object used in event - * - * @param Array $params - * @return kDBBase - * @access public - */ - public function getObject(array $params = Array()) - { - if ( !$this->Application->hasObject($this->prefixSpecial) ) { - $top_event = $this; - - // when OnSave calls OnPreSave in first line, then this would make sure OnSave is used - while ( is_object($top_event->MasterEvent) ) { - $top_event = $top_event->MasterEvent; - } + return array_key_exists($name, $this->_specificParams) ? $this->_specificParams[$name] : false; + } - $params['parent_event'] = $top_event; + /** + * Returns all event parameters. + * + * @return array + */ + public function getEventParams() + { + return $this->_specificParams; + } + + /** + * Set's pseudo class that differs from the one specified in $Prefix. + * + * @param string $appendix Appendix. + * + * @return void + */ + public function setPseudoClass($appendix) + { + $this->_pseudoClass = $this->Prefix . $appendix; + } + + /** + * Performs event initialization. + * + * Also sets pseudo class same $prefix. + * + * @param string $prefix Prefix. + * @param string $special Special. + * + * @return void + */ + public function Init($prefix, $special) + { + $this->_pseudoClass = $prefix; + + parent::Init($prefix, $special); + } + + /** + * Returns object used in event. + * + * @param array $params Params. + * + * @return kDBBase + */ + public function getObject(array $params = array()) + { + if ( !$this->Application->hasObject($this->prefixSpecial) ) { + $top_event = $this; + + // When OnSave calls OnPreSave in first line, then this would make sure OnSave is used. + while ( is_object($top_event->MasterEvent) ) { + $top_event = $top_event->MasterEvent; } - return $this->Application->recallObject($this->prefixSpecial, $this->pseudoClass, $params); + $params['parent_event'] = $top_event; } - /** - * Executes given event in context of current event - * Sub-event gets this event in "kEvent::MasterEvent" attribute. - * Sub-event execution results (status and redirect* properties) are copied back to current event. - * - * @param string $name name of callable event (optionally could contain prefix_special as well) - * @see kEvent::MasterEvent - * @todo Will overwrite master event data with called event data, which makes 'parent_event' useless in most cases - */ - public function CallSubEvent($name) - { - if ( strpos($name, ':') === false ) { - // PrefixSpecial not specified -> use from current event - $name = $this->getPrefixSpecial() . ':' . $name; - } + return $this->Application->recallObject($this->prefixSpecial, $this->_pseudoClass, $params); + } - $child_event = new kEvent($name); - $child_event->copyFrom($this, true); + /** + * Executes given event in context of current event. + * + * Sub-event gets this event in "kEvent::MasterEvent" attribute. + * Sub-event execution results (status and redirect* properties) are copied back to current event. + * + * @param string $name Name of callable event (optionally could contain prefix_special as well). + * + * @return void + * @see kEvent::MasterEvent + * @todo Overwrites master event data with called event data, which makes 'parent_event' useless in most cases. + */ + public function CallSubEvent($name) + { + if ( strpos($name, ':') === false ) { + // PrefixSpecial not specified -> use from current event. + $name = $this->getPrefixSpecial() . ':' . $name; + } + + $child_event = new kEvent($name); + $child_event->copyFrom($this, true); + + $this->Application->HandleEvent($child_event); + $this->copyFrom($child_event); + $this->_specificParams = $child_event->_specificParams; + } - $this->Application->HandleEvent($child_event); - $this->copyFrom($child_event); - $this->specificParams = $child_event->specificParams; - } - - /** - * Allows to copy data between events - * - * @param kEvent $source_event - * @param bool $inherit - * @access public - */ - public function copyFrom($source_event, $inherit = false) - { - if ( $inherit ) { - $this->MasterEvent = $source_event; - } - else { - $this->status = $source_event->status; - } + /** + * Allows to copy data between events. + * + * @param kEvent $source_event Source event. + * @param boolean $inherit Keep reference to source event in copied event. + * + * @return void + */ + public function copyFrom(kEvent $source_event, $inherit = false) + { + if ( $inherit ) { + $this->MasterEvent = $source_event; + } + else { + $this->status = $source_event->status; + } + + $this->redirect = $source_event->redirect; + $this->_redirectParams = $source_event->_redirectParams; + $this->redirectScript = $source_event->redirectScript; + $this->_specificParams = $source_event->_specificParams; + } - $this->redirect = $source_event->redirect; - $this->redirectParams = $source_event->redirectParams; - $this->redirectScript = $source_event->redirectScript; - $this->specificParams = $source_event->specificParams; - } - - /** - * Returns all redirect parameters - * - * @return Array - * @access public - */ - public function getRedirectParams() - { - return $this->redirectParams; - } - - /** - * Returns redirect parameter - * - * @param string $name - * @return mixed - * @access public - */ - public function getRedirectParam($name) - { - return array_key_exists($name, $this->redirectParams) ? $this->redirectParams[$name] : false; - } - - /** - * Set's redirect param for event - * - * @param string $name - * @param string $value - * @access public - */ - public function SetRedirectParam($name, $value) - { - $this->redirectParams[$name] = $value; - } - - /** - * Allows to merge passed redirect params hash with existing ones - * - * @param Array $params - * @param bool $append - * @access public - */ - public function setRedirectParams($params, $append = true) - { - if ( $append ) { - // append new parameters to parameters set before - $params = kUtil::array_merge_recursive($this->redirectParams, $params); - } + /** + * Returns all redirect parameters. + * + * @return array + */ + public function getRedirectParams() + { + return $this->_redirectParams; + } - $this->redirectParams = $params; - } + /** + * Returns redirect parameter. + * + * @param string $name Name. + * + * @return mixed + */ + public function getRedirectParam($name) + { + return array_key_exists($name, $this->_redirectParams) ? $this->_redirectParams[$name] : false; + } - /** - * Allows to tell if this event was called some how (e.g. subevent, hook) from event requested - * - * @param string $event_key event key in format [prefix[.special]:]event_name - * @return bool - * @access public - */ - public function hasAncestor($event_key) - { - if ( strpos($event_key, ':') === false ) { - $event_key = $this->getPrefixSpecial() . ':' . $event_key; - } + /** + * Set's redirect param for event. + * + * @param string $name Name. + * @param string $value Value. + * + * @return void + */ + public function SetRedirectParam($name, $value) + { + $this->_redirectParams[$name] = $value; + } - return $this->Application->EventManager->eventRunning($event_key); + /** + * Allows to merge passed redirect params hash with existing ones. + * + * @param array $params Params. + * @param boolean $append Append to existing parameters. + * + * @return void + */ + public function setRedirectParams(array $params, $append = true) + { + if ( $append ) { + $params = kUtil::array_merge_recursive($this->_redirectParams, $params); } - /** - * Returns permission section associated with event - * - * @return string - * @access public - */ - public function getSection() - { - $perm_section = $this->getEventParam('PermSection'); + $this->_redirectParams = $params; + } - if ( $perm_section ) { - return $perm_section; - } + /** + * Allows to tell if this event was called some how (e.g. sub-event, hook) from event requested. + * + * @param string $event_key Event key in format: "[prefix[.special]:]event_name". + * + * @return boolean + */ + public function hasAncestor($event_key) + { + if ( strpos($event_key, ':') === false ) { + $event_key = $this->getPrefixSpecial() . ':' . $event_key; + } - // 1. get section by current top_prefix - $top_prefix = $this->getEventParam('top_prefix'); + return $this->Application->EventManager->eventRunning($event_key); + } - if ( $top_prefix == false ) { - $top_prefix = $this->Application->GetTopmostPrefix($this->Prefix, true); - $this->setEventParam('top_prefix', $top_prefix); - } + /** + * Returns permission section associated with event. + * + * @return string + * @throws Exception When permission section not specified for event's unit. + */ + public function getSection() + { + $perm_section = $this->getEventParam('PermSection'); - $section = $this->Application->getUnitConfig($top_prefix)->getPermSectionByName('main'); + if ( $perm_section ) { + return $perm_section; + } - // 2. check if this section has perm_prefix mapping to other prefix - $sections_helper = $this->Application->recallObject('SectionsHelper'); - /* @var $sections_helper kSectionsHelper */ + // 1. get section by current top_prefix. + $top_prefix = $this->getEventParam('top_prefix'); - $section_data =& $sections_helper->getSectionData($section); + if ( $top_prefix == false ) { + $top_prefix = $this->Application->GetTopmostPrefix($this->Prefix, true); + $this->setEventParam('top_prefix', $top_prefix); + } - if ( $section_data && isset($section_data['perm_prefix']) && $section_data['perm_prefix'] != $top_prefix ) { - $this->setEventParam('top_prefix', $section_data['perm_prefix']); - $section = $this->Application->getUnitConfig($section_data['perm_prefix'])->getPermSectionByName('main'); - } + $section = $this->Application->getUnitConfig($top_prefix)->getPermSectionByName('main'); - if ( !$section ) { - throw new Exception('Permission section not specified for prefix ' . $top_prefix . ''); - } + // 2. check if this section has perm_prefix mapping to other prefix. + $sections_helper = $this->Application->recallObject('SectionsHelper'); + /* @var $sections_helper kSectionsHelper */ - return $section; + $section_data =& $sections_helper->getSectionData($section); + + if ( $section_data && isset($section_data['perm_prefix']) && $section_data['perm_prefix'] != $top_prefix ) { + $this->setEventParam('top_prefix', $section_data['perm_prefix']); + $section = $this->Application->getUnitConfig($section_data['perm_prefix'])->getPermSectionByName('main'); } - public function __toString() - { - return $this->getPrefixSpecial() . ':' . $this->Name; + if ( !$section ) { + $error_msg = 'Permission section not specified for'; + $error_msg .= ' prefix ' . $top_prefix . ''; + throw new Exception($error_msg); } + + return $section; } + + /** + * Casts object to string. + * + * @return string + */ + public function __toString() + { + return $this->getPrefixSpecial() . ':' . $this->Name; + } + +} Index: branches/5.3.x/core/units/priorites/priority_eh.php =================================================================== --- branches/5.3.x/core/units/priorites/priority_eh.php (revision 16221) +++ branches/5.3.x/core/units/priorites/priority_eh.php (revision 16222) @@ -1,402 +1,402 @@ Array ('self' => true), ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Define alternative event processing method names * * @return void * @see kEventHandler::$eventMethods * @access protected */ protected function mapEvents() { parent::mapEvents(); $events_map = Array ( 'OnMassMoveUp' => 'OnChangePriority', 'OnMassMoveDown' => 'OnChangePriority', ); $this->eventMethods = array_merge($this->eventMethods, $events_map); } /** * Occurs, when config was parsed, allows to change config data dynamically * * @param kEvent $event * @return void * @access protected */ protected function OnAfterConfigRead(kEvent $event) { parent::OnAfterConfigRead($event); $hooks = Array( Array( 'Mode' => hAFTER, 'Conditional' => false, 'HookToPrefix' => '', 'HookToSpecial' => '*', 'HookToEvent' => Array('OnAfterItemLoad', 'OnPreCreate', 'OnListBuild'), 'DoPrefix' => 'priority', 'DoSpecial' => '*', 'DoEvent' => 'OnPreparePriorities', 'Conditional' => false, ), Array( 'Mode' => hBEFORE, 'Conditional' => false, 'HookToPrefix' => '', 'HookToSpecial' => '*', 'HookToEvent' => Array('OnPreSaveCreated'), 'DoPrefix' => 'priority', 'DoSpecial' => '*', 'DoEvent' => 'OnPreparePriorities', 'Conditional' => false, ), Array( 'Mode' => hAFTER, 'Conditional' => false, 'HookToPrefix' => '', 'HookToSpecial' => '*', 'HookToEvent' => Array('OnPreSave', 'OnPreSaveCreated', 'OnSave', 'OnUpdate'), 'DoPrefix' => 'priority', 'DoSpecial' => '*', 'DoEvent' => 'OnSavePriorityChanges', 'Conditional' => false, ), Array( 'Mode' => hAFTER, 'Conditional' => false, 'HookToPrefix' => '', 'HookToSpecial' => '*', 'HookToEvent' => Array('OnSave'), 'DoPrefix' => 'priority', 'DoSpecial' => '*', 'DoEvent' => 'OnSaveItems', 'Conditional' => false, ), Array( 'Mode' => hBEFORE, 'Conditional' => false, 'HookToPrefix' => '', 'HookToSpecial' => '*', 'HookToEvent' => Array('OnBeforeItemCreate'), 'DoPrefix' => 'priority', 'DoSpecial' => '*', 'DoEvent' => 'OnItemCreate', 'Conditional' => false, ), Array( 'Mode' => hBEFORE, 'Conditional' => false, 'HookToPrefix' => '', 'HookToSpecial' => '*', 'HookToEvent' => Array('OnAfterItemDelete'), 'DoPrefix' => 'priority', 'DoSpecial' => '*', 'DoEvent' => 'OnItemDelete', 'Conditional' => false, ) ); $prefixes = $event->getUnitConfig()->getProcessPrefixes(Array ()); foreach ($prefixes as $prefix) { foreach ($hooks as $hook) { if ( !is_array($hook['HookToEvent']) ) { $hook['HookToEvent'] = Array($hook['HookToEvent']); } foreach ($hook['HookToEvent'] as $hook_event) { $this->Application->registerHook( $prefix . '.' . $hook['HookToSpecial'] . ':' . $hook_event, $event->Prefix . '.' . $hook['DoSpecial'] . ':' . $hook['DoEvent'], $hook['Mode'], $hook['Conditional'] ); } } } } /** * Should be hooked to OnAfterItemLoad, OnPreSaveCreated (why latter?) * * @param kEvent $event */ function OnPreparePriorities($event) { if ( !$this->Application->isAdminUser ) { return ; } $priority_helper = $this->Application->recallObject('PriorityHelper'); /* @var $priority_helper kPriorityHelper */ list ($constrain, $joins) = $this->getConstrainInfo($event); $is_new = $event->MasterEvent->Name == 'OnPreCreate' || $event->MasterEvent->Name == 'OnPreSaveCreated'; $priority_helper->preparePriorities($event->MasterEvent, $is_new, $constrain, $joins); } /** * Enter description here... * * @param kEvent $event */ function OnSavePriorityChanges($event) { if ($event->MasterEvent->status != kEvent::erSUCCESS) { // don't update priorities, when OnSave validation failed return ; } $object = $event->MasterEvent->getObject(); /* @var $object kDBItem */ $tmp = $this->Application->RecallVar('priority_changes'.$this->Application->GetVar('m_wid')); $changes = $tmp ? unserialize($tmp) : array(); if (!isset($changes[$object->GetID()])) { $changes[$object->GetId()]['old'] = $object->GetID() == 0 ? 'new' : $object->GetDBField('OldPriority'); } if ($changes[$object->GetId()]['old'] == $object->GetDBField('Priority')) return ; $changes[$object->GetId()]['new'] = $object->GetDBField('Priority'); list ($constrain, $joins) = $this->getConstrainInfo($event); if ($constrain) { $changes[$object->GetId()]['constrain'] = $constrain; } $this->Application->StoreVar('priority_changes'.$this->Application->GetVar('m_wid'), serialize($changes)); } /** * Enter description here... * * @param kEvent $event */ function OnItemDelete($event) { // just store the prefix in which the items were deleted $del = $this->Application->RecallVar('priority_deleted' . $this->Application->GetVar('m_wid')); $del = $del ? unserialize($del) : array(); list ($constrain, $joins) = $this->getConstrainInfo($event); $cache_key = crc32($event->MasterEvent->Prefix . ':' . $constrain . ':' . $joins); if ( !isset($del[$cache_key]) ) { $del[$cache_key] = Array ( 'prefix' => $event->MasterEvent->Prefix, 'constrain' => $constrain, 'joins' => $joins, ); $this->Application->StoreVar('priority_deleted' . $this->Application->GetVar('m_wid'), serialize($del)); } } /** * Called before script shut-down and recalculate all deleted prefixes, to avoid recalculation on each deleted item * * @param kEvent $event */ function OnBeforeShutDown($event) { $del = $this->Application->RecallVar('priority_deleted'.$this->Application->GetVar('m_wid')); $del = $del ? unserialize($del) : array(); $priority_helper = $this->Application->recallObject('PriorityHelper'); /* @var $priority_helper kPriorityHelper */ foreach ($del as $del_info) { - $dummy_event = new kEvent( array('prefix'=>$del_info['prefix'], 'name'=>'Dummy' ) ); + $dummy_event = new kEvent($del_info['prefix'] . ':OnDummy'); $ids = $priority_helper->recalculatePriorities($dummy_event, $del_info['constrain'], $del_info['joins']); if ($ids) { $priority_helper->massUpdateChanged($del_info['prefix'], $ids); } } $this->Application->RemoveVar('priority_deleted'.$this->Application->GetVar('m_wid')); } /** * Enter description here... * * @param kEvent $event */ function OnSaveItems($event) { $tmp = $this->Application->RecallVar('priority_changes'.$this->Application->GetVar('m_wid')); $changes = $tmp ? unserialize($tmp) : array(); $priority_helper = $this->Application->recallObject('PriorityHelper'); /* @var $priority_helper kPriorityHelper */ list ($constrain, $joins) = $this->getConstrainInfo($event); $ids = $priority_helper->updatePriorities($event->MasterEvent, $changes, Array (0 => $event->MasterEvent->getEventParam('ids')), $constrain, $joins); if ($ids) { $priority_helper->massUpdateChanged($event->MasterEvent->Prefix, $ids); } } function OnItemCreate($event) { $object = $event->MasterEvent->getObject(); /* @var $object kDBItem */ if ($object->GetDBField('Priority') == 0) { $priority_helper = $this->Application->recallObject('PriorityHelper'); /* @var $priority_helper kPriorityHelper */ list ($constrain, $joins) = $this->getConstrainInfo($event); $priority_helper->preparePriorities($event->MasterEvent, true, $constrain, $joins); } } /** * Processes OnMassMoveUp, OnMassMoveDown events * * @param kEvent $event */ function OnChangePriority($event) { $prefix = $this->Application->GetVar('priority_prefix'); - $dummy_event = new kEvent( array('prefix'=>$prefix, 'name'=>'Dummy' ) ); + $dummy_event = new kEvent($prefix . ':OnDummy'); $ids = $this->StoreSelectedIDs($dummy_event); if ($ids) { $config = $this->Application->getUnitConfig($prefix); $id_field = $config->getIDField(); $table_name = $config->getTableName(); if ( $this->Application->IsTempMode($prefix) ) { $table_name = $this->Application->GetTempName($table_name, 'prefix:' . $prefix); } $sql = 'SELECT Priority, '.$id_field.' FROM '.$table_name.' WHERE '.$id_field.' IN ('.implode(',', $ids).') ORDER BY Priority DESC'; $priorities = $this->Conn->GetCol($sql, $id_field); $priority_helper = $this->Application->recallObject('PriorityHelper'); /* @var $priority_helper kPriorityHelper */ list ($constrain, $joins) = $this->getConstrainInfo($event); $sql = 'SELECT IFNULL(MIN(item_table.Priority), -1) FROM '.$table_name . ' item_table ' . $joins; if ( $constrain ) { $sql .= ' WHERE ' . $priority_helper->normalizeConstrain($constrain); } $min_priority = $this->Conn->GetOne($sql); foreach ($ids as $id) { $new_priority = $priorities[$id] + ($event->Name == 'OnMassMoveUp' ? +1 : -1); if ($new_priority > -1 || $new_priority < $min_priority) { continue; } $changes = Array ( $id => Array ('old' => $priorities[$id], 'new' => $new_priority), ); if ($constrain) { $changes[$id]['constrain'] = $constrain; } $sql = 'UPDATE '.$table_name.' SET Priority = '.$new_priority.' WHERE '.$id_field.' = '.$id; $this->Conn->Query($sql); $ids = $priority_helper->updatePriorities($dummy_event, $changes, Array ($id => $id), $constrain, $joins); if ($ids) { $priority_helper->massUpdateChanged($prefix, $ids); } } } $this->clearSelectedIDs($dummy_event); } /** * Completely recalculates priorities in current category * * @param kEvent $event */ function OnRecalculatePriorities($event) { $priority_helper = $this->Application->recallObject('PriorityHelper'); /* @var $priority_helper kPriorityHelper */ $prefix = $this->Application->GetVar('priority_prefix'); $dummy_event = new kEvent($prefix . ':Dummy'); list ($constrain, $joins) = $this->getConstrainInfo($event); $ids = $priority_helper->recalculatePriorities($dummy_event, $constrain, $joins); if ($ids) { $priority_helper->massUpdateChanged($prefix, $ids); } } /** * Returns constrain for current priority calculations * * @param kEvent $event * @return Array */ function getConstrainInfo($event) { $constrain_event = new kEvent($event->MasterEvent->getPrefixSpecial() . ':OnGetConstrainInfo'); $constrain_event->setEventParam('actual_event', $event->Name); $constrain_event->setEventParam('original_special', $event->MasterEvent->Special); $constrain_event->setEventParam('original_event', $event->MasterEvent->Name); $this->Application->HandleEvent($constrain_event); return $constrain_event->getEventParam('constrain_info'); } }