Создание формы регистрации и авторизации на PHP
Пример кода PHP-сценария для построения веб-формы с помощью приемов объектно-ориентированного программирования
В этой статье мы с вами поговорим о создании формы для авторизации и регистрации пользователей на сайте. Веб формы (html-формы) существуют настолько давно, что многие из на уже и не смогут ответить на вопрос, сколько именно лет пользователи интернета видят их то там, то здесь. Они стали настолько неотъемлемой частью нашей жизни во всемирной паутине, что мысль о том, что форм обратной связи когда-то и не было.
В одной из своих статей я немного уже затронул тему построения формы. Но там речь шла не о самом написании кода html-формы на PHP, а о реализации алгоритма авторизации и регистрации пользователей.
Сейчас же мы поговорим не просто о том, как с помощью PHP упростить для себя «написание» формы, но и создать инструмент для многократного применения, да ещё и не только конкретно в нашем обсуждаемом случае.
Как мы обычно делаем, например, форму обратной связи себе на сайт? Примерно так...
И вот так выглядел бы html-код этой формы авторизации на сайте.
<div id="form_wrapper">
<form action="" method="post" name="userAuthForm" onsubmit="return false;" autocomplete="no">
<div class="row">
<label for="login">Логин пользователя:</label>
<span class="table-row"></span>
<input type="text" name="login" id="login" placeholder="Введите логин пользователя" />
</div>
<div class="row">
<label for="password">Пароль пользователя:</label>
<span class="table-row"></span>
<input type="password" name="password" id="password" placeholder="Введите пароль пользователя" />
</div>
<div class="row">
<label for="saveAuth">Не выходить из системы:
<input type="checkbox" name="saveAuth" id="saveAuth" checked />
</label>
</div>
<div class="row">
<input type="submit" value="Войти" name="btn-submit" id="btn-submit" />
</div>
</form>
<p><a href="#">Зарегистрироваться</a></p>
</div>
А теперь давайте представим, что пользователь не зарегистрирован, и потому ему перед авторизацией потребуется заполнить данные формы регистрации на нашем сайте. Форма могла бы выглядеть так.
У нас добавились два текстовых поля: одно для повторного ввода пароля, второе для адреса электронной почты пользователя. Наш флажок теперь подпишет пользователя на рассылку, а кнопок стало две. HTML-код такой формы регистрации пользователя мог бы выглядеть так.
<div class="form_wrapper">
<form action="" method="post" name="userRegForm" onsubmit="return false;" autocomplete="no">
<div class="row">
<label for="login">Логин пользователя:</label>
<span class="table-row"></span>
<input type="text" name="login" id="login" placeholder="Введите логин пользователя" />
</div>
<div class="row">
<label for="password">Пароль пользователя:</label>
<span class="table-row"></span>
<input type="password" name="password" id="password" placeholder="Введите пароль пользователя" />
</div>
<div class="row">
<label for="passwordApproove">Пароль пользователя:</label>
<span class="table-row"></span>
<input type="password" name="passwordApproove" id="passwordApproove" placeholder="Повторите ввод пароля" />
</div>
<div class="row">
<label for="email">Электропочта:</label>
<span class="table-row"></span>
<input type="text" name="email" id="email" placeholder="Адрес вашей электропочты" />
</div>
<div class="row">
<label for="signNews">Подписаться на рассылку:
<input type="checkbox" name="saveAuth" id="saveAuth" checked />
</label>
</div>
<div class="row">
<input type="submit" value="Зарегистрироваться" name="btn-submit" id="btn-submit" />
</div>
<div class="row">
<input type="reset" value="Сбросить" name="btn-reset" id="btn-reser" />
</div>
</form>
<p><a href="#auth">Вернуться к авторизации</a></p>
</div>
Ну, добавилось и добавилось... скажете вы... что такого? Ничего. А если после регистрации вам нужно будет попросить пользователя заполнить форму с подробной информацией о себе? Приведенные примеры форм регистрации и авторизации пользователя не имеют полей для сообщений об ошибках, полей с подсказками. Нет обозначений обязательности заполнений полей.
Другими словами, что делать, когда появляется необходимость создать большое количество однотипных или идентичных полей? Писать всё руками? Ну, может быть. А если потом потребуется добавить всем полям атрибут... data-parent_id=""
, например. Поиск с заменой не поможет, так как значение атрибута, допустим, должно быть у каждого поля своим.
Привычное для многих использование PHP не даст сразу верный ответ на поставленный вопрос. А ответ прост: написать собственный класс для построения формы обратной связи, формы регистрации и авторизации пользователей и множества других веб-форм.
Если такой класс объявлен в системе, написание вышеупомянутой формы авторизации могло бы выглядеть так.
<?php
// Создаем экземпляр объекта класса, отвечающего за построение формы
// Вызываем статический метод instance() класса Core_Form
$oCore_Form = Core_Form::instance()
// Атрибуту name тега <form> устанавливаем значение authUser
->name( 'authUser' )
// Устанавливаем значение атрибута id формы
->id( 'authUser' )
// Значение javascript-атриуба onsubmit для тега <form>
->onsubmit( 'return false;' )
// Значение атрибута для автозаполнения полей формы
->autocomplete( 'no' )
// Добавляем поле формы, вызвав метод add() класса Core_Form
->add(
// Вызываем статический метод класса createField() Core_Form
// В качестве аргумента передаем этому методу значение типа поля
// Это значение хранится внутри класса Core_Form в константе
// Чтобы не ошибиться и не опечататься, передаем это значение таким образом
Core_Form::createField( Core_Form::FIELD_INPUT )
// Атрибут type тега <input>
->type( 'text' )
// Атрибут id
->id( 'login' )
// Атрибут name
->name( 'login' )
// Атрибут placeholder
->placeholder( 'Введите логин пользователя' )
// Заголовок поля в теге <label>
->label( 'Логин пользователя:' )
// Текст для поля подсказки
->instr( 'Логин может содержать только буквы и цифры латинского алфавита' )
// Поле будет обязательным для заполнения
->requireField( TRUE )
// С этим полем пока что всё, переходим к следующему
)
// Действуем аналогично, теперь у нас будет поле <input type="password" />
->add(
Core_Form::createField( Core_Form::FIELD_INPUT )
->type( 'password' )
->id( 'password' )
->name( 'password' )
->placeholder( 'Введите пароль пользователя' )
->label( 'Пароль пользователя:' )
->instr( 'Пароль может содержать только буквы и цифры латинского алфавита' )
->requireField( TRUE )
)
// Добавляем поле <input type="checkbox" />
->add(
Core_Form::createField( Core_Form::FIELD_INPUT )
->type( 'checkbox' )
->id( 'saveAuth' )
->name( 'saveAuth' )
->label( 'Не выходить из системы:' )
->checked( TRUE )
)
// Добавляем кнопку отправки формы на обработку
->add(
Core_Form::createField( Core_Form::FIELD_INPUT )
->type( 'submit' )
->id( 'btn-submit' )
->name( 'btn-submit' )
->value( 'Войти' )
);
/**
* Данные для построения формы собраны, готовы.
*
* За отображение формы на экране отвечать будет класс Core_Form_Show
* Вызываем конструктор этого класса, передав ему в виде аргумента экземпляр
* объекта нашей формы
*
*/
$oCore_Form_Show = new Core_Form_Show( $oCore_Form );
/**
* Дальнейшая обработка формы происходит по следующему алгоритму.
*
* 1. Вызывается метод show() класса Core_Form_Show. Этот метод сформирует промежуточный XML-документ,
* в который поместит всю информацию о форме, её атрибутах и полях.
* 2. XML-документ будет передан XSLT-процессору.
* 3. XSLT-процессор посредством обработки XSL-шаблона представит нам форму в таком виде, в каком мы захотим.
* 4. Имя XSL-шаблона указываем вызвав метод byXSLName(), передав имя шаблона в виде аргумента.
*
*/
$oCore_Form_Show->show(
Core_Xsltprocessor::instance()
->byXSLName( '1' ));
?>
Этот код позволил бы построить веб-форму следующего вида...
Это был представлен уже пользовательский код для сборки и отображения формы. В комментариях было упомянуто, что информация о форме собирается в промежуточный XML-документ, содержимое которого представлено ниже.
<?xml version="1.0" encoding="utf-8"?>
<document>
<form_wrapper id="form_wrapper">
<form>
<fields>
<field>
<label for="login">Логин пользователя:</label>
<input>
<field_options>
<id>login</id>
<name>login</name>
<placeholder>Введите логин пользователя</placeholder>
<type>text</type>
<required>1</required>
</field_options>
<instr>Логин может содержать только буквы и цифры латинского алфавита</instr>
</input>
</field>
<field>
<label for="password">Пароль пользователя:</label>
<input>
<field_options>
<id>password</id>
<name>password</name>
<placeholder>Введите пароль пользователя</placeholder>
<type>password</type>
<required>1</required>
</field_options>
<instr>Пароль может содержать только буквы и цифры латинского алфавита</instr>
</input>
</field>
<field>
<checkbox_group id="0">
<entity>
<label for="saveAuth">Не выходить из системы:</label>
<field_options>
<id>saveAuth</id>
<name>saveAuth</name>
<type>checkbox</type>
<checked>1</checked>
</field_options>
</entity>
<input/>
</checkbox_group>
</field>
<field>
<input>
<field_options>
<id>btn-submit</id>
<name>btn-submit</name>
<value>Войти</value>
<type>submit</type>
</field_options>
</input>
</field>
</fields>
<form_options>
<onsubmit>return false;</onsubmit>
<autocomplete>no</autocomplete>
<method>post</method>
<id>authUser</id>
<name>authUser</name>
</form_options>
</form>
</form_wrapper>
</document>
Этот документ был передан XSLT-процессору, который обработал его так, как было задано в XSL-шаблоне/ Давайте посмотрим на этот шаблон.
<?xml version = '1.0' encoding = 'utf-8' ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" xsl:extension-element-prefixes="php">
<xsl:output method="xml" indent="yes" encoding="utf-8" />
<xsl:namespace-alias stylesheet-prefix="php" result-prefix="xsl" />
<!-- Обработка корневого узла XML-документа -->
<xsl:template match="/document">
<!-- Если в документе есть объект формы -->
<xsl:if test="count(//form)">
<!-- Если у формы есть узел-обертка -->
<xsl:if test="count(./form_wrapper)">
<!-- Вызвать шаблон для узла-обертки -->
<xsl:apply-templates select="./form_wrapper" />
</xsl:if>
</xsl:if>
</xsl:template><!-- Обработка корневого узла XML-документа -->
<!-- Шаблон обработки узла-обертки для веб-формы -->
<xsl:template match="form_wrapper">
<!-- Создаем контейнер, помещаем внутрь его нашу форму -->
<!-- Элементу DIV добавляем атрибут ID узла-обертки -->
<div id="{@id}">
<!-- Создаем тег формы -->
<form>
<!-- Если у формы есть свои свойства или атрибуты -->
<xsl:if test="count(./form/form_options)">
<!-- Для каждого из них -->
<xsl:for-each select="./form/form_options/child::node()">
<!-- Сохранить в переменной имя атрибута -->
<xsl:variable name="attrName" select="name()" />
<!-- Создать атрибут -->
<xsl:attribute name="{$attrName}">
<!-- Присвоить ему значение -->
<xsl:value-of select="." disable-output-escaping="yes" />
</xsl:attribute>
</xsl:for-each>
</xsl:if><!-- Если у формы есть свои свойства или атрибуты -->
<!-- Если у формы есть поля -->
<xsl:if test="count(./form//field)">
<!-- Вызвать шаблон обработки полей формы -->
<xsl:apply-templates select="./form/fields" />
</xsl:if>
</form>
</div><!-- Контейнер узла-обертки для формы -->
</xsl:template><!-- Шаблон обработки узла-обертки для веб-формы -->
<!-- Шаблон обработки полей формы -->
<xsl:template match="fields">
<!-- Вызываем шаблон обработки поля формы -->
<xsl:apply-templates select="field"/>
</xsl:template><!-- Шаблон обработки полей формы -->
<!-- Шаблон обработки поля формы -->
<xsl:template match="field">
<!-- Сохранить в переменной атрибут required, если он есть -->
<xsl:variable name="required" select=".//child::field_options/required" />
<!-- Контейнер для всего, что так или иначе относится к понятию одного экземпляра поля формы -->
<div class="row">
<!-- Создать переменную для хранения значения поля подсказки к полю формы -->
<xsl:variable name="instr">
<xsl:choose>
<!-- Если у поля есть узел подсказки -->
<xsl:when test="count(./node()/instr)">
<!-- Сохранить в переменной текст этого узла -->
<xsl:value-of select="./node()/instr" disable-output-escaping="yes" />
</xsl:when>
<!-- Иначе сохранить строку null -->
<xsl:otherwise>
<xsl:text>null</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable><!-- Создать переменную для хранения значения поля подсказки к полю формы -->
<!-- Аналогичным образом действуем с полем сообщения об ошибке -->
<!-- Создать переменную для хранения значения поля сообщения об ошибке к полю формы -->
<xsl:variable name="error">
<xsl:choose>
<!-- Если у поля есть узел сообщения об ошибке -->
<xsl:when test="count(./node()/error)">
<!-- Сохранить в переменной текст этого узла -->
<xsl:value-of select="./node()/error" disable-output-escaping="yes" />
</xsl:when>
<!-- Иначе сохранить строку null -->
<xsl:otherwise>
<xsl:text>null</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable><!-- Создать переменную для хранения значения поля сообщения об ошибке к полю формы -->
<!-- Обработка полей формы -->
<xsl:choose>
<!-- Если в текущем узле нет груп полей <input type="radio" /> или <input type="checkbox" /> -->
<xsl:when test="count(radio_group) = 0 and count(checkbox_group) = 0">
<!-- Если у узла поля есть заголовок -->
<xsl:if test="count(child::label)">
<div class="caption">
<!-- Сохранить в переменной значение атрибута for тега <label> -->
<xsl:variable name="for" select="./label/@for" />
<!-- Формируем код тега <label> -->
<label for="{$for}"><xsl:value-of select="node()" disable-output-escaping="yes" /></label>
<!-- Если поле обязательное для заполнения -->
<xsl:if test="$required = 1">
<!-- Добавить соответствующий символ -->
<span class="required-field">*</span>
</xsl:if>
</div>
</xsl:if><!-- Если у узла поля есть заголовок -->
<!-- В зависимости от типа поля вызывается соответствующий шаблон -->
<xsl:choose>
<!-- Если это поле input -->
<xsl:when test="count(./input)">
<xsl:apply-templates select="./input" mode="text" />
</xsl:when>
<!-- Если это поле Select -->
<xsl:when test="count(./select)">
<xsl:apply-templates select="select" />
</xsl:when>
<!-- Если это поле Textarea -->
<xsl:when test="count(./textarea)">
<xsl:apply-templates select="textarea" />
</xsl:when>
<!-- Если это поле button -->
<xsl:when test="count(./button)">
<xsl:apply-templates select="button" />
</xsl:when>
</xsl:choose><!-- В зависимости от типа поля вызывается соответствующий шаблон -->
</xsl:when><!-- Если в текущем узле нет груп полей <input type="radio" /> или <input type="checkbox" /> -->
<!-- Если мы обрабатываем группу полей <input type="radio" /> -->
<xsl:when test="count(radio_group)">
<!-- Вызываем соответствующий шаблон -->
<xsl:apply-templates select="//radio_group" />
</xsl:when><!-- Если мы обрабатываем группу полей <input type="radio /> -->
<!-- Если мы обрабатываем группу полей <input type="checkbox" /> -->
<xsl:when test="count(checkbox_group)">
<!-- Вызываем соответствующий шаблон -->
<xsl:apply-templates select="//checkbox_group" />
</xsl:when><!-- Если мы обрабатываем группу полей <input type="checkbox" /> -->
</xsl:choose><!-- Обработка полей формы -->
<!-- Если у поля есть узел с сообщением с подсказкой -->
<xsl:if test="$instr != 'null'">
<!-- Создаем поле с текстом сообщения -->
<div class="instr" id="{./node()/field_options/id}-instr">
<xsl:value-of select="$instr" disable-output-escaping="yes" />
</div>
</xsl:if><!-- Если у поля есть узел с сообщением с подсказкой -->
<!-- Если у поля есть узел с сообщением об ошибке -->
<xsl:if test="$error != 'null'">
<!-- Создаем поле с текстом сообщения -->
<div class="error" id="{./node()/field_options/id}-error">
<xsl:value-of select="$error" disable-output-escaping="yes" />
</div>
</xsl:if><!-- Если у поля есть узел с сообщением об ошибке -->
</div><!-- Контейнер для всего, что так или иначе относится к понятию одного экземпляра поля формы -->
</xsl:template><!-- Шаблон обработки поля формы -->
<!-- Шаблон обработки группы полей <input type="radio" /> -->
<xsl:template match="radio_group">
<!-- Контейнер поля формы -->
<div class="field">
<!-- Вызываем шаблон для обработк поля формы -->
<xsl:apply-templates select="entity" />
</div><!-- Контейнер поля формы -->
</xsl:template><!-- Шаблон обработки группы полей <input type="radio" /> -->
<!-- Шаблон обработки группы полей <input type="checkbox" /> -->
<xsl:template match="checkbox_group">
<!-- Контейнер поля формы -->
<div class="field">
<!-- Вызываем шаблон для обработк поля формы -->
<xsl:apply-templates select="entity" />
</div><!-- Контейнер поля формы -->
</xsl:template><!-- Шаблон обработки группы полей <input type="checkbox" /> -->
<!-- Шаблон для обработки полей формы input -->
<xsl:template match="input" mode="text">
<!-- Контейнер поля формы -->
<div class="field">
<!-- Создаем тег поля формы -->
<input>
<!-- Для каждого из узла его свойст и атрибутов -->
<xsl:for-each select="./field_options/child::node()">
<!-- Сохраняем в переменной имя атрибута -->
<xsl:variable name="attrName" select="name()" />
<!-- Добавляем атрибут -->
<xsl:attribute name="{$attrName}">
<!-- Если это не атрибут обязательного поля, отключенного поля или отмеченного поля -->
<xsl:choose>
<xsl:when test="name() != 'required' and name() != 'disabled' and name() != 'checked'">
<!-- Устанавливаем значение для атрибута -->
<xsl:value-of select="./node()" disable-output-escaping="yes" />
</xsl:when>
</xsl:choose>
</xsl:attribute>
</xsl:for-each><!-- Для каждого из узла его свойст и атрибутов -->
</input>
</div><!-- Контейнер поля формы -->
</xsl:template><!-- Шаблон для обработки полей формы input -->
<!-- Шаблон для обработки полей формы button -->
<xsl:template match="button">
<!-- Контейнер поля формы -->
<div class="field">
<!-- Создаем тег поля формы -->
<button>
<!-- Для каждого из узла его свойст и атрибутов -->
<xsl:for-each select="./field_options/child::node()">
<!-- Сохраняем в переменной имя атрибута -->
<xsl:variable name="attrName" select="name()" />
<!-- Добавляем атрибут -->
<xsl:attribute name="{$attrName}">
<!-- Если это не атрибут обязательного поля, или отмеченного поля -->
<xsl:choose>
<xsl:when test="name() != 'required' and name() != 'checked'">
<!-- Устанавливаем значение для атрибута -->
<xsl:value-of select="./node()" disable-output-escaping="yes" />
</xsl:when>
</xsl:choose>
</xsl:attribute>
</xsl:for-each><!-- Для каждого из узла его свойст и атрибутов -->
<xsl:choose>
<!-- Если для кнопки задано значение действия -->
<xsl:when test="./field_options/value != ''">
<!-- Выводим его для этой кнопки -->
<xsl:value-of select="./field_options/value" disable-output-escaping="yes" />
</xsl:when>
<xsl:otherwise>
<!-- В ином случае пишем на ней абстрактное... -->
<xsl:text>Кнопка</xsl:text>
</xsl:otherwise>
</xsl:choose>
</button>
</div><!-- Контейнер поля формы -->
</xsl:template><!-- Шаблон для обработки полей формы input -->
<!-- Шаблон для обработки полей формы <input type="radio" /> или <input type="checkbox" /> -->
<xsl:template match="entity">
<xsl:choose>
<!-- Если у поля есть заголовок -->
<xsl:when test="count(child::label)">
<!-- Сохраняем в переменной значение атрибута for -->
<xsl:variable name="for" select="./label/@for" />
<!-- Открываем тег <label> -->
<label for="{./label/@for}">
<!-- Если это первое поле из всей группы -->
<xsl:if test="position() = '1'">
<!-- Добавляем к нему атрибут class -->
<xsl:attribute name="class">
<!-- Если ранее этот атрибут уже существовал у поля, к его значению добавим значение first -->
<xsl:value-of select="concat( ./field_options/class, ' first' ) " disable-output-escaping="yes" />
</xsl:attribute>
</xsl:if><!-- Если это первое поле из всей группы -->
<!-- Создаем тег поля input -->
<input>
<!-- Для каждого из свойств и атрибутов поля формы -->
<xsl:for-each select="./field_options/child::node()">
<!-- Сохраняем имя атрибута в переменной -->
<xsl:variable name="attrName" select="name()" />
<!-- Создаем атрибут -->
<xsl:attribute name="{$attrName}">
<xsl:choose>
<!-- Если это не атрибут обязательности поля, отключенного поля или выбранного -->
<xsl:when test="name() != 'required' and name() != 'disabled' and name() != 'checked'">
<!-- Присвоить значение атрибуту -->
<xsl:value-of select="./node()" disable-output-escaping="yes" />
</xsl:when>
</xsl:choose>
</xsl:attribute><!-- Создаем атрибут -->
</xsl:for-each><!-- Для каждого из свойств и атрибутов поля формы -->
</input>
<!-- Выводим значение текста тега <label> -->
<xsl:value-of select="child::label" disable-output-escaping="yes" />
<!-- Закрываем тег <label> -->
</label>
</xsl:when><!-- Если у поля есть заголовок -->
</xsl:choose>
</xsl:template><!-- Шаблон для обработки полей формы <input type="radio" /> или <input type="checkbox" /> -->
<!-- Шаблон для обработки полей списков -->
<xsl:template match="select">
<!-- Создаем контейнер для поля формы -->
<div class="field">
<!-- Создаем элемент поля списка -->
<select>
<!-- Для каждого из свойств и атрибутов поля формы -->
<xsl:for-each select="./field_options/child::node()">
<!-- Сохраняем имя атрибута в переменной -->
<xsl:variable name="attrName" select="name()" />
<!-- Создаем атрибут -->
<xsl:attribute name="{$attrName}">
<xsl:choose>
<!-- Если это не атрибут обязательности поля, отключенного поля -->
<xsl:when test="name() != 'required' and name() != 'disabled'">
<!-- Присвоить значение атрибуту -->
<xsl:value-of select="./node()" disable-output-escaping="yes" />
</xsl:when>
</xsl:choose>
</xsl:attribute><!-- Создаем атрибут -->
</xsl:for-each><!-- Для каждого из свойств и атрибутов поля формы -->
<!-- Вызываем шаблон для элементов списка — тегов <option> -->
<xsl:apply-templates select="option" />
</select>
</div><!-- Создаем контейнер для поля формы -->
</xsl:template><!-- Шаблон для обработки полей списков -->
<!-- Шаблон для элементов списка — тегов <option> -->
<xsl:template match="option">
<!-- Открываем тег -->
<option value="{@value}">
<!-- Если у тега есть атрибут selected -->
<xsl:if test="count(@selected)">
<!-- Устанавливаем этот атрибут элементу -->
<xsl:attribute name="selected" />
</xsl:if>
<!-- Вставляем текстовое значение элемента -->
<xsl:value-of select="." disable-output-escaping="yes" />
</option>
</xsl:template>
<!-- Шаблон для обработки поля типа textarea -->
<xsl:template match="textarea">
<!-- Создаем контейнер для поля формы -->
<div class="field">
<!-- Открываем тег textarea -->
<textarea>
<!-- Для каждого из свойств и атрибутов поля формы -->
<xsl:for-each select="./field_options/child::node()">
<!-- Сохраняем имя атрибута в переменной -->
<xsl:variable name="attrName" select="name()" />
<!-- Создаем атрибут -->
<xsl:attribute name="{$attrName}">
<xsl:choose>
<!-- Если это не статус отключенного поля или поля обязательного -->
<xsl:when test="name() != 'required' and name() != 'disabled'">
<!-- Присваиваем значение атрибуту -->
<xsl:value-of select="./node()" disable-output-escaping="yes" />
</xsl:when>
</xsl:choose>
</xsl:attribute>
</xsl:for-each><!-- Для каждого из свойств и атрибутов поля формы -->
<!-- Помещаем в поле формы текст -->
<xsl:value-of select="text" disable-output-escaping="no" />
</textarea>
</div><!-- Создаем контейнер для поля формы -->
</xsl:template><!-- Шаблон для обработки поля типа textarea -->
</xsl:stylesheet>
А давайте теперь посмотрим, насколько «сложнее» будет сделать форму регистрации подобную этой:
<?php
// Создаем экземпляр объекта класса, отвечающего за построение формы
// Вызываем статический метод instance() класса Core_Form
$oCore_Form = Core_Form::instance()
// Атрибуту name тега <form> устанавливаем значение regUser
->name( 'regUser' )
// Устанавливаем значение атрибута id формы
->id( 'regUser' )
// Значение javascript-атриуба onsubmit для тега <form>
->onsubmit( 'return false;' )
// Значение атрибута для автозаполнения полей формы
->autocomplete( 'no' )
// Добавляем поле формы, вызвав метод add() класса Core_Form
->add(
// Вызываем статический метод класса createField() Core_Form
// В качестве аргумента передаем этому методу значение типа поля
// Это значение хранится внутри класса Core_Form в константе
// Чтобы не ошибиться и не опечататься, передаем это значение таким образом
Core_Form::createField( Core_Form::FIELD_INPUT )
// Атрибут type тега <input>
->type( 'text' )
// Атрибут id
->id( 'login' )
// Атрибут name
->name( 'login' )
// Атрибут placeholder
->placeholder( 'Введите логин пользователя' )
// Заголовок поля в теге <label>
->label( 'Логин пользователя:' )
// Текст для поля подсказки
->instr( 'Логин может содержать только буквы и цифры латинского алфавита' )
// Поле будет обязательным для заполнения
->requireField( TRUE )
// С этим полем пока что всё, переходим к следующему
)
// Действуем аналогично, теперь у нас будет поле <input type="password" />
->add(
Core_Form::createField( Core_Form::FIELD_INPUT )
->type( 'password' )
->id( 'password' )
->name( 'password' )
->placeholder( 'Введите пароль пользователя' )
->label( 'Пароль пользователя:' )
->instr( 'Пароль может содержать только буквы и цифры латинского алфавита' )
->requireField( TRUE )
)
// Действуем аналогично, пользователю нужно повторить пароль, чтобы снизить риск его опечатки
->add(
Core_Form::createField( Core_Form::FIELD_INPUT )
->type( 'password' )
->id( 'passwordApproove' )
->name( 'passwordApproove' )
->placeholder( 'Снова введите пароль' )
->label( 'Повторный ввод пароля:' )
->instr( 'Пароль должен в точности совпадать с предыдущим вводом' )
->requireField( TRUE )
)
// Добавляем поле для ввода email
->add(
Core_Form::createField( Core_Form::FIELD_INPUT )
->type( 'text' )
->id( 'email' )
->name( 'email' )
->placeholder( 'Введите адрес электропочты' )
->label( 'Электропочта пользователя:' )
->instr( 'На указанный адрес электронной почты будет отправлено письмо с описаний действия для активации вашей учетной записи' )
->requireField( TRUE )
)
// Добавляем поле <input type="checkbox" />
->add(
Core_Form::createField( Core_Form::FIELD_INPUT )
->type( 'checkbox' )
->id( 'signNews' )
->name( 'signNews' )
->label( 'Подписаться на рассылку:' )
->checked( TRUE )
)
// Добавляем кнопку отправки формы на обработку
->add(
Core_Form::createField( Core_Form::FIELD_INPUT )
->type( 'submit' )
->id( 'btn-submit' )
->name( 'btn-submit' )
->value( 'Зарегистрироваться' )
)
// Добавляем кнопку очистки полей формы
->add(
Core_Form::createField( Core_Form::FIELD_INPUT )
->type( 'reset' )
->id( 'btn-reset' )
->name( 'btn-reset' )
->value( 'Очистить поля' )
)
// Добавляем кнопку возврата к авторизации
->add(
Core_Form::createField( Core_Form::FIELD_BUTTON )
->id( 'btn-back' )
->name( 'btn-back' )
->value( 'Вернуться к авторизации' )
);
/**
* Данные для построения формы собраны, готовы.
*
* За отображение формы на экране отвечать будет класс Core_Form_Show
* Вызываем конструктор этого класса, передав ему в виде аргумента экземпляр
* объекта нашей формы
*
*/
$oCore_Form_Show = new Core_Form_Show( $oCore_Form );
/**
* Дальнейшая обработка формы происходит по следующему алгоритму.
*
* 1. Вызывается метод show() класса Core_Form_Show. Этот метод сформирует промежуточный XML-документ,
* в который поместит всю информацию о форме, её атрибутах и полях.
* 2. XML-документ будет передан XSLT-процессору.
* 3. XSLT-процессор посредством обработки XSL-шаблона представит нам форму в таком виде, в каком мы захотим.
* 4. Имя XSL-шаблона указываем вызвав метод byXSLName(), передав имя шаблона в виде аргумента.
*
*/
$oCore_Form_Show->show(
Core_Xsltprocessor::instance()
->byXSLName( '1' ));
?>
Считаю подобный алгоритм лучшим вариантом реализации построения веб-формы (авторизации пользователей, регистрации пользователей и вообще всего того, что связано с формами). Мы один раз написали класс, в котором реализовали сбор информации о полях формы. Этот класс отдает собранные данные, чтобы сформировать из них XML-документ, который будет обработан XSL-шаблоном и выведен на экран.
Подобный алгоритм позволяет нам при написании класса для построения формы не зацикливаться над тем, как построить html-код формы. И что делать, допустим, если мы захотим добавить в форму различные информационные блоки (всплывающие подсказки и другие).
Любые изменения внешнего вида никак не затронут реализацию класса. Все эти изменения можно применить либо изменив указанный XSL-шаблон, либо написав новый XSL-шаблон.
Я не привел код реализации класса. Пока что. Многие из вас поймут, что там даже не один класс, а... несколько. Но, наверное, вы хотели бы лично убедиться в его работоспособности, не так ли? Что будет, если я вам скажу, что даже весь вышеупомянутый код писать нет необходимости? Не верите? Смотрите сами!
- Я опубликовал эту статью:08.06.2019
- 14 395