Архитектура таблицы разделов сайта

Иван Шумков

Новичок
Архитектура таблицы разделов сайта

Как удобнее (оптимальнее в плане скорости) хранить данные о разделах сайта. Разделов ожидается не более 50.

Работа с разделами проста: скрипт парсит урл и сверяет по таблице url разделов пока не пройдет весь урл. Если путь не верный - 404, если верный то смотрим в таблице как обработчик и параметры стоят у последнего раздела и запускаем обработчик.

Как организовать такую проверку на практике. Или есть более правильная схема?
 

SelenIT

IT-лунатик :)
Иван Шумков
если я правильно понял, речь идет о виртуальных путях ЧПУ?
 

Иван Шумков

Новичок
SelenIT
Да, вы правильно поняли.

-~{}~ 31.07.05 20:15:

Вот что у меня пришло в голову:
id - ид раздела
parent_id - ид родителя
title - название раздела
url - его урл (либо писать сюда весь путь к разделу?)
handler - обработчик
source_id - ид данных

Если писать урл только конкретного раздела, то надо рекурсивной функцией бежать по всей цепочки урлов до конца, таким образом проверяя есть ли такой раздел.

Либо, если указывать полный путь в урл то можно один запросом это проверять, но тогда сложнее реализовать редактирование/создание разделов.

Если есть документ определяем хендлер и ид данных, и передаем управление ему. Он же знает из какой таблицы брать данные по иду.

Или все это маразм?
Как реализуются такие вещи?
 

mani13

Новичок
pid - page id - идентификатор страницы
[title] - заголовок страницы
url - полный урл страницы
handler - обработчик

в простом варианте так
искать:
1. посмотрели базовый урл, нет такого - отрезали часть, записали в параметры
2. посмотрели базовый урл, нет такого - 404 Not Found

а source_id -- это что за id данных?

всё - ИМХО
 

mani13

Новичок
Иван Шумков
1.
есть, например,
/news/sport и /news/net, отображающие категории новостей, и есть /news, отображающая все новости
добавляем в БД запись
/news/ | news.php

а при загрузке страницы
если в базе есть полностью, то берём полностью
если нет, то отрезаем часть(/news/sport -> /news), а sport записываем в первый параметр, повторяем операцию

ИТОГО: удобно для чего-нибудь с параметрами(дата, ид топика и проч.), так как параметры откинутся + можно под определённые условия создать отдельный обработчик(например, захотелось добавить /news/tv со своим супер-пупер форматом)
но, ИМХО, не совсем красиво получается, если нет страницы(например, /shop), так как просто отобразится главная страница

2. писать полные урлы и искать именно их полностью
то есть
/news/sport/ | news.php
/news/net/ | news.php
/news/ | news.php
только там уже придётся в news.php писать что-то, что будет само определять есть ли категория либо заводить по обработчику на категорию, что не очень хорошо при изменении одного...
ИТОГО: со страницами всё нормально - нет, так нет...
но, если есть динамический контент(например, просмотр каждой новости отдельно), надо заводить в базу все эти новости, а их может быть очень много....
 

crocodile2u

http://vbolshov.org.ru
Иван Шумков
Если писать урл только конкретного раздела, то надо рекурсивной функцией бежать по всей цепочки урлов до конца, таким образом проверяя есть ли такой раздел.
Зачем рекурсивной функцией?
Допустим, есть URL: /news/sport/smth
Выбираем из базы:
[sql]
SELECT * FROM menu WHERE url IN ('news','sport','smth')
[/sql]
Дальше остается только немного обработать результаты выборки.
 

SelenIT

IT-лунатик :)
Используя подход, описанный здесь, можно по идее выбрать и проверить вообще все сразу одним запросом, наподобие такого:
[sql]
SELECT t02.id FROM tree t00 LEFT JOIN tree t01 ON (t01.parent_id=t00.id) LEFT JOIN tree t02 ON (t02.parent_id=t01.id) WHERE t00.url='news' AND t01.url='sport' AND t02.url='smth' [/sql]
По идее, с правильными индексами работает такая вещь быстро, так что на 50-100 записях проблем вообще не предвидится.

P.S. До вчерашнего дня я сам склонялся к хранению псевдоурлов целиком, но теперь крепко задумался и уже ни в чем не уверен...
 

SelenIT

IT-лунатик :)
Во-первых, этот вариант не такой уж и мой ;), во-вторых, результат такого запроса не надо обрабатывать, он уже говорит сам за себя (если цепочке /news/sport/smth соответствует какой-то раздел - будет сразу найден его id, если не соответствует - результат будет пустым). Правда, это все в предположении, что все элементы URLа кодируют раздел.
 

Иван Шумков

Новичок
SelenIT
А что если не все?
Например в урле /main/news/2005/, main и news - разделы, а 2005 параметр? Тогда не совсем ваш запрос не помойму не подходит :)
 

SelenIT

IT-лунатик :)
Навскидку для такого случая пойдет такой запрос:
[sql]
SELECT IF (
t02.id IS NOT NULL , t02.id,
IF (
t01.id IS NOT NULL , t01.id, t00.id
)
)
FROM tree t00
LEFT JOIN tree t01 ON ( t01.parent_id = t00.id
AND t01.url = 'sport' )
LEFT JOIN tree t02 ON ( t02.parent_id = t01.id
AND t02.url = '2005' )
WHERE t00.url = 'news'
[/sql]
 

Иван Шумков

Новичок
SelenIT
Мы же изначально не знаем что 2005! Это может быть раздел!

-~{}~ 01.08.05 17:34:

Я пытался сказать, что мы изначально (при определении обработчика) не знаем, что у нас в урле параметр, а что раздел.
 

mani13

Новичок
[sql]SELECT t00.id as t00id, t01.id as t01id, t02.id as t02id from tree t00
left join tree t01 on ( t01.parent_id = t00.id && t01.url = 'news' )
left join tree t02 on ( t02.parent_id = t01.id && t02.url = '2005' )
where t00.url = 'main' && t00.parent_id = 0[/sql]
что-то вроде этого...
а далее проверяем
Код:
if (!empty set) {
 if (t02id is null) {
  if (t01id is null) {
   $id = t00id
  } else $id = t01id
 } else $id = t02id
} else $id = 0
p.s.: это почти то же самое, что написал SelenIT
 

Иван Шумков

Новичок
mani13
Ни как не могу сгенерить sql и условия проверки.

Попробую на словах:
1. Есть урл main/news/2005
2. Получаем массив $array = array('main', 'news', '2005');
3. Как сгенерить sql?
4. Как сгенерить проверку?
[/php]
 

SelenIT

IT-лунатик :)
Иван Шумков
Каковы критерии "раздела" и параметров? Если есть какие-то априорные признаки параметра (например, содержание только цифр или специальный префикс) - то по-моему нужно учесть их при парсинге урла (например, в регулярке) и запросу скармливать только заведомо "непараметрическую" часть. Если же единственный признак "раздела" - наличие в базе, то приведенные примеры запросов в состоянии справиться с проверкой по этому критерию.

А вообще - целесообразно ли делить подобным образом и так условное ЧПУ? Не проще ли для заведомо конечного набора "почти статических" параметров (типа тех же календарных интервалов) предусмотреть "разделы" (это нетрудно автоматизировать), а "явно динамические" и неактуальные для поисковиков (типа SID-ов) вообще не конвертировать в ЧПУ?
 

Иван Шумков

Новичок
SelenIT
Не проще ли для заведомо конечного набора "почти статических" параметров
Это не очень гибко.

Я понял что подобный запрос мне подходит. Только пока никак не могу его сгенерировать.
 

mani13

Новичок
Иван Шумков
3. for ($i=1;$i<count($array);++$i) add join
4. for ($i=count($array)-1;$i>0;--$i) check - break
 

SelenIT

IT-лунатик :)
Вариант генерации запроса, не требующего дальнейшего разбора:
PHP:
$sql1 = 't0.id';
$sql2 = " FROM $tablename t0 ";
for($i=1, $c=count($array); $i<$c; $i++) {
   $sql1 = "IF (t$i.id IS NOT NULL, t$i.id, " . $sql1 . ")";
   $sql2 .= "LEFT JOIN $tablename t$i ON (t$i.parent_id = t".($i-1).".id AND t$i.url = '" . mysql_real_escape_string($array[$i]) . "') ";
}
$sql = "SELECT " . $sql1 . $sql2 . " WHERE t0.parent_id = 0 AND t0.url = '" . mysql_real_escape_string($array[0]) . "'";
 

Иван Шумков

Новичок
SelenIT

Спасибо большое. Все замечательно. Если результат запроса пустить через mysql_fetch_array, то на выходе имеем:
Array
(
[0] => 4
[IF (t1.id IS NOT NULL, t1.id, t0.id)] => 4
)
Первый - это id, а вот зачем второй элемент я не знаю. Это не ошибка?
 
Сверху