ВСТУП
Останнім часом набули великого поширення системи управління вмістом сайту (Content| Management| System| — CMS|). CMS| – це система, яка дозволяє власникові сайту управляти текстовою і графічною інформацією сайту без кодування з використанням технологій PHP|, MYSQL|, HTML|, JavaScript|, Flash| і так далі.
Поява найрізноманітніших CMS| викликана двома причинами:
- програмісти відходять від практики розробки сайту як витвору мистецтва; жорсткі терміни примушують їх переходити до конвеєрного виробництва (принаймні, в області системи адміністрування і баз даних);
- замовники більше не сприймають Web-сайти| як іграшку, що демонструє спроможність компанії. У сайт вкладають засоби, і часто він служить для розширення бізнесу і витягання прибутків. Все це приводить до того, що власники сайту бажають мати повний контроль над кожним елементом сайту через систему адміністрування.
Стандарту в області побудови CMS| немає: це може бути як проста форма для зміни e-mail| і адреси в блоці зворотного зв'язку, так і система, що включає десятки блоків і сотні настройок, що дозволяють змінювати вміст меню, тексти статей і навіть структуру сайту. Система управління може бути винесена як в окремий блок, так і бути інтегрованою в блоки управління на сайті і включатися при вході на сайт адміністратора. CMS| може бути орієнтована на адміністратора і редактора (зручність використання) або на розробника (зручність розширення і введення нових блоків). Швидше за все, створення універсальної CMS| неможливе – сайти (та і самі CMS|) призначені для вирішення різноманітних задач —| облік всіх можливостей приведе до створення дуже складного інтерфейсу, вивчення якого стане непереборною перешкодою для більшості користувачів і розробників.
Система адміністрування - це область сайту, доступна тільки адміністраторам. Система уявлення - область сайту, доступна відвідувачам. Обидві системи працюють з однією і тією ж базою даних. Системи можуть бути інтегровані між собою, а можуть бути розділені і знаходитися в різних директоріях.
1 Набір класів. Framework|
Створюючи об'єктно-орієнтовані застосування, слід ретельно стежити, щоб класи і об'єкти могли повторно використовуватися, збільшували продуктивність і гнучкість системи. Класи і об'єкти не повинні створюватися тільки ради того, щоб програма виправдала звання об'єктно-орієнтованої.
Розділення движка, бізнес-логіки| і дизайну прогами часто описують в рамках архітектури MVC| (Model,View|, Controller|) – Модель, Вигляд, Контроллер.
Єдина архітектура MVC| в Web-сайтах| найчастіше розділяється на компоненти відповідно до однієї з наступних моделей:
- розділення дизайну і програмного коду, яке найчастіше реалізується у вигляді шаблонів
- розділення бізнес-логіки| і реалізації рутинних операцій, що зазвичай реалізовується у вигляді фреймворка| (framewok|) – набору класів, які реалізують остов застосування і надає розробникові готові програмні блоки, що сполучаються між собою залежно від бізнес-логіки| конкретного застосування.
Створення движка або Framework-системи| ідеально підходить для застосування об'єктно-орієнтованого підходу. Одного разу розроблений набір класів може застосовуватися для створення великої кількості застосувань, а його старі версії можуть замінюватися без збитку для логіки застосувань новими версіями.
Велика частина часу розробника CMS| витрачається на створення всіляких HTML-форм| і їх обробників. Можна добитися значного скорочення часу розробки, якщо створити готові компоненти HTML-форм|, в яких автоматично здійснюватиметься перевірка правильності введення і обробка результатів при подальшій вставці в базу даних. Об'єкти елементів управління HTML-форми| самі можуть ставати членами класу HTML-форми|.
Таким чином можна добитися високого ступеня повторного використання коди і в той же час надати розробникам широкі можливості для внесення змін до набору класів за рахунок спадкоємства і включення вже існуючих об'єктів.
Вимоги до набору класів
Кінцевою метою створення фреймворка| є набір класів, що дозволяє створювати HTML-форми| високого ступеню| складності. Такий набір надає розробникові ряд переваг:
- автоматично здійснюється перевірка правильності введення інформації
- автоматично виконується екранування спеціальних символів перед приміщенням інформації в базу даних, що запобігає будь-якій можливості SQL-ін`єкций|;
- HTML-форму| можна серіалізовати| і у будь-який момент відновити
1.2 Базовий клас field|
Всі класи елементів управління успадковані від єдиного базового класу field|. Оскільки даний клас є прототипом і його екземпляри не буде потрібно, він оголошений абстракнтим|.
Клас field| містить ряд захищених членів (Таб. 1.1), що ініціалізувалися через конструктор.
Таблиця 1.1 Список захищених членів класу field|
Член класу field| |
Опис |
protected| $name |
ім'я елементу управління |
protected| $type |
тип елементу управління |
protected| $ caption| |
назва, яка розташовується зліва від елементу управління |
protected| $value |
значення елементу управління |
protected| $is_required |
приймає значення true|, якщо елемент управління обов'язковий до заповнення, false| – інакше |
protected| $parameters |
рядок додаткових параметрів |
protected| $help |
текст підказки |
protected| $help_url |
посилання на підказку |
protected| $css_class |
клас css| |
protected| $css_style |
стиль css| |
Приведемо код класу field|
<?php
error_reporting|(E_ALL| & ~E_NOTICE);
////////////////////////////////////////////////////////////
// Базовий клас елементу управління HTML-формы|, від
// його успадковується решта всіх елементів управління
////////////////////////////////////////////////////////////
abstract| class| field|
{
///////////////
// Члени класу
///////////////
// Ім'я елементу управління
protected| $name;
// Тип елементу управління
protected| $type;
// Назва зліва від елементу управління
protected| $caption;
// Значення елементу управління
protected| $value;
// Чи обов'язковий елемент до заповнення
protected| $is_required;
// Рядок додаткових параметрів
protected| $parameters;
// Підказка
protected| $help;
// Посилання на підказку
protected| $help_url;
// Клас CSS|
public| $css_class;
// Стиль CSS|
public| $css_style;
////////////////
// Методи класу
////////////////
// Конструктор класу
function| __construct($name,
$type,
$caption,
$is_required = false|
$value = ""
$parameters = ""
$help = ""
$help_url = "")
{
$this->name = $this->encodestring($name);
$this->type = $type;
$this->caption = $caption;
$this->value = $value;
$this->is_required = $is_required;
$this->parameters = $parameters;
$this->help = $help;
$this->help_url = $help_url;
}
// Метод перевіряючий коректність заповнення поля
abstract| function| check|();
// Абстрактний метод, для повернення імені назви поля
// і самого тега елементу управління (кожен спадкоємець
// повинен цей метод перевизначити)
abstract| function| get_html|();
// Доступ до закритих і захищених елементів класу
// тільки для читання
public| function| __get($key)
{
if|(isset|($this->$key)) return| $this->$key;
else|
{
throw| new| ExceptionMember|($key,
"Член ".__CLASS__."::$key не існує");
}
}
// функція превода| тексту з російської мови в траслит|
protected| function| encodestring|($st)
{
// Спочатку замінюємо "односимвольні" фонеми.
$st=strtr($st,"абвгдеезийклмнопрстуфхъыэ_",
"abvgdeeziyklmnoprstufh'iei|");
$st=strtr($st,"АБВГДЕЕЗИЙКЛМНОПРСТУФХЪЫЭ_",
"ABVGDEEZIYKLMNOPRSTUFH'IEI|");
// Потім - "багатосимвольні".
$st=strtr($st,
array|(
"ж"=>"zh|", "ц"=>"ts|", "ч"=>"ch|", "ш"=>"sh|"
"щ"=>"shch","ь"=>"|", "ю"=>"yu|", "я"=>"ya|"
"Ж"=>"zh", "Ц"=>"ts", "Ч"=>"ch", "Ш"=>"sh"
"Щ"=>"shch","ь"=>"", "Ю"=>"yu", "Я"=>"ya"
"ї"=>"i|", "Ї"=>"Yi|", "є"=>"ie|", "Є"=>"Ye|"
)
);
// Повертаємо результат.
return| $st;
}
}
?>
Крім конструктора, клас field| міститиме два абстрактні методи: check|() і get_html|(), призначені для перевантаження в похідних класах. Метод check|() перевірятиме коректність введеної інформації і повертатиме при успішній перевірці порожній рядок, інакше – повідомлення про помилку. Метод get_html|() повертатиме масив з назвою елементу управління, підказок і тега| елементу управління. Використовуючи цей масив, клас form|, відображуючий| HTML-форму|, формуватиме елемент управління.
1.3 Клас form|
HTML-форма| може містити безліч елементів управління різного типу, тому доцільно включити до складу класу, що моделює форму, масив об'єктів $fields. Член $fields буде оголошений відкритим для зручного доступу до елементів управління.
Всі HTML-форми|, які представлені в даній CMS| містять одну кнопку типу submit|, що відправляє дані обробникові форми. Для назви кнопки в класі передбачений захищений член $button_name.
Сама HTML-форма| будується за допомогою таблиці. Для оформлення елементів таблиці використано двох членів: $css_td_class і $css_td_style, визначальний клас і стиль таблиць CSS|. Крім того, два члени $css_fld_class і $css_fld_style визначають клас і стиль каскадних таблиць CSS| для елементів управління форми (ці поля є відкритими в класах, похідних від field|).
Крім конструктора, призначеного для ініціалізації членів методу, клас form| містить наступні методи:
- print_form|() – виводить HTML-форму| у вікно браузера|
- __toString() – перевантажений спеціальний метод, аналогічний по дії методу print_form|()
- check| () – викликає методи перевірки всіх елементів управління і формує масив з повідомленням про помилки.
Приведемо код класу form|
<?php
error_reporting|(E_ALL| & ~E_NOTICE);
////////////////////////////////////////////////////////////
// Клас HTML-формы|
////////////////////////////////////////////////////////////
class| form|
{
// Масив елементів управління
public| $fields;
// Назва кнопки HTML-формы|
protected| $button_name;
// Клас CSS| елементу таблиці
protected| $css_td_class;
// Стиль CSS| елементу таблиці
protected| $css_td_style;
// Клас CSS| елементу управління
protected| $css_fld_class;
// Стиль CSS| елементу управління
protected| $css_fld_style;
// Конструктор класу
public| function| __construct($flds,
$button_name,
$css_td_class = ""
$css_td_style = ""
$css_fld_class = ""
$css_fld_style = "")
{
$this->fields = $flds;
$this->button_name = $button_name;
$this->css_td_class = $css_td_class;
$this->css_td_style = $css_td_style;
$this->css_fld_class = $css_fld_class;
$this->css_fld_style = $css_fld_style;
// Перевіряємо, чи є елементи масиву $flds
// похідними класу field|
foreach|($flds as| $key => $obj)
{
if|(!is_subclass_of($obj, "field|"))
{
throw| new| ExceptionObject|($key,
"\"$key\|" не є елементом управління");
}
}
}
// Виведення HTML-формы| у вікно браузера|
public| function| print_form|()
{
$enctype = "";
if|(!empty($this->fields))
{
foreach|($this->fields as| $obj)
{
// Призначаємо всім елементам управління єдиний стиль
if|(!empty($this->css_fld_class))
{
$obj->css_class = $this->css_fld_class;
}
if|(!empty($this->css_fld_class))
{
$obj->css_style = $this->css_fld_style;
}
// Перевіряємо чи немає серед елементів управління
// поля file|, якщо є, включаємо рядок
// enctype='multipart/form-data'
if|($obj->type == "file|")
{
$enctype = "enctype='multipart/form-data'";
}
}
}
// Якщо елементи оформлення не порожні - враховуємо їх
if|(!empty($this->css_td_style))
{
$style = "style=\"|".$this->css_td_style."\"";
}
else| $style = "";
if|(!empty($this->css_td_class))
{
$class = "class=\"|".$this->css_td_class."\"";
}
else| $class = "";
// Виводимо HTML-форму|
echo| "<form| name=form| $enctype method=post|>";
echo| "<table>|";
if|(!empty($this->fields))
{
foreach|($this->fields as| $obj)
{
// Отримуємо назву поля, і його HTML-представление|
list|($caption, $tag, $help, $alternative)= $obj->get_html();
if|(is_array|($tag))$tag = implode|("<br>",$tag|);
switch|($obj->type)
{
case| "hidden|":
// Приховане поле
echo| $tag;
break|;
case| "paragraph|":
case| "title|":
echo| "<tr|>
<td| $style $class colspan=2| valign=top>$tag</td>
</tr>\n";
break|;
/* case| "city|":
echo| "<tr|>
<td| width=100| $style $class valign=top>$caption|:</td>
<td| $style $class>$tag</td>
</tr>\n";
echo| "<tr|>
<td| width=100| $style $class valign=top>Если| города<br|> немає в списку:</td>
<td| $style $class>$alternative $help</td>
</tr>\n";
break|;*/
default|:
// Елементи управління за умовчанням
echo| "<tr|>
<td| width=100|
$style $class valign=top>$caption|:</td>
<td| $style $class valign=top>$tag</td>
</tr>\n";
if|(!empty($help))
{
echo| "<tr|>
<td> |;</td>
<td| $style $class valign=top>$help</td>
</tr>";
}
break|;
}
}
}
// Виводимо кнопку підтвердження
echo| "<tr|>
<td| $style $class></td>
<td| $style $class>
<input| class=button|
type=submit|
value=\|"".htmlspecialchars($this->button_name, ENT_QUOTES|)."\">
</td>
</tr>\n";
echo| "</table>";
echo| "</form>";
}
// Перевантаження спеціального методу __toString()
public| function| __toString()
{
$this->print_form();
}
// Метод, перевіряючий коректність введення даних у форму
public| function| check|()
{
// Послідовно викликаємо метод check| для кожного
// об'єкту field|, що належать класу
$arr = array|();
if|(!empty($this->fields))
{
foreach|($this->fields as| $obj)
{
$str = $obj->check();
if|(!empty($str))$arr[] = $str;
}
}
return| $arr;
}
}
?>
Конструктор класу form| приймає як перший параметр масив об'єктів, класи яких повинні бути похідними класами field|, інакше генерується виключення ExceptionObject|. Такий підхід дозволяє бути |упевненим, що будь-який елемент масиву елементів управління містить реалізацію абстрактних методів check|() і get_html|(), необхідних для нормального функціонування класу form|.
Метод check|() викликає однойменні методи елементів управління, формуючи масив повідомлень про некоректне заповнення полів. Метод print_form|() формує таблицю з HTML-формою|, отримуючи HTML-фрагменти| елементу управління за допомогою методу get_html|(). Елементи поверненого масиву розподіляються по змінним за допомогою конструкції list|().
1.4 Обробка виняткових ситуацій
У міру роботи з набором класів неминуче виникатимуть виняткові ситуації. Тому, перш ніж перейти до розробки набору класів, слід створити ієрархію виключень, що обробляються наступні помилки:
- ExceptionMember| – помилки класу, пов'язані із зверненням до неіснуючих членів класів. Як правило, це виключення генерується в спеціальних методах _get|() і _set|();
- ExceptionObject| – помилки класу, зв'язані з використанням змінних, що не є об'єктами. Клас HTML-форми| буде виступтати| як контейнер об'єктів елементів управління. Даний тип виключення генеруватиметься, якщо замість такого об'єкту помилково буде передана змінна або об'єкт неприпустимого типу;
- ExceptionMySQL| – помилки класу, пов'язані із зверненням до СУБД MYSQL|.
Код класу ExceptionMember
|
<?php
error_reporting|(E_ALL| & ~E_NOTICE);
////////////////////////////////////////////////////////////
// Звернення до неіснуючого члена
////////////////////////////////////////////////////////////
class| ExceptionMember| extends| Exception|
{
// Ім'я не існуючого члена
protected| $key;
public| function| __construct($key, $message)
{
$this->key = $key;
// Викликаємо конструктор базового класу
parent|::__construct($message);
}
public| function| getKey|()
{
return| $this->key;
}
}
?>
Код класу ExceptionMySQL|
<?php
error_reporting|(E_ALL| & ~E_NOTICE);
////////////////////////////////////////////////////////////
// Помилки звернення до СУБД MYSQL|
////////////////////////////////////////////////////////////
class| ExceptionMySQL| extends| Exception|
{
// Повідомлення про помилку
protected| $mysql_error;
// SQL-запрос|
protected| $sql_query;
public| function| __construct($mysql_error, $sql_query, $message)
{
$this->mysql_error = $mysql_error;
$this->sql_query = $sql_query;
// Викликаємо конструктор базового класу
parent|::__construct($message);
}
public| function| getMySQLError|()
{
return| $this->mysql_error;
}
public| function| getSQLQuery|()
{
return| $this->sql_query;
}
}
?>
Код класу ExceptionObject|
<?php
error_reporting|(E_ALL| & ~E_NOTICE);
////////////////////////////////////////////////////////////
// Звернення до об'єкту, відмінного від field-производного|
////////////////////////////////////////////////////////////
class| ExceptionObject| extends| Exception|
{
// Ім'я об'єкту
protected| $key;
public| function| __construct($key, $message)
{
$this->key = $key;
// Викликаємо конструктор базового класу
parent|::__construct($message);
}
public| function| getKey|()
{
return| $this->key;
}
}
?>