Я недавно сел разбираться, как же всё таки работает JHTML. И появилась мысль всё, чему научусь сам, задокументировать в виде темы на форуме.
Порыскал по форуму, нашёл похожую тему. Она и становится отправной точкой, а так же в честь неё названа эта тема.

В указанной теме приведён пример выпадающего списка SELECT. Но там всё расписано не подробно, моей же целью является описать максимальные возможности JHTML по созданию элементов форм. По этому не в обиду автору, но чуть позже я повторюсь и приведу здесь пример создания выпадающего списка с более объёмными и подробными комментариями.

Как работает JHTML::_()?

Практически всегда доступ к объектам JHTML осуществляется через загрузочную функцию JHTML::_().
Первый параметр является строкой, указывающей, какому helper-методу необходимо будет передать все последующие параметры. Параметр имеет вид строки, содержащей название префикса класса хелпера, название самого класса хелпера и название вызываемого метода, разделённые точкой. Первые два (префикс и название класса) являются не обязательными, но чаще всего название класса указывается. Таким образом, если строка состоит из двух частей, разделённых точкой, то указано название класса и метода.
Теперь, увидев в коде


Код

$p = JHTML::_("select.genericlist", $params, $value, $text, $attribs);

 

мы понимаем, что JHTML::_() загрузит класс с префиксом JHTML (этот префикс стоит по умолчанию) и названием Select и вызовет метод genericlist, передав ему все остальные параметры ($params, $value, $text, $attribs).
Сам класс JHTML и функция-загрузчик определены в файле JOOMLA/libraries/html/html.php
Вызываемый в нашем примере класс JHTMLSelect и метод genericlist описаны в JOOMLA/libraries/html/html/select.php

Пример создания выпадающего списка (<SELECT>)
Пример взят из приведённой выше темы и немного дополнен.

Код:

    // Получаем объект базы данных
     $database =& JFactory::getDBO();
     // Формируем запрос
     $query = "SELECT c.id AS value, c.title AS text FROM #__categories AS c WHERE c.section='com_qcontacts_details'";
     // Выполняем запрос
     $database->setQuery($query);
     // Получаем массив объектов
     $categorylist = $database->loadObjectList();
     // Создаём первый элемент выпадающего списка (<option value="0">Выберите категорию</option>)
     $categories[] = JHTML::_('select.option',  '0', "Выберите категорию", 'value', 'text' );
     // Добавляем массив данных из базы данных
     $categories = array_merge( $categories, $categorylist);
     // Получаем выпадающий список
     $list = JHTML::_(
                         'select.genericlist' /* тип элемента формы */,
                         $categories /* массив, каждый элемент которого содержит value и текст */,
                         'cid' /* id и name select`a формы */,
                         'class="inputbox" size="1"' /* другие атрибуты элемента select */,
                         'value' /* название поля в массиве объектов содержащего ключ */,
                         'text' /* название поля в массиве объектов содержащего значение */,
                         0 /* value элемента, который должен быть выбран (selected) по умолчанию */,
                         'cid' /* id select'a формы */,
                         true /* пропускать ли элементы полей text через JText::_(), default = false */
                      );



Разберём код поподробнее.
Код:

    // Формируем запрос
     $query = "SELECT c.id AS value, c.title AS text FROM #__categories AS c WHERE c.section='com_qcontacts_details'";


Здесь стоит обратить внимание на то, что поля id и title из таблицы выбираются с параметром AS. Это означает, что впоследствии эти поля будут доступны по псевдонимам (value и text соотв. в нашем случае. Они будут использоваться в дальнейшем при работе с классом)). Впрочем, выборку можно было делать и без подобных излишеств. Позже укажу как именно.


Код:

    // Создаём первый элемент выпадающего списка (<option value="0">Выберите категорию</option>)
     $categories[] = JHTML::_('select.option',  '0', "Выберите категорию", 'value', 'text' );



Здесь я хочу обратить внимание на то, что здесь мы получаем объект. Объект будет иметь поля value и text (их можно определить и по-другому), и содержать значения, соответственно, 0 и "Выберите категорию".


Код:

    // Получаем выпадающий список
     $list = JHTML::_(
                         'select.genericlist' /* тип элемента формы */,
                         $categories /* массив, каждый элемент которого содержит value и текст */,
                         'name' /* id и name select`a формы */,
                         'class="inputbox" size="1"' /* другие атрибуты элемента select */,
                         'value' /* название поля в массиве объектов содержащего ключ */,
                         'text' /* название поля в массиве объектов содержащего значение */,
                         0 /* value элемента, который должен быть выбран (selected) по умолчанию */,
                         'cid' /* id select'a формы */,
                         true /* пропускать ли элементы полей text через JText::_(), default = false */
                      );





Ну а здесь мы остановимся поподробнее.
Первый парамерт - см. выше.
Второй параметр ($categories) - это обязательно должен быть массив объектов, либо массив ассоциативных массивов. В случае массива объектов каждый объект должен иметь поля value и text, а в случае массива ассоциативных массивов - каждый из последних должен содержать ключи value и text (только в нашем случае, см. пятый и шестой параметры), которые будут содержать значение value, передаваемое каждому элементу <OPTION> (<OPTION value="..." />), и текст, который будет отображаться в выпадающем списке, соответственно.
Третий параметр ('name') - это, как было сказано, name и id select'a формы. Впрочем, id можно задать отличным от name. См. восьмой параметр.
Четвёртый параметр - ясно.
Пятый и шестой параметры - это соответственно названия полей объектов, содержащих значения для value OPTION'a и отображаемого текста, в случае, если $categories - массив объектов, и названия ключей ассоциативного массива в случае, если $categories - массив ассоциативных массивов.
Седьмой параметр - value элемента, который должен быть выбран (selected) по умолчанию(Может быть задан в виде массива значений или массива объектов, что очень удобно. Но такой подход требуется для multiply select)
Восьмой параметр - это id selecta. Если он не задан, id будет совпадать с name, заданным третьим параметром.
Девятый параметр - это флаг, показывающий, нужно ли пропускать элементы полей (в нашем случае) text  через функцию JText::_(), и имеющий гордое название $translate. Проще говоря, элемент для мультиязычности. По умолчанию в функции равен false.

Ну и живой пример, в нём я намеренно сделаю названия полей отличными от приведённых в примере выше, а так же проделаю другие шалости.


Код:

    // Получаем объект базы данных
     $database =& JFactory::getDBO();
     // Формируем запрос
     $query = "SELECT c.id, c.title FROM #__categories AS c WHERE c.section='com_qcontacts_details'";
     // Выполняем запрос
     $database->setQuery($query);
     // Получаем массив ассоциативных массивов, ключи которых соответствуют полям в базе данных, т.е. id и title
     $categorylist = $database->loadAssocList();
     // Создаём первый элемент выпадающего списка (<option value="0">Выберите категорию</option>)
     // Обратите внимание, что мы указываем в параметрах названия полей будущего объекта, id и title.
     // Они должны совпадать с ключами массивов, пришедших из базы данных
     $categories[] = JHTML::_('select.option',  '0', "Выберите категорию", 'id', 'title' );
     // Добавляем массив данных из базы данных
     // Обращаю ваше внимание на то, что мы объединяем массив ассоциативных массивов и массив объектов.
     // Такая конструкция "прокатит"
     $categories = array_merge( $categories, $categorylist);
     // Получаем выпадающий список
     $list = JHTML::_(
                         'select.genericlist' /* генерируем выпадающий список */,
                         /* массив, каждый элемент которого является ассоциативным
                         массивом с ключами id и title ЛИБО объектом с полями id и title  */
                         $categories,
                         'name' /* только name select`a формы */,
                         'class="inputbox" size="1"' /* другие атрибуты элемента select */,
                         'id' /* название поля в массиве объектов содержащего ключ */,
                         'title' /* название поля в массиве объектов содержащего значение */,
                         0 /* value элемента, который должен быть выбран (selected) по умолчанию. */,
                         'cid' /* id select'a формы */,
                         true /* пропускать ли элементы полей text через JText::_(), default = false */
                      );

Пример создания multiply select (<SELECT>)

Пример беру из вышеприведённого и немного адаптирую.
В комментариях попытался расписать всё как можно подробнее. Если возникнут вопросы - милости прошу)


Код:

// Получаем объект базы данных
     $database =& JFactory::getDBO();
     // Формируем запрос
     $query = "SELECT c.id AS value, c.title AS text, c.published AS selected FROM #__categories AS c WHERE c.section='com_qcontacts_details'";
     // Выполняем запрос
     $database->setQuery($query);
     // Получаем массив объектов
     $categorylist = $database->loadObjectList();
     // Формируем массив объектов, которые будут выбраны по умолчанию после формирования списка
     $selected = array ();
     foreach ($categorylist as $key => $value)
     {
        if ((int)$value->selected == 1)
        {
          // Обратите внимание, мы присваиваем элементу массива [u]объект[/u]
          // здесь можно было создать массив значений, а не объектов: $selected[] =& $value->value;
          // но гибкость JHTML позволяет делать по-другому.
          $selected[] =& $value;
        }
     }
     // размер списка
     $size = count ($categorylist);
     // Получаем multiselect список
     $list = JHTML::_(
                         'select.genericlist' /* генерируем multiply select список */,
                         /* массив, каждый элемент которого является ассоциативным
                         массивом с ключами id и title ЛИБО объектом с полями id и title  */
                         $categories,
                         'cid[]' /* id и name select`a формы */,
                         'class="inputbox" size=" . $size . " MULTIPLE' /* другие атрибуты элемента select */,
                         'value' /* название поля в массиве объектов содержащего ключ */,
                         'text' /* название поля в массиве объектов содержащего значение */,
                         /* в нашем случае - массив объектов, указывающих, какие элементы списка будут выбраны по умолчанию
                             Для этого объекты обязательно должны содержать поле, указанное пятым параметром,
                             и иметь те же значения, что и в списке $categories */
                         $selected
                      );



upd: Вспомнил. По 3-му параметру пара замечаний.
В multiselect'е я указал его со скобочками, и в качестве восьмого параметра я не указал id. Метод сам отрежет квадратные скобки и подставит оставшееся значение в поле id
И вообще, это не всё) Я продолжу, и опишу создание radiоbox'ов и т.д. А так же буду дополнять уже написанное, ибо есть чем.

Ну что ж, продолжим.

Пример создания radiobox'ов (<input type="radio" ... />)

Как и обещал, Radiobox
Тут, вобщем то, ничего тяжёлого нет. Всё делается практически так же, как с genericlist. Снова беру первый пример и немного адаптирую:


Код:

   // Получаем объект базы данных
     $database =& JFactory::getDBO();
     // Формируем запрос
     $query = "SELECT c.id AS value, c.title AS text FROM #__categories AS c WHERE c.section='com_qcontacts_details'";
     // Выполняем запрос
     $database->setQuery($query);
     // Получаем массив объектов, поля которых соответствуют полям в базе данных, т.е. value и text
     $categorylist = $database->loadObjectList();
     // Получаем список radiobox'ов
     $list = JHTML::_(
                         'select.radiolist' /* генерируем список radiobox'ов */,
                         /* массив, каждый элемент которого является
                           ИСКЛЮЧИТЕЛЬНО объектом с полями value и text  */
                         $categories,
                         'name' /* name каждого из radio-элементов */,
                         'class="radiobox"' /* другие атрибуты элемента input */,
                         'value' /* название поля в массиве объектов содержащего ключ */,
                         'text' /* название поля в массиве объектов содержащего значение */,
                         0 /* value элемента, который должен быть выбран (selected) по умолчанию. */,
                         'cid' /* т.н. id_text - текст, который подставится в атрибут id тега input
                            и к которому в конце добавится значение поля value, которое, не забываем, для
                            каждого элемента input в списке будет различным */,
                         true /* пропускать ли элементы полей text через JText::_(), default = false */
                      );


Должен обратить внимание на коренное отличие от метода genericlist - мы не может передавать массив ассоциативных массивов - мы обязаны передавать массив объектов. Не знаю, почему так. Почему здесь авторы этого метода убрали такую удобную на мой взгляд гибкость JHTML - но из кода ясно, что это из лени, не в обиду им будет сказано. Это, кстати, легко исправить.

Кстати, я раньше не обращал на это ваше внимание. Может быть кому то будет интересно. В качестве списка атрибутов тегов (четвёртый параметр) можно передавать не строку, а массив. Это можно делать и в genericlist, и тут. Т.е., обращаясь к примеру из первого поста (там больше атрибутов), можно было передать не

Код:

'class="inputbox" size="1"'

Код:

array ("class" => "inputbox", "size" = 1)




Как вы понимаете, этот метод не подходит для multiselect - нам не удастся передать просто слово MULTISELECT, если мы передаём массив - строка параметров формируется по методу: "ключ элемента массива"="значение элемента массива"

Кстати, есть такая интересная фишка в radiolist: если в у объектов массива будет поле id (по этому я его в примере изменил на value) - то функция подставит в конце каждого radio-input'a значение из этого поля. Но в этом случае в тег будет подставляться два id  - сначала id=id_text+value, а потом, после value (это уже такой атрибут у input'a) - ещё раз id=значение_поля_id. Не знаю, валидно ли это с точки зрения верстки, но явно удобно, что бы присвоить конкретные id для каждого input'a. К слову, эта штука на половину реализована и в genericlist - но предусмотрительно закомментирована, т.к, как вы понимаете, там не имеет смысла.

Немного насчёт selected. Что бы получить отмеченную радио-точку, нужно передать значение, равное полю value в одном из объектов массива. Тогда у соответствующего input'a будет дописано в конце  checked="checked".
Но тут есть ещё такая хитрость - можно передать массив значений, и если будут находиться соответствия с полями value - каждому input'у будет добавляться в конце  selected="selected" (НЕ checked="checked"). Эффекта это не даёт никакого. Практической пользы от этого я не вижу, может быть кто то сможет мне объяснить)

Ну и на последок. Рядом с каждым <input type="radio" ... /> (справа) создаётся тег <label for="...">поле $text объекта</label>, в for подставляется соотв. id input'a.
Генерируются инпуты вместе с служебными знаками - \n\t и \n, а именно, перед каждым инпутом и label'ом ставится \n\t, и ещё в самом конце списка добавляется \n. Если хотите создать удобочитаемый список - заменяйте эти знаки через JString::str_ireplace () на "<br />". Кто не знает - \n - знак переноса строки, \t - знак табуляции.

Пример создания да/нет radiolist-а (<input type="radio" ... />)

Да, есть и такое) Создаёт радиолист с двумя пунктами - да и нет. Текст можно задавать свой. Передаются значения 1 или 0. Текст прогоняется через JText::_() принудительно, без спроса. Фактически является оболочкой для работы с другими функциями хелпер-класса, использует select.option и select.radiolist.
Пример использования:

Код:

$list = JHTML::_(
                    "select.booleanlist", // вызываем метод booleanlist
                    "name", // имя для наших input'ов
                    "class=boolclass", // доп. атрибуты, опять же, можно передавать массивом
                    0, // значение по умолчанию, может быть только 1 или 0, приводится к типу integer.
                    "Да", // текст для пункта со значением 1, default="yes"
                    "Нет", // текст для пункта со значением 0, default="no"
                    "cid"  // id для полей, по принципу 8-го параметра из примера выше
);





Здесь описаны все параметры, принимаемые функцией.

Пример создания списка чисел (<select>...</select>)

Мы можем создать select список исключительно чисел, задав диапазон и шаг. Не уверен в особой практической выгоде, но может быть кому то и будет удобно. Привожу пример с комментариями:

Код:

$list = JHTML::_(
                     "select.integerlist", // вызываем метод integerlist
                     -15, // нижняя граница диапазона
                     15, // верхняя граница диапазона
                     3, // шаг
                     "intlist", // имя для select'a
                     "class=\"select_intlist\"", // доп. атрибуты, можно передавать массивом
                     12, // selected
                     "%+d" // формат выводимой строки. Если параметр задан, то каждое число прогоняется через функицю sprintf с соотв. форматом.
);


Метод является обёрткой, использует всё те же select.option и select.genericlist

Надеюсь, кому то это будет полезным, потому что, если не ошибаюсь, метод JHTML::_() будет и в J!1.6

Следующим делом хочу описать создание выпадающих фильтров, как при просмотре материалов в менеджере материалов (по категориям, автору и т.д.), но чуть хитрее, а так же реализацию сортировки таблицы по полям с использованием JHTML. Надеюсь до конца выходных управлюсь.

Пример создания своего JHTML класса, который будет вызываться загрузочной функцией JHTML::_()

Ничего сложного в этом, как оказалось, нету)
Обязательным условием будет то, что наш класс будет находиться в админпапке нашего компонента (можно и в фронт-энд папку положить)

И так, в админпапке нашего компонента создаём папку HTML (без разницы как назвать).
В этой папке создаём файл с именем нашего хелпер-класса, например, myjhtmlclass.php.
В этом файле, в самом начале, пишем

Код

 

defined('JPATH_BASE') or die();

 

а затем создаём наш класс. Сразу скажу несколько слов по этому поводу. В первом посте я описывал, как работает загрузочная функция JHTML::_(). Если помните, ей первым параметром передаётся строка, разделяющая точкой название префикса класса, имя класса и имя метода, к которому мы будем обращаться. В нашем примере я специально создам класс с отличным от JHTML префиксом - условимся называть его MYJHTML. Имя нашего хелпер-класса будет Myjhtmlclass, ну а методы мы сможем называть как захотим.
И так, объявляем класс:

Код

 

class MYJHTMLMyjhtmlclass
{
function simplepostform ($name)
{
 $html = "<form name=\"" . $name . "\" action=\"index.php\" method=\"POST\">";
 $html .= "<input type=\"text\" name=\"input1\" id=\"id1\" value=\"value1\" /><br />";
 $html .= "<input type=\"text\" name=\"input2\" id=\"id2\" value=\"value2\" /><br />";
 $html .= "<input type=\"submit\" name=\"submitbutton\" id=\"id3\" value=\"PRESS ME PLEASE\" /><br />";
 $html .= "</form>";
 
 return $html;
}
}

 

Теперь у нас готов класс и метод, к которым мы можем обратиться через загрузочную функцию JHTML::_()
Обратите внимание - метод нашего хелпер-класса принимает один параметр.

Что бы обратиться к этому методу, нам нужно в том месте, где мы обращаемся, всего лишь добавить путь, в котором загрузочная функция будет искать наш класс. Делается это следующим образом:

Код

 

JHTML::addIncludePath (JPATH_COMPONENT_ADMINISTRATOR . DS . "html");

Имя папки (html), как я говорил, может быть другим.
Теперь мы можем обратиться к нашему хелпер-классу и его методам следующим образом:

Код

$form = JHTML::_("MYJHTML.myjhtmlclass.simplepostform", "formname");

Мы указываем и префикс, этого можно было не делать, если бы мы назвали наш класс JHTMLMyjhtmlclass. Тогда мы могли бы обратиться к классу следующим образом:

Код

$form = JHTML::_("myjhtmlclass.simplepostform", "formname");


Второй параметр, "formname", передастся в нашу функцию.
Обратите внимание на регистр префикса и класса.
Когда мы объявляем наш класс, а так же когда обращаемся через загрузочную функцию,все символы в префиксе (MYJHTML) должны быть заглавными, но имя класса (Myjhtmlclass) при объявлении должно начинаться с заглавной буквы, а остальные буквы должны быть строчными, а при обращении все буквы класса и метода должны быть строчными.

Вот вроде и всё) Будут вопросы - пишите, разберёмся.

Никаких мыслей по поводу “Красота JHTML, или создание элементов формы средствами Joomla!”