- Введение
- Пути файлов
- Наборы полей Joomla
- Группы полей Joomla
- Динамически изменяемые формы в Joomla
- Методы отражения в Joomla
- Пример кода компонента Joomla
Введение.
Это одно из серии руководств по API, цель которых - помочь понять, как использовать API Joomla, предоставляя подробные объяснения и примеры кода, которые вы можете легко установить и запустить.
Это руководство описывает более продвинутые возможности API Joomla Form
, чем те, которые рассматриваются в руководстве по основам использования форм в Joomla (Basic form guide), и включает в себя следующие аспекты:
- Установка пути к файлу, чтобы Joomla могла найти ваши определения формы, поля формы и валидацию полей формы, в случае, если вы не следуете стандартам Joomla.
- Определение групп полей - Joomla предоставляет два типа, а именно наборы полей и группы полей.
- Динамическое изменение формы (после ее загрузки из XML-файла).
- Методы, подобные отражению, которые позволяют извлекать информацию из структуры и данных формы.
В конце руководства приводится пример компонента с примерами вышеперечисленных аспектов.
Пути файлов.
По умолчанию Joomla будет искать XML-определение формы в папке .../models/forms
вашего компонента, в файлах сайта, если форма отображается на пользовательской стороне, или в файлах администратора, если форма отображается в админке. Статическая функция addFormPath()
позволяет вам добавить другой каталог в список каталогов, которые Joomla будет искать.
Аналогично функция addFieldPath()
позволяет определить другую директорию для любых пользовательских определений полей формы (по умолчанию это .../models/fields
), а функция addRulePath()
позволяет вам определить другую директорию для любых пользовательских правил валидации (по умолчанию это .../models/rules
).
Примеры всех трех функций приведены в примере кода компонента в конце данного руководства.
Наборы полей Joomla.
Наборы полей (Fieldsets) в Joomla связаны с элементом <fieldset name="myfieldset">
в XML-определении формы. Преимущество использования наборов полей заключается в том, что в файле макета вы можете использовать
$form->renderFieldset("myfieldset");
для рендеринга всех полей, имеющих элементы <field>
внутри открывающего и закрывающего тегов <fieldset>
. Вместо того, чтобы вызывать renderField()
для каждого поля в наборе полей.
Набор полей можно рассматривать как набор полей, которые должны отображаться в форме, и, таким образом, они похожи по концепции на элемент HTML <fieldset>
. Однако обратите внимание, что renderFieldset()
не выводит HTML <fieldset>
или связанные с ним теги.
Группы полей Joomla.
Группы полей (Field Groups) связаны в Jomla с элементом <fields name="mygroup">
в XML определении формы. Это влияет на атрибут name
HTML, который присваивается элементам input
HTML полей, определенных в открывающем и закрывающем тегах <fields>
в XML определении формы, и, следовательно, на имя параметра, отправляемого на сервер в HTTP POST запросе.
Если вы укажете опцию "control" => "myform"
при настройке экземпляра формы, то значения полей ввода будут отправлены на сервер в HTTP POST запросе в следующем виде
myform[field1]
myform[field2]
myform[field3]
Если вы заключите эти поля в XML определение формы в элемент <fields name="mygroup">
, то POST параметры будут отправлены с именами типа
myform[mygroup][field1]
myform[mygroup][field2]
myform[mygroup][field3]
Если ваш компонент имеет таблицу базы данных и вы храните ряд параметров в json-строке в одном из столбцов таблицы, то вы можете сгруппировать HTML элементы ввода этих параметров внутри элемента <fields>
. Если вы назовете тег fields
в соответствии с названием колонки, то вы можете использовать функциональность класса Table
Joomla для легкого преобразования ассоциативного массива PHP, возникающего из POST-параметров, в json-строку для хранения в базе данных.
Параметр $group
, который появляется в нескольких методах класса Form
API Joomla, ссылается на атрибут name тега <fields>
в XML определении формы.
Примеры такого подхода можно увидеть в учебнике Joomla MVC "Добавление шага изображения" и во многих основных компонентах Joomla.
Обратите внимание, что наборы полей и группы полей являются независимыми. В XML определении формы можно иметь элементы <fields>
внутри элементов <fieldset>
, а также элементы <fieldset>
внутри элементов <fields>
.
Динамически изменяемые формы в Joomla.
Если вы определили свою форму статически в XML-файле, то после ее загрузки вы можете изменить ее диамически в своем PHP-коде, используя API класса Form
Joomla:
- добавлением дополнительных полей в форму путем загрузки другого XML-определения формы,
- изменение существующего поля или полей,
- удаление поля или группы полей.
Добавление полей через определение формы в Joomla.
Чтобы включить в форму дополнительные определения из файла, сделайте следующее
$form->loadFile($filename);
передавая в $filename
имя и путь до XML-файла, структурированный таким же образом, как и основной файл определений вашей формы.
В качестве альтернативы можно создать SimpleXMLElement ($xml say)
в коде, который содержит тот же XML и затем вызвать
$form->load($xml);
(Код Joomla для loadFile()
просто считывает данные из файла в переменную SimpleXMLElement
и затем вызывает load()
).
Обеим этим функциям можно передать дополнительные параметры:
$replace
(в методеload()
) /$reset
(в методеloadFile()
)- оба параметра имеют одинаковый эффект и относятся к случаю, когда поле в загружаемом XML имеет имя
name
, совпадающее с именем поля в форме. - Если установлено значение
true
, то новое поле заменяет старое. - Если установлено значение
false
, то новое поле игнорируется.
- оба параметра имеют одинаковый эффект и относятся к случаю, когда поле в загружаемом XML имеет имя
$xpath
если вы хотите, чтобы рассматривалась только часть загружаемой структуры XML, вы можете указать
xpath
для выбора части или частей XML, которые вы хотите включить.
В дополнение к примеру, приведенному в примере кода ниже, можно найти примеры загрузки дополнительных XML файлов в основном коде com_menu
администратора Joomla, относящиеся к тому, когда администратор настраивает опции меню сайта. Основные опции для пункта меню сайта задаются в файле item.xml
в каталоге administrator/com_menus/models/forms
, но в коде com_menu
модели item.php
они дополняются опциями, определенными в XML-файле, который находится в каталоге шаблона, относящемся к странице сайта, которая будет отображаться.
Пример построения и загрузки XML-структуры приведен в статье по разработке Joomla MVC в разделе "Добавление ассоциаций", где поля ассоциаций добавляются динамически таким образом, потому что добавляемые ассоциации зависят от языка записи.
Динамическая настройка полей в Joomla.
Вы можете использовать setField()
для добавления или замены одного поля в экземпляре формы, а setFields()
- для добавления или замены нескольких полей. Чтобы использовать эти функции, создайте XML, относящийся к полю, а затем передайте его в setField()
$xml = new SimpleXMLElement('<field name="newfield" … />');
setField($xml);
Аналогично вы можете определить массив таких XML-элементов и передать их в setFields()
, что эквивалентно вызову setField()
для каждого отдельного элемента.
Укажите параметры $group
и $fieldset
, чтобы включить новое поле в определенную группу полей и набор полей.
- Если параметр
$replace
имеет значениеtrue
, то при обнаружении существующего поля с той же группой полей и именем оно будет заменено. - Если параметр
$replace
имеет значениеfalse
и найдено существующее поле с той же группой полей и именем, то новое поле будет проигнорировано.
Установка атрибутов и значений полей в Joomla.
setFieldAttribute()
позволяет установить / изменить атрибут, связанный с полем. Обратите внимание, что атрибут относится к атрибуту поля Joomla, а не к атрибуту HTML элемента ввода. Например, чтобы установить атрибут HTML placeholder
, вы должны установить атрибут поля hint
Joomla, и это работает только в том случае, если тип поля формы поддерживает этот атрибут.
Атрибут HTML value
обрабатывается несколько иначе, чем другие атрибуты HTML. Как указано в руководстве по основам использования форм, в экземпляре формы Joomla структура XML формы (определенная XML-файлом определения формы) хранится отдельно от данных предварительного заполнения формы (передаваемых в методе bind()
). То, что выводится в атрибуте value
элемента input
HTML, в первую очередь является атрибутом поля формы Joomla default
(если он поддерживается для данного типа поля), но это value
отменяется любым значением, указанным для этого поля в вызове bind()
.
Таким образом, вы можете установить атрибут default
с помощью setFieldAttribute()
, но для установки значения поля непосредственно в данных предварительного заполнения используйте setValue()
.
Удаление полей в Joomla.
Вы можете удалить поля из определения формы, вызвав removeField()
для удаления конкретного поля или removeGroup()
для удаления всех полей в указанной группе полей.
Методы отражения в Joomla.
Существует ряд методов, позволяющих получить доступ к различным аспектам данных экземпляра формы. В основном они достаточно просты для понимания, и только те случаи, когда они могут быть не совсем понятны, объясняются ниже.
getData()
возвращает в виде объекта реестра Joomla данные предварительного заполнения, которые были установлены с помощью вызова метода bind()
класса Form
.
Методы getField()
, getFieldset()
и getGroup()
возвращают поля как объекты FormField
Joomla, а не как они хранятся внутри экземпляра формы.
getFieldsets()
возвращает массив объектов Fieldset
со свойствами, которые отражают тег <fieldset>
в файле определения формы. Таким образом, если имеется
<fieldset name="myfieldset" label="myfieldsetLabel" description="myfieldsetDescription">
тогда вы можно
$fieldsets = $form->getFieldsets();
echo $fieldsets['myfieldset']->label; // вывод "myfieldsetLabel"
getFormControl()
возвращает строку из параметра $options
, переданного при создании экземпляра формы. Если вы использовали стандарт Joomla "control" => "jform"
в этом массиве $options
, то getFormControl()
вернет строку jform
.
getInput()
и getLabel()
возвращают HTML для тега <input>
и <label>
соответственно поля, которое было передано в качестве параметра. Однако обратите внимание, что ни один из этих методов не работает, если у вас есть пользовательское поле. Также обратите внимание, что эти методы класса Form
отличаются от методов getInput()
и getLabel()
класса FormField
, которые нужно предоставить при настройке некоторых типов пользовательских полей.
getValue()
возвращает значение поля, которое вы передаете в качестве параметра, считывая его из данных, переданных в вызове bind()
. При этом не учитывается атрибут default
, установленный для поля, который будет преобразован в атрибут значения поля HTML, если для этого поля не предоставлены данные для предварительного заполнения.
Пример кода компонента Joomla.
Ниже приведены 6 файлов, составляющих небольшой компонент, который вы можете установить и запустить для демонстрации ряда функций, описанных выше, и который вы можете адаптировать для экспериментов с другими функциями.
Создайте первые 3 файла в папке com_sample_form3
, а остальные 3 файла в подкаталоге этой папки com_sample_form3/extra
. Затем заархивируйте папку com_sample_form3
, чтобы создать файл com_sample_form3.zip
и установите его как расширение в админке Joomla. После установки перейдите через браузер на ваш сайт Joomla и добавьте параметр URL &option=com_sample_form3
, который должен будет отобразить форму и позволить ввести данные и отправить форму. Комментарии в коде должны дать понять, что происходит.
Как описано в соответствующем руководстве по основам использования форм, это не лучший способ проектирования компонента Joomla MVC, но он написан таким образом, чтобы сделать возможным использование API Form
как можно более понятным.
com_sample_form3.xml
Файл манифеста для компонента
<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3.1.0" method="upgrade">
<name>com_sample_form3</name>
<version>1.0.0</version>
<description>Пример form 3</description>
<administration>
</administration>
<files folder="site">
<filename>sample_form3.php</filename>
<filename>sample_form.xml</filename>
<folder>extra</folder>
</files>
</extension>
sample_form.xml
Файл, содержащий XML для определения формы.
Три поля заключены в набор полей mainFieldset
, а поля email и номера телефона находятся в группе полей details
. Поле сообщения имеет пользовательскую валидацию noasterisk
.
<?xml version="1.0" encoding="utf-8"?>
<form name="myFormName">
<fieldset name="mainFieldset" label="mainFieldsetLabel" description="mainFieldsetDescription">
<field
name="message"
type="text"
label="Message"
size="40"
validate="noasterisk"
class="inputbox"
required="true" />
<fields name="details">
<fieldset name="detailsFieldset">
<field name="email"
type="email"
label="Email"
required="true"
size="40"
class="inputbox" />
</fieldset>
<field name="telephone"
type="tel"
label="Telephone number"
required="true"
size="40"
class="inputbox"
validate="tel" />
</fields>
</fieldset>
</form>
sample_form3.php
Основной файл кода, который запускается, когда HTTP GET или POST запрашивают этот компонент.
<?php
defined('_JEXEC') or die('Запрещённый доступ! Всем кыш!');
use Joomla\CMS\Form\Form;
use Joomla\CMS\Factory;
// определение базовой формы
$form = Form::getInstance("sample", __DIR__ . "/sample_form.xml", array("control" => "myform"));
// поскольку email и telephone относятся к группе "details", данные предварительного заполнения должны отражать это
$prefillData = array("details" => array("email" => ".@.", "telephone" => "0"), "time" => "12:34");
// добаление путей формы и поля (путь правила добавляется позже, перед валидацией при обработке HTTP POST)
Form::addFieldPath(__DIR__ . "/extra");
Form::addFormPath(__DIR__ . "/extra");
// с помощью параметра xpath включить только поле "time" из extra_form.xml, а не поле "ignored"
$extraForm = $form->loadFile("extra_form", true, "//field[@name='time']");
// добавить новый элемент в форму, в группу "details" и набор полей "mainFieldset"
$xml = new SimpleXMLElement('<field name="upload" type="file" label="Photo" accept="image/*" />');
$form->setField($xml, 'details', true, "mainFieldset");
// Изменить надпись в поле сообщения на "Description" и установите подсказку (html-заполнитель) на "No asterisks!"
$form->setFieldAttribute("message", "label", "Description");
$form->setFieldAttribute("message", "hint", "No asterisks!");
// Удалить поле telephone - для активации не раскомментировать строку ниже
// $form->removeField("telephone", "details");
// Некоторые методы отображения
echo "<h2>Reflection methods output</h2>";
$formName = $form->getAttribute("name");
echo "Form name is: $formName<br>";
$formControl = $form->getFormControl();
echo "Form control is: $formControl<br>";
$detailsGroup = $form->getGroup('details');
echo "Fields in details group: <br>";
foreach ($detailsGroup as $key => $value)
{
echo "Key is: $key, PHP class of field is " . get_class($value) . ", and name attribute is " . $value->getAttribute("name") . "<br>";
}
$fieldsets = $form->getFieldsets();
echo "Fieldset label for mainFieldset is " . $fieldsets['mainFieldset']->label . "<br>";
if ($_SERVER['REQUEST_METHOD'] === 'POST')
{
$app = Factory::getApplication();
$data = $app->input->post->get('myform', array(), "array");
echo "<h2>POST data</h2>";
echo "Message was " . $data["message"] .
", email was " . $data["details"]["email"] .
", and time was " . $data["time"] . "<br>";
// добавление пути правила для валидации
Form::addRulePath(__DIR__ . "/extra");
$filteredData = $form->filter($data);
$result = $form->validate($filteredData);
if ($result)
{
echo "Validation passed ok<br>";
}
else
{
echo "Validation failed<br>";
$errors = $form->getErrors();
foreach ($errors as $error)
{
echo $error->getMessage() . "<br>";
}
// в повторно отображаемой форме показывать то, что ввел пользователь (после фильтрации данных)
$prefillData = $filteredData;
}
}
$form->bind($prefillData);
$data = $form->getData();
echo "<br>Form data is: $data<br>";
?>
<form action="<?php echo JRoute::_('index.php?option=com_sample_form3'); ?>"
method="post" name="sampleForm" id="adminForm" enctype="multipart/form-data">
<h2>mainFieldset fieldset</h2>
<?php echo $form->renderFieldset('mainFieldset'); ?>
<h2>time field</h2>
<?php echo $form->renderField('time'); ?>
<h2>ignored field - should be blank</h2>
<?php echo $form->renderField('ignored'); ?>
<button type="submit">Заслать! =D</button>
</form>
extra/extra_form.xml
Определение формы для дополнительных полей формы, которые будут добавлены в форму.
Код компонента включает только поле time
из этого определения формы, и это пользовательское поле типа mytime
.
<?xml version="1.0" encoding="utf-8"?>
<form>
<field
name="ignored"
type="number"
label="Number"
step="0.1"
class="inputbox"
required="true" />
<field name="time"
type="mytime"
label="Enter time"
required="true"
class="inputbox" />
</form>
extra/Mytime.php
Здесь содержится HTML-элемент <input>
для пользовательского поля mytime
.
Поскольку здесь нет метода getLabel()
, метка label
будет взята из XML определения поля формы.
<?php
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\FormField;
class JFormFieldMytime extends FormField
{
protected $type = 'Mytime';
protected function getInput()
{
// Установить атрибуты - здесь только CSS класс для элемента input, если он указан.
$attr = !empty($this->class) ? ' class="' . $this->class . '"' : '';
// настройка html, включая value и другие атрибуты
$html = '<input type="time" name="' . $this->name . '" value="' . $this->value . '"' . $attr . '/>';
return $html;
}
}
extra/noasterisk.php
Здесь содержится правило валидации для пользовательской валидации noasterisk
для поля сообщения.
<?php
defined('_JEXEC') or die('Restricted access');
class JFormRuleNoasterisk extends JFormRule
{
// регулярное выражение, чтобы разрешить все, кроме звездочки
protected $regex = '^[^\*]+$';
}
Перевод с английского официальной документации Joomla:
https://docs.joomla.org/Advanced_form_guide
Заберите ссылку на статью к себе, чтобы потом легко её найти!
Раз уж досюда дочитали, то может может есть желание рассказать об этом месте своим друзьям, знакомым и просто мимо проходящим?
Не надо себя сдерживать! ;)