[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Многоуровневое меню в файле :)
m4a1fox
Доброй ночи господа. Решил я тут потренироваться на файлах, заодно и себе собственный велосипед собрать :). Так как ответа на эту не поступило. Я сам решился...
Итак! Я думаю получится маленький пост в плане - Как сделать многоуровневое меню на файлах

Как сделать многоуровневое меню на файлах
Часть II.

Приступим, помолившись! :)
Итак, начинаем с конфиг файла, где определяем 2 константы, а именно нашу папку в кот. будет находится галерея, и корень сайта

/**
* Establishes a physical path to a root directory of a script
* Устанавливает физический путь до корневой директории скрипта
*/

define('M4A1_ROOT', str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT']) .'/');

/**
* Establishes a path to a script root for main folder of menu
* Устанавливает путь до корневой директории меню
* в этой папке будут содержаться как пункты меню так и их подпункты
*/

define('M4A1_MAIN_MENU', 'gmenu/');

Дальше, по известной традиции мы создаем только одну точку входа на наш сайт!
Весь код index файла приводить не буду, только блок отвечающий за переадресацию на нужные файлы

switch(LinkTo()){
case (LinkTo()):
if(LinkTo() && file_exists('./'.LinkTo().'/run.php')){
include M4A1_ROOT.LinkTo().'/run.php';
}elseif(LinkTo() && is_dir(M4A1_MAIN_MENU . LinkTo())){
include M4A1_ROOT . M4A1_MAIN_MENU . 'run.php';
}else{
include M4A1_ROOT.'default/index.php';
}
break;
}

Итак, тут встречаются нам уже функции, о них ниже, сначала логика :)
Что тут происходит? Первая строчка думаю понятно, пояснение не нужны. Итак,
case(LinkTo()) – эта функция отвечает за GET параметр обычного меню! По сути возвращает то, что пришло в GET. Дальше. Если в GET таки что то пришло и это что то является папкой в кот. есть фай run.php то мы его запускаем (подключаем), иначе если, то что пришло папка по пути - M4A1_MAIN_MENU . LinkTo(), то мы идем в папку по такому пути - M4A1_ROOT . M4A1_MAIN_MENU и вытаскиваем от туда файл run.php, кот. собственно и является роутером, т.е. файлом кот перенаправляет запросы. Я обещал функции? Пожалуйте. Самые элементарные :) Я старался!

function LinkTo(){
if(isset($_GET['do']))
return $_GET['do'];
}

function LinkToItem(){
if(isset($_GET['item']))
return $_GET['item'];
}

Сейчас конечно борцы за чистоту кода и проверку данных разинули рты, мол, это же фигня и говнокод, ни проверок, ни фига. Но проверки можно добавить и все прочее тоже. Сейчас суть не в этом. Это что касалось только роутера на главной странице. Поехали дальше! Итак, допустим мы вызвали файл и прошли проверку по второму условию вот тут

elseif(LinkTo() && is_dir(M4A1_MAIN_MENU . LinkTo())){
include M4A1_ROOT . M4A1_MAIN_MENU . 'run.php';
}

Подключаем файл M4A1_ROOT . M4A1_MAIN_MENU . 'run.php'; и смотрим его внимательно:
<?php GoMainMenu(); ?>
Не многословен, не так ли. Думаю позже оцените почему. Итак, новая функция GoMainMenu(). Она собственно также страдает на отсутствие защиты, но дело поправимое! Сама функция:

function GoMainMenu(){
if(isset($_GET['do']) && isset($_GET['item'])){
include M4A1_ROOT . M4A1_MAIN_MENU . LinkTo().'/'.LinkToItem().'/model.php';
include M4A1_ROOT . M4A1_MAIN_MENU . LinkTo().'/'.LinkToItem().'/view.php';
}else{
include M4A1_ROOT . M4A1_MAIN_MENU . LinkTo().'/model.php';
include M4A1_ROOT . M4A1_MAIN_MENU . LinkTo().'/view.php';
}
}


Функция нубская, и проста в логике. Если есть в адресной строке LinkTo() && LinkToItem() то подключаем файлы из папки что возвращает LinkTo() и LinkToItem() – соответственно!
Это была самая легкая часть, занявшая у меня в сумме не более 2 часов. А вот до этого было почти целый день мозговыносимости :) В общем, как полагается хорошему детективу, мой рассказ, так же был начал с конца…. Может не стоило, но соблазн был велик.
Как сделать многоуровневое меню на файлах
Часть I

Все началось с того, что у стал делать для себя «песочницу». А так как к БД, нет настроения коннектится, мало ли что, решил все делать на файлах. Сделать пункт добавления нового меню, меня подтолкнула, запара с тем, что, что бы сделать новую страницу, нкжно открывать файл с меню и править его, плюс создавать новую папку, называть ее так же как и ссылку в пункте меню…. Ну в общем написал скрипт кот, это делает, то есть, я открываю определенную страницу на сайте, там есть форма, вбиваю слово, русский, анг, не принципиально, и создается папка, с уже вложенным файлами. А точнее с такими. model.php – это модель, тут только PHP. view.php – тут html + легкий PHP. run.php – файл в кот. подключаются 2 предыдущих. Сделать было не сложно, и все хорошо закончилось.

И вот спустя время, наверно недельку, я задумался сделать многоуровневое меню так же, на файла, так как на БД уже делал, и там все в принципе понятно и не сложно, а вот с файлами, мало работал, и надо практиковаться… Чет понесло меня… что ж, друзья, к коду:
Не знаю с чего начать! :)
О! Начнем пожалуй с формы добавления нового пункта меню. Форма имеет, некую не аккуратность! Кто хочет, можете разделить их…

<form action="" method="post">
<input
type="text" name="under_menu" <?php echo $error;?> />
<input
type="submit" name="create_under_menu" value="create" />
</form>


<hr />


<form
action="" method="post">
<select
name="item" id="select">
<?php
echo UMenu($filename);?>
</select>
<input
type="text" name="item_menu" <?php echo $error;?> />

<input
type="submit" name="create_item_menu" value="create" />
</form>


В порядке очереди! На странице находится 2 формы. Первая – добавляет новый пункт меню, вторая добавляет подпункт в меню.
Продолжим… сейчас приятное.
Обработчик первой формы. Сразу извините за код, если кому то что то не нравится, я попрошу сказать мне, и я исправлю! Так что кидаться сразу, фу фигня, не стоит. Спасибо! Итак! Обработчик первой формы:

$cl = file($filename); // про это позже
$filename = "./tpl/under_menu.inc"; // файл для занесения изменения меню
if(isset($_POST['create_under_menu'])){ // проверка на сущ. Отправки формы
$name = !empty($_POST['under_menu']) ? trim($_POST['under_menu']) : FALSE; // простая проверка введенных данных
$encode = translate($name); // это интересный момент, о нем чуть позже
$wroteSTR = "<li><span id=\"umenu\"><a href='?do=".$encode."'>".$name." &darr;</a></span>\n\t<ul>\n\t\t\n\t</ul>\n</li>\n"; // а вот эта строка кот. мы пудем записывать в файл
if($name){ // если $name таки TRUE
$fd = fopen($filename, "ab"); // открываем файл для записи, в конец файла
fwrite($fd, $wroteSTR); // записываем в файл строку
fclose($fd); // закрываем файл (это делать рекоммендуют)
mkdir(M4A1_MAIN_MENU .$encode); // создаем директорию нового пункта меню
OpenWriteClose(M4A1_MAIN_MENU .$encode."/model.php", "<?php\r\techo '<J>".$name."</J>';\r?>"); // про эту функцию позже
touch(M4A1_MAIN_MENU .$encode."/view.php"); // создаем файл, думаю по пути понятно что за файл
if(!file_exists('./gmenu/run.php')){ // проверка на сущ. Файла в каталоге M4A1_MAIN_MENU,
OpenWriteClose(M4A1_MAIN_MENU . "run.php", "<?php\r\tGoMainMenu();\r?>"); // если то…. Чуть позже про эту функцию
}
}
else{ // Иначе
$error = 'id="error-link"'; // в $error – заносим ошибку!
}
}


Как и обещал: 2 функции – 1. – translate(), 2 – OpenWriteClose.
Первая. Translate():

<?php
function
translate($str){
$tr = array("." => "", "'" => "", "\"" => "", " - " => "-",
" " => "-", "," =>"", "!" => "", "?" => "", "..." => "", "ё" => "e", "й" => "ii",
"ц" => "c", "у" => "u", "к" => "k", "е" => "e", "н" => "n", "г" => "g", "ш" => "sh",
"щ" => "sh", "з" => "z", "х" => "x", "ъ" => "", "ф" => "f", "ы" => "", "в" => "v",
"а" => "a", "п" => "p", "р" => "r", "о" => "o", "л" => "l", "д" => "d", "ж" => "j",
"э" => "e", "я" => "ya", "ч" => "ch", "с" => "s", "м" => "m", "и" => "i", "т" => "t",
"ь" => "", "б" => "b", "ю" => "uy", "Ё" => "e", "Й" => "ii", "Ц" => "c", "У" => "u",
"К" => "k", "Е" => "e", "Н" => "n", "Г" => "g", "Ш" => "sh", "Щ" => "sh", "З" => "z",
"Х" => "x", "Ъ" => "", "Ф" => "f", "Ы" => "", "В" => "v", "А" => "a", "П" => "p",
"Р" => "r", "О" => "o", "Л" => "l", "Д" => "d", "Ж" => "j", "Э" => "e", "Я" => "ya",
"Ч" => "ch", "С" => "s", "М" => "m", "И" => "i", "Т" => "t", "Ь" => "", "Б" => "b",
"Ю" => "uy", "A" => "a", "B" => "b", "C" => "c", "D" => "d", "E" => "e", "F" => "f",
"G" => "g", "H" => "h", "I" => "i", "J" => "j", "K" => "k", "L" => "l", "M" => "m",
"N" => "n", "O" => "o", "P" => "p", "Q" => "q", "R" => "r", "S" => "s", "T" => "t",
"U" => "u", "V" => "v", "W" => "w", "X" => "x", "Y" => "y", "Z" => "z");
return strtr($str, $tr);
}

Ничего гениального. Функция принимает в качестве первого и единственного параметра строку и переводит в латиницу. Нужна для того, что бы если пункт меню был бы на русском, папка и ссылка были бы на латинице.

Ну и вторая. OpenWriteClose. Так же проста до безобразия. Смотрим.

function OpenWriteClose($filename, $string=null){
touch($filename);
$file = fopen($filename, "w");
fwrite($file, $string);
fclose($file);
}

Принимает 2 параметра. Первый – файл, 2 – строка кот. нужно добавить в файл. Если ее нет(строки), то ничего не заносим. Думаю, теперь все для всех прояснилось.
Поехали дальше! Собственно это тоже не было сложно реализовать. Да и вообще, оценивая сейчас что есть, я удивляюсь почему было потрачено столько времени! Ну да бог сним…

Вторая форма. Вы наверняка должны были заметить, во второй форме, напомним ее

<form action="" method="post">
<select
name="item" id="select">
<?php
echo UMenu($filename);?>
</select>
<input
type="text" name="item_menu" <?php echo $error;?> />
<input
type="submit" name="create_item_menu" value="create" />
</form>


Функцию - UMenu($filename). В качестве параметра принимает ссылку на файл с меню, и вот для чего. Функция:

function UMenu($file){ // тут все понятно
$er = file_get_contents($file);
preg_match_all('#<span\sid="umenu"><a.*>(.*)\s&darr;</a>#isU', $er, $match);
unset($match[0]);
foreach($match[1] as $val){
echo '<option value="'.$val.'">'.$val.'</option>';
}
}


Пройдемся по строчкам.

$er = file_get_contents($file); // читаем содержимое файла и переводим в строку.
preg_match_all('#<span\sid="umenu"><a.*>(.*)\s&darr;</a>#isU', $er, $match); // ищем все совпадения условию регулярного выражения.
unset($match[0]); // уничтожаем первый найденный массив, он нафиг не нужен
foreach($match[1] as $val){ // перебираем его
'<option value="'.$val.'">'.$val.'</option>'; // и выводим в option то что нашли
} – закрываем foreach.

Так, с добавлением пункта меню – вроде как разобрались, а теперь сладкое. :D Как добавить подпункт меню в меню? Код с пояснением!

if(isset($_POST['create_item_menu'])){ // проверяем на сущ. Нажатой кнопки
$item = strtolower($_POST['item']); // делаем мальньким.
$item_menu = !empty($_POST['item_menu']) ? trim($_POST['item_menu']) : NULL; // тут можно не объяснять просто проверка на не пустоту.
if($item_menu){ // если TRUE – поехали дальше
$item_encode_menu = translate($item_menu); // переводим в латиницу. Вы уже в курсе
$link = "?do=".$item."&item=".$item_encode_menu; // создаем link
$wrote = "\t\t<li><span><a href='./index.php".$link."'>".$item_menu." &darr;</a></span></li>\n\n"; // вставляем линк. Это будет помещаться в файл меню $i=0; // объяиляем переменную i равной нуля
foreach($cl as $key=>$val){ // перебираем массив cl
$i++; // прибавляем каждый раз один, пока
if(preg_match("#".$_POST['item']."#is", $val)){ // пока не натыкаемся на совпадение в регулярном выражении. Это нужно что бы определить куда конкретно будет вставлена строка $wrote
$findline = $i+1; // прибавляем 1 – так надо, ибо отсчитывать надо правильно от строки где найдено совпадение, плюс там еще записыватся <ul> - поэтому строчку прибавляю.
}
}

array_splice($cl, $findline, 0, $wrote); // Очень полезная оказалась конструкция. Делает вот что, берет массив $cl, находит строчку - $findline, 0 – означает что вставить строку надо после $findline, и собственно строка - , $wrote
file_put_contents($filename, $cl); // помещаем все это в файл с меню
mkdir(M4A1_MAIN_MENU .$item."/".$item_encode_menu); // создаем папку по пути что передали в POST запросе
OpenWriteClose(M4A1_MAIN_MENU .$item."/".$item_encode_menu."/model.php", "<?php\r\techo '".$item_menu."';\r?>"); // это вы уже знаете
OpenWriteClose(M4A1_MAIN_MENU .$item."/".$item_encode_menu."/view.php"); // аналогично
}else{
$error = 'id="error-link"'; // ошибка, если input пуст
}


В общем пока что все! Если нужны пояснения – спрашивайте. Но ответить наверно только либо рано утром смогу либо вечером. Наверно еще скрины стоит выложить! В общем поживем увидим!

Вывод. В папке - M4A1_MAIN_MENU, создается папка (это основное меню + 2 файла - model.php + view.php при клике на пункт меню они вступают в роль), в каждой папке, создаются подпапки - это подпункты основных меню, в них структура каталогов аналогична! Спасибо за внимание. И да, прошу прощение за длинные строки, позже укорочу! Спасибо всем за внимание! Ах да, забыл! Насчет безопасности входящих данных - сделаю но позже, ибо время уже позднее!



Спустя 5 минут, 30 секунд (17.12.2011 - 03:08) Игорь_Vasinsky написал(а):
стой стой стой.. чё то ты на мудрил..конструкция switch->case используется как аналог if->else

не понял...

Спустя 2 минуты, 25 секунд (17.12.2011 - 03:10) m4a1fox написал(а):
Игорь_Vasinsky
Я ХЗ конечно, но работает! Поправь меня если не сложно!

Спустя 15 минут, 23 секунды (17.12.2011 - 03:25) Игорь_Vasinsky написал(а):
не ну по существу трудно сказать.. у меня утро.. которое начаось после вечера пятницы))

вот может проглядел, но в транслите "ё" не увидел...


остальное - много данных для анализа))

и потом.. ты в начале ловко придерживаешся MVC, а под конуц - примясь PHP+HTML

всётаки - смарти это весч wink.gif а то смысл паттерна теряется

Спустя 2 минуты, 17 секунд (17.12.2011 - 03:28) m4a1fox написал(а):
Игорь_Vasinsky
Цитата
а под конуц - примясь PHP+HTML

Да, я так прикинул, нафиг много роутеров, и сделал один! С одной стороны я выигрываю в том, что не плодится не нужный файл, по сути, но с другой, проигрываю в том что, если нужно будет еще файлы включить в какой нибудь под пункт, то тут придется ручками корячится!
Цитата
вот может проглядел, но в транслите "ё" не увидел...
есть! Проверил! smile.gif

Спустя 2 часа, 6 секунд (17.12.2011 - 05:28) bodja написал(а):
Фигасе blink.gif
Это для чего всего столько...
Только меню построить?

Спустя 6 часов, 30 минут, 53 секунды (17.12.2011 - 11:59) sharki написал(а):
действительно ппц, если уже на файлах (используя как БД) то достаточно было использовать serialize, не? Но не столько же всего..

---------------------------------------------------

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

$fd = fopen($filename, "ab"); // открываем файл для записи, в конец файла
fwrite($fd, $wroteSTR); // записываем в файл строку
fclose($fd); // закрываем файл (это делать рекоммендуют)
mkdir(M4A1_MAIN_MENU .$encode); // создаем директорию нового пункта меню
OpenWriteClose(M4A1_MAIN_MENU .$encode."/model.php", "<?php\r\techo '<J>".$name."</J>';\r?>"); // про эту функцию позже


Ты же уже писал выше про OpenWriteClose, а тут опять эти fwrite и т.п
А почему же не взять вместо fwrite file_put_contents ?


Спустя 11 минут, 34 секунды (17.12.2011 - 12:10) Игорь_Vasinsky написал(а):
а может и сразу удобней file()

Спустя 5 часов, 50 минут, 54 секунды (17.12.2011 - 18:01) m4a1fox написал(а):
bodja
Цитата
Только меню построить?

Да, только для меню! В принципе не сложно!

sharki
Цитата
то достаточно было использовать serializ

Да,тут не спорю!наверно serializ удобнее. Но так уж вышло, что построил на файле!
Цитата

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

Да, точно! Спасибо, сразу и не заметил!
Цитата

А почему же не взять вместо fwrite file_put_contents ?

Возможно и так стоит сделать! Посмотрим.

Цитата
а может и сразу удобней file()

Может и удобнее, но иногда строка нужнее массива

Спустя 18 минут, 44 секунды (17.12.2011 - 18:20) Игорь_Vasinsky написал(а):
ну строка и есть wink.gif - элемент массива

Спустя 1 день, 21 минута, 27 секунд (18.12.2011 - 18:41) Winston написал(а):
Это статья или как ?

Спустя 54 минуты, 51 секунда (18.12.2011 - 19:36) m4a1fox написал(а):
Winston
Цитата
Это статья или как ?


Да черт его знает! Хотел сначала статью! Потом, по отзывам понял, что тема не популярна а решение тривиально. Поэтому, наверно это просто описание моего мучения. Хотя наверно стоит добавить картинки для ясности.... в общем вам решать.
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.