Всем привет! Хочу показать как можно работать с формами не прибегая к «фримворкам» в несколько килобайт кода.
Вступление
Как то раз пришлось мне создать небольшой проект портала с большим количеством форм как в «back» так и в «front» и тут возник вопрос что использовать? Сначала решил прикрутить что то на подобии Symfony. Но при разработке вышло такое количество строк кода что через некоторое время я сам начал путаться. И тут я решил изобрести велосипед.
Разработка
Для начала создал все таблицы в БД, вот например листинг одной:
CREATE TABLE IF NOT EXISTS `cms_articles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) DEFAULT NULL,
`article` text,
`author` varchar(255) DEFAULT NULL,
`edited` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`url` varchar(100) DEFAULT NULL,
`rating` int(10) NOT NULL DEFAULT '0',
`views` int(10) NOT NULL DEFAULT '0',
`comments` int(10) unsigned NOT NULL DEFAULT '0',
`parent` int(10) NOT NULL DEFAULT '0',
`key` text NOT NULL,
`desc` text NOT NULL,
`tags` varchar(250) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Следующим этапом стало написание HTML кода для формы.
И тут начинается суть моего способа: название элементов в шаблоне должно соответствовать названиям полей таблицы.
<body>
<font size='5px' class='title'>[page:name]</font>
<span style="float: right; padding-top: 10px;">[page:path]</span>
[page:message]
<form class="form-list" action="" method="post" name="Form" enctype="multipart/form-data" accept-charset="UTF-8">
<div class="section">
<ul class="tabs">
<li class="current"><a href="#tab1">Основные параметри статьи</a></li>
<li class=""><a href="#tab2">Текст статьи</a></li>
</ul>
<div class="boxu visible">
<div class="item">
<label>Заголовок</label><span class="required">*</span><br>
<input type="text" class="big" value="" name="title">
<br>
<label class="descript">Заголовок должен содержать смысл страницы</label>
</div>
<div class="item">
<label>Родитель</label><br>
<select class="big" name="parent" id="">
<option selected value="153">- без родителя -</option>
[page:parent]
</select><br>
<label class="descript">Содержимое, к которому добавляется страница</label></div><div class="item ">
<label>Адрес</label><br>
<input type="text" class="medium" value="" name="url">
<br>
<label class="descript">URL адрес страницы</label>
</div>
<div class="item">
<label>Автор</label><br>
<input type="text" class="big" value="" name="author">
<br>
<label class="descript">Автор статти ...</label>
</div>
<div class="item">
<label>Описание</label><br>
<textarea class="" name="desc" rows="2"></textarea><br>
<label class="descript">Краткое описание сайта. Используются поисковыми системами (Яндекс, Google...)</label>
</div>
<div class="item">
<label>Ключевые слова</label><br>
<textarea name="key" rows="2"></textarea><br>
<label class="descript">Ключевые слова через запятую. Используются поисковыми системами (Яндекс, Google...)</label>
</div>
<table width="600px">
<tr><td>
<div class="item">
<label>Рейтинг</label><br>
<input type="text" class="lbig" value="" name="rating">
<br>
<label class="descript">Рейтинг статти ...</label>
</div>
</td><td>
<div class="item">
<label>Просмотры</label><br>
<input type="text" class="lbig" value="" name="views">
<br>
<label class="descript">Количество просмотров ...</label>
</div>
</td></tr>
</table>
<div class="item">
<label>Разрешыть коментирование</label><br>
<span><input name="comments" type="radio" value="1" checked>Да</span>
<span><input name="comments" type="radio" value="0">Нет</span><br>
Пользователи могут оставлять коментарии.<br>
</div>
</div>
<div class="boxu">
<div class="item">
<label>Текст</label><br>
<textarea name="article" rows="28" id="article"></textarea><br>
<label class="descript">Текст страницы. Разрешено использование HTML тегов</label>
</div>
<div class="item">
<label>Теги</label><br>
<input type="text" style="width: 200px;" value="" name="tags" id="tags"><br>
<label class="descript">Теги к даному тексту (Вводить через кому).</label>
</div>
<div class="item-buttons">
<input type="submit" name="submit" id="submit" value="Сохранить">
</div>
</div>
</div>
</form>
</body>
Вот как выглядит форма (Орфографические ошибки на рисунке остались от заказчика я их не правил):
Далее сохранил шаблон в файл, под названием «article.tpl». И начал писать обработчик. Для его написание решил использовать DOM кто хочет пускай перепишет под «simpleDom».
Вот маленькая функция которая находит элемент по названию а не по ID.
private function GetElementByName($_dom, $_name){
// Experimental search by name
$xpath = new DOMXPath($_dom);
return $xpath->query('//*[@name="'.$_name.'"]')->item(0);
}
Вот тут я написал функцию которая автоматически заполняет форму из таблицы. Учитывая тип элемента и его свойства.
public function LoadShowFormAll($query, $template) {
$page_encoding = 'UTF-8';
$dom = new DomDocument();
@$dom->loadHTML('<meta http-equiv="content-type" content="text/html; charset=' . $page_encoding . '">' . file_get_contents(TMP_DIR.$template.".tpl"));
if ($result = $this->base->select($query)) {
foreach ($result as $key => $value) {
$obj = $this->GetElementByName($dom, $value['name']); //$dom->getElementById($val->name);
switch ($obj->nodeName) {
case "input":
if ($obj->getAttribute('type') == 'radio') {
$optionTags = $dom->getElementsByTagName('input');
for ($i = 0; $i < $optionTags->length; $i++) {
if ($optionTags->item($i)->getAttribute('name') == $value['name']) {
if ($optionTags->item($i)->getAttribute('value') == $value['param']) {
$optionTags->item($i)->SetAttribute('checked', 'checked');
}
}
}
if ($value['param'] == 1) {
$obj->SetAttribute('checked', 'checked');
}
} else
if ($obj->getAttribute('type') == 'checkbox') {
if ($value['param'] == 1) {
$obj->SetAttribute('checked', 'checked');
}
} else {
$obj->SetAttribute('value', $value['param']);
}
break;
case "textarea":
$obj->nodeValue = $value['param'];
break;
case "select":
$optionTags = $obj->getElementsByTagName('option');
for ($i = 0; $i < $optionTags->length; $i++) {
if ($optionTags->item($i)->getAttribute('value') == $value['param']) {
$optionTags->item($i)->SetAttribute('selected', 'selected');
}
}
break;
case "":
break;
}
}
}
preg_match_all("#<body>(.*)</body>#isUu", $dom->saveHTML(), $str);
return $str[1][0];
}
Использовать следующим образом:
echo $Core->LoadShowForm('SELECT * FROM cms_articles WHERE id='.(int)($get_id), 'article');
После этого возникла необходимость сохранять значения в базу и изменять их для этих заданий я написал две простые функции.
public function InsertNewValue($post, $table, $custom = null) {
$query = '';
$sep = false;
$tmp = array();
if ($result = $this->base->query("SELECT * FROM `$table` LIMIT 1")) {
$fields = $result->fetch_fields();
} else {
return false;
exit();
}
foreach ($post as $col => $val) {
$col = mysql_real_escape_string($col);
$val = mysql_real_escape_string($val);
$tmp[$col] = $val;
}
if ($custom != null) {
foreach ($custom as $col => $val) {
$col = mysql_real_escape_string($col);
$val = mysql_real_escape_string($val);
$tmp[$col] = $val;
}
}
foreach ($tmp as $column => $val) {
foreach ($fields as $fval) {
if ($column == $fval->name) {
if ($sep == true) {
$query .= ", `$column` = '$val'";
} else {
$query .= "`$column` = '$val'";
}
$sep = true;
}
}
}
return $this->base->query("INSERT INTO `$table` SET " . $query);
}
function UpdateValue($post, $table, $custom = null, $where) {
$query = '';
$sep = false;
$tmp = array();
if ($result = $this->base->query("SELECT * FROM `$table` LIMIT 1")) {
$fields = $result->fetch_fields();
} else {
return false;
exit();
}
foreach ($post as $col => $val) {
$col = mysql_real_escape_string($col);
$val = mysql_real_escape_string($val);
$tmp[$col] = $val;
}
if ($custom != null) {
foreach ($custom as $col => $val) {
$col = mysql_real_escape_string($col);
$val = mysql_real_escape_string($val);
$tmp[$col] = $val;
}
}
foreach ($tmp as $column => $val) {
foreach ($fields as $fval) {
if ($column == $fval->name) {
if ($sep == true) {
$query .= ", `$column` = '$val'";
} else {
$query .= "`$column` = '$val'";
}
$sep = true;
}
}
}
return $this->base->query("UPDATE `$table` SET " . $query . " WHERE " . $where);
}
Ну и остальная часть:
$Core->UpdateValue($_POST, 'cms_articles', null, ' id='.(int)($get_id)); // обновление
$Core->InsertNewValue($_POST, 'cms_articles');
Заключение
Лично мне очень понравилось работать таким образом с формами (При том что в проекте их было приблизительно: 250).
При необходимости добавления в форму элемента нужно прописать код в шаблоне и добавить значение в базе и все.
Большое спасибо!