Files
domnitor/app/Helpers/ViewHelper.php
Hosteroid 3688c8b71b Add import/export and update system
Implement CSV/JSON import and export for domains, notification groups and tags (with masking for sensitive channel data), including size/format validation, in-memory CSV building, and logging. Add tag transfer and bulk transfer actions (admin-only). Introduce a new update system: Add UpdateController and UpdateService, migration 025_add_update_system_v1.1.3.sql, and installer changes to include the new migration and version handling; provide endpoints to check, apply, rollback and configure updates. Update helpers and UI bits: add getUpdateBadgeInfo in LayoutHelper, update notification icons/redirects, and add getMaxUploadSize in ViewHelper. Misc: add NotificationGroup::findByName, tweak .gitignore backups path, and update related views and routes.
2026-02-11 17:43:23 +02:00

201 lines
6.8 KiB
PHP

<?php
namespace App\Helpers;
class ViewHelper
{
/**
* Generate sort URL for table headers
*/
public static function sortUrl(string $column, string $currentSort, string $currentOrder, array $currentFilters = []): string
{
$newOrder = ($currentSort === $column && $currentOrder === 'asc') ? 'desc' : 'asc';
$params = $currentFilters;
$params['sort'] = $column;
$params['order'] = $newOrder;
$currentPath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
return $currentPath . '?' . http_build_query($params);
}
/**
* Generate sort icon HTML for table headers
*/
public static function sortIcon(string $column, string $currentSort, string $currentOrder): string
{
if ($currentSort !== $column) {
return '<i class="fas fa-sort text-gray-400 ml-1 text-xs"></i>';
}
$icon = $currentOrder === 'asc' ? 'fa-sort-up' : 'fa-sort-down';
return '<i class="fas ' . $icon . ' text-primary ml-1 text-xs"></i>';
}
/**
* Generate pagination URL
*/
public static function paginationUrl(int $page, array $filters, int $perPage): string
{
$params = $filters;
$params['page'] = $page;
$params['per_page'] = $perPage;
$currentPath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
return $currentPath . '?' . http_build_query($params);
}
/**
* Format status badge
*/
public static function statusBadge(string $status): string
{
$statusClasses = [
'active' => 'bg-green-100 text-green-800 border-green-200',
'expiring_soon' => 'bg-orange-100 text-orange-800 border-orange-200',
'expired' => 'bg-red-100 text-red-800 border-red-200',
'available' => 'bg-blue-100 text-blue-800 border-blue-200',
'redemption_period' => 'bg-amber-100 text-amber-800 border-amber-200',
'pending_delete' => 'bg-rose-100 text-rose-800 border-rose-200',
'inactive' => 'bg-gray-100 text-gray-800 border-gray-200',
];
$statusLabels = [
'active' => 'Active',
'expiring_soon' => 'Expiring Soon',
'expired' => 'Expired',
'available' => 'Available',
'redemption_period' => 'Redemption Period',
'pending_delete' => 'Pending Delete',
'inactive' => 'Inactive',
];
$class = $statusClasses[$status] ?? $statusClasses['inactive'];
$label = $statusLabels[$status] ?? ucfirst($status);
return '<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold border ' . $class . '">' . htmlspecialchars($label) . '</span>';
}
/**
* Truncate text with ellipsis
*/
public static function truncate(string $text, int $length = 50, string $suffix = '...'): string
{
if (mb_strlen($text) <= $length) {
return htmlspecialchars($text);
}
return htmlspecialchars(mb_substr($text, 0, $length)) . $suffix;
}
/**
* Format bytes to human readable size
*/
public static function formatBytes(int $bytes, int $precision = 2): string
{
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
$bytes /= 1024;
}
return round($bytes, $precision) . ' ' . $units[$i];
}
/**
* Generate breadcrumb navigation
*/
public static function breadcrumbs(array $items): string
{
$html = '<nav class="flex mb-4" aria-label="Breadcrumb"><ol class="inline-flex items-center space-x-1 md:space-x-3">';
foreach ($items as $index => $item) {
$isLast = $index === count($items) - 1;
if ($index > 0) {
$html .= '<li><div class="flex items-center"><i class="fas fa-chevron-right text-gray-400 text-xs"></i></div></li>';
}
$html .= '<li class="inline-flex items-center">';
if (!$isLast && isset($item['url'])) {
$html .= '<a href="' . htmlspecialchars($item['url']) . '" class="inline-flex items-center text-sm font-medium text-gray-700 hover:text-primary">';
if (isset($item['icon'])) {
$html .= '<i class="' . htmlspecialchars($item['icon']) . ' mr-2 text-xs"></i>';
}
$html .= htmlspecialchars($item['label']) . '</a>';
} else {
$html .= '<span class="text-sm font-medium text-gray-500">';
if (isset($item['icon'])) {
$html .= '<i class="' . htmlspecialchars($item['icon']) . ' mr-2 text-xs"></i>';
}
$html .= htmlspecialchars($item['label']) . '</span>';
}
$html .= '</li>';
}
$html .= '</ol></nav>';
return $html;
}
/**
* Get the PHP max upload size from ini settings.
* Returns the lower of upload_max_filesize and post_max_size as a human-readable string.
*
* @return string Human-readable size (e.g. "128 MB")
*/
public static function getMaxUploadSize(): string
{
$phpUploadMax = self::parseIniSize(ini_get('upload_max_filesize') ?: '2M');
$phpPostMax = self::parseIniSize(ini_get('post_max_size') ?: '8M');
$phpLimit = min($phpUploadMax, $phpPostMax);
return self::formatBytes($phpLimit, 0);
}
/**
* Parse a PHP ini size value (e.g. "2M", "128K", "1G") into bytes.
*/
private static function parseIniSize(string $size): int
{
$value = (int) $size;
$unit = strtolower(substr(trim($size), -1));
return match ($unit) {
'g' => $value * 1073741824,
'm' => $value * 1048576,
'k' => $value * 1024,
default => $value,
};
}
/**
* Generate alert message HTML
*/
public static function alert(string $type, string $message): string
{
$classes = [
'success' => 'bg-green-50 border-green-200 text-green-800',
'error' => 'bg-red-50 border-red-200 text-red-800',
'warning' => 'bg-orange-50 border-orange-200 text-orange-800',
'info' => 'bg-blue-50 border-blue-200 text-blue-800',
];
$icons = [
'success' => 'fa-check-circle',
'error' => 'fa-exclamation-circle',
'warning' => 'fa-exclamation-triangle',
'info' => 'fa-info-circle',
];
$class = $classes[$type] ?? $classes['info'];
$icon = $icons[$type] ?? $icons['info'];
return '<div class="border rounded-lg p-4 ' . $class . ' flex items-start">
<i class="fas ' . $icon . ' mr-3 mt-0.5"></i>
<div class="flex-1">' . htmlspecialchars($message) . '</div>
</div>';
}
}