Здравствуйте. Есть такая структура сайта в базе (классические айдишка–парэнт_айдишка): Админ Логин Смена пароля Выход Допустим, я захожу сюда — www.site.com/admin/login/recover (здесь, типа, напоминалка пароля, например). Так вот, как мне узнать айдишку последнего, третьего сегмента (recover)? Причем нужно пошагово пройтись по всем сегментам УРИ и проверить их наличие в базе. Пошагово по дереву нужно пройти потому, что у меня могут быть, например, такие разделы — www.site.com/user/login/recover — здесь тоже третий сегмент называется «recover» и такое дерево реально есть в базе (так же, как и на первой картинке). Только пожалуйста, не надо прдираться к структуре — эти УРИ я привел для наглядности. Так же не предлагать передавать вот этот «recover» как параметр. Мне нужен совет именно в том, как наиболее нересурсоемко пройтись от вершины дерева до нужного номера сегмента. Сейчас я делаю это такой вот рекурсией: PHP: $path = explode("/", $_SERVER['REQUEST_URI']); /* Array ( [0] => [1] => admin [2] => login [3] => recover ) */ function get_id($p_id, $i='1'){ // $i равна еденице, потому, что массив $path начинается с первого элемента (нулевой элемент пуст — он нам не нужен) global $path; $sql = "SELECT id FROM `structure` WHERE p_id=".$p_id." AND url='".$path[$i]."' LIMIT 1"; $res = mysql_query($sql); if(mysql_num_rows($res)<1){ return $p_id; } $row = mysql_fetch_object($res); return get_lastid($row->id, ++$i); // вот тут рекурсия, айдишка передается как парэнт_айдишка } Получаются такие запросы: SELECT id FROM `structure` WHERE p_id='0' AND url='admin' LIMIT 1 // сейчас айдишка = 1 SELECT id FROM `structure` WHERE p_id='1' AND url='login' LIMIT 1 // сейчас айдишка = 2 SELECT id FROM `structure` WHERE p_id='2' AND url='recover' LIMIT 1 // сейчас айдишка = 3 всё, узнали айдишку Много запросов получается. На данный момент я переделал функцию — один единственный запрос выбирает абсолютно всё дерево сайта и заносит его в массив. Дальше уже этот массив я рекурсивно обхожу, чтобы узнать айдишку (и другую инфу). Всеравно не то. Хоть запрос и один, но теперь не нравится рекурсия. Так вот, как пройти от вершины дерева (от «admin») до последнего элемента («recover») (ну, или до заданного, неважно)? Как бы вы это сделали? В каком виде сохранить само дерево сайта, саму стркутуру разделов, чтобы по дереву можно было легко перемещаться от верхнего уровня до требумоего (ну, напрмер, массив парэнт_айдишек, в нем массив айдишек, а уже в них вся инфа о сайте).
Просмотрел. 1) Видишь ли, не всегда возможна структура сайта по типу — www.example.com/class/method/id/ — этот шаблон записи УРИ используется много где, в Code Igniter, например. Мне это не подходит. 2) Дальше. У меня динамические УРИ — сегменты могут менять свои первоначальные названия. www.example.com/admin/login/recover/ может измениться в www.example.com/administracija/vhod/novij_parol/ по желанию пользователя (он сам в ЦМСке это исправит по своему вкусу, например). И тогда класс с названием «admin» в котором есть метод «login» не будет подгружаться. Поэтому мне нужно разбить УРИ на сегменты и пройтись по базе в такой последовательности, как расположены эти сегменты. www.example.com/products/computers/sony/vaio/ — вот такой УРИ и именно такая структура дерева в базе, с айдишками и парэнт_айдишками. А есть и такой раздел: www.example.com/products/mp3players/sony/ — так вот чтобы узнать айдишку у «sony», я должен пройтись по ступенькам, от записи «products» в базе, до записи «sony» (в базе для раздела «sony» у меня уже есть запись и с шаблоном и с классом, который должен выполняться в этом разделе). Опять таки повторяю, не придерайтесь вы к УРЛ'у — вопрос не в том, как правильно структуру создать. Вопрос в том, как по динамическому УРИ пройтись в базе как по ступенькам.
МИТ, ты читаешь то, что я пишу? www.example.com/products/computers/sony/ www.example.com/products/mp3players/sony/ У меня есть раздел «Компьютеры» и в нем «Сони» А еще есть раздел «МП3 Плееры» и в нем тоже «Сони» Поэтому и речи не может быть про то, что просто взять «sony» из базы, так как у меня там 2 раза встречается этот «sony». Поэтому нужно пройтись по ступенькам по базе, исходя из того, какой у нас УРИ.
Нет, у меня именно структура /products/computers/sony/. Можно и по-другому, если хочешь — /products/sony/computers/. И в этом случае мой вопрос не изменяется.
PHP: <?php //$path = explode( '/', $_SERVER['REQUEST_URI']); /* Array ( [0] => [1] => admin [2] => login [3] => recover ) */ $path = array( '', 'admin', 'login', 'recover'); function BuildQuery( $path, $step = 0) { $query = '(SELECT `id` FROM `structure` WHERE `url` = "' .mysql_real_escape_string( $path[$step]) .'" '; if( ++$step != count( $path)) $query .= 'AND `p_id` = ' .BuildQuery( $path, $step); $query .= 'LIMIT 1) '; return $query; } function GetID( $path) { if( !is_array( $path) || count( $path) < 2) return false; array_shift( $path); $path = array_reverse( $path); $query = trim( BuildQuery( $path), '() '); return mysql_result( mysql_query( $query), 0, 'id'); } echo GetID( $path); ?>
тогда рекурсия или читать про другие виды деревьев. однако я бы сделал так /products/{Category_ID}/ и не парился с велосипедами или накрайняк сделал бы сони не как отдельную категорию а как фильтр при выборке
neverlose Спасибо тебе за труд, но ты предлагаешь то, отчего я уже избавился — куча запросов к базе. Вроде да, придется использовать ее величество. А другие виды деревьев — это какие? Материализованный путь? Нэстэд сэт? Они вопрос не решат, полюбому нужно будет перебирать записи в базе.
artuska он предлагает ОДИН запрос, с кучей подзапросов, что ещё хуже чем много запросов передавай лучше ID категории, или прям так надо передовать названия?
Ну тоже самое. Нет, нужен именно такой путь в каталогах, который пользователь без труда запомнит ассоциативно. «Я был в разделе продукты, в подразделе компьютеры, в разделе фирмы Сони» — /products/computers/sony/. А вот «Я был в разделе продукты, в разделе номер 65399» пользователь так не размышляет. Дальше. Админ ЦМС'ки возьмет, и захочет создать раздел вот по такому пути www.example.com/products/computers/sony/for_free и напихает туда компы, котрые нахаляву. Вот мне и нужно узнать айдишку раздела «for_free», по которой я потом в базе выберу именно компьютеры фирмы «Сони», которые «бесплатны». А сразу взять слово «for_free» я не могу, ведь может быть и такой УРИ: www.example.com/products/computers/hewl ... d/for_free Поэтому нужно пройтись по нашей структуре как по лестнице, от «products» до «for_free», чтобы не наткнуться на какой-нибудь другой раздел, где есть «for_free». А передавать наши «sony», «hewlett_packard» и «for_free» как параметры, я не могу — не смогу потом сделать менюшку сайта в виде дерева. Продукты Компьютеры Sony Vaio Забесплатно Hewlett Packard Забесплатно
Вы иначе не сделаете. Мой алгоритм минимален. Можно сделать только другую реализацию, чтобы ускорить алгоритм. Да и к тому же, количество подзапросов = количество элементов в $path минус 2.
artuska база у тебя не подходящая, ты должен указать в ней уже все дерево а потом как кто-то писал, выбрать "ВСЕ" дерево и обходить его рекурсивно - вариант зе бест по твоему примеру, что б понять как тебе перестроить бд Код (Text): Продукты (id=1, pid=0) Компьютеры (id=2, pid=1) Sony (id=2, pid=2) Vaio (id=3, pid=2) Забесплатно (id=4, pid=3) Hewlett Packard (id=4, pid=2) Забесплатно (id=6, pid=4) т.е. что б нормально без мозгоё.. обойти дерево ты должен указывать дочерней категории родительскую... а иногда и родительской нужно указать есть ли у него ребенок... upd потом ты имеешь вид бд примерно: Продукты (id=1, pid=0) Компьютеры (id=2, pid=1) Sony (id=2, pid=2) Vaio (id=3, pid=2) Забесплатно (id=4, pid=3) Hewlett Packard (id=4, pid=2) Забесплатно (id=6, pid=4) 1. извлек все 2. начинаешь обход рекурсивно (без нее тут практически никак) 3. выбираешь root потом опускаешься ниже и ниже, что б был вид дерева просто делаешь margin-left: n (в зависимости от дизайна) где n рекурсивно увеличиваешь
alexeurodnepr Да, так и буду делать — перестраивать там ничего не нужно, структура идиентична твоей — айдишка-парэнт_айдишка. Без рекурсии действительно не обойтись. Всем спасибо, тема может быть закрыта.