0 Пользователей и 1 Гость просматривают эту тему.
  • 36 Ответов
  • 845 Просмотров
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
Здравствуйте!

Ищу пример того, как в разрабатываемом мной компоненте можно вывести содержимое некоторой таблицы в зависимости от выбранного значения в выпадающем списке. То есть это фильтр по значениям из связанной таблицы.
Мне в com_content в список статей?
*

b2z

  • Глобальный модератор
  • 7107
  • 769 / 0
  • Разраблю понемногу
Цитировать
Мне в com_content в список статей?
Как вариант. А в чём сложность? Фильтр же работает по полю, которое участвует в WHERE.

В com_content - это категория.
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
Сложность в том, что нет примера :)
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
А вообще есть понятие, как фильтры делать?
Доброе утро! Пока не хватает всех пазлов в картине. Из того, что я пока изучил, у меня сложилась такая картина для получения фильтра:
1. Вот такой вид(view.html.php):
Спойлер
[свернуть]
2. Вот такая модель для этого вида:
Спойлер
[свернуть]
3. Это XML формы фильтра, который располагается по пути site/models/forms/filter_contacts.xml(у меня вид для фронта)
Спойлер
[свернуть]
4. layout вида:
Спойлер
[свернуть]
В браузере данный вид пока выкидывает ошибку, что не может найти getItem, что понятно, его я пока не определил. Верной дорогой иду я, товарищи, к построению фильтра книг(аналог фильтра по категории среди списка статей в com_content)? Особенно интересует какой должная быть функция loadFormData(), которая, как надеюсь, должна наполнять фильтр книг, в которые сгруппированы отображаемые видом контакты.
*

sivers

  • Завсегдатай
  • 1731
  • 239 / 0
Чтение фильтра обычно добавляю в метод модели populateState, который имеет вид:
Код
	protected function populateState( $ordering = null, $direction = null )
{
parent::populateState( $ordering, $direction );
$input = JFactory::getApplication()->input;
$params = JComponentHelper::getParams( 'com_component' );
$this->setState( 'list.start', $input->get( 'start' ) );
$this->setState( 'list.limit', $params->get( 'limit', 10 ) );
}
Фрагмент кода взят из конструктора компонент на сайте _http://inet-reklama.com/ за что спасибо автору - пользуюсь регулярно.

А вот на отсутствие метода getItem ругани быть не должно - у вас же модель листинга, а в ней используется getItems. Но этот метод есть в родительском классе, а значит и его не обязательно определять в модели. Ищите причину ругани в другом. Возможно, где-то в коде вы забыли удалить вызов getItem при переносе кода с другого места.
На связи в телеге @sivers
https://sivers.su/
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
sivers, не увидел в вашем коде, как вы собственно 1. фильтруете листинг и как 2. наполняете фильтр значениями. Можете подробнее?
А мой подход рабочий?
populateState используется для сохранения значений переменных для использования в следующем обращении к данным модели?
*

sivers

  • Завсегдатай
  • 1731
  • 239 / 0
sivers, не увидел в вашем коде, как вы собственно 1. фильтруете листинг и как 2. наполняете фильтр значениями. Можете подробнее?
А мой подход рабочий?
populateState используется для сохранения значений переменных для использования в следующем обращении к данным модели?
Ваш код не проверял.
Да, в populateState читаю значения фильтра и записываю в state методом $this->setState - так же, как и метод сортировки в фрагменте выше.
В файле view.html.php делаю сперва $this->state = $this->get('State'); (при этом отрабатывает populateState), а потом уже $this->items = $this->get('Items');.
При запросе элементов сперва отрабатывает getListQuery(), в котором получаю параметры фильтра через $this->state->get('param1') (если получать через $this->getState, то будет повторно отрабатывать populateState, а это бывает нежелательно). Параметры фильтра используете для построения части WHERE запроса. У вас это вроде бы есть.
Если над прочитанными из БД объектами никаких действий делать не требуется, то метод модели getItems можно не определять. Иначе пишете:
Код
public function getItems()
{
   $items = parent::getItems();
   foreach($items as $i => $item){
      $items[$i]->link = ....;
      ......
   }
   return $items;
}
Это бывает полезно для подготовки объектов к выводу. Чтоб не перегружать sql-запрос форматированием данных (как у вас), либо для дополнения объектов вычисляемыми свойствами (та же ссылка к примеру).
На связи в телеге @sivers
https://sivers.su/
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
sivers, спасибо. Пока у меня что-то не срастается все в целую картину :) Как вы наполняете фильтр(выпадающий список) значениями и затем его выводите? Приложил скриншот о чем я говорю.
*

sivers

  • Завсегдатай
  • 1731
  • 239 / 0
Как вы наполняете фильтр(выпадающий список) значениями и затем его выводите? Приложил скриншот о чем я говорю.
А, понятно теперь. Т.е. вы про верстку фильтра, а не о его применении. Делать можно по разному. Например, модулем. Дергаете из БД справочники полей, по которым хотите фильтровать, и строите из них селекты.
Если же вы разобрались как использовать XML для построения фильтров, то можно использовать Поле с типом sql для получения значений справочника (те же категории или свойства какие-нибудь). Синтаксис поля здесь:
https://docs.joomla.org/Special:MyLanguage/SQL_form_field_type
Про все поля здесь:
https://docs.joomla.org/Form_field#Standard_form_field_types
Если стандартных типов полей недостаточно, то можно на их основе делать свои. Они складываются в папку компонента /models/fields/mytype.php

Если сложность с рендерингом формы через модель компонента, то можете создать тестовый компонент в конструкторе (ссылку выше давал) - там добавьте 1 таблицу и 1 представление для админки с функцией редактирования и той таблицей. Потом скачайте и посмотрите как там все подключено в представлении админки. Для фронта аналогично все. Не знаю только делает ли конструктор для фронта фильтр (не проверял), но для админки точно делает.

А если надо в отрыве от компонента (допустим, в модуле), то вот есть еще одна мини-инструкция:
Спойлер
[свернуть]
На связи в телеге @sivers
https://sivers.su/
*

b2z

  • Глобальный модератор
  • 7107
  • 769 / 0
  • Разраблю понемногу
Делаем свой тип поля, добавляем в XML фильтров - профит ;) Но это в админке.

На фронте я лично не использую search tools, а вывожу каждый список отдельно. Ну например вот так:

Код
<div>
    <label class="filter-status-lbl" for="filter-status" hidden>
        <?php echo JText::_('COM_COMPETITION_FILTER_STATUS_LABEL'); ?>
    </label>

    <select name="filter-status" class="uk-select" onchange="this.form.submit()">
        <?php echo
        JHtml::_('select.options',
            CompetitionHelperHtmlFilters::getStatusOptions(),
            'value',
            'text',
            $this->state->get('filter.status'),
            true
        );
        ?>
    </select>
</div>

Код
public static function getStatusOptions($showFirstOption = true)
{
    $options = array();

    if ($showFirstOption)
    {
        $options[] = JHtml::_('select.option', -1, JText::_('COM_COMPETITION_ALL'));
    }

    $options[] = JHtml::_('select.option', 1, JText::_('COM_COMPETITION_STATUSES_ACTIVE'));
    $options[] = JHtml::_('select.option', 0, JText::_('COM_COMPETITION_STATUSES_CLOSED'));

    return $options;
}
Вообще тут нужно пространство для манёвра, всё таки это фронт. Если использовать search tools, то будешь привязан к BS2.

Далее в модели учитываю этот фильтр, согласно классическому применению.

Спойлер
[свернуть]
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
Здравствуйте!
Спасибо, попробую что-то скомпилировать из ваших советов.
BS2 - это bootstrap2?
b2z, скажите, где должен лежать и как подключать файл, содержащий определение функции getStatusOptions?Увидеть бы как он строится. Этот файл должен подключаться в главном контроллере?
Как понимаю в этой самой getStatusOptions мне нужно добыть из БД мои варианты для выпадающего списка?
Не заметил, где вы используете getStoreId()...
Получается в $config['filter_fields'] упоминаются не только поля, по которым возможна сортировка, но и фильтруемые поля...
« Последнее редактирование: 22.08.2020, 15:23:19 от borro »
*

b2z

  • Глобальный модератор
  • 7107
  • 769 / 0
  • Разраблю понемногу
Здравствуйте!
Спасибо, попробую что-то скомпилировать из ваших советов.
BS2 - это bootstrap2?
Он самый  ^-^

b2z, скажите, где должен лежать и как подключать файл, содержащий определение функции getStatusOptions?Увидеть бы как он строится. Этот файл должен подключаться в главном контроллере?
Это просто класс со статическими функциями.

Например у меня он находится в site/helpers/html/filters.php, а подключаю сразу в точке входа через JLoader:
Код
\JLoader::discover('CompetitionHelperHtml', NC_PATH_SITE . '/helpers/html');
Но это зависит от ситации. Если он только в парочке мест нужен, то можно его в конкретном файле через JLoader подключить.

Как понимаю в этой самой getStatusOptions мне нужно добыть из БД мои варианты для выпадающего списка?
Именно так.

Не заметил, где вы используете getStoreId()...
В модели.

Получается в $config['filter_fields'] упоминаются не только поля, по которым возможна сортировка, но и фильтруемые поля...
Глянул в ListModel, действительно, не обязательно добавлять фильтры в $config['filter_fields']. Но если используется Search Tools, то надо, так как этот массив участвует в getActiveFilters().
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
Здравствуйте!
Например у меня он находится в site/helpers/html/filters.php, а подключаю сразу в точке входа через JLoader:
Код
\JLoader::discover('CompetitionHelperHtml', NC_PATH_SITE . '/helpers/html');
Дмитрий, почему-то у меня этот метод, использованный в точке входа в компонент, возвращает
Цитировать
0 - Class 'AnysendHelperHtmlFilters' not found
Заметил, что вылетает предупреждение:
Цитировать
Use of undefined constant NC_PATH_SITE
Заменил ее на JPATH_COMPONENT_SITE и ошибка ушла, появилась следующая. Буду разбираться :)
« Последнее редактирование: 29.08.2020, 12:07:52 от borro »
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
Здравствуйте, товарищи!

При перезагрузке страницы не могу получить значение, выбранное в фильтре. Помогите разобраться, пожалуйста.
Вот layout, который выводит фильтр(он с виду наполняется правильно, по крайней мере предлагает к выбору разные текстовые строки)(кстати, может надо добавить какой-то hidden input внизу формы для создаваемого фильтра?):
Спойлер
[свернуть]
Вот view.html.php:
Спойлер
[свернуть]
Вот модель с populateState():
Спойлер
[свернуть]
А вот на всякий случай наполняющая фильтр данными функция getBookOptions() из хелпера:
Спойлер
[свернуть]
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
$params = JComponentHelper::getParams( 'com_component' );
Здравствуйте! sivers, можно про эту строку подробнее? Вы здесь добываете дефолтные настройки, которые задаются пользователем в настройках компонента?
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
Код
...
$params = $app->getParams();
$status = $app->getUserStateFromRequest(
    $this->context . '.filter.status',
    'filter-status',
    $params->get('competitions_default_status_filter', -1),
    'string'
);
...
Дмитрий, вы здесь тоже получаете дефолтную настройку, которую пользователь задает в админке в настройках компонета?
В чем разница между добычей дефолтных значений по методу sivers и методу Дмитрия?
« Последнее редактирование: 02.10.2020, 16:59:49 от borro »
*

sivers

  • Завсегдатай
  • 1731
  • 239 / 0
Здравствуйте! sivers, можно про эту строку подробнее? Вы здесь добываете дефолтные настройки, которые задаются пользователем в настройках компонента?
Добрый день. Здесь вы берете настройки любого компонента, который вам нужен. Второй способ ($app->getParams();) точно не знаю что возвращает (не пользовался им). Возможно, настройки текущего компонента. Сравните вывод.
На связи в телеге @sivers
https://sivers.su/
*

b2z

  • Глобальный модератор
  • 7107
  • 769 / 0
  • Разраблю понемногу
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
Здравствуйте!

Спасибо!

На текущий момент осталась одна непонятка: почему-то данные, выбранные в выпадающем списке, не видны в getUserStateFromRequest(), вызываемой во время перезагрузки страницы
Вот как я вывожу фильтр в default.php:
Код
...
<form action="index.php?option=com_anysend&view=contacts" method="post" id="adminForm" name="adminForm">
...
  <select name="filter-book" class="uk-select" onchange="this.form.submit()">
<?php echo JHtml::_('select.options',
AnysendHelperHtmlFilters::getBookOptions(),
'value',
'text',
$this->state->get('filter_book'),
true
);
?>
</select>
...
        <input type="hidden" name="filter_book" value="<?php echo $bookSelected; ?>"/>
<?php echo JHtml::_('form.token'); ?>
</form>
...
В модели этого представления пытаюсь поймать отправленное значение:
Код
        protected function populateState( $ordering = null, $direction = null )
        {
            ...
            $book = $app->getUserStateFromRequest(
                $this->context . '.filter.book',
                'filter_book',
                $results[0]->book_name, //дефолтное значение
                'string'
            );
            $this->setState('filter.book', $book);
        }
и получаю пустую строку, хотя отправляется непустое дефолтное значение. Внутри функции getUserStateFromRequest видно, что переменная $cur_state равна подставленному дефолтному значению, но $new_state уже содержит пустую строку(скриншот)
*

sivers

  • Завсегдатай
  • 1731
  • 239 / 0
А в каком месте из всего этого читается переданный параметр "filter-book"?
На связи в телеге @sivers
https://sivers.su/
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
А в каком месте из всего этого читается переданный параметр "filter-book"?
в приведенной populateState(). Замена 'filter_book' на 'filter-book' не помогла :)
*

b2z

  • Глобальный модератор
  • 7107
  • 769 / 0
  • Разраблю понемногу
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
А почему одновременно
<select name="filter-book" class="uk-select" onchange="this.form.submit()">
и
<input type="hidden" name="filter_book" value="<?php echo $bookSelected; ?>"/>
От незнания. Как правильно, нужен ли инпут или дело в подчеркивании?
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
input вообще не нужен. У вас из select прилетает значение.
Здравствуйте!
Спасибо. Уже не знаю, что еще можно попробовать изменить в коде. Может вы опытным глазом увидите. Прикладываю установочный архив компонента. Проблема все таже. В модели с именем contacts (фронтенд) не отлавливается параметр, вводимый в теге <select name="filter_book"> этого же представления. А именно в функции populateState модели строка
Код
            $book = $app->getUserStateFromRequest(
                $this->context . '.filter_book',
                'filter_book',
                $results[0]->book_name,
                'string'
            );
возвращает пустую строку, что все ломает.
« Последнее редактирование: 12.10.2020, 18:09:00 от borro »
*

sivers

  • Завсегдатай
  • 1731
  • 239 / 0
в приведенной populateState(). Замена 'filter_book' на 'filter-book' не помогла :)
Менять может и не надо было, но читаться оно где-то должно
возвращает пустую строку, что все ломает.
а для чего там getUserStateFromRequest?
почему не прочитать строку как $book = $app->input->getString('filter_book', '');?
Или там как-то на сессии увязано?

И еще стоит проверить (удостовериться) идет ли передача этого параметра при отправке формы - это в отладчике браузера можно.
На связи в телеге @sivers
https://sivers.su/
*

robert

  • Живу я здесь
  • 4974
  • 457 / 20
Вы записываете данные в 'filter_book', но хотите их извлечь из $this->context . '.filter_book'.
А populateState() выполняется только 1 раз при каждом вызове модели, я вам об этом уже давно говорил.
И значение 'filter_book' из селекта будет в 'jform', $app->input->get('filter_book') вам его не даст.
« Последнее редактирование: 13.10.2020, 16:10:11 от robert »
Не будь паразитом, сделай что-нибудь самостоятельно!
*

borro

  • Завсегдатай
  • 1379
  • 22 / 0
  • желаю вам счастья
Здравствуйте! Спасибо.
Получается populateState() должна читать фильтр следующим образом:
Код
$book = $app->getUserStateFromRequest(
                'filter_book',
                'filter_book',
                $results[0]->book_name,
                'string'
            );
А populateState() выполняется только 1 раз при каждом вызове модели, я вам об этом уже давно говорил.
А вот этот совет я не понял, как применить. Нужно еще раз параметр где-то считать и сохранить?
*

b2z

  • Глобальный модератор
  • 7107
  • 769 / 0
  • Разраблю понемногу
@robert
Цитировать
Вы записываете данные в 'filter_book', но хотите их извлечь из $this->context . '.filter_book'.
Нет, это не так. В getUserStateFromRequest первый параметр - это ключ в сессии. Вытаскивается из инпута по второму параметру, а он верный - filter_book.

Цитировать
И значение 'filter_book' из селекта будет в 'jform', $app->input->get('filter_book') вам его не даст.
С чего это вдруг? Это простой select в простой форме и это никак не связано с JForm. Фильтр выбирается, происходит отправка формы. А значит всё должно быть в $app->input.

@borro есть же отладчик, проверь, что приходит в $app->input->get('filter_book'). Можешь также в отладчике посмотреть глобальные массивы POST и REQUEST, что там за данные находятся.

P.S.
Исходный код компонента посмотрел, не увидел, где может быть проблема...
Чтобы оставить сообщение,
Вам необходимо Войти или Зарегистрироваться