GenericTable: refactor order and pagination initalisation

This commit is contained in:
Aaron van Geffen 2024-12-19 15:00:00 +01:00
parent 06c95853f5
commit bb8a8bad27
6 changed files with 85 additions and 118 deletions

View File

@ -54,27 +54,19 @@ class ManageAlbums extends HTMLController
'value' => 'count', 'value' => 'count',
], ],
], ],
'start' => !empty($_GET['start']) ? (int) $_GET['start'] : 0, 'default_sort_order' => 'tag',
'sort_order' => !empty($_GET['order']) ? $_GET['order'] : null, 'default_sort_direction' => 'up',
'sort_direction' => !empty($_GET['dir']) ? $_GET['dir'] : null, 'start' => $_GET['start'] ?? 0,
'sort_order' => $_GET['order'] ?? '',
'sort_direction' => $_GET['dir'] ?? '',
'title' => 'Manage albums', 'title' => 'Manage albums',
'no_items_label' => 'No albums meet the requirements of the current filter.', 'no_items_label' => 'No albums meet the requirements of the current filter.',
'items_per_page' => 9999, 'items_per_page' => 9999,
'index_class' => 'col-md-6', 'index_class' => 'col-md-6',
'base_url' => BASEURL . '/managealbums/', 'base_url' => BASEURL . '/managealbums/',
'get_data' => function($offset = 0, $limit = 9999, $order = '', $direction = 'up') { 'get_data' => function($offset, $limit, $order, $direction) {
if (!in_array($order, ['id_tag', 'tag', 'slug', 'count'])) assert(in_array($order, ['id_tag', 'tag', 'slug', 'count']));
$order = 'tag'; return PhotoAlbum::getHierarchy($order, $direction);
if (!in_array($direction, ['up', 'down']))
$direction = 'up';
$rows = PhotoAlbum::getHierarchy($order, $direction);
return [
'rows' => $rows,
'order' => $order,
'direction' => ($direction == 'up' ? 'up' : 'down'),
];
}, },
'get_count' => function() { 'get_count' => function() {
return 9999; return 9999;

View File

@ -121,19 +121,20 @@ class ManageAssets extends HTMLController
], ],
], ],
], ],
'start' => !empty($_GET['start']) ? (int) $_GET['start'] : 0, 'default_sort_order' => 'id_asset',
'sort_order' => !empty($_GET['order']) ? $_GET['order'] : '', 'default_sort_direction' => 'down',
'sort_direction' => !empty($_GET['dir']) ? $_GET['dir'] : '', 'start' => $_GET['start'] ?? 0,
'sort_order' => $_GET['order'] ?? '',
'sort_direction' => $_GET['dir'] ?? '',
'title' => 'Manage assets', 'title' => 'Manage assets',
'no_items_label' => 'No assets meet the requirements of the current filter.', 'no_items_label' => 'No assets meet the requirements of the current filter.',
'items_per_page' => 30, 'items_per_page' => 30,
'index_class' => 'col-md-6', 'index_class' => 'col-md-6',
'base_url' => BASEURL . '/manageassets/', 'base_url' => BASEURL . '/manageassets/',
'get_data' => function($offset = 0, $limit = 30, $order = '', $direction = 'down') { 'get_data' => function($offset, $limit, $order, $direction) {
if (!in_array($order, ['id_asset', 'id_user_uploaded', 'title', 'subdir', 'filename'])) assert(in_array($order, ['id_asset', 'id_user_uploaded', 'title', 'subdir', 'filename']));
$order = 'id_asset';
$data = Registry::get('db')->queryAssocs(' return Registry::get('db')->queryAssocs('
SELECT a.id_asset, a.subdir, a.filename, SELECT a.id_asset, a.subdir, a.filename,
a.image_width, a.image_height, a.mimetype, a.image_width, a.image_height, a.mimetype,
u.id_user, u.first_name, u.surname u.id_user, u.first_name, u.surname
@ -146,12 +147,6 @@ class ManageAssets extends HTMLController
'offset' => $offset, 'offset' => $offset,
'limit' => $limit, 'limit' => $limit,
]); ]);
return [
'rows' => $data,
'order' => $order,
'direction' => $direction,
];
}, },
'get_count' => 'Asset::getCount', 'get_count' => 'Asset::getCount',
]; ];

View File

@ -14,8 +14,8 @@ class ManageErrors extends HTMLController
if (!Registry::get('user')->isAdmin()) if (!Registry::get('user')->isAdmin())
throw new NotAllowedException(); throw new NotAllowedException();
// Flushing, are we? // Clearing, are we?
if (isset($_POST['flush']) && Session::validateSession('get')) if (isset($_POST['clear']) && Session::validateSession('get'))
{ {
ErrorLog::flush(); ErrorLog::flush();
header('Location: ' . BASEURL . '/manageerrors/'); header('Location: ' . BASEURL . '/manageerrors/');
@ -31,7 +31,7 @@ class ManageErrors extends HTMLController
'method' => 'post', 'method' => 'post',
'class' => 'col-md-6 text-end', 'class' => 'col-md-6 text-end',
'buttons' => [ 'buttons' => [
'flush' => [ 'clear' => [
'type' => 'submit', 'type' => 'submit',
'caption' => 'Delete all', 'caption' => 'Delete all',
'class' => 'btn-danger', 'class' => 'btn-danger',
@ -39,7 +39,7 @@ class ManageErrors extends HTMLController
], ],
], ],
'columns' => [ 'columns' => [
'id' => [ 'id_entry' => [
'value' => 'id_entry', 'value' => 'id_entry',
'header' => '#', 'header' => '#',
'is_sortable' => true, 'is_sortable' => true,
@ -95,19 +95,20 @@ class ManageErrors extends HTMLController
], ],
], ],
], ],
'start' => !empty($_GET['start']) ? (int) $_GET['start'] : 0, 'default_sort_order' => 'id_entry',
'sort_order' => !empty($_GET['order']) ? $_GET['order'] : '', 'default_sort_direction' => 'down',
'sort_direction' => !empty($_GET['dir']) ? $_GET['dir'] : '', 'start' => $_GET['start'] ?? 0,
'sort_order' => $_GET['order'] ?? '',
'sort_direction' => $_GET['dir'] ?? '',
'no_items_label' => "No errors to display -- we're all good!", 'no_items_label' => "No errors to display -- we're all good!",
'items_per_page' => 20, 'items_per_page' => 20,
'index_class' => 'col-md-6', 'index_class' => 'col-md-6',
'base_url' => BASEURL . '/manageerrors/', 'base_url' => BASEURL . '/manageerrors/',
'get_count' => 'ErrorLog::getCount', 'get_count' => 'ErrorLog::getCount',
'get_data' => function($offset = 0, $limit = 20, $order = '', $direction = 'down') { 'get_data' => function($offset, $limit, $order, $direction) {
if (!in_array($order, ['id_entry', 'file', 'line', 'time', 'ipaddress', 'id_user'])) assert(in_array($order, ['id_entry', 'file', 'line', 'time', 'ipaddress', 'id_user']));
$order = 'id_entry';
$data = Registry::get('db')->queryAssocs(' return Registry::get('db')->queryAssocs('
SELECT * SELECT *
FROM log_errors FROM log_errors
ORDER BY {raw:order} ORDER BY {raw:order}
@ -117,12 +118,6 @@ class ManageErrors extends HTMLController
'offset' => $offset, 'offset' => $offset,
'limit' => $limit, 'limit' => $limit,
]); ]);
return [
'rows' => $data,
'order' => $order,
'direction' => $direction,
];
}, },
]; ];

View File

@ -70,21 +70,20 @@ class ManageTags extends HTMLController
'value' => 'count', 'value' => 'count',
], ],
], ],
'start' => !empty($_GET['start']) ? (int) $_GET['start'] : 0, 'default_sort_order' => 'tag',
'sort_order' => !empty($_GET['order']) ? $_GET['order'] : null, 'default_sort_direction' => 'up',
'sort_direction' => !empty($_GET['dir']) ? $_GET['dir'] : null, 'start' => $_GET['start'] ?? 0,
'sort_order' => $_GET['order'] ?? '',
'sort_direction' => $_GET['dir'] ?? '',
'title' => 'Manage tags', 'title' => 'Manage tags',
'no_items_label' => 'No tags meet the requirements of the current filter.', 'no_items_label' => 'No tags meet the requirements of the current filter.',
'items_per_page' => 30, 'items_per_page' => 30,
'index_class' => 'col-md-6', 'index_class' => 'col-md-6',
'base_url' => BASEURL . '/managetags/', 'base_url' => BASEURL . '/managetags/',
'get_data' => function($offset = 0, $limit = 30, $order = '', $direction = 'up') { 'get_data' => function($offset, $limit, $order, $direction) {
if (!in_array($order, ['id_tag', 'tag', 'slug', 'kind', 'count'])) assert(in_array($order, ['id_tag', 'tag', 'slug', 'count']));
$order = 'tag';
if (!in_array($direction, ['up', 'down']))
$direction = 'up';
$data = Registry::get('db')->queryAssocs(' return Registry::get('db')->queryAssocs('
SELECT t.*, u.id_user, u.first_name, u.surname SELECT t.*, u.id_user, u.first_name, u.surname
FROM tags AS t FROM tags AS t
LEFT JOIN users AS u ON t.id_user_owner = u.id_user LEFT JOIN users AS u ON t.id_user_owner = u.id_user
@ -97,12 +96,6 @@ class ManageTags extends HTMLController
'limit' => $limit, 'limit' => $limit,
'album' => 'Album', 'album' => 'Album',
]); ]);
return [
'rows' => $data,
'order' => $order,
'direction' => ($direction == 'up' ? 'up' : 'down'),
];
}, },
'get_count' => function() { 'get_count' => function() {
return Registry::get('db')->queryValue(' return Registry::get('db')->queryValue('

View File

@ -90,19 +90,20 @@ class ManageUsers extends HTMLController
], ],
], ],
], ],
'start' => !empty($_GET['start']) ? (int) $_GET['start'] : 0, 'default_sort_order' => 'id_user',
'sort_order' => !empty($_GET['order']) ? $_GET['order'] : '', 'default_sort_direction' => 'down',
'sort_direction' => !empty($_GET['dir']) ? $_GET['dir'] : '', 'start' => $_GET['start'] ?? 0,
'sort_order' => $_GET['order'] ?? '',
'sort_direction' => $_GET['dir'] ?? '',
'title' => 'Manage users', 'title' => 'Manage users',
'no_items_label' => 'No users meet the requirements of the current filter.', 'no_items_label' => 'No users meet the requirements of the current filter.',
'items_per_page' => 30, 'items_per_page' => 30,
'index_class' => 'col-md-6', 'index_class' => 'col-md-6',
'base_url' => BASEURL . '/manageusers/', 'base_url' => BASEURL . '/manageusers/',
'get_data' => function($offset = 0, $limit = 30, $order = '', $direction = 'down') { 'get_data' => function($offset, $limit, $order, $direction) {
if (!in_array($order, ['id_user', 'surname', 'first_name', 'slug', 'emailaddress', 'last_action_time', 'ip_address', 'is_admin'])) assert(in_array($order, ['id_user', 'surname', 'first_name', 'slug', 'emailaddress', 'last_action_time', 'ip_address', 'is_admin']));
$order = 'id_user';
$data = Registry::get('db')->queryAssocs(' return Registry::get('db')->queryAssocs('
SELECT * SELECT *
FROM users FROM users
ORDER BY {raw:order} ORDER BY {raw:order}
@ -112,18 +113,8 @@ class ManageUsers extends HTMLController
'offset' => $offset, 'offset' => $offset,
'limit' => $limit, 'limit' => $limit,
]); ]);
return [
'rows' => $data,
'order' => $order,
'direction' => $direction,
];
}, },
'get_count' => function() { 'get_count' => 'Member::getCount',
return Registry::get('db')->queryValue('
SELECT COUNT(*)
FROM users');
}
]; ];
$table = new GenericTable($options); $table = new GenericTable($options);

View File

@ -28,53 +28,22 @@ class GenericTable
public function __construct($options) public function __construct($options)
{ {
// Make sure we're actually sorting on something sortable. $this->initOrder($options);
if (!isset($options['sort_order']) || (!empty($options['sort_order']) && empty($options['columns'][$options['sort_order']]['is_sortable']))) $this->initPagination($options);
$options['sort_order'] = '';
// Order in which direction? $data = $options['get_data']($this->start, $this->items_per_page,
if (!empty($options['sort_direction']) && !in_array($options['sort_direction'], ['up', 'down'])) $this->sort_order, $this->sort_direction);
$options['sort_direction'] = 'up';
// How much data do we have?
$this->recordCount = $options['get_count']();
// How much data do we need to retrieve?
$this->items_per_page = !empty($options['items_per_page']) ? $options['items_per_page'] : 30;
// Figure out where to start.
$this->start = empty($options['start']) || !is_numeric($options['start']) || $options['start'] < 0 || $options['start'] > $this->recordCount ? 0 : $options['start'];
// Figure out where we are on the whole, too.
$numPages = max(1, ceil($this->recordCount / $this->items_per_page));
$this->currentPage = min(ceil($this->start / $this->items_per_page) + 1, $numPages);
// Let's bear a few things in mind...
$this->base_url = $options['base_url'];
// Gather parameters for the data gather function first.
$parameters = [$this->start, $this->items_per_page, $options['sort_order'], $options['sort_direction']];
// Okay, let's fetch the data!
$data = $options['get_data'](...$parameters);
// Extract data into local variables.
$rawRowData = $data['rows'];
$this->sort_order = $data['order'];
$this->sort_direction = $data['direction'];
unset($data);
// Okay, now for the column headers... // Okay, now for the column headers...
$this->generateColumnHeaders($options); $this->generateColumnHeaders($options);
// Should we create a page index? // Should we create a page index?
$needsPageIndex = !empty($this->items_per_page) && $this->recordCount > $this->items_per_page; if ($this->recordCount > $this->items_per_page)
if ($needsPageIndex)
$this->generatePageIndex($options); $this->generatePageIndex($options);
// Process the data to be shown into rows. // Process the data to be shown into rows.
if (!empty($rawRowData)) if (!empty($data))
$this->processAllRows($rawRowData, $options); $this->processAllRows($data, $options);
else else
$this->body = $options['no_items_label'] ?? ''; $this->body = $options['no_items_label'] ?? '';
@ -89,6 +58,38 @@ class GenericTable
$this->form_below = $options['form_below'] ?? $options['form'] ?? null; $this->form_below = $options['form_below'] ?? $options['form'] ?? null;
} }
private function initOrder($options)
{
assert(isset($options['default_sort_order']));
assert(isset($options['default_sort_direction']));
// Validate sort order (column)
$this->sort_order = $options['sort_order'];
if (empty($this->sort_order) || empty($options['columns'][$this->sort_order]['is_sortable']))
$this->sort_order = $options['default_sort_order'];
// Validate sort direction
$this->sort_direction = $options['sort_direction'];
if (empty($this->sort_direction) || !in_array($this->sort_direction, ['up', 'down']))
$this->sort_direction = $options['default_sort_direction'];
}
private function initPagination(array $options)
{
assert(isset($options['base_url']));
assert(isset($options['items_per_page']));
$this->base_url = $options['base_url'];
$this->recordCount = $options['get_count']();
$this->items_per_page = !empty($options['items_per_page']) ? $options['items_per_page'] : 30;
$this->start = empty($options['start']) || !is_numeric($options['start']) || $options['start'] < 0 || $options['start'] > $this->recordCount ? 0 : $options['start'];
$numPages = max(1, ceil($this->recordCount / $this->items_per_page));
$this->currentPage = min(ceil($this->start / $this->items_per_page) + 1, $numPages);
}
private function generateColumnHeaders($options) private function generateColumnHeaders($options)
{ {
foreach ($options['columns'] as $key => $column) foreach ($options['columns'] as $key => $column)
@ -218,7 +219,7 @@ class GenericTable
{ {
// Basic option: simply take a use a particular data property. // Basic option: simply take a use a particular data property.
case 'value': case 'value':
$value = htmlspecialchars($rowData[$options['data']]); $value = htmlspecialchars($rowData[$options['data']] ?? '');
break; break;
// Processing via a lambda function. // Processing via a lambda function.