Создание компонента для Joomla

Часть 14 - добавляем сортировку и порядок списка

Joomla

Часть 14 - добавляем сортировку и порядок списка

Для добавления сортировки и порядка списка сообщений нам понадобится выполнить следующие шаги:

  1. Внести изменения в таблицу #__helloworld.
  2. Добавить поддержку в модель списка сообщений.
  3. Изменить представление списка сообщений.
  4. Внести изменения в шаблоны списка сообщений.

Изменяем SQL файлы

Для поддержки порядка отображения списка необходимо изменить структуру таблицы #__helloworld и добавить поле ordering. Это позволит нам использовать имеющиеся методы фреймворка Joomla и не писать свои собственные.

Вносим изменения в файл admin/sql/install.mysql.utf8.sql:

DROP TABLE IF EXISTS `#__helloworld`;
 
CREATE TABLE `#__helloworld` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `asset_id` INT(10) NOT NULL DEFAULT '0',
 `greeting` varchar(25) NOT NULL,
 `catid` int(11) NOT NULL DEFAULT '0',
 `ordering` INT(11) NOT NULL DEFAULT '0',
 `params` TEXT NOT NULL DEFAULT '',
 PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
 
INSERT INTO `#__helloworld` (`greeting`) VALUES
 ('Hello World!'),
 ('Good bye World!');

Не забудьте создать файл admin/sql/updates/mysql/0.0.14.sql для изменения структуры таблицы во время установки новой версии компонента:

ALTER TABLE `#__helloworld` ADD `ordering` INT(11) NOT NULL DEFAULT '0' AFTER `catid`;

Изменяем модель списка сообщений

Открываем файл admin/models/helloworlds.php и меняем код на следующий:

<?php
// Запрет прямого доступа.
defined('_JEXEC') or die;
 
// Подключаем библиотеку modellist Joomla.
jimport('joomla.application.component.modellist');
 
/**
 * Модель списка сообщений компонента HelloWorld.
 */
class HelloWorldModelHelloWorlds extends JModelList
{
    /**
     * Конструктор.
     *
     * @param   array  $config  Массив с конфигурационными параметрами.
     */
    public function __construct($config = array())
    {
        // Добавляем валидные поля для фильтров и сортировки.
        if (empty($config['filter_fields']))
        {
            $config['filter_fields'] = array(
                'id', 'id',
                'greeting', 'greeting',
                'ordering', 'ordering',
            );
        }
 
        parent::__construct($config);
    }
 
    /**
     * Метод для построения SQL запроса для загрузки списка данных.
     *
     * @return  string  SQL запрос.
     */
    protected function getListQuery()
    {
        // Создаем новый query объект.
        $db = JFactory::getDbo();
        $query = $db->getQuery(true);
 
        // Выбераем поля.
        $query->select('id, greeting, ordering');
 
        // Из таблицы helloworld.
        $query->from('#__helloworld');
 
        // Добавляем сортировку.
        $orderCol  = $this->state->get('list.ordering', 'id');
        $orderDirn = $this->state->get('list.direction', 'desc');
        $query->order($db->escape($orderCol . ' ' . $orderDirn));
 
        return $query;
    }
 
    /**
     * Метод для авто-заполнения состояния модели.
     *
     * @param   string  $ordering   Поле сортировки.
     * @param   string  $direction  Направление сортировки (asc|desc).
     *
     * @return  void
     */
    protected function populateState($ordering = null, $direction = null)
    {
        parent::populateState('id', 'desc');
    }
}

Итак, в модели было выполнено следующее:

  1. Добавлен конструктор. В нем указаны валидные поля для фильтров и сортировки.
  2. Добавлен метод populateState(). Этот метод используется для автозаполнения состояния модели. В нем мы просто вызываем родительский метод с параметрами сортировки по умолчанию. Таким образом состояние модели будет заполнено двумя значениями:
    • list.ordering - поле, по которому будет выполнена сортировка. В нашем случае это поле id;
    • list.direction - направление сортировки. У нас это направление desc.
  3. В метод getListQuery() добавлена сортировка. Мы обращаемся к состоянию модели, получаем параметры сортировки и применяем их в запросе. Также в выборку $query->select добавлено поле ordering.

Изменяем представление списка сообщений

Так как в модели теперь есть необходимые для нас данные по сортировке и порядку отображения списка, нам необходимо получить состояние модели (содержащие эти данные) в представлении. Меняем код файла admin/views/helloworlds/view.html.php на:

<?php
// Запрет прямого доступа.
defined('_JEXEC') or die;
 
// Подключаем библиотеку представления Joomla.
jimport('joomla.application.component.view');
 
/**
 * HTML представление списка сообщений компонента HelloWorld.
 */
class HelloWorldViewHelloWorlds extends JViewLegacy
{
    /**
     * Сообщения.
     *
     * @var  array
     */
    protected $items;
 
    /**
     * Постраничная навигация.
     *
     * @var  object
     */
    protected $pagination;
 
    /**
     * Состояние модели.
     *
     * @var  object
     */
    protected $state;
 
    /**
     * Доступы пользователя.
     *
     * @var  object
     */
    protected $canDo;
 
    /**
     * Отображаем список сообщений.
     *
     * @param   string  $tpl  Имя файла шаблона.
     *
     * @return  void
     *
     * @throws  Exception
     */
    public function display($tpl = null)
    {
        try
        {
            // Получаем данные из модели.
            $this->items = $this->get('Items');
 
            // Получаем объект постраничной навигации.
            $this->pagination = $this->get('Pagination');
 
            // Получаем объект состояния модели.
            $this->state = $this->get('State');
 
            // Получаем доступы пользователя.
            $this->canDo = HelloWorldHelper::getActions();
 
            // Устанавливаем панель инструментов.
            $this->addToolBar();
 
            // Отображаем представление.
            parent::display($tpl);
        }
        catch (Exception $e)
        {
            throw new Exception($e->getMessage());
        }
    }
 
    /**
     * Устанавливает панель инструментов.
     *
     * @return void
     */
    protected function addToolBar()
    {
        JToolBarHelper::title(JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLDS'), 'helloworld');
 
        if ($this->canDo->get('core.create'))
        {
            JToolBarHelper::addNew('helloworld.add');
        }
 
        if ($this->canDo->get('core.edit'))
        {
            JToolBarHelper::editList('helloworld.edit');
        }
 
         if ($this->canDo->get('core.delete'))
        {
            JToolBarHelper::divider();
            JToolBarHelper::deleteList('', 'helloworlds.delete');
        }
 
        if ($this->canDo->get('core.admin'))
        {
            JToolBarHelper::divider();
            JToolBarHelper::preferences('com_helloworld');
        }
    }
}

Изменяем шаблоны списка сообщений

Сначала мы изменим главный шаблон admin/views/helloworlds/tmpl/default.php и добавим в него два скрытых поля:

<input type="hidden" name="filter_order" value="<?php echo $this->escape($this->state->get('list.ordering')); ?>" />
<input type="hidden" name="filter_order_Dir" value="<?php echo $this->escape($this->state->get('list.direction')); ?>" />

сразу после строки:

<input type="hidden" name="boxchecked" value="0" />

Далее изменим суб-шаблон заголовков списков admin/views/helloworlds/tmpl/default_head.php:

<?php
// Запрет прямого доступа.
defined('_JEXEC') or die;
 
// Данные по сортировке.
$listOrder    = $this->escape($this->state->get('list.ordering'));
$listDirn    = $this->escape($this->state->get('list.direction'));
?>
<tr>
    <th width="1%">
        <input type="checkbox" name="checkall-toggle" value="" title="<?php echo JText::_('JGLOBAL_CHECK_ALL'); ?>" on-click="Joomla.checkAll(this)"
    </th>
    <th>
        <?php echo JHtml::_('grid.sort', 'COM_HELLOWORLD_HELLOWORLD_HEADING_GREETING', 'greeting', $listDirn, $listOrder); ?>
    </th>
    <th width="10%">
        <?php echo JHtml::_('grid.sort', 'JGRID_HEADING_ORDERING', 'ordering', $listDirn, $listOrder); ?>
        <?php if ($listOrder == 'ordering') : ?>
            <?php echo JHtml::_('grid.order', $this->items, 'filesave.png', 'helloworlds.saveorder'); ?>
        <?php endif; ?>
    </th>
    <th width="1%">
        <?php echo JHtml::_('grid.sort', 'COM_HELLOWORLD_HELLOWORLD_HEADING_ID', 'id', $listDirn, $listOrder); ?>
    </th>
</tr>

Мы заменили статические заголовки на вызовы метода grid.sort класса JHtmlGrid, а также добавили еще один заголовок для порядка списка с помощью grid.order. Теперь при клике на заголовок grid.sort выполнит вызов javascript функции tableOrdering, которая "положит" имя колонки (на которую кликнули) и направление сортировки в скрытые поля (filter_order и filter_order_Dir соответственно), а также выполнит отправку формы. Далее новые данные попадут в модель, она выполнит новый запрос, изменив при этом порядок списка сообщений.

Следующие изменения мы вносим в суб-шаблон admin/views/helloworlds/tmpl/default_body.php:

<?php
// Запрет прямого доступа.
defined('_JEXEC') or die;
 
// Данные по сортировке.
$listDirn    = $this->escape($this->state->get('list.direction'));
$listOrder    = $this->escape($this->state->get('list.ordering'));
$saveOrder    = $listOrder == 'ordering';
 
foreach ($this->items as $i => $item) :
    $canEdit = JFactory::getUser()->authorise('core.edit', 'com_helloworld.message.' . $item->id); ?>
    <tr>
        <td>
            <?php echo JHtml::_('grid.id', $i, $item->id); ?>
        </td>
        <td>
            <?php if ($canEdit) : ?>
                <a href="/<?php echo JRoute::_('index.php?option=com_helloworld&task=helloworld.edit&id=' . (int) $item->id); ?>">
                    <?php echo $item->greeting; ?>
                </a>
            <?php else: ?>
                <?php echo $item->greeting; ?>
            <?php endif; ?>
        </td>
        <td>
            <?php if ($saveOrder) : ?>
                <?php if ($listDirn == 'asc') : ?>
                    <span><?php echo $this->pagination->orderUpIcon($i, true, 'helloworlds.orderup', 'JLIB_HTML_MOVE_UP', $saveOrder); ?></span>
                    <span><?php echo $this->pagination->orderDownIcon($i, $this->pagination->total, true, 'helloworlds.orderdown', 'JLIB_HTML_MOVE_DOWN', $saveOrder); ?></span>
                <?php elseif ($listDirn == 'desc') : ?>
                    <span><?php echo $this->pagination->orderUpIcon($i, true, 'helloworlds.orderdown', 'JLIB_HTML_MOVE_UP', $saveOrder); ?></span>
                    <span><?php echo $this->pagination->orderDownIcon($i, $this->pagination->total, true, 'helloworlds.orderup', 'JLIB_HTML_MOVE_DOWN', $saveOrder); ?></span>
                <?php endif; ?>
            <?php endif; ?>
            <?php $disabled = $saveOrder ?  '' : 'disabled="disabled"'; ?>
            <input type="text" name="order[]" size="5" value="<?php echo $item->ordering; ?>" <?php echo $disabled; ?> />
        </td>
        <td>
            <?php echo $item->id; ?>
        </td>
    </tr>
<?php endforeach; ?>

Здесь основное изменение относится к добавлению дополнительной колонки порядка сообщений. В ней мы выводим порядковый номер сообщения. Если мы находимся в режиме изменения порядка, то с помощью методов $this->pagination->orderUpIcon() и $this->pagination->orderDownIcon() дополнительно выводятся специальные стрелочки, которые помогают нам изменять порядок сообщений.

Ну и последнее. Так как у нас теперь не три колонки, а четыре, то сделаем небольшое изменение в суб-шаблоне admin/views/helloworlds/tmpl/default_foot.php - меняем <td colspan="3"> на <td colspan="4">.

Собираем пакет установки компонента

Не забудьте поменять номер версии в файле helloworld.xml:

<version>0.0.14</version>

helloworld.xml

<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="2.5.0" method="upgrade">
 
    <name>COM_HELLOWORLD</name>
    <!-- Следующие элементы необязательны -->
    <creationDate>Июль 2012</creationDate>
    <author>Вася Пупкин</author>
    <authorEmail>Ваш e-mail</authorEmail>
    <authorUrl>Ваш сайт</authorUrl>
    <copyright>Информация о копирайте</copyright>
    <license>Информация о лицензии</license>
    <!--  Версия записывается в таблицу компонентов -->
    <version>0.0.14</version>
    <!-- Описание необязательно -->
    <description>COM_HELLOWORLD_DESCRIPTION</description>
 
    <!-- Запускается при установке/удалении/обновлении -->
    <scriptfile>script.php</scriptfile>
 
    <!-- Запускается при установке -->
    <install>
        <sql>
            <file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
        </sql>
    </install>
    <!-- Запускается при удалении -->
    <uninstall>
        <sql>
            <file driver="mysql" charset="utf8">sql/uninstall.mysql.utf8.sql</file>
        </sql>
    </uninstall>
    <!-- Запускается при обновлении -->
    <update>
        <schemas>
            <schemapath type="mysql">sql/updates/mysql</schemapath>
        </schemas>
    </update>
 
    <!-- Раздел основных файлов сайта -->
    <!-- Обратите внимание на значение аттрибута folder: Этот аттрибут описывает папку нашего пакета-установщика из которой должны копироваться файлы. 
    Поэтому указанные в этом разделе файлы будут скопированы из папки /site/ нашего пакета-установщика в соответствующую папку установки. -->
    <files folder="site">
        <filename>index.html</filename>
        <filename>controller.php</filename>
        <filename>helloworld.php</filename>
        <folder>language</folder>
        <folder>models</folder>
        <folder>views</folder>
    </files>
 
    <media destination="com_helloworld" folder="media">
        <filename>index.html</filename>
        <folder>images</folder>
    </media>
 
    <!-- Администрирование -->
    <administration>
        <!-- Раздел Меню -->
        <menu img="../media/com_helloworld/images/hello-16x16.png">COM_HELLOWORLD_MENU</menu>
        <!-- Раздел основных файлов администрирования  -->
        <!-- Обратите внимание на значение аттрибута folder: Этот аттрибут описывает папку нашего пакета-установщика из которой должны копироваться файлы. 
        Поэтому указанные в этом разделе файлы будут скопированы из папки /admin/ нашего пакета-установщика в соответствующую папку установки. -->
        <files folder="admin">
            <filename>index.html</filename>
            <filename>access.xml</filename>
            <filename>config.xml</filename>
            <filename>controller.php</filename>
            <filename>helloworld.php</filename>
            <folder>controllers</folder>
            <folder>helpers</folder>
            <folder>models</folder>
            <folder>sql</folder>
            <folder>tables</folder>
            <folder>views</folder>
        </files>
        <languages folder="admin">
            <language tag="en-GB">language/en-GB/en-GB.com_helloworld.ini</language>
            <language tag="en-GB">language/en-GB/en-GB.com_helloworld.sys.ini</language>
            <language tag="ru-RU">language/ru-RU/ru-RU.com_helloworld.ini</language>
            <language tag="ru-RU">language/ru-RU/ru-RU.com_helloworld.sys.ini</language>
        </languages>
    </administration>

    
    <!-- Сервер обновлений -->
    <updateservers>
        <!-- Заметка: Не допускаются пробелы или переносы строк между тегам server -->
        <server type="extension" priority="1" name="Сайт обновлений компонента Hello World!">http://вашдомен.ru/update/helloworld-update.xml</server>
    </updateservers>
 
</extension>

Содержимое директории с кодом:

helloworld.xml
script.php
site/index.html
site/helloworld.php
site/controller.php
site/language/index.html
site/language/en-GB/index.html
site/language/en-GB/en-GB.com_helloworld.ini
site/language/ru-RU/index.html
site/language/ru-RU/ru-RU.com_helloworld.ini
site/models/index.html
site/models/helloworld.php
site/views/index.html
site/views/helloworld/index.html
site/views/helloworld/view.html.php
site/views/helloworld/tmpl/index.html
site/views/helloworld/tmpl/default.xml
site/views/helloworld/tmpl/default.php
admin/index.html
admin/access.xml
admin/config.xml
admin/controller.php
admin/helloworld.php
admin/controllers/index.html
admin/controllers/helloworld.php
admin/controllers/helloworlds.php
admin/helpers/index.html
admin/helpers/helloworld.php
admin/language/index.html
admin/language/en-GB/index.html
admin/language/en-GB/en-GB.com_helloworld.ini
admin/language/en-GB/en-GB.com_helloworld.sys.ini
admin/language/ru-RU/index.html
admin/language/ru-RU/ru-RU.com_helloworld.ini
admin/language/ru-RU/ru-RU.com_helloworld.sys.ini
admin/models/index.html
admin/models/helloworld.php
admin/models/helloworlds.php
admin/models/fields/index.html
admin/models/fields/helloworld.php
admin/models/forms/index.html
admin/models/forms/helloworld.js
admin/models/forms/helloworld.xml
admin/models/rules/index.html
admin/models/rules/greeting.php
admin/sql/index.html
admin/sql/install.mysql.utf8.sql
admin/sql/uninstall.mysql.utf8.sql
admin/sql/updates/index.html
admin/sql/updates/mysql/index.html
admin/sql/updates/mysql/0.0.1.sql
admin/sql/updates/mysql/0.0.4.sql
admin/sql/updates/mysql/0.0.9.sql
admin/sql/updates/mysql/0.0.10.sql
admin/sql/updates/mysql/0.0.12.sql
admin/sql/updates/mysql/0.0.14.sql
admin/tables/index.html
admin/tables/helloworld.php
admin/views/index.html
admin/views/helloworld/index.html
admin/views/helloworld/view.html.php
admin/views/helloworld/submitbutton.js
admin/views/helloworld/tmpl/index.html
admin/views/helloworld/tmpl/edit.php
admin/views/helloworlds/index.html
admin/views/helloworlds/view.html.php
admin/views/helloworlds/tmpl/index.html
admin/views/helloworlds/tmpl/default.php
admin/views/helloworlds/tmpl/default_body.php
admin/views/helloworlds/tmpl/default_foot.php
admin/views/helloworlds/tmpl/default_head.php
language/index.html
language/en-GB/index.html
language/en-GB/en-GB.com_helloworld.sys.ini
language/ru-RU/index.html
language/ru-RU/ru-RU.com_helloworld.sys.ini
media/index.html
media/images/index.html
media/images/hello-16x16.png
media/images/hello-48x48.png

Запакуйте директорию в архивный файл (zip, tar, tar.gz, bz2) или скачайте его напрямую c GitHub. Далее установите его, используя менеджер расширений Joomla. Теперь у нас есть возможность сортировать список, а также изменять и сохранять порядок сообщений.

Cортировка и порядок списка

Код для этой части

Скачать com_helloworld часть 14

Актуальный код части 14 на GitHub

Dmitry Rekun
Работаю в банковской сфере, а с веб-разработкой (непосредственно с Joomla) столкнулся в 2007 году. Теперь это моё хобби и время от времени вторая работа. Какое-то время вёл свой блог, но решил попробовать работать в команде. И вот c 2012 года я здесь :)