Index: branches/5.2.x/core/units/helpers/list_helper.php =================================================================== diff -u -N -r14628 -r14646 --- branches/5.2.x/core/units/helpers/list_helper.php (.../list_helper.php) (revision 14628) +++ branches/5.2.x/core/units/helpers/list_helper.php (.../list_helper.php) (revision 14646) @@ -33,7 +33,7 @@ $sort_fields = is_array($sorting) ? array_keys($sorting) : Array (); for ($order_number = 0; $order_number < 2; $order_number++) { - // currect sorting in list + // current sorting in list $sorting_pos = $user_sorting_start + $order_number; $current_order_field = $list->GetOrderField($sorting_pos, true); $current_order_direction = $list->GetOrderDirection($sorting_pos, true); @@ -120,6 +120,82 @@ if ( $forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting') ) { $user_sorting_start = count($forced_sorting); } + return $user_sorting_start; } + + /** + * Returns ID of previous/next record related to current record + * + * @param kDBItem $object + * @param string $list_prefix + * @param bool $next + * @return int + */ + function getNavigationResource(&$object, $list_prefix, $next = true, $select_fields = null) + { + $list =& $this->Application->recallObject($list_prefix); + /* @var $list kDBList */ + + if ( !isset($select_fields) ) { + $select_fields = '%1$s.' . $object->IDField; + } + + if ( is_array($select_fields) ) { + $select_fields = implode(', ', $select_fields); + } + + $list->SetSelectSQL( str_replace(Array ('%1$s.*', '%2$s'), Array ($select_fields, ''), $list->GetPlainSelectSQL()) ); + + $operators = Array ( + 'asc' => $next ? '>' : '<', + 'desc' => $next ? '<' : '>', + ); + + $where_clause = Array (); + $lang = $this->Application->GetVar('m_lang'); + $order_fields = $order_fields_backup = $list->getOrderFields(); + + foreach ($order_fields as $index => $order) { + $where_clause[$index] = Array (); + + if ( !$next ) { + $list->changeOrderDirection($index, $order_fields_backup[$index][1] == 'asc' ? 'desc' : 'asc'); + } + + for ($i = 0; $i <= $index; $i++) { + $order_field = $order_fields_backup[$i][0]; + $is_expression = $order_fields_backup[$i][2]; + + if ( preg_match('/^IF\(COALESCE\(.*?\.(l' . $lang . '_.*?), ""\),/', $order_field, $regs) ) { + // undo result of kDBList::getMLSortField method + $order_field = $regs[1]; + $is_expression = false; + } + + $order_direction = $order_fields_backup[$i][1]; + + $field_prefix = $list->isVirtualField($order_field) || $is_expression ? '' : '%1$s.'; + + $actual_operator = $i == $index ? $operators[$order_direction] : '='; + $where_clause[$index][] = $field_prefix . $order_field . ' ' . $actual_operator . ' ' . $this->Conn->qstr($object->GetDBField($order_field)); + } + + $where_clause[$index] = '(' . implode(') AND (', $where_clause[$index]) . ')'; + } + + $where_clause = '(%1$s.' . $object->IDField . ' != ' . $object->GetID() . ') AND ((' . implode(') OR (', $where_clause) . '))'; + $list->addFilter('navigation_filter', $where_clause); + + $sql = $list->extractCalculatedFields($list->GetSelectSQL()); + + $list->removeFilter('navigation_filter'); + $list->setOrderFields($order_fields_backup); + + if ( $this->Application->isDebugMode() ) { + $this->Application->Debugger->appendHTML('Quering ' . ($next ? 'next' : 'previous') . ' item for "' . $list_prefix . '" list:'); + } + + return $this->Conn->GetOne($sql); + } } \ No newline at end of file Index: branches/5.2.x/core/kernel/db/cat_tag_processor.php =================================================================== diff -u -N -r14628 -r14646 --- branches/5.2.x/core/kernel/db/cat_tag_processor.php (.../cat_tag_processor.php) (revision 14628) +++ branches/5.2.x/core/kernel/db/cat_tag_processor.php (.../cat_tag_processor.php) (revision 14646) @@ -1,6 +1,6 @@ Prefix; } - $item_id = isset($params[$id_prefix.'_id']) && $params[$id_prefix.'_id']; - if (!$item_id) { - $item_id = $this->Application->GetVar($this->getPrefixSpecial().'_id'); - if (!$item_id) { - $item_id = $this->Application->GetVar($this->Prefix.'_id'); - } + // set by PrintList2 tag + $item_id = $this->Application->GetVar($this->getPrefixSpecial() . '_id'); + + if ( !$item_id && ($this->Special != 'next' && $this->Special != 'previous') ) { + // set from page url + $item_id = $this->Application->GetVar($this->Prefix . '_id'); } $object =& $this->getObject($params); Index: branches/5.2.x/core/kernel/db/db_tag_processor.php =================================================================== diff -u -N -r14614 -r14646 --- branches/5.2.x/core/kernel/db/db_tag_processor.php (.../db_tag_processor.php) (revision 14614) +++ branches/5.2.x/core/kernel/db/db_tag_processor.php (.../db_tag_processor.php) (revision 14646) @@ -1,6 +1,6 @@ getObject($params); + /* @var $object kDBItem */ + + $list_helper =& $this->Application->recallObject('ListHelper'); + /* @var $list_helper ListHelper */ + + return $list_helper->getNavigationResource($object, $params['list'], false); + } + + /** + * 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 */ + + return $list_helper->getNavigationResource($object, $params['list'], true); + } + + /** * Allows to modify block params & current list record before PrintList parses record * * @param kDBList $object Index: branches/5.2.x/core/kernel/db/dblist.php =================================================================== diff -u -N -r14602 -r14646 --- branches/5.2.x/core/kernel/db/dblist.php (.../dblist.php) (revision 14602) +++ branches/5.2.x/core/kernel/db/dblist.php (.../dblist.php) (revision 14646) @@ -1,6 +1,6 @@ 'HavingFilter', self::AGGREGATE_FILTER => 'AggregateFilter' ); - + $filter_name = $filter_source[$filter_type]; $filter =& $this->$filter_name; @@ -346,7 +346,7 @@ $filter =& $this->$filter_name; $filter =& $filter[$filter_scope]; /* @var $filter kMultipleFilter */ - + return $filter->getFilter($name); } @@ -371,7 +371,7 @@ $filter =& $this->$filter_name; $filter =& $filter[$filter_scope]; /* @var $filter kMultipleFilter */ - + $filter->removeFilter($name); } @@ -702,14 +702,14 @@ } /** - * Replaces all calculated field occurences with their associated expressions + * Replaces all calculated field occurrences with their associated expressions * * @param string $clause where clause to extract calculated fields from * @param int $aggregated 0 - having + aggregated, 1 - having only, 2 - aggregated only * @return string - * @access private + * @access public */ - private function extractCalculatedFields($clause, $aggregated = 1) + public function extractCalculatedFields($clause, $aggregated = 1) { $fields = $this->getCalculatedFields($aggregated); if (is_array($fields) && count($fields) > 0) { @@ -733,7 +733,7 @@ { $where =& $this->Application->makeClass('kMultipleFilter'); /* @var $where kMultipleFilter */ - + $where->addFilter('system_where', $this->WhereFilter[self::FLT_SYSTEM] ); if (!$system_filters_only) { @@ -748,7 +748,7 @@ // CUSTOM $search_w = $this->WhereFilter[self::FLT_CUSTOM]->getSQL(); - + if ($search_w || $for_counting) { // move search_having to search_where in case search_where isset or we are counting $search_h = $this->extractCalculatedFields( $this->HavingFilter[self::FLT_CUSTOM]->getSQL() ); $search_w = ($search_w && $search_h) ? $search_w.' AND '.$search_h : $search_w.$search_h; @@ -845,13 +845,14 @@ } /** - * Adds order field to ORDER BY clause - * - * @param string $field Field name - * @param string $direction Direction of ordering (asc|desc) - * @param bool $is_expression this is expression, that should not be escapted by "`" symbols - * @access public - */ + * Adds order field to ORDER BY clause + * + * @param string $field Field name + * @param string $direction Direction of ordering (asc|desc) + * @param bool $is_expression this is expression, that should not be escapted by "`" symbols + * @return int + * @access public + */ public function AddOrderField($field, $direction = 'asc', $is_expression = false) { // original multilanguage field - convert to current lang field @@ -868,9 +869,40 @@ } $this->OrderFields[] = Array($field, $direction, $is_expression); + + return count($this->OrderFields) - 1; } /** + * Sets new order fields, replacing existing ones + * + * @param Array $order_fields + * @return void + * @access public + */ + public function setOrderFields($order_fields) + { + $this->OrderFields = $order_fields; + } + + /** + * Changes sorting direction for a given sorting field index + * + * @param int $field_index + * @param string $direction + * @return void + * @access public + */ + public function changeOrderDirection($field_index, $direction) + { + if ( !isset($this->OrderFields[$field_index]) ) { + return; + } + + $this->OrderFields[$field_index][1] = $direction; + } + + /** * Returns expression, used to sort given multilingual field * * @param string $field @@ -954,6 +986,17 @@ } /** + * Returns list order fields + * + * @return Array + * @access public + */ + public function getOrderFields() + { + return $this->OrderFields; + } + + /** * Returns order field direction in given position * * @param int $pos @@ -1504,7 +1547,7 @@ /** * Detects relations between LEFT JOINs - * + * * @return void * @access private */ @@ -1527,7 +1570,7 @@ /** * Removes scheduled LEFT JOINs, but only if they are not protected - * + * * @return void * @access private */ @@ -1544,7 +1587,7 @@ /** * Schedules unused LEFT JOINs to for removal - * + * * @return void * @access private */ Index: branches/5.2.x/core/kernel/db/db_event_handler.php =================================================================== diff -u -N -r14632 -r14646 --- branches/5.2.x/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 14632) +++ branches/5.2.x/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 14646) @@ -1,6 +1,6 @@ setEventParam('raise_warnings', 1); } + if ( $event->Special == 'previous' || $event->Special == 'next' ) { + $object =& $this->Application->recallObject( $event->getEventParam('item') ); + /* @var $object kDBItem */ + + $list_helper =& $this->Application->recallObject('ListHelper'); + /* @var $list_helper ListHelper */ + + return $list_helper->getNavigationResource($object, $event->getEventParam('list'), $event->Special == 'next'); + } + if (preg_match('/^auto-(.*)/', $event->Special, $regs) && $this->Application->prefixRegistred($regs[1])) { // - returns field DateFormat value from language (LanguageId is extracted from current phrase object) $main_object =& $this->Application->recallObject($regs[1]); @@ -1010,6 +1020,9 @@ $this->Application->ConfigValue($sorting_configs['DefaultSorting1Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting1Dir']), $this->Application->ConfigValue($sorting_configs['DefaultSorting2Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting2Dir']), ); + + // TODO: lowercase configuration variable values in db, instead of here + $list_sortings[$sorting_prefix]['Sorting'] = array_map('strtolower', $list_sortings[$sorting_prefix]['Sorting']); } // use default if not specified in session