Горбунов Олег правильно убедил. Есть логика приложения, но бывает ещё и логика шаблона когда к примеру надо сделать черезстрочные background в таблице или отображать кнопку при определённых условиях. Такие вещи меняются в шаблонах а не в самом приложении. Так легче и сильно упрощается логика приложения.
Меня никогда не подводил. Мне ли бояться своего кода? Что же касается заказчика... Здесь +Sten+ уже спрашивал: а сможет ли "не программист" правильно переделать шаблон? Проверено многократно: нет, не сможет. Поэтому пусть управляет содержанием (контентом) -- что и отражает термин CMS. Честно говоря, в моём CMS шаблонов нет вообще.
а также нет модели и контроллеров В моей CMS ни одного бага! tmanager А если серьезно, то расскажи как у тебя структура построена. Уж очень заинтересовал подход без шаблонов. А то я дурак мучаюсь всю жизнь шаблоны рисую, вдруг зря
Есть класс page. Он занимается составлением HTML-кода страницы, сохранением его на диск, сохранением параметров страницы в базе данных и извлечением этих параметров из базы данных. "Дети" этого класса могут переопределять частично или полностью логику построения HTML-кода страницы. Т.е. появились страницы, для которых нужна особая логика -- пишешь подкласс и записываешь его в папку для классов. "Пропишется" он в моём CMS автоматически. Работа с CMS строится так: создаётся структура меню для каждой языковой версии. К пунктам меню подкючаются страницы -- указывается класс создаваемой страницы (в списке, понятно, человеческие названия, типа "статья" и т.п.) -- и выводятся все поня, которые для данного типа надо заполнить. Мой CMS не исключает шаблоны. Соотв. метод может принять параметр ИмяШаблона и склепать по нему страничку. Ни разу не пригодилось. Ну если так удобней -- то не зря. Был бы результат хороший. А мне, признаться, неудобно. Поддержку шаблонов я вообще-то для заказчиков делал. Думал, вдруг на них нападёт блажь шаблоны редактировать. Пока Бог миловал.
Спасибо за развернутый ответ, но вопросы конечно остались. Т.е. у тебя в классе Page логика отобображения страницы + HTML-код? Приведи пожалуйста пример одного из своих классов Page
Класс page для tmanager.ru Синтаксис ещё 4-го php, так как класс древний. Всё не соберусь переписать. PHP: <?php require_once dirname(__FILE__)."/../inc/conn.php"; //Подключение к MySQL require_once dirname(__FILE__)."/menu.class.php"; //Формирование меню require_once dirname(__FILE__)."/select.class.php"; //Простроение <select> require_once dirname(__FILE__).'/area.class.php'; //"шапки" и нижние части require_once dirname(__FILE__).'/banner.class.php'; //Для кого-то делал баннерную рулетку //Базовый класс для всех страниц. class page { //Определяем свойства var $id; // id страницы в таблице pages var $itemID; // id пункта меню (таблица items) var $title; var $keywords; var $description; var $css; var $jsFile; var $js;//Не надо в базу var $content; //Текст, который метод content() дочерних классов может быть использован как параметр var $contentName; //название текста в $this->content var $classID; // Класс страницы var $className; // Класс страницы var $lng; //Язык страницы (int) var $language; //Язык страницы (string) var $filename; //Имя файла страницы var $left; var $base;// относительный путь к корневой папке -- для меню var $menu_prefix; // var $textarea_h_mm;// Высота текстареа для ввода контента. Для разных классов -- может быть разной //---------------------------- //Получение свойств (не всех -- а только "абстрактных") // страницы из базы данных function get() { //echo "Началсь get(".$this->id.")"; global $conn; //Установим значения свойств по умолчанию if (!isset($this->itemID)) $this->itemID=0; $this->title="ТурМенеджер"; $this->css="../default.css"; $this->jsFile=""; $this->js="";//Не надо в базу $this->keywords="туризм автоматизация ТурМенеджер Максименко Кашаев"; $this->description="Сайт программы ТурМенеджер"; $this->content=""; $this->lng=1; $this->language="russian"; $this->left=""; if ($this->id!=null) { $query="select * from pages where id=" .$this->id; $res=mysql_query($query,$conn) or die(mysql_error()); while ($row=mysql_fetch_assoc($res)) { $this->title=stripslashes($row["title"]); $this->css=stripslashes($row["css"]); $this->jsFile=stripslashes($row["jsFile"]); $this->content=stripslashes($row["content"]); $this->lng=(int)$row["lng"]; if ($this->lng!=1) $this->get_language(); $this->classID=(int)$row["classID"]; //$this->className=$row["className"]; $this->itemID=(int)$row["itemID"]; $this->filename=$row["filename"]; $this->keywords=str_replace(""","",stripslashes($row["keywords"])); $this->description=str_replace(""","",stripslashes($row["description"])); } mysql_free_result($res); } } //--------------------------------------------------------------------------------------- function get_language() { global $conn; global $_SERVER; $query="select language from languages where id=". $this->lng; $result2=mysql_query($query,$conn); while ($row2=mysql_fetch_array($result2,MYSQL_ASSOC)) { $this->language=strtolower ($row2["languageName"]); } mysql_free_result($result2); } //--------------------------------------------------------------------------------------- //получение класса по ID function page_class($id) { global $conn; $classID=null; if ($id==null) { $query="select id as classID from classes limit 0,1"; } else { $query="select classID from pages where id=$id"; } $result=mysql_query($query,$conn); while($row=mysql_fetch_array($result,MYSQL_ASSOC)) { $classID=$row["classID"]; } mysql_free_result($result); //Проверим $query="select count(id) as n from classes where id=$classID"; $result=mysql_query($query,$conn); $n=mysql_result($result,0,0); mysql_free_result($result); if ($n==0) $classID=null; if (($id!=null)&&($classID==null)) { $className=""; $query="select className from pages where id=$id"; $result=mysql_query($query,$conn); while($row=mysql_fetch_array($result,MYSQL_ASSOC)) { $className=$row["className"]; } mysql_free_result($result); if ($className!="") { $query="select id as classID from classes where className='$className'"; $result=mysql_query($query,$conn); while($row=mysql_fetch_array($result,MYSQL_ASSOC)) { $classID=$row["classID"]; } } } return $classID; } //--------------------------------------------------------------------------------------- function get_classID() { global $conn; global $_SERVER; $query="select id as classID from classes where className='".$this->className."'"; $result=mysql_query($query,$conn); while($row=mysql_fetch_array($result,MYSQL_ASSOC)) { $this->classID=$row["classID"]; } } //--------------------------------------------------------------------------------------- function get_parent() { global $conn; $parentID=-1; $query="select parentID from items where id=".$this->itemID; $result=mysql_query($query,$conn); while($row=mysql_fetch_array($result,MYSQL_ASSOC)) { $parentID=$row["parentID"]; } return $parentID; } //-------------------------------------------------------------------------------------- //Форма редактирования свойств страницы function form($action, $method="post") { global $conn; global $_SERVER; if ($_SERVER["SERVER_NAME"]=="nav") mysql_query("SET NAMES cp1251",$conn); $html="<script type="text/javascript"> <!-- function resize(delta) { var textarea=document.pageform.content; var hh=textarea.style.height; var h=parseInt(hh.substr(0,hh.length-2)); h+=delta; textarea.style.height=h+'mm'; } //--> </script>"; $html.="<script type="text/javascript" src="toolbar.js"></script>"; $html.="\n<form id="pageform" name="pageform" action="$action" method="$method">\n"; if ($this->id!=null) $html.="<input type="hidden" name="id" value="".$this->id."">\n"; $html.="<table>"; $html.="\n<tr><td>Пункт меню</td><td>"; $m=new menu($this->lng,0); $html.=$m->select_items($this->itemID,"itemID"); $html.="</td></tr>\n"; $html.="\n<tr><td><title></td><td>"; $html.="<input type="text" style="width:120mm" name="title" value="".$this->title."">"; $html.="</td></tr>"; $html.="\n<tr><td><meta name="Keywords" ></td><td>"; $html.="<textarea name="keywords" style="width:120mm;height:15mm" >"; $html.=$this->keywords; $html.="</textarea>"; $html.="</td></tr>"; $html.="\n<tr><td><meta name="description" ></td><td>"; $html.="<textarea name="description" style="width:120mm;height:15mm" >"; $html.=$this->description; $html.="</textarea>"; $html.="</td></tr>"; $html.="\n<tr><td>Файл css</td><td>"; $html.="<input type="text" style="width:50mm" name="css" value="".$this->css."">"; $html.="</td></tr>"; $html.="\n<tr><td>Файл JavaScript</td><td>"; $html.="<input type="text" style="width:50mm" name="jsFile" value="".$this->jsFile."">"; $html.="</td></tr>"; $html.="\n<tr><td>". $this->contentName. "</td><td>"; $toolbar=array("Ж","К","Маркер","Маркер","Ч","Параграф с кр. строкой","Параграф без кр. строки","Ссылка","«»"); $html.="\n<script type="text/javascript">\n document.write('<input type="button" value="".$toolbar[0]."" onclick="tag(0,document.pageform.content);" class="toolbar" title="Помечает выделенный текст для показа его жирным" style="font-weight:bold;width:7mm"> ');"; $html.="\n document.write('<input type="button" value="".$toolbar[1]."" onclick="tag(2,document.pageform.content);" class="toolbar" title="Помечает выделенный текст для показа его курсивом" style="font-style:italic;width:7mm"> ');"; $html.="\n document.write('<input type="button" value="".$toolbar[4]."" onclick="tag(10,document.pageform.content);" class="toolbar" title="Помечает выделенный текст для показа его подчёркнутым" style="text-decoration:underline;width:7mm"> ');"; $html.="\n document.write('<input type="button" value="".$toolbar[2]."" onclick="tag(6,document.pageform.content);" style="background-color:yellow;color:blue;font-weight:bold"class="toolbar" title="Помечает текст для выделения его жёлтым маркером"> ');"; $html.="\n document.write('<input type="button" value="".$toolbar[3]."" onclick="tag(8,document.pageform.content);" style="background-color:red;color:white;font-weight:bold" class="toolbar" title="Помечает выделенный текст для выделения его красным маркером"> ');"; $html.="\n document.write('<input type="button" value="".$toolbar[5]."" onclick="tag(12,document.pageform.content);" class="toolbar" title="Выделите участок текста для того, чтоб отметить его как параграф"> ');"; $html.="\n document.write('<input type="button" value="".$toolbar[6]."" onclick="tag(14,document.pageform.content);" class="toolbar" title="Выделите участок текста для того, чтоб отметить его как параграф"> ');"; $html.="\n document.write('<input type="button" value="".$toolbar[7]."" onclick="tag(16,document.pageform.content);" class="toolbar" title="Выделите участок текста для того, чтоб отметить его как ссылку"> ');"; $html.="\n document.write('<input type="button" value="".$toolbar[8]."" onclick="tag(18,document.pageform.content);" class="toolbar" title="Выделите участок текста для того, чтоб заключить его в кавычки"> ');"; $html.="</script>\n<br />"; $content=$this->content; $content=str_replace("textarea","textarea",$content); $html.="<textarea style="width:180mm;height:".$this->textarea_h_mm."mm;font-size:12pt" name="content">".$content."</textarea>"; $html.="\n<br /><input type="button" name="plus" value="+" onclick="resize(30);">"; $html.="<input type="button" name="minus" value="-" onclick="resize(-30);">"; $html.="</td></tr>"; $html.="\n<tr><td>Класс страницы</td><td>"; $query="select id,friendlyName from classes order by friendlyName"; $result=mysql_query($query,$conn); $classes=array(); while($row=mysql_fetch_array($result,MYSQL_ASSOC)) { $key=$row["id"]; $classes[$key]=stripslashes($row["friendlyName"]); } mysql_free_result($result); $select=new select("classID",$classes,$this->classID); $html.=$select->html(); $html.="</td></tr>"; $html.="\n<tr><td>Язык страницы</td><td>"; $query="select id,language from languages order by language"; $result=mysql_query($query,$conn); $lngs=array(); while($row=mysql_fetch_array($result,MYSQL_ASSOC)) { $key=$row["id"]; $lngs[$key]=stripslashes($row["language"]); } mysql_free_result($result); $select=new select("lng",$lngs,$this->lng); $html.=$select->html(); $html.="</td></tr>"; $html.="\n<tr><td>Имя файла страницы</td><td>"; $html.="<input type="text" style="width:50mm" name="filename" value="".$this->filename."">"; $html.="</td></tr>"; $fields=$this->special_fields(); //абстрактный метод -- на откуп подклассам if ($fields!="") { $html.=$fields; } $html.="\n<tr><td colspan="2" style="text-align:center">"; $html.="<input type="submit" name="save" value="Сохранить!">"; $html.=" <input type="submit" name="save_and_refresh" value="Сохранить и обновить сайт!">"; /* $query="select content from backup where pageID=".$this->id; $result=mysql_query($query,$conn); $content=""; while($row=mysql_fetch_array($result,MYSQL_ASSOC)) { $content=stripslashes($row["content"]); } mysql_free_result($result); */ if ($content!="") { $html.="<script type="text/javascript">"; $html.="<!--"; $content=preg_replace("/\r?\n/","###",$content); $array = explode("###", $content); $html.="\nfunction from_backup() { var f=document.getElementById('pageform'); var textarea=f.elements['content']; textarea.value='';\n"; foreach ($array as $s) $html.="textarea.value+='".addslashes($s)."'+'\\n';\n"; $html.="}\n"; $html.="//-->"; $html.="</script>\n"; $html.=" <input type="button" name="backup" value="Восстановить ".$this->contentName." из резервной копии " onclick="from_backup()" />"; } else $html.=" <span style="color:red">Резервной копии нет</span>"; $html.="</td></tr>"; $html.="</table>"; $html.="\n</form>\n"; return $html; } //--------------------------------------------------------------------------------------- //Получение данных Формы редактирования function submit($method_array) { if (!isset($method_array["save"]) && !isset($method_array["save_and_refresh"])) return "no_submit"; foreach ($method_array as $propertyName=>$propertyValue) { if (($propertyName!="save") && ($propertyName!="save_and_refresh")) { $value=$propertyValue; if ($propertyName=="content") $value=str_replace("textarea","textarea",$value); if (get_magic_quotes_gpc()) $value=stripslashes($value); $this->$propertyName=$value; } } $this->special_submit($method_array); //абстрактный метод return "Ok"; } //--------------------------------------------------------------------------------------- //Возвращает html-код страницы function html($step=1) //В php4 нельзя "спрятать" метод от вызова извне { $htm=$this->headers(); $htm.="\n<body>"; $htm.=$this->table(); $htm.="</body>\n</html>"; return $htm; } //------------------------------------------------- function headers() { $html="<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">"; $html.="\n<html xmlns="http://www.w3.org/1999/xhtml">\n<head>\n"; $html.="<title>".$this->title."</title>"; $html.="\n<meta http-equiv="Content-Type" content="text/html; charset=windows-1251"/> "; $html.="\n<meta name="Keywords" content="".quotemeta($this->keywords).""/>"; $html.="\n<meta name="Description" content="".quotemeta($this->description).""/>"; $html.="\n<link href="".$this->css."" rel="stylesheet" type="text/css"/>\n"; $html.="\n<script src="../menu.js" type="text/javascript" ></script>"; $html.=$this->js; $html.="\n</head>\n\n"; return $html; } //------------------------------------------------- function table() { $htm="<table border="0" align="center" cellpadding="0" cellspacing="3" class="global">"; $htm.="\n<tr><!-- Строка шапки -->\n<td class="title" colspan="2">" . $this->top() ."</td></tr>"; $htm.="\n<tr><!-- Строка главного меню -->\n<td class="mainmenu" align="center" colspan="2">" . $this->mainmenu() ."</td></tr>"; $htm.="<!-- Строка подменю и содержания -->"; $htm.="\n<tr>\n"; $htm.="\n<!-- Столбец содержания -->\n"; $htm.="\n<td class="content" onclick="hide();" onmouseover="div_out();">\n\n" ; $htm.=$this->content(); $htm.="\n\n</td>"; $htm.="\n<td class="submenu" align="left" valign="top">" ; $htm.=$this->submenu(); $htm.="</td>"; $htm.="</tr>"; $htm.="\n<tr><td class="bottom" colspan="2">" . $this->bottom() ."</td></tr>"; $htm.="\n</table> <!--Закончилась таблица, содержащая всю страницу -->\n"; return $htm; } //---------------------------------------------------- function top() { $area=new area($this->lng,$this->classID); $top=$area->top; if ($top=="") { $area=new area($this->lng,0); $top=$area->top; } return $top; } //------------------------------------------------- function mainmenu() { $parentID=$this->get_parent(); $m=new menu($this->lng,$parentID,$this->itemID); $html=$m->main_menu(); return $html; } function submenu() { $parentID=$this->get_parent(); $submenu=new menu($this->lng,$parentID); $html=$submenu->sub_menu($this->itemID,$this->menu_prefix); return $html; } //------------------------------------------------- function bottom() { $area=new area($this->lng,$this->classID); $bottom=$area->bottom; if ($bottom=="") { $area=new area($this->lng,0); $bottom=$area->bottom; } return $bottom; } //------------------------------------------------- function folder() { $folder=dirname(__FILE__)."/../".$this->language; return $folder; } //------------------------------------------------ //Сохраняем страницу на диске function toHDD() { if ($this->filename=="") return "Файл не имеет имени"; $folder=$this->folder(); if(!file_exists($folder)) mkdir($folder); $f=fopen($folder."/".$this->filename,"w"); if ($f===false) { $result ="не смогли открыть файл на запись"; return $result; } $z=$this->html(); $i=fwrite($f,$z); if ($i===false) { $result ="не смогли записать в открытый файл"; fclose($f); return $result; } elseif ($i==0) { $result ="пустой файл!"; fclose($f); return $result; } $i=fclose($f); if ($i===false) { $result ="не смогли сохранить файл"; return $result; } return "Ok"; } //------------------------------- //------------------------------ //Сохранение свойств страницы в базе данных function save() { global $conn; global $_SERVER; if ($this->id==null) { $query="insert into pages( itemID,lng,title,keywords,description,css,jsFile,content,classID,className,filename,createdAt) values("; $query.=$this->itemID.","; $query.=$this->lng.","; $title=$this->title; $title=addslashes($title); $query.="'".$title."',"; $query.="'".addslashes($this->keywords)."',"; $query.="'".addslashes($this->description)."',"; $query.="'".$this->css."',"; $query.="'".$this->jsFile."',"; $content=$this->content; $content=addslashes($content); $query.="'".$content."',"; $query.=$this->classID.","; $query.="'".$this->className."',"; $query.="'".$this->filename."',"; $query.="Now()"; $query.=")"; mysql_query($query,$conn); $this->id=mysql_insert_id($conn); } else { $query="update pages set "; $query.="itemID=".$this->itemID.","; $query.="lng=".$this->lng.","; $title=$this->title; $title=addslashes($title); $query.="title='".$title."',"; $query.="keywords='".addslashes($this->keywords)."',"; $query.="description='".addslashes($this->description)."',"; $query.="css='".$this->css."',"; $query.="jsFile='".$this->jsFile."',"; $content=$this->content; $content=addslashes($content); $query.="content='".$content."',"; $query.="classID=".$this->classID.","; $query.="className='".$this->className."',"; $query.="filename='".$this->filename."' where id=".$this->id; mysql_query($query,$conn); } //echo $query."<br>"; $this->write_backup($content); //Дети пусть сами сохраняют свои параметры $this->saveParms(); } //------------------------------ function banners() { $banner=new banner($this->lng); return $banner->html(); } //---------------------------------- function write_backup($content) { global $conn; if ($this->id!=null) { global $conn; $query="delete from backup where pageID=".$this->id; mysql_query($query,$conn); $query="insert into backup(pageID,content) values(".$this->id.",'".stripslashes($content)."')"; mysql_query($query,$conn); } } } //end class ?>
Прекрасно работает. А придраться, как гласит старый анекдот, можно и к столбу. Не говоря о реально работающем проекте. А Вы и придраться-то не смогли.
О боооги.. HTML перемешан с PHP, местами запросы вообще не экранированы... Я даже боюсь спрашивать про производительность...
А Вы не бойтесь. Прекрасная производительность -- за счёт того, что почти все страницы сохраняются в виде HTML-страниц. И меняются только при изменении содержания пользователем. Заради той самой производительности. Скажем, в именах классов не бывает апострофов.
Clone +1. А если нужно будет постороннему человеку изменить цвет 1 гребаной ячейки. А если захочется добавить еще 1 поле в базе? Сколько времени у него займёт на то, чтобы понять где что менять + проверить, не рухнет ли всё после изменений. Даже дети понимают пользу трафаретов - зарисовал пустое пространство в виде каракули и готово. А не будь трафарета, пришлось бы самому выводить контур, потом аккуратно зарисовывать, чтобы не было торчащих заусениц. Сейчас любая моя система держится на 2х классах: класс работы с базой данных и смарти. В результате получается ну очень удобно - в PHP коде: PHP: <? //Подключене классов... //Проверки, проверки..... $user = array('id'=>$id, 'name'=>$DATA['name'], 'pas'=>$DATA['pas'], 'email'=>$DATA['email'], 'home'=>$DATA['home'], 'isq'=>$DATA['isq'], 'date'=>$date, 'signat'=>$DATA['sign'], 'avatar'=>$FileName, 'count'=>0); $DB->BuildInsert($user); $TPL->assign(array('message'=>"Спасибо за регистрацию, <b>$DATA[name]</b>!")); $TPL->display('redirect.tpl'); В redirect.tpl: Код (Text): {include file="header.tpl" title="Идёт перенаправление..." } <p> </p> <p> </p> <p> </p> <div align="center">{message}</div> <script language="javascript"> setTimeout("window.location = '{location}'", 5000000); </script> {include file="footer.tpl"} Всё по полочкам, всё понятно...
+1 tmanager Хотелось бы увидеть производный класс от Page. Может просто один класс Page выглядит как монстр, а его наследники все причесанные В любом случае не понимаю, почему методы типа Page::form() не реализовать так: PHP: <?php function form() { requiry_once('form_add_tur.tpl'); }
Посторонних -- в сад. А заказчики -- пусть редактируют содержание и посылают пожелания по дизайну. Не проблема. Хуже, если надумает удалить. Столько, сколько требуется для написания письма с вопросом ( ну или чтения руководства -- но его ж никто не читает...) Столько, сколько требуется для написания письма с вопросом (ну или чтения руководства -- но его ж никто не читает...) Но мы-то не дети. За это и платятся гонорары -- за эксклюзив. За креатив...
Да, ещё методы, имхо, очень туманно названы... Да и жёсткая система "Шапка+контент+футер" не есть гут, имхо... Что если мне захочется что-нить из контента переместить в шапку? Придётся код из одного метода в другой двигать... А там ещё поди разберись будет ли всё также гладко. Может, конечно, создавать классы на базе будет и удобно, но я предпочту кеширование данных + смарти(который, кстати, тоже поддерживает кеширование HTML).
Вам-то всё понятно, что Вы написали. Как сказали бы образованные, Stercus cuique suum bene olet Вопрос в том, поймёт ли "посторонние люди", как в этой теме выражаются.
Вы хочете песен? Их есть у меня. PHP: <?php /*==Простая HTML-страница==*/ require_once dirname(__FILE__)."/page.class.php"; //Страницы с заданным и постоянным HTML-кодом. class simple extends page { function simple($id=null,$filename="",$content="",$lng=1) { $this->lng=$lng; $this->className="simple"; $this->contentName="Текст страницы"; $this->textarea_h_mm=70; $this->id=$id; $this->get(); //Получение "абстрактных" свойств страницы if ($id==null) { if ($filename!="") $this->filename=$filename; if ($content!="") $this->content=$content; } $this->base="../"; $this->menu_prefix=""; } //------------------------------------------------- function /*override*/ content() { return $this->content; } //------------------------------------------------- } //end class ?>
Clone, а это не классы и ООП. Это называется по умному "эмулирование пространства имен функций". Я не образованный, но скажу - Argumenta ponderantur, non numerantur.
Совершенно с Вами согласен. Поэтому она и не жётская. Переопределяй соотв. методы в "ребёнке" Ну кроме того, что появляется новое требование -- установленный смарти -- особых возражений нет. Только замечание. "Постороннему человеку" легче не станет.