значение * @param string $url * * 3. Замена всех указанных переменных на одно и то же значение, обычно используется для удаления переменных из адреса (3 аргумента): * ($names, $value, $url = FALSE) * От случая № 2 отличается тем, что массив не ассоциативный, а обычный. Проверяем по первому элементу. * * @param string[] $names имена переменных для коллективной замены * @param string|int|null $value * @param string $url * * 4. Удаление переменных, кроме указанных, с возможной заменой значений указанных (2 аргумента): * ($params, $url = FALSE) * * @param assoc $names первый элемент массива должен иметь ключ = 0 и значение = '-', он является индиактором включения режима удаления переменных, кроме указанных; остальные члены массива интерпретируются так: если ключом является число, то значение интерпретируется как имя переменной и эта переменная остается без изменений; если же ключом является строка, то она воспринмается как имя переменной, и в адрес этой переменной подставляется значение данного элемента. * @param string $url * * @return string во всех случаях результатом работы является полученный URL * */ function substitute_url_get_parameter($arg1, $arg2 = FALSE, $arg3 = FALSE) { $mode = FALSE; // Сейчас будем определять, в каком из режимов вызвана функция if (!is_array($arg1)) $mode = 1; else { reset($arg1); $first_key = key($arg1); $first_value = current($arg1); // можно было получить из reset(), но так понятней if (!is_numeric($first_key)) $mode = 2; else { if ($first_key == 0 AND $first_value == '-') $mode = 4; else $mode = 3; } } $url = ($mode == 1 OR $mode == 3) ? $arg3 : $arg2; if (!$url) $url = $_SERVER['REQUEST_URI']; $url_parts = parse_url($url); // Текущие значения GET-параметров URL запишем в переменную $vars, они понадобятся для случаев 1 и 4. parse_str( ( isset($url_parts['query']) ? $url_parts['query'] : '' ), $vars ); $fn = __FUNCTION__; switch ($mode) { case 1: if (!is_null($arg2)) // переписываем переменную $vars[$arg1] = $arg2; // либо добавляем новую else unset($vars[$arg1]); // убираем переменную совсем $new_query = http_build_query($vars); // if ($clean) // c версии 1.2.0 параметр упразднили и замену производим всегда $new_query = preg_replace( '/=(?=&|\z)/', '', $new_query); if ($new_query) $new_query = '?' . $new_query; $result_url = (isset($url_parts['scheme']) ? "$url_parts[scheme]://" : '') . (isset($url_parts['host']) ? "$url_parts[host]" : '') . (isset($url_parts['path']) ? "$url_parts[path]" : '') . $new_query . (isset($url_parts['fragment']) ? "#$url_parts[fragment]" : '') ; break; case 2: $result_url = $url; foreach ($arg1 as $name => $value) $result_url = $fn($name, $value, $result_url); break; case 3: $result_url = $url; foreach ($arg1 as $name) $result_url = $fn($name, $arg2, $result_url); break; case 4: $mode_indicator = array_slice($arg1, 0, 1); // элемент-индикатор сохраняем отдельно $preserve = []; // Сюда записываем значения параметров, которые требуется сохранить или заменить foreach ( array_slice($arg1, 1) as $key => $value ) { // проходимся по всем, кроме первого элемента-индикатора if (is_numeric($key)) { // переменная указана без нового значения - сохраняем текущее if (isset($vars[$value])) $preserve[$value] = $vars[$value]; else ; // если среди переменных её не нашлось, сохранять нечего - ничего не делаем } else // устанавливаем указанное значение переменной $preserve[$key] = $value; } $remove = array_fill_keys( array_keys($vars), NULL); // Все текущие GET-параметры представляем к удалению // Окончательный набор значений для замены $all = $preserve + $remove ; // именно в таком порядке: ключи массива, следущего при сложении первым, имеют приоритет! $result_url = $fn($all, $url); break; } return $result_url; } function nav_pages( $varname, // 'p' - строка с именем переменной $per_page_cfg, // ['N',20] или 20 (имя переменной + по умолчанию или жестко число) $total_rows, // общее количество записей $max_length = FALSE, // общее максимальное число ссылок (включая активную) $url = FALSE ) { // На выходе: // list: [ (item), (item), ... ], // special: [ current, next, prev, first, last ] // item: [ url, num, min, max, current (если надо) ] if (!$total_rows) return array(); if (!$url) $url = $_SERVER['REQUEST_URI']; parse_str(parse_url($url, PHP_URL_QUERY), $query); $page = (isset($query[$varname])) ? intval($query[$varname]) : 1; if (is_array($per_page_cfg)) $per_page = (isset($query[$per_page_cfg[0]]) AND $query[$per_page_cfg[0]]) ? intval($query[$per_page_cfg[0]]) : $per_page_cfg[1]; else $per_page = $per_page_cfg; $total_pages = ceil($total_rows/$per_page); if ($total_pages == 1) return array(); // только одна страница - список не показываем # Получаем номера начальной и конечной страниц if ($page > $total_pages) $page = $total_pages; if ($max_length) { $start = max(1, $page - floor( ($max_length - 1) / 2) ); $end = min( $start + $max_length - 1, $total_pages); if ($end == $total_pages) $start = max(1, $end - $max_length + 1); } else { $start = 1; $end = $total_pages; } # Стандартный список $list = array(); $i = $start; while ($i <= $end) { $list[$i] = array( 'url' => substitute_url_get_parameter( $varname, ( ($i != 1) ? $i : NULL), $url ), 'num' => $i, 'min'=> ($i-1)*$per_page + 1, 'max' => $i*$per_page ); $i++; } $list[$page]['current'] = TRUE; if ($end == $total_pages) $list[$end]['max'] = $total_rows; # Специальные страницы (предыдущая, следующая и пр.) $special = array(); $special['current'] = $list[$page]; unset($special['current']['current']); // для порядка if ( $page > 1 ) // сейчас не первая страница - $special['prev'] = $list[$page - 1];; // нужна ссылка "предыдущая" if ( $page < $total_pages ) // сейчас не последняя страница - $special['next'] = $list[$page + 1]; // нужна ссылка "следующая" if ( min(array_keys($list)) > 1 ) // ссылка на первую страницу, $special['first'] = array( // (если таковая не встречается в обычном списке) 'url' => substitute_url_get_parameter($varname, NULL, $url), 'num' => 1, 'min' => 1, 'max' => $per_page ); if ( max(array_keys($list)) < $total_pages ) // ссылка на первую страницу, $special['last'] = array( // (если таковая не встречается в обычном списке) 'url' => substitute_url_get_parameter($varname, $total_pages, $url), 'num' => $total_pages, 'min' => ($total_pages - 1) * $per_page + 1, 'max' => $total_rows ); return compact('list', 'special'); } function nav_sort($sort_key, $fields, $page_key = 'p', $baseurl = FALSE) { // cfgstr имеет вид '[*] text [DESC]' // (в скобках указаны необязательные части). // // Режим с отдельной ссылкой на каждое направление сортировки // включается нотацией (часть названия для ASC|часть названия для DESC) // (одна или обе части могут отсутствовать - в этом случае вместо метки // будет подставлена пустая строка). // Тогда вместо одной ссылки с атрибутом direction в массив попадут // две отдельные без этого атрибута (по его наличию эти ссылки // следует отличать в шаблонах). if (!$baseurl) $baseurl = $_SERVER['REQUEST_URI']; parse_str(parse_url($baseurl, PHP_URL_QUERY), $query); $links = array(); # 0. Ищем сортировку по умолчанию $default = array(); // Чтоб два раза не писать один и тот же код, // пришлось инкапсулировать в функцию $fn_set_default = function($name, $cfg) { $result['name'] = $name; $result['direction'] = (preg_match('/\sDESC$/', trim($cfg))) ? 'DESC' : 'ASC' ; return $result; }; // Сначала пробуем найти по * в тексте ссылки foreach ($fields as $name => $cfg) if (strpos($cfg, '*') === 0) $default = $fn_set_default($name, $cfg); if (!$default) // Сортировка по умолчанию явно не указана - // просто берем первую запись из конфигурации foreach ($fields as $name => $cfg) { $default = $fn_set_default($name, $cfg); break; } # 1. Определяем ключ и направление текущей сортировки $now = array(); # 1.1. Если в запросе присутствует параметр сортировки, # он ее и определяет. if (isset($query[$sort_key])) { preg_match( '/^(\w+)\s*(ASC|DESC)?$/', trim($query[$sort_key]), $matches ); if ($matches) { $now['name'] = $matches[1]; $now['direction'] = (isset($matches[2])) ? $matches[2] : 'ASC' ; } } # 1.2. Параметр сортировки в запросе отсутствует. # Устанавливаем сортировку по умолчанию в качестве текущей. if (!$now) $now = $default; // # 1.3. Если и после этого не удалось определить сортировку - // # значит, значение по умолчанию не указано: выдаем предупреждение // // if (!$now) { // // trigger_error("Default sort is not defined", E_USER_WARNING); // // return array(); // } # 2. Для каждого из полей, у которого указана конфигурация сортировки, # определяем свойства ссылок foreach ($fields as $name => $cfg) { $link = array(); # Текст ссылки (убираем все служебные указания и метки) $text_clean = trim(preg_replace( array( '/^\*/', '/\s*DESC$/' ) , '', $cfg )); # Далее в зависимости от указанной конфигурации каждого поля # существует два варианта. # 2.1. Две ссылки — на каждое направление if (preg_match('/ \{ ([^|]*\|.*?) \}/x', $cfg, $matches)) { $texts = explode('|', $matches[1]); foreach (array('ASC', 'DESC') AS $D) { # current - является ли текущей $current = ($name == $now['name'] AND $D == $now['direction']); // # направление сортировки // $direction = $D; // Одинарным ссылкам это не нужно, // т.к. текущий CSS // Пока убрали; // именно отсутствие элемента direction // позволяет отличать одинарные ссылки от # text $m = ($D == 'ASC') ? 0 : 1 ; $text = trim(str_replace($matches[0], $texts[$m], $text_clean)); unset($m); # url if ($name == $default['name'] AND $D == $default['direction']) $v = NULL ; // название и направление сортировки по умолачанию else { $v = $name; if ($D == 'DESC') // DESC дописываем, ASC - нет $v .= ' DESC'; } $url = substitute_url_get_parameter( [ $sort_key => $v, $page_key => NULL], $baseurl ); unset($v); if ($url == $baseurl) // ссылку на ту же страницу упраздняем unset($url); $links[$name][$D] = compact('current', 'url', 'text'); } } # 2.2. Одна ссылка на оба направления else { # 2.2.1. Является ли сортировка текущей $current = ($name == $now['name']); # 2.2.2. Направление сортировки if ($current) // для текущего режима определяем из GET-параметра $direction = $now['direction']; else // в остальных случаях определяем из конфигурации $direction = (preg_match('/\s*DESC$/', $cfg)) ? 'DESC' : 'ASC' ; # 2.2.3. Текст ссылки $text = ($text_clean) ? $text_clean : $name; # 2.2.4. Адрес ссылки $v = $name; if ($current) // Для текущей сортировки ссылка указывает на противоположное направление $D = ($direction == 'DESC') ? 'ASC' : 'DESC'; else $D = $direction; if ($name == $default['name'] AND $D == $default['direction']) $v = NULL; // ссылка на сортировку по умолчанию else { $v = $name; if ($D == 'DESC') // DESC дописываем, ASC - нет $v .= ' DESC'; } $url = substitute_url_get_parameter( [ $sort_key => $v, $page_key => NULL], $baseurl ); unset($v); $links[$name] = compact('current', 'direction', 'url', 'text'); } } return $links; } function nav_switches( $varname, // на основе какой переменной строить ссылки $list, // а) value (пойдет и в value, и в title) б) 'title' => 'value'; '' => 'value' - значение по умоланию $exclude = FALSE, // какие переменные исключить из ссылок (зачастую - номер страницы) $url = FALSE ) { $out = array(); if (!$url) $url = $_SERVER['REQUEST_URI']; parse_str(parse_url($url, PHP_URL_QUERY), $query); foreach ($list as $k => $v) { if (!is_array($v)) { // передали пару 'значение' => 'текст' или просто 'значение' if (is_int($k)) $row = array( 'value' => $v, 'text' => $v ); else $row = array('value' => $k, 'text' => $v); } else { // в $v передали массив вида [ 'значение', 'текст'] // или [ 'value' => 'значение', 'text' => 'текст' ] if (is_int(key($v))) $row = array('value' => $v[0], 'text' => $v[1]); else $row = $v; } if ($varname == '' OR $varname == '/') { $row['url'] = $url; if ($row['value']) { $row['url'] .= urlencode($row['value']); if ($varname == '/') $row['url'] .= '/'; } // сравниваемс пути if (parse_url($url, PHP_URL_PATH) == $row['url']) $row['current'] = TRUE; } else { $is_default = ($row['value'] === ''); // Пункт, активный по умолчанию, if (!isset($query[$varname])) $row['current'] = $is_default; else $row['current'] = ($query[$varname] == $row['value']); $v = (!$is_default) ? $row['value'] : NULL; $row['url'] = substitute_url_get_parameter($varname, $v, $url); } if ($exclude) $row['url'] = substitute_url_get_parameter($exclude, NULL, $row['url']); $out[] = $row; } return $out; }; ?>