I creating my custom component for Joomla 5. This is like a list of workers with different fields + I connected for this component native Joomla categories.
Categories working (I mean creating, edit, delete), but I can't understand how to create filter by categories in the list of workers and displaying the category titles in the table of list.
Below you can see code for file WorkersModel.php:
Code: Select all
<?php
namespace VPJoomla\Component\Workers\Administrator\Model;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\CMS\Table\Table;
use Joomla\Database\ParameterType;
use Joomla\Utilities\ArrayHelper;
defined('_JEXEC') or exit();
class WorkersModel extends ListModel {
/**
* Конструктор.
* @param array $config Массив с конфигурационными параметрами.
*/
public function __construct($config = []){
// Добавляем валидные поля для фильтров и сортировки.
if (empty($config['filter_fields'])) {
$config['filter_fields'] = array(
'id', 'a.id',
'name', 'a.name',
'catid', 'a.catid', 'category_title',
'alias', 'a.alias',
'country', 'a.country',
'city', 'a.city',
'sex', 'a.sex',
'availability', 'a.availability',
'ordering', 'a.ordering',
'state', 'a.state',
'created', 'a.created',
'modified', 'a.modified'
);
}
parent::__construct($config);
}
/**
* Method to get a list of items.
*
* @return mixed An array of data items on success, false on failure.
*/
public function getItems()
{
$items = parent::getItems();
return $items;
}
/**
* Метод для построения SQL запроса для загрузки списка данных.
* @return string SQL запрос.
*/
protected function getListQuery(): string
{
$db = $this->getDatabase();
$query = $db->getQuery(true);
$query->select(
$this->getState(
'list.select',
[
$db->quoteName('a.id'),
$db->quoteName('a.name'),
$db->quoteName('a.catid'),
$db->quoteName('a.alias'),
$db->quoteName('a.country'),
$db->quoteName('a.city'),
$db->quoteName('a.sex'),
$db->quoteName('a.availability'),
$db->quoteName('a.state'),
$db->quoteName('a.created'),
$db->quoteName('a.modified'),
$db->quoteName('a.ordering'),
]
)
)
->select($db->quoteName('c.title', 'category_title'))
->from($db->quoteName('#__workers', 'a'))
->where($db->quoteName('wa.extension') . ' = ' . $db->quote('com_workers.worker'))
->join('LEFT', $db->quoteName('#__categories', 'c'), $db->quoteName('c.id') . ' = ' . $db->quoteName('a.catid'));
// Фильтр по состоянию полученному из запроса
$published = (string) $this->getState('filter.published');
if (is_numeric($published))
{
$query->where($db->quoteName('a.state') . ' = '.$published);
}
elseif ($published === '')
{
$query->where('(' . $db->quoteName('a.state') . ' = 0 OR ' . $db->quoteName('a.state') . ' = 1)');
}
// Фильтр по категории
$categoryId = $this->getState('filter.category_id', []);
if (!\is_array($categoryId)) {
$categoryId = $categoryId ? [$categoryId] : [];
}
if (\count($categoryId)) {
$categoryId = ArrayHelper::toInteger($categoryId);
$categoryTable = Table::getInstance('Category', '\\Joomla\\CMS\\Table\\');
$subCatItemsWhere = [];
foreach ($categoryId as $key => $filter_catid) {
$categoryTable->load($filter_catid);
// Because values to $query->bind() are passed by reference, using $query->bindArray() here instead to prevent overwriting.
$valuesToBind = [$categoryTable->lft, $categoryTable->rgt];
// Bind values and get parameter names.
$bounded = $query->bindArray($valuesToBind);
$categoryWhere = $db->quoteName('c.lft') . ' >= ' . $bounded[0] . ' AND ' . $db->quoteName('c.rgt') . ' <= ' . $bounded[1];
$subCatItemsWhere[] = '(' . $categoryWhere . ')';
}
$query->where('(' . implode(' OR ', $subCatItemsWhere) . ')');
}
//Фильтр поиска по стране
$country = $this->getState('filter.country');
if (!empty($country)) {
$query->where($db->quoteName('a.country') . ' = ' . $db->quote($country));
}
//Фильтр поиска по полу
$sex = (int) $this->getState('filter.sex');
if ($sex) {
$query->where($db->quoteName('a.sex') . ' = ' . $db->quote($sex));
}
//Фильтр поиска по доступности
$availability = (string) $this->getState('filter.availability');
if (\in_array($availability, ['0','1'])) {
$availability = (int) $availability;
$query->where($db->quoteName('a.availability') . ' = :availability')
->bind(':availability', $featured, ParameterType::INTEGER);
}
// Фильтр поиска по названию.
$search = $this->getState('filter.search');
if (!empty($search))
{
$search = $db->quote('%' . str_replace(' ', '%', $db->escape(trim($search), true) . '%'));
$query->where('(a.name LIKE ' . $search . ')');
}
// Добавляем сортировку.
$orderCol = $this->state->get('list.ordering', 'id');
$orderDirn = $this->state->get('list.direction', 'desc');
$query->order($db->escape($orderCol . ' ' . $orderDirn));
return $query;
}
protected function populateState($ordering = 'a.id', $direction = 'desc')
{
$app = Factory::getApplication();
$input = $app->input;
$search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search');
$this->setState('filter.search', $search);
$published = $this->getUserStateFromRequest($this->context . '.filter.published', 'filter_published', '');
$this->setState('filter.published', $published);
$country = $this->getUserStateFromRequest($this->context . '.filter.country', 'filter_country', '');
$this->setState('filter.country', $country);
$sex = $this->getUserStateFromRequest($this->context . '.filter.sex', 'filter_sex', '');
$this->setState('filter.sex', $sex);
$availability = $this->getUserStateFromRequest($this->context . '.filter.availability', 'filter_availability', '');
$this->setState('filter.availability', $availability);
// Set the default ordering and direction if not already set
parent::populateState($ordering, $direction);
}
protected function getStoreId($id = ''): string
{
// Compile the store id.
$id .= ':' . $this->getState('filter.search');
$id .= ':' . serialize($this->getState('filter.category_id'));
$id .= ':' . $this->getState('filter.country');
$id .= ':' . $this->getState('filter.sex');
$id .= ':' . $this->getState('filter.availability');
return parent::getStoreId($id);
}
/* Prepare a faqcontentiten record for saving in the database */
protected function prepareTable($table): void
{
// Set ordering to the last item if not set
if (empty($table->ordering))
{
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select('MAX(ordering)')
->from('#__workers');
$db->setQuery($query);
$max = $db->loadResult();
$table->ordering = $max + 1;
}
}
/**
* Method to change the published state of one or more records.
*
* @param array &$pks A list of the primary keys to change.
* @param integer $value The value of the published state.
*
* @return boolean True on success.
*
* @since 4.0.0
*/
public function publish(array &$pks, int $value = 1) {
if (empty($pks)) {
return false; // No records to update
}
$db = $this->getDatabase();
// Sanitize the value
$value = (int) $value;
try {
$query = $db->getQuery(true)
->update($db->quoteName('#__workers'))
->set($db->quoteName('state') . ' = ' . $value)
->whereIn($db->quoteName('id'), $pks);
$db->setQuery($query);
$db->execute();
return true;
} catch (\Exception $e) {
return false;
}
}
/**
* Method to change the published state of one or more records to unpublished.
*
* @param array &$pks A list of the primary keys to change.
*
* @return boolean True on success.
*/
public function unpublish(array &$pks) {
return $this->publish($pks, 0);
}
/**
* Method to change the published state of one or more records to archived.
*
* @param array &$pks A list of the primary keys to change.
*
* @return boolean True on success.
*/
public function archive(array &$pks) {
return $this->publish($pks, 2);
}
/**
* Method to change the published state of one or more records to trashed.
*
* @param array &$pks A list of the primary keys to change.
*
* @return boolean True on success.
*/
public function trash(array &$pks) {
return $this->publish($pks, -2);
}
}
Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<form>
<fields name="filter">
<field
name="search"
type="text"
hint="JSEARCH_FILTER"
/>
<field
name="published"
type="status"
label="JOPTION_SELECT_PUBLISHED"
class="js-select-submit-on-change"
extension="com_workers"
>
<option value="">JOPTION_SELECT_PUBLISHED</option>
</field>
<field
name="category_id"
type="category"
label="JCATEGORY"
multiple="true"
extension="com_workers"
layout="joomla.form.field.list-fancy-select"
hint="JOPTION_SELECT_CATEGORY"
class="js-select-submit-on-change"
published="0,1,2"
/>
<field
name="country"
type="country"
label="COM_WORKERS_WORKERS_SELECT_COUNTRY"
class="js-select-submit-on-change"
>
<option value="">COM_WORKERS_WORKERS_SELECT_COUNTRY</option>
</field>
<field
name="sex"
type="sex"
label="COM_WORKERS_WORKERS_SELECT_SEX"
class="js-select-submit-on-change"
>
<option value="">COM_WORKERS_WORKERS_SELECT_SEX</option>
</field>
<field
name="availability"
type="availability"
label="COM_WORKERS_WORKERS_SELECT_AVAILABILITY"
class="js-select-submit-on-change"
>
<option value="">COM_WORKERS_WORKERS_SELECT_AVAILABILITY</option>
</field>
</fields>
<fields name="list">
<field name="fullordering"
type="list"
label="JGLOBAL_SORT_BY"
class="js-select-submit-on-change"
default="a.published DESC"
validate="options"
>
<option value="">JGLOBAL_SORT_BY</option>
<option value="a.ordering ASC">JGRID_HEADING_ORDERING_ASC</option>
<option value="a.ordering DESC">JGRID_HEADING_ORDERING_DESC</option>
<option value="category_title ASC">JCATEGORY_ASC</option>
<option value="category_title DESC">JCATEGORY_DESC</option>
<option value="a.state ASC">JSTATUS_ASC</option>
<option value="a.state DESC">JSTATUS_DESC</option>
<option value="a.created ASC">JDATE_ASC</option>
<option value="a.created DESC">JDATE_DESC</option>
<option value="a.modified ASC">COM_WORKERS_MODIFIED_ASC</option>
<option value="a.modified DESC">COM_WORKERS_MODIFIED_DESC</option>
<option value="a.name ASC">COM_WORKERS_NAME_ASC</option>
<option value="a.name DESC">COM_WORKERS_NAME_DESC</option>
<option value="a.id ASC">JGRID_HEADING_ID_ASC</option>
<option value="a.id DESC">JGRID_HEADING_ID_DESC</option>
</field>
<field
name="limit"
type="limitbox"
label="JGLOBAL_LIST_LIMIT"
default="25"
class="js-select-submit-on-change"
/>
</fields>
</form>