Advanced form guide Joomla (Продвинутое руководство по использования форм в Joomla)

  1. Введение
  2. Пути файлов
  3. Наборы полей Joomla
  4. Группы полей Joomla
  5. Динамически изменяемые формы в Joomla
    1. Добавление полей через определение формы в Joomla
    2. Динамическая настройка полей в Joomla
    3. Установка атрибутов и значений полей в Joomla
    4. Удаление полей в Joomla
  6. Методы отражения в Joomla
  7. Пример кода компонента 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, то новое поле игнорируется.
  • $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

Заберите ссылку на статью к себе, чтобы потом легко её найти!
Раз уж досюда дочитали, то может может есть желание рассказать об этом месте своим друзьям, знакомым и просто мимо проходящим?
Не надо себя сдерживать! ;)

Старт! Горячий старт на просторы интернета
Старт! Горячий старт на просторы интернета
Старт! Меню