Создание типа

Бывают ситуации, когда стандартные типы полей для формы не подходят. В Joomla можно создавать свои типы параметров в расширениях.

Основной код для создания типа будет, примерно, такой:

<?php
// Защита от прямого доступа к файлу
defined('_JEXEC') ordie('Restricted access');
// Подключение требуемых файлов
jimport('joomla.form.formfield');
/**
 * Создаем класс. Fieldname - имя типа
 */
class JFormFieldFieldname extends JFormField
{
	/**
	* @var $type Имя типа
	*/
	protected $type= 'Fieldname';
	/**
	* Метод, определяющий что будет выводить параметр
	*
	* @return Результат вывода типа
	*/
	protected function getInput()
	{
		$html= '';
		// ...
		// Какой-то код, в котором определяется что нужно выводить
		// ...
		return $html;
	}
}
 

 

Получение атрибутов

Как видно из кода выше в данном случае используется родительский класс JFormField, для получения атрибутов достаточно взять родительский объект $element:

protected function getInput()
{
	// Получение атрибута some-attr
	$this->element['some-attr']);
	// ...

 

Получение потомков

Если предполагается использовать сложный тип, состоящий из нескольких элементов, например:

 

<field name="some-name" type="fieldname">
 <some-action value="1">One</some-action>
 <some-action value="2">Two</some-action>
</field>

 

 

 

Общий код для получения потомков будет примерно такой:

protected function getInput()
{
	foreach($this->element->children() as $action) 
	{
		// Берем только нужные элементы, в данном случае some-action
		if($action->getName() != 'some-action') 
		{
			continue;
		}
		// Здесь будут значения value
		$action['value'];
		// Здесь будут значения содержащиеся между тегов some-action
		$action;
		//...
	}
 

 

Расширение или изменение стандартных типов

Бывают ситуации, когда нужно дополнить или изменить стандартный тип, используемый в Joomla. Для этого не стоит заново переписывать нужный тип, можно просто его расширить. Допустим, нужно изменить стандартный тип list, это будет выглядеть так:

<?php
// Защита от прямого доступа к файлу
defined('_JEXEC') or die('(@)|(@)');
// Подключение требуемых файлов
jimport('joomla.form.formfield');
jimport('joomla.form.helper');
JFormHelper::loadFieldClass('list');
/**
 * Создаем класс. Fieldname - имя типа
 */
class JFormFieldFieldname extends JFormFieldList
{
	/**
	* @var $type Имя типа
	*/
	protected $type= 'Fieldname';
	/**
	* Метод, заменяющий родительский JFormFieldList::getOptions()
	*
	* @return $options;
	*/
	protected function getOptions()
	{
		// ...
		// Какой-то код, в котором определяется что нужно выводить
		// ...
		return $options;
	}
}
 

 

Подключение в Компоненте

Допустим, в модели компонента подключается форма:

-com_component
--models
----forms
-----some-form.xml
----some-model.php

И в форме (some-form.xml) нужно добавить свой тип для поля. Для этого достаточно создать файл /com_component/models/fields/fieldname.php, где fieldname — это имя нужного типа.
После того как данный файл будет создан, можно добавлять этот тип в форму (/com_component/models/forms/some-form.xml)

 

<field name="some_name" type="fieldname" />

 

 

 

Подключение в Модуле или Плагине

Если нужно добавить нужный тип поля в модуле или плагине, то для этого достаточно указать в XML файле директорию, в которой надо искать нужный тип.

Допустим, в модуле есть группа параметров:

 

...
<fieldset name="Some-Name">
 ...
 <field name="name1" type="text"/>
 <field name="name2" type="fieldname"/>
 ...
</fieldset>
...

 

 

 

Чтобы определить тип fieldname, нужно указать путь в fieldset, где искать данный тип. И Joomla автоматически найдет данный файл, если такой будет существовать.

 

...

<fieldset name="Some-Name"ad...
 ...
 <fieldset name="Some-Name"addfieldpath="/administrator/components/com_component/models/fields">
 ...
 <field name="name1"type="text"/>
 <field name="name2"type="fieldname"/>
 ...
 </fieldset>
...

 

 

 Обратная связь.

Передача параметров обратно из формы осуществляется через строку запроса.

protected function getInput()
    {
        JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_webenar'.DS.'tables');
        $table =  JTable::getInstance( 'webenar', 'webenarTable');
        // Создание переменной для вывода html поля этого типа
        $html[] ='
        <table class="adminlist" width="60%">
        <tr>
            <th width="2%"><input type="checkbox" name="checkall-toggle" 
             value="" title="'.JText::_('JGLOBAL_CHECK_ALL').'" onclick="Joomla.checkAll(this)" /></th>
            <th width="30%">'.JText::_('COM_WEBENAR_WEBENAR_FIELD_STUDENTS_NAME').'</th>
            <th>'.JText::_('COM_WEBENAR_WEBENAR_FIELD_STUDENTS_EMAIL').'</th></tr>'
            ;
        
        $table->load($this->form->getValue('id'));
        $students = $table->params->get('students'); 
        foreach ( $students as $id => $student)   { 
        $html[] ='
            <tr class="row'.sprintf( '%02d',$id).'">
                <td>'.JHTML::_('grid.id', $id, $id,false,'student').'</td>
                 <td>'.$student->name.'</td>
                 <td><a href="mailto:<?'.$student->email.'">'.$student->email.'</a></td>   
             </tr>';
        }
        
        $html[] = '</table>';
        // Передача параметров обратно в метод save() для корректной процедуры сохранения формы
        $html[] = '<input type="hidden" name="'.$this->name.'" value="'.urlencode (json_encode ($this->__get('value'))).'"/>';
       
        return implode($html);
    }



Процедура чтения этого параметра в методе save() модели.

public function save($data)
    {
        // Декодирование нестандартных параметров формы
        $data['params']['students'] = json_decode(urldecode($data['params']['students']));
        // Вызов метода sava класса JModelAdmin
        return parent::save($data);
    }

 

Создание всплывающего поля формы

 Если требуется создать модальное пользовательское поле, например всплывающий выбор из списка.

Добавляем модальное поле в xml файл /components/com_library/views/book/default.xml 

 

<fields name="request" addfieldpath="administrator/components/com_library/models/fields">
        <fieldset name="request">
                <field 
                        name="id" 
                        type="modal_book" 
                        label="COM_LIBRARY_BOOK_FIELD_ID_LABEL" 
                        description="COM_LIBRARY_BOOK_FIELD_ID_DESC"
                        required="true"
                />
        </fieldset>
</fields>

 

 

Обратите внимание, в обеих определениях "fields" и "fieldset" мы добавляем name="request" это преписывает пункту меню добавить имя поля и его значение в url. Пользовательский тип определяется как modal_book и место определения класса задается в addfieldpath.

Создаем клас вользовательского поля в administrator/components/com_library/models/fields/modal/book.php и переопределяем метод getInput()

 

 // No direct access
 defined('_JEXEC') or die('Restricted access');
 
 jimport('joomla.form.formfield');
 
 /**
  * Book form field class
  */
 class JFormFieldModal_Book extends JFormField
 {
        /**
         * field type
         * @var string
         */
        protected $type = 'Modal_Book';
		
		/**
		* Method to get the field input markup
		*/
		  protected function getInput()
		  {
				  // Load modal behavior
				  JHtml::_('behavior.modal', 'a.modal');
		 
				  // Build the script
				  $script = array();
				  $script[] = '    function jSelectBook_'.$this->id.'(id, title, object) {';
				  $script[] = '        document.id("'.$this->id.'_id").value = id;';
				  $script[] = '        document.id("'.$this->id.'_name").value = title;';
				  $script[] = '        SqueezeBox.close();';
				  $script[] = '    }';
		 
				  // Add to document head
				  JFactory::getDocument()->addScriptDeclaration(implode("\n", $script));
		 
				  // Setup variables for display
				  $html = array();
				  $link = 'index.php?option=com_library&amp;view=books&amp;layout=modal'.
						  '&amp;tmpl=component&amp;function=jSelectBook_'.$this->id;
		 
				  $db = JFactory::getDbo();
				  $query = $db->getQuery(true);
				  $query->select('title');
				  $query->from('#__books');
				  $query->where('id='.(int)$this->value);
				  $db->setQuery($query);
				  if (!$title = $db->loadResult()) {
						  JError::raiseWarning(500, $db->getErrorMsg());
				  }
				  if (empty($title)) {
						  $title = JText::_('COM_LIBRARY_FIELD_SELECT_BOOK');
				  }
				  $title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
		 
				  // The current book input field
				  $html[] = '<div class="fltlft">';
				  $html[] = '  <input type="text" id="'.$this->id.'_name" value="'.$title.'" disabled="disabled" size="35" />';
				  $html[] = '</div>';
		 
				  // The book select button
				  $html[] = '<div class="button2-left">';
				  $html[] = '  <div class="blank">';
				  $html[] = '    <a class="modal" title="'.JText::_('COM_LIBRARY_SELECT_BOOK_TITLE').'" href="'.$link.
								 '" rel="{handler: \'iframe\', size: {x:800, y:450}}">'.
								 JText::_('COM_LIBRARY_BUTTON_SELECT_BOOK').'</a>';
				  $html[] = '  </div>';
				  $html[] = '</div>';
		 
				  // The active book id field
				  if (0 == (int)$this->value) {
						  $value = '';
				  } else {
						  $value = (int)$this->value;
				  }
		 
				  // class='required' for client side validation
				  $class = '';
				  if ($this->required) {
						  $class = ' class="required modal-value"';
				  }
		 
				  $html[] = '<input type="hidden" id="'.$this->id.'_id"'.$class.' name="'.$this->name.'" value="'.$value.'" />';
		 
				  return implode("\n", $html);
		  }
 
 }

 

 

Давайте внимательнее посмотрим на метод.

    Загружается модальное поведение .
    Определяется JavaScript функция SelectBook_jform_request_id и будет вставлена в <head> документа с addScriptDeclaration (). Обратите внимание - $this->id = jform_request_id. 'Jform' это имя формы задана в способе loadForm в нашей модели. 'request'  отражает, что это поле запроса, и «ID» это имя нашей области.
    Есть несколько важных моментов, в ссылке, которая создается, чтобы открыть модальное окно. Мы включаем layout=modal, так как это будет альтернативный макет представления списка для 'books'.  function=jSelectBook_.$this->id будут использоваться в модальном макет определении функции, которая будет вызываться при выборе книги.
    Далее, мы получаем звание выбранного в данный момент книги из базы данных или вернуть исходное "Select Book" фразу, которая будет показана в поле ввода.
    Создается выход HTML . Обратите внимание, что это включает в себя скрытое поле, которое будет иметь идентификатор "jform_request_id_id 'и будет принимать значение документа книги, выбранного в модальном окне.

 

Дорабатываем вид. /administrator/components/com_library/views/books/view.html.php

Поскольку нам не понадобится панель инструментов

 

  public function display($tpl = null)
  {
          // Get data from the model
          $items = $this->get('Items');
          $pagination = $this->get('Pagination');
          $state = $this->get('State');
 
          // Check for errors
          if (count($errors = $this->get('Errors'))) {
                  JError::raiseError(500, implode('<br />', $errors));
                  return false;
          }
 
          // Assign data to the view
          $this->items = $items;
          $this->pagination = $pagination;
          $this->state = $state;
 
          // Only set the toolbar if not modal
          if ($this->getLayout() !== 'modal') {
                  $this->addToolBar();
          }
 
          // Display the template
          parent::display($tpl);
 
          // Set the document
          $this->setDocument();
  }

 

Создаем всплывающий шаблон.  /administrator/components/com_library/views/books/tmpl/modal.php.

Создание отдельного модальный макета необходимо для того, чтобы включить ссылки со OnClick действия, что будет вызывать функцию SelectBook_jform_request_id. Во многом, эта точка зрения список будет отражать мнение списка по умолчанию, но вы можете выбрать, чтобы оставить некоторые столбцы, такие как избранных флажков.

 

// No direct access
 defined('_JEXEC') or die('Restricted access');
 
 // Load tooltip behavior
 JHtml::_('behavior.tooltip');
 $listOrder     = $this->escape($this->state->get('list.ordering'));
 $listDirn      = $this->escape($this->state->get('list.direction'));
 
 $function = JFactory::getApplication->input->getCmd('function', 'jSelectBook');
?>
<form action="<?php echo $this->action; ?>" method="post" name="adminForm" id="adminForm">
<table class="adminlist">
    <thead>
        <tr>
            <th>
                <?php echo JHtml::_('grid.sort', 'COM_LIBRARY_BOOKS_HEADING_TITLE', 'title', $listDirn, $listOrder); ?>
            </th>
            <th>
                <?php echo JHtml::_('grid.sort', 'COM_LIBRARY_BOOKS_HEADING_STATE', 'state', $listDirn, $listOrder); ?>
            </th>
            <th>
                <?php echo JHtml::_('grid.sort', 'COM_LIBRARY_BOOKS_HEADING_HITS', 'hits', $listDirn, $listOrder); ?>
            </th>
            <th>
                <?php echo JHtml::_('grid.sort', 'COM_LIBRARY_BOOKS_HEADING_CREATED', 'created', $listDirn, $listOrder); ?>
            </th>
            <th>
                <?php echo JHtml::_('grid.sort', 'COM_LIBRARY_BOOKS_HEADING_MODIFIED', 'modified', $listDirn, $listOrder); ?>
            </th>
            <th width="5">
                <?php echo JHtml::_('grid.sort', 'COM_LIBRARY_BOOKS_HEADING_ID', 'id', $listDirn, $listOrder); ?>
            </th>
        </tr>
    </thead>
    <tfoot>
        <tr>
            <td colspan="6"><?php echo $this->pagination->getListFooter(); ?></td>
        </tr>
    </tfoot>
    <tbody>
<?php foreach ($this->items as $i => $item) : ?>
        <tr class="row<?php echo $i % 2; ?>">
            <td>
                <a class="pointer" onclick="if (window.parent) window.parent.<?php echo $this->escape($function);?>('<?php echo $item->id; ?>', 
					'<?php echo $this->escape(addslashes($item->title)); ?>');">
					<?php echo $this->escape($item->title); ?></a>
            </td>
            <td align="center"><?php echo JHtml::_('jgrid.published', $item->state, $i, 'books.'); ?></td>
            <td align="right"><?php echo $item->hits; ?></td>
            <td align="center"><?php echo $item->created; ?></td>
            <td align="center"><?php echo $item->modified; ?></td>
            <td><?php echo $item->id; ?></td>
        </tr>
<?php endforeach; ?>
    </tbody>
</table>
<div>
    <input type="hidden" name="task" value="" />
    <input type="hidden" name="boxchecked" value="0" />
    <input type="hidden" name="filter_order" value="<?php echo $listOrder; ?>" />
    <input type="hidden" name="filter_order_Dir" value="<?php echo $listDirn; ?>" />
    <?php echo JHtml::_('form.token'); ?>
</div>
</form>

 

Этот макет имеет два важных отличия по сравнению с макета по умолчанию.

    Получаем имя яваскрипта функции, используя JFactory::getApplication->input->getCmd('function', 'jSelectBook').
    Значение $ функции затем используется в случае OnClick на название ссылки.

Никаких мыслей по поводу “Создание своего типа поля”