diff --git a/admin_admins.php b/admin_admins.php
index b22b7c21..72009a7f 100644
--- a/admin_admins.php
+++ b/admin_admins.php
@@ -32,19 +32,17 @@ if ($page == 'admins' && $userinfo['change_serversettings'] == '1') {
if ($action == '') {
$log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed admin_admins");
- $admin_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.admins.php';
try {
- // get filtered collection
- $list = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Admins::class, $userinfo))
- ->withPagination($admin_list_data['admin_list']['columns'])
- ->getList();
+ $admin_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.admins.php';
+ $collection = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Admins::class, $userinfo))
+ ->withPagination($admin_list_data['admin_list']['columns']);
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
UI::twigBuffer('user/table.html.twig', [
- 'listing' => \Froxlor\UI\Listing::format($list, $admin_list_data['admin_list']),
+ 'listing' => \Froxlor\UI\Listing::format($collection, $admin_list_data['admin_list']),
]);
UI::twigOutputBuffer();
} elseif ($action == 'su') {
diff --git a/admin_customers.php b/admin_customers.php
index a7b43f19..b32aac0c 100644
--- a/admin_customers.php
+++ b/admin_customers.php
@@ -34,16 +34,15 @@ if ($page == 'customers' && $userinfo['customers'] != '0') {
try {
$customer_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.customers.php';
- $list = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Customers::class, $userinfo))
+ $collection = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Customers::class, $userinfo))
->has('admin', \Froxlor\Api\Commands\Admins::class, 'adminid', 'adminid')
- ->withPagination($customer_list_data['customer_list']['columns'])
- ->getList();
+ ->withPagination($customer_list_data['customer_list']['columns']);
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
UI::twigBuffer('user/table.html.twig', [
- 'listing' => \Froxlor\UI\Listing::format($list, $customer_list_data['customer_list']),
+ 'listing' => \Froxlor\UI\Listing::format($collection, $customer_list_data['customer_list']),
]);
UI::twigOutputBuffer();
} elseif ($action == 'su' && $id != 0) {
diff --git a/admin_domains.php b/admin_domains.php
index e8d32190..3170667f 100644
--- a/admin_domains.php
+++ b/admin_domains.php
@@ -35,16 +35,15 @@ if ($page == 'domains' || $page == 'overview') {
try {
$domain_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.domains.php';
- $list = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Domains::class, $userinfo))
+ $collection = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Domains::class, $userinfo))
->has('customer', \Froxlor\Api\Commands\Customers::class, 'customerid', 'customerid')
- ->withPagination($domain_list_data['domain_list']['columns'])
- ->getList();
+ ->withPagination($domain_list_data['domain_list']['columns']);
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
UI::twigBuffer('user/table.html.twig', [
- 'listing' => \Froxlor\UI\Listing::format($list, $domain_list_data['domain_list']),
+ 'listing' => \Froxlor\UI\Listing::format($collection, $domain_list_data['domain_list']),
]);
UI::twigOutputBuffer();
} elseif ($action == 'delete' && $id != 0) {
diff --git a/admin_ipsandports.php b/admin_ipsandports.php
index 172806c6..8f641d29 100644
--- a/admin_ipsandports.php
+++ b/admin_ipsandports.php
@@ -33,15 +33,14 @@ if ($page == 'ipsandports' || $page == 'overview') {
try {
$ipsandports_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.ipsandports.php';
- $list = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\IpsAndPorts::class, $userinfo))
- ->withPagination($ipsandports_list_data['ipsandports_list']['columns'])
- ->getList();
+ $collection = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\IpsAndPorts::class, $userinfo))
+ ->withPagination($ipsandports_list_data['ipsandports_list']['columns']);
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
UI::twigBuffer('user/table.html.twig', [
- 'listing' => \Froxlor\UI\Listing::format($list, $ipsandports_list_data['ipsandports_list']),
+ 'listing' => \Froxlor\UI\Listing::format($collection, $ipsandports_list_data['ipsandports_list']),
]);
UI::twigOutputBuffer();
} elseif ($action == 'delete' && $id != 0) {
diff --git a/admin_plans.php b/admin_plans.php
index c856766e..23132af0 100644
--- a/admin_plans.php
+++ b/admin_plans.php
@@ -34,15 +34,14 @@ if ($page == '' || $page == 'overview') {
try {
$plan_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.plans.php';
- $list = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\HostingPlans::class, $userinfo))
- ->withPagination($plan_list_data['plan_list']['columns'])
- ->getList();
+ $collection = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\HostingPlans::class, $userinfo))
+ ->withPagination($plan_list_data['plan_list']['columns']);
} catch (Exception $e) {
\Froxlor\UI\Response::dynamic_error($e->getMessage());
}
UI::twigBuffer('user/table.html.twig', [
- 'listing' => \Froxlor\UI\Listing::format($list, $plan_list_data['plan_list']),
+ 'listing' => \Froxlor\UI\Listing::format($collection, $plan_list_data['plan_list']),
]);
UI::twigOutputBuffer();
} elseif ($action == 'delete' && $id != 0) {
diff --git a/lib/Froxlor/UI/Collection.php b/lib/Froxlor/UI/Collection.php
index 82f216c8..5c175a95 100644
--- a/lib/Froxlor/UI/Collection.php
+++ b/lib/Froxlor/UI/Collection.php
@@ -23,6 +23,7 @@ class Collection
private array $has = [];
private array $params;
private array $userinfo;
+ private ?Pagination $pagination;
public function __construct(string $class, array $userInfo, array $params = [])
{
@@ -60,6 +61,11 @@ class Collection
}
}
+ // attach pagination if available
+ if ($this->pagination) {
+ $result = array_merge($result, $this->pagination->getApiResponseParams());
+ }
+
return $result;
}
@@ -93,10 +99,17 @@ class Collection
public function withPagination(array $columns): Collection
{
- // TODO: handle 'sortable' => true in $columns
+ // Get only searchable columns
+ $sortableColumns = [];
+ foreach ($columns as $key => $column) {
+ if (isset($column['sortable']) && $column['sortable']) {
+ $sortableColumns[$key] = $column;
+ }
+ }
- $pagination = new Pagination($this->userinfo, $columns, $this->count());
- $this->params = array_merge($this->params, $pagination->getApiCommandParams());
+ // Prepare pagination
+ $this->pagination = new Pagination($this->userinfo, $sortableColumns, $this->count());
+ $this->params = array_merge($this->params, $this->pagination->getApiCommandParams());
return $this;
}
diff --git a/lib/Froxlor/UI/Listing.php b/lib/Froxlor/UI/Listing.php
index a6d3b200..6b1ee8fa 100644
--- a/lib/Froxlor/UI/Listing.php
+++ b/lib/Froxlor/UI/Listing.php
@@ -20,16 +20,18 @@ use Froxlor\UI\Panel\UI;
*/
class Listing
{
- public static function format(array $list, array $tabellisting): array
+ public static function format(Collection $collection, array $tabellisting): array
{
+ $collection = $collection->get();
+
return [
'title' => $tabellisting['title'],
'icon' => $tabellisting['icon'],
'table' => [
'th' => self::generateTableHeadings($tabellisting),
- 'tr' => self::generateTableRows($list, $tabellisting),
+ 'tr' => self::generateTableRows($collection['data']['list'], $tabellisting),
],
- 'pagination' => null, // TODO: write some logic
+ 'pagination' => $collection['pagination'],
];
}
@@ -43,7 +45,7 @@ class Listing
continue;
}
- $heading[] = [
+ $heading[$visible_column] = [
'text' => $tabellisting['columns'][$visible_column]['label'],
'class' => $tabellisting['columns'][$visible_column]['class'] ?? null,
];
@@ -51,7 +53,7 @@ class Listing
// Table headings for actions
if (isset($tabellisting['actions'])) {
- $heading[] = [
+ $heading['actions'] = [
'text' => UI::getLng('panel.options'),
'class' => 'text-end',
];
diff --git a/lib/Froxlor/UI/Pagination.php b/lib/Froxlor/UI/Pagination.php
index 91a1699d..65eae496 100644
--- a/lib/Froxlor/UI/Pagination.php
+++ b/lib/Froxlor/UI/Pagination.php
@@ -1,6 +1,8 @@
fields = $fields;
$this->entries = $total_entries;
+ $this->perPage = $perPage;
$this->pageno = 1;
// add default limitation by settings
- $this->addLimit(\Froxlor\Settings::Get('panel.paging'));
+ $this->addLimit(Settings::Get('panel.paging'));
// check search request
$this->searchtext = '';
if (count($fields) > 0) {
@@ -91,23 +96,21 @@ class Pagination
if (isset($_REQUEST['pageno']) && intval($_REQUEST['pageno']) != 0) {
$this->pageno = intval($_REQUEST['pageno']);
}
- if (($this->pageno - 1) * \Froxlor\Settings::Get('panel.paging') > $this->entries) {
+ if (($this->pageno - 1) * Settings::Get('panel.paging') > $this->entries) {
$this->pageno = 1;
}
- $this->addOffset(($this->pageno - 1) * \Froxlor\Settings::Get('panel.paging'));
+ $this->addOffset(($this->pageno - 1) * Settings::Get('panel.paging'));
}
/**
* add a field for ordering
*
* @param string $field
- * @param string $order
- * optional, default 'ASC'
- *
- * @return \Froxlor\UI\Pagination
+ * @param string $order optional, default 'ASC'
+ * @return Pagination
*/
- public function addOrderBy($field = null, $order = 'ASC')
- {
+ public function addOrderBy($field = null, $order = 'ASC'): Pagination
+ {
if (! isset($this->data['sql_orderby'])) {
$this->data['sql_orderby'] = array();
}
@@ -118,42 +121,40 @@ class Pagination
/**
* add a limit
*
- * @param number $limit
+ * @param int $limit
* optional, default 0
*
- * @return \Froxlor\UI\Pagination
+ * @return Pagination
*/
- public function addLimit($limit = 0)
- {
- $this->data['sql_limit'] = (int) $limit;
+ public function addLimit(int $limit = 0): Pagination
+ {
+ $this->data['sql_limit'] = $limit;
return $this;
}
/**
* add an offset
*
- * @param number $offset
- * optional, default 0
- *
- * @return \Froxlor\UI\Pagination
+ * @param int $offset optional, default 0
+ * @return Pagination
*/
- public function addOffset($offset = 0)
- {
- $this->data['sql_offset'] = (int) $offset;
+ public function addOffset(int $offset = 0): Pagination
+ {
+ $this->data['sql_offset'] = $offset;
return $this;
}
- /**
- * add a search operation
- *
- * @param string $searchtext
- * @param string $field
- * @param string $operator
- *
- * @return \Froxlor\UI\Pagination
- */
- public function addSearch($searchtext = null, $field = null, $operator = null)
- {
+ /**
+ * add a search operation
+ *
+ * @param string|null $searchtext
+ * @param string|null $field
+ * @param string|null $operator
+ *
+ * @return Pagination
+ */
+ public function addSearch(string $searchtext = null, string $field = null, string $operator = null): Pagination
+ {
if (! isset($this->data['sql_search'])) {
$this->data['sql_search'] = array();
}
@@ -175,150 +176,28 @@ class Pagination
*
* @return number
*/
- public function getEntries()
- {
+ public function getEntries(): int
+ {
return $this->entries;
}
- /**
- * Returns html code for sorting field
- *
- * @param array $lng
- * Language array
- * @return string the html sortcode
- */
- public function getHtmlSortCode($lng, $break = false)
- {
- $sortcode = '';
- $fieldoptions = '';
- $orderoptions = '';
-
- foreach ($this->fields as $fieldname => $fieldcaption) {
- $fieldoptions .= HTML::makeoption($fieldcaption, $fieldname, $this->sortfield, true, true);
- }
-
- $breakorws = ($break ? '
' : ' ');
- foreach (array(
- 'asc' => $lng['panel']['ascending'],
- 'desc' => $lng['panel']['descending']
- ) as $sortordertype => $sortorderdescription) {
- $orderoptions .= HTML::makeoption($sortorderdescription, $sortordertype, $this->sortorder, true, true);
- }
-
- eval("\$sortcode =\"" . Template::getTemplate("misc/htmlsortcode", '1') . "\";");
- return $sortcode;
- }
-
- /**
- * Returns html code for sorting arrows
- *
- * @param string $baseurl
- * URL to use as base for links
- * @param string $field
- * If set, only this field will be returned
- *
- * @return mixed An array or a string (if field is set) of html code of arrows
- */
- public function getHtmlArrowCode($baseurl, $field = '')
- {
- global $theme;
- if ($field != '' && isset($this->fields[$field])) {
- $baseurl = htmlspecialchars($baseurl);
- $fieldname = htmlspecialchars($field);
- eval("\$arrowcode =\"" . Template::getTemplate("misc/htmlarrowcode", '1') . "\";");
- } else {
- $baseurl = htmlspecialchars($baseurl);
- $arrowcode = array();
- foreach ($this->fields as $fieldname => $fieldcaption) {
- $fieldname = htmlspecialchars($fieldname);
- eval("\$arrowcode[\$fieldname] =\"" . Template::getTemplate("misc/htmlarrowcode", '1') . "\";");
- }
- }
- return $arrowcode;
- }
-
- /**
- * Returns html code for searching field
- *
- * @param array $lng
- * Language array
- *
- * @return string the html searchcode
- */
- public function getHtmlSearchCode($lng)
- {
- $searchcode = '';
- $fieldoptions = '';
- $searchtext = htmlspecialchars($this->searchtext);
- foreach ($this->fields as $fieldname => $fieldcaption) {
- $fieldoptions .= HTML::makeoption($fieldcaption, $fieldname, $this->searchfield, true, true);
- }
- eval("\$searchcode =\"" . Template::getTemplate("misc/htmlsearchcode", '1') . "\";");
- return $searchcode;
- }
-
- /**
- * Returns html code for paging
- *
- * @param string $baseurl
- * URL to use as base for links
- *
- * @return string the html pagingcode
- */
- public function getHtmlPagingCode($baseurl)
- {
- if (\Froxlor\Settings::Get('panel.paging') == 0 || $this->is_search) {
- return '';
- } else {
- $pages = intval($this->getEntries() / \Froxlor\Settings::Get('panel.paging'));
- }
-
- if ($this->getEntries() % \Froxlor\Settings::Get('panel.paging') != 0) {
- $pages ++;
- }
-
- if ($pages > 1) {
-
- $start = $this->pageno - 4;
- if ($start < 1) {
- $start = 1;
- }
-
- $stop = $this->pageno + 4;
- if ($stop > $pages) {
- $stop = $pages;
- }
-
- // check for possible sorting values and keep it
- $orderstr = '';
- if (!empty($this->sortfield)) {
- $fieldname = htmlspecialchars($this->sortfield);
- $orderstr .= '&sortfield=' . $fieldname . '&sortorder=' . $this->sortorder;
- }
-
- $pagingcode = '« < ';
- for ($i = $start; $i <= $stop; $i ++) {
- if ($i != $this->pageno) {
- $pagingcode .= ' ' . $i . ' ';
- } else {
- $pagingcode .= ' ' . $i . ' ';
- }
- }
- $pagingcode .= ' > »';
- } else {
- $pagingcode = '';
- }
-
- return $pagingcode;
- }
-
- /**
- * return parameter array for API command parameters $sql_search, $sql_limit, $sql_offset and $sql_orderby
- *
- * @return array
- */
- public function getApiCommandParams()
+ public function getApiCommandParams(): array
{
return $this->data;
}
+
+ public function getApiResponseParams(): array
+ {
+ return [
+ 'pagination' => [
+ "total" => $this->entries,
+ "per_page" => $this->perPage,
+ "current_page" => $this->pageno,
+ "last_page" => ceil($this->entries / $this->perPage),
+ "from" => $this->data['sql_offset'] ?? null,
+ "to" => min($this->data['sql_offset'] + $this->perPage, $this->entries),
+ 'sortfields' => array_keys($this->fields),
+ ]
+ ];
+ }
}
diff --git a/lib/Froxlor/UI/Paging.php b/lib/Froxlor/UI/Paging.php
index 6b7e5ee7..0ea498c9 100644
--- a/lib/Froxlor/UI/Paging.php
+++ b/lib/Froxlor/UI/Paging.php
@@ -22,6 +22,7 @@ namespace Froxlor\UI;
* Class to manage paging system
*
* @package Functions
+ * @deprecated
*/
class Paging
{
diff --git a/lib/tablelisting/admin/tablelisting.domains.php b/lib/tablelisting/admin/tablelisting.domains.php
index fb54fdcc..602df146 100644
--- a/lib/tablelisting/admin/tablelisting.domains.php
+++ b/lib/tablelisting/admin/tablelisting.domains.php
@@ -27,6 +27,7 @@ return [
'd.domain_ace' => [
'label' => $lng['domains']['domainname'],
'column' => 'domain_ace',
+ 'sortable' => true,
],
'c.name' => [
'label' => $lng['customer']['name'],
@@ -44,6 +45,7 @@ return [
'label' => $lng['login']['username'],
'column' => 'customer.loginname',
'format_callback' => [Impersonate::class, 'customer'],
+ 'sortable' => true,
],
'd.aliasdomain' => [
'label' => $lng['domains']['aliasdomain'],
diff --git a/ssl_certificates.php b/ssl_certificates.php
index 62864a9f..aa97141d 100644
--- a/ssl_certificates.php
+++ b/ssl_certificates.php
@@ -51,14 +51,13 @@ $log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed domains::ssl_cert
try {
$certificates_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.sslcertificates.php';
- $list = (new Collection(Certificates::class, $userinfo))
- ->withPagination($certificates_list_data['sslcertificates_list']['columns'])
- ->getList();
+ $collection = (new Collection(Certificates::class, $userinfo))
+ ->withPagination($certificates_list_data['sslcertificates_list']['columns']);
} catch (Exception $e) {
Response::dynamic_error($e->getMessage());
}
UI::twigBuffer('user/table.html.twig', [
- 'listing' => Listing::format($list, $certificates_list_data['sslcertificates_list']),
+ 'listing' => Listing::format($collection, $certificates_list_data['sslcertificates_list']),
]);
UI::twigOutputBuffer();
diff --git a/templates/Froxlor/table/pagination.html.twig b/templates/Froxlor/table/pagination.html.twig
new file mode 100644
index 00000000..c3a9b570
--- /dev/null
+++ b/templates/Froxlor/table/pagination.html.twig
@@ -0,0 +1,28 @@
+{% macro paging(pagination) %}
+