Laravel 11, Vuexy Admin 10.3, by admin@koneko.mx
This commit is contained in:
215
modules/Admin/App/Services/AdminSettingsService.php
Normal file
215
modules/Admin/App/Services/AdminSettingsService.php
Normal file
@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Admin\App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Intervention\Image\ImageManager;
|
||||
use Modules\Admin\App\Models\Setting;
|
||||
|
||||
class AdminSettingsService
|
||||
{
|
||||
private $driver;
|
||||
private $imageDisk = 'public';
|
||||
private $favicon_basePath = 'favicon/';
|
||||
private $image_logo_basePath = 'images/logo/';
|
||||
|
||||
private $faviconsSizes = [
|
||||
'180x180' => [180, 180],
|
||||
'192x192' => [192, 192],
|
||||
'152x152' => [152, 152],
|
||||
'120x120' => [120, 120],
|
||||
'76x76' => [76, 76],
|
||||
'16x16' => [16, 16],
|
||||
];
|
||||
|
||||
private $imageLogoMaxPixels1 = 22500; // Primera versión (px^2)
|
||||
private $imageLogoMaxPixels2 = 75625; // Segunda versión (px^2)
|
||||
private $imageLogoMaxPixels3 = 262144; // Tercera versión (px^2)
|
||||
private $imageLogoMaxPixels4 = 230400; // Tercera versión (px^2) en Base64
|
||||
|
||||
protected $cacheTTL = 60 * 24 * 30; // 30 días en minutos
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->driver = config('image.driver', 'gd');
|
||||
}
|
||||
|
||||
public function updateSetting(string $key, string $value): bool
|
||||
{
|
||||
$setting = Setting::updateOrCreate(
|
||||
['key' => $key],
|
||||
['value' => trim($value)]
|
||||
);
|
||||
|
||||
return $setting->save();
|
||||
}
|
||||
|
||||
public function processAndSaveFavicon($image): void
|
||||
{
|
||||
Storage::makeDirectory($this->imageDisk . '/' . $this->favicon_basePath);
|
||||
|
||||
// Eliminar favicons antiguos
|
||||
$this->deleteOldFavicons();
|
||||
|
||||
// Guardar imagen original
|
||||
$imageManager = new ImageManager($this->driver);
|
||||
|
||||
$imageName = uniqid('admin_favicon_');
|
||||
|
||||
$image = $imageManager->read($image->getRealPath());
|
||||
|
||||
foreach ($this->faviconsSizes as $size => [$width, $height]) {
|
||||
$resizedPath = $this->favicon_basePath . $imageName . "_{$size}.png";
|
||||
|
||||
$image->cover($width, $height);
|
||||
|
||||
Storage::disk($this->imageDisk)->put($resizedPath, $image->toPng(indexed: true));
|
||||
}
|
||||
|
||||
$this->updateSetting('admin_favicon_ns', $this->favicon_basePath . $imageName);
|
||||
}
|
||||
|
||||
protected function deleteOldFavicons(): void
|
||||
{
|
||||
// Obtener el favicon actual desde la base de datos
|
||||
$currentFavicon = Setting::where('key', 'admin_favicon_ns')->value('value');
|
||||
|
||||
if ($currentFavicon) {
|
||||
$filePaths = [
|
||||
$this->imageDisk . '/' . $currentFavicon,
|
||||
$this->imageDisk . '/' . $currentFavicon . '_16x16.png',
|
||||
$this->imageDisk . '/' . $currentFavicon . '_76x76.png',
|
||||
$this->imageDisk . '/' . $currentFavicon . '_120x120.png',
|
||||
$this->imageDisk . '/' . $currentFavicon . '_152x152.png',
|
||||
$this->imageDisk . '/' . $currentFavicon . '_180x180.png',
|
||||
$this->imageDisk . '/' . $currentFavicon . '_192x192.png',
|
||||
];
|
||||
|
||||
foreach ($filePaths as $filePath) {
|
||||
if (Storage::exists($filePath)) {
|
||||
Storage::delete($filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function processAndSaveImageLogo($image, string $type = ''): void
|
||||
{
|
||||
// Crear directorio si no existe
|
||||
Storage::makeDirectory($this->imageDisk . '/' . $this->image_logo_basePath);
|
||||
|
||||
// Eliminar imágenes antiguas
|
||||
$this->deleteOldImageWebapp($type);
|
||||
|
||||
// Leer imagen original
|
||||
$imageManager = new ImageManager($this->driver);
|
||||
$image = $imageManager->read($image->getRealPath());
|
||||
|
||||
// Generar tres versiones con diferentes áreas máximas
|
||||
$this->generateAndSaveImage($image, $type, $this->imageLogoMaxPixels1, 'small'); // Versión 1
|
||||
$this->generateAndSaveImage($image, $type, $this->imageLogoMaxPixels2, 'medium'); // Versión 2
|
||||
$this->generateAndSaveImage($image, $type, $this->imageLogoMaxPixels3); // Versión 3
|
||||
$this->generateAndSaveImageAsBase64($image, $type, $this->imageLogoMaxPixels4); // Versión 3
|
||||
}
|
||||
|
||||
private function generateAndSaveImage($image, string $type, int $maxPixels, string $suffix = ''): void
|
||||
{
|
||||
$imageClone = clone $image;
|
||||
|
||||
// Escalar imagen conservando aspecto
|
||||
$this->resizeImageToMaxPixels($imageClone, $maxPixels);
|
||||
|
||||
$imageName = 'admin_image_logo' . ($suffix ? '_' . $suffix : '') . ($type == 'dark' ? '_dark' : '');
|
||||
|
||||
// Generar nombre y ruta
|
||||
$imageNameUid = uniqid($imageName . '_', ".png");
|
||||
$resizedPath = $this->image_logo_basePath . $imageNameUid;
|
||||
|
||||
// Guardar imagen en PNG
|
||||
Storage::disk($this->imageDisk)->put($resizedPath, $imageClone->toPng(indexed: true));
|
||||
|
||||
// Actualizar configuración
|
||||
$this->updateSetting($imageName, $resizedPath);
|
||||
}
|
||||
|
||||
private function resizeImageToMaxPixels($image, int $maxPixels)
|
||||
{
|
||||
// Obtener dimensiones originales de la imagen
|
||||
$originalWidth = $image->width(); // Método para obtener el ancho
|
||||
$originalHeight = $image->height(); // Método para obtener el alto
|
||||
|
||||
// Calcular el aspecto
|
||||
$aspectRatio = $originalWidth / $originalHeight;
|
||||
|
||||
// Calcular dimensiones redimensionadas conservando aspecto
|
||||
if ($aspectRatio > 1) { // Ancho es dominante
|
||||
$newWidth = sqrt($maxPixels * $aspectRatio);
|
||||
$newHeight = $newWidth / $aspectRatio;
|
||||
} else { // Alto es dominante
|
||||
$newHeight = sqrt($maxPixels / $aspectRatio);
|
||||
$newWidth = $newHeight * $aspectRatio;
|
||||
}
|
||||
|
||||
// Redimensionar la imagen
|
||||
$image->resize(
|
||||
round($newWidth), // Redondear para evitar problemas con números decimales
|
||||
round($newHeight),
|
||||
function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
$constraint->upsize();
|
||||
}
|
||||
);
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
|
||||
private function generateAndSaveImageAsBase64($image, string $type, int $maxPixels): void
|
||||
{
|
||||
$imageClone = clone $image;
|
||||
|
||||
// Redimensionar imagen conservando el aspecto
|
||||
$this->resizeImageToMaxPixels($imageClone, $maxPixels);
|
||||
|
||||
// Convertir a Base64
|
||||
$base64Image = (string) $imageClone->toJpg(40)->toDataUri();
|
||||
|
||||
// Guardar como configuración
|
||||
$this->updateSetting(
|
||||
"admin_image_logo_base64" . ($type === 'dark' ? '_dark' : ''),
|
||||
$base64Image // Ya incluye "data:image/png;base64,"
|
||||
);
|
||||
}
|
||||
|
||||
protected function deleteOldImageWebapp(string $type = ''): void
|
||||
{
|
||||
// Determinar prefijo según el tipo (normal o dark)
|
||||
$suffix = $type === 'dark' ? '_dark' : '';
|
||||
|
||||
// Claves relacionadas con las imágenes que queremos limpiar
|
||||
$imageKeys = [
|
||||
"admin_image_logo{$suffix}",
|
||||
"admin_image_logo_small{$suffix}",
|
||||
"admin_image_logo_medium{$suffix}",
|
||||
];
|
||||
|
||||
// Recuperar las imágenes actuales en una sola consulta
|
||||
$settings = Setting::whereIn('key', $imageKeys)->pluck('value', 'key');
|
||||
|
||||
foreach ($imageKeys as $key) {
|
||||
// Obtener la imagen correspondiente
|
||||
$currentImage = $settings[$key] ?? null;
|
||||
|
||||
if ($currentImage) {
|
||||
// Construir la ruta del archivo y eliminarlo si existe
|
||||
$filePath = $this->imageDisk . '/' . $currentImage;
|
||||
if (Storage::exists($filePath)) {
|
||||
Storage::delete($filePath);
|
||||
}
|
||||
|
||||
// Eliminar la configuración de la base de datos
|
||||
Setting::where('key', $key)->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
129
modules/Admin/App/Services/AdminTemplateService.php
Normal file
129
modules/Admin/App/Services/AdminTemplateService.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Admin\App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Modules\Admin\App\Models\Setting;
|
||||
|
||||
class AdminTemplateService
|
||||
{
|
||||
protected $cacheTTL = 60 * 24 * 30; // 30 días en minutos
|
||||
|
||||
public function updateSetting(string $key, string $value): bool
|
||||
{
|
||||
$setting = Setting::updateOrCreate(
|
||||
['key' => $key],
|
||||
['value' => trim($value)]
|
||||
);
|
||||
|
||||
return $setting->save();
|
||||
}
|
||||
|
||||
public function getAdminVars($adminSetting = false)
|
||||
{
|
||||
try {
|
||||
return Cache::remember('admin_settings', $this->cacheTTL, function () use ($adminSetting) {
|
||||
$settings = Setting::global()
|
||||
->where('key', 'LIKE', 'admin_%')
|
||||
->pluck('value', 'key')
|
||||
->toArray();
|
||||
|
||||
$adminSettings = [
|
||||
'title' => $settings['admin_title'] ?? config('_var.appTitle'),
|
||||
'author' => config('_var.author'),
|
||||
'description' => config('_var.description'),
|
||||
'favicon' => $this->getFaviconPaths($settings),
|
||||
'app_name' => $settings['admin_app_name'] ?? config('_var.appName'),
|
||||
'image_logo' => $this->getImageLogoPaths($settings),
|
||||
];
|
||||
|
||||
return $adminSetting
|
||||
? $adminSettings[$adminSetting]
|
||||
: $adminSettings;
|
||||
});
|
||||
} catch (\Exception $e) {
|
||||
echo __METHOD__;
|
||||
echo "<br>" . $e->getMessage() . "<br><br>";
|
||||
die('You must configure the database.');
|
||||
}
|
||||
}
|
||||
|
||||
public function getVuexyCustomizerVars()
|
||||
{
|
||||
// Obtener valores de la base de datos
|
||||
$settings = Setting::global()
|
||||
->where('key', 'LIKE', 'vuexy_%')
|
||||
->pluck('value', 'key')
|
||||
->toArray();
|
||||
|
||||
// Obtener configuraciones predeterminadas
|
||||
$defaultConfig = Config::get('custom.custom', []);
|
||||
|
||||
// Mezclar las configuraciones predeterminadas con las de la base de datos
|
||||
return collect($defaultConfig)
|
||||
->mapWithKeys(function ($defaultValue, $key) use ($settings) {
|
||||
$vuexyKey = 'vuexy_' . $key; // Convertir clave al formato de la base de datos
|
||||
|
||||
// Obtener valor desde la base de datos o usar el predeterminado
|
||||
$value = $settings[$vuexyKey] ?? $defaultValue;
|
||||
|
||||
// Forzar booleanos para claves específicas
|
||||
if (in_array($key, ['displayCustomizer', 'footerFixed', 'menuFixed', 'menuCollapsed', 'showDropdownOnHover'])) {
|
||||
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
|
||||
return [$key => $value];
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene los paths de favicon en distintos tamaños.
|
||||
*/
|
||||
private function getFaviconPaths(array $settings): array
|
||||
{
|
||||
$defaultFavicon = config('_var.appFavicon');
|
||||
$namespace = $settings['admin_favicon_ns'] ?? null;
|
||||
|
||||
return [
|
||||
'namespace' => $namespace,
|
||||
'16x16' => $namespace ? "{$namespace}_16x16.png" : $defaultFavicon,
|
||||
'76x76' => $namespace ? "{$namespace}_76x76.png" : $defaultFavicon,
|
||||
'120x120' => $namespace ? "{$namespace}_120x120.png" : $defaultFavicon,
|
||||
'152x152' => $namespace ? "{$namespace}_152x152.png" : $defaultFavicon,
|
||||
'180x180' => $namespace ? "{$namespace}_180x180.png" : $defaultFavicon,
|
||||
'192x192' => $namespace ? "{$namespace}_192x192.png" : $defaultFavicon,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene los paths de los logos en distintos tamaños.
|
||||
*/
|
||||
private function getImageLogoPaths(array $settings): array
|
||||
{
|
||||
$defaultLogo = config('_var.appLogo');
|
||||
|
||||
return [
|
||||
'small' => $this->getImagePath($settings, 'admin_image_logo_small', $defaultLogo),
|
||||
'medium' => $this->getImagePath($settings, 'admin_image_logo_medium', $defaultLogo),
|
||||
'large' => $this->getImagePath($settings, 'admin_image_logo', $defaultLogo),
|
||||
'small_dark' => $this->getImagePath($settings, 'admin_image_logo_small_dark', $defaultLogo),
|
||||
'medium_dark' => $this->getImagePath($settings, 'admin_image_logo_medium_dark', $defaultLogo),
|
||||
'large_dark' => $this->getImagePath($settings, 'admin_image_logo_dark', $defaultLogo),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene un path de imagen o retorna un valor predeterminado.
|
||||
*/
|
||||
private function getImagePath(array $settings, string $key, string $default): string
|
||||
{
|
||||
return $settings[$key] ?? $default;
|
||||
}
|
||||
|
||||
public static function clearAdminVarsCache()
|
||||
{
|
||||
Cache::forget("admin_settings");
|
||||
}
|
||||
}
|
235
modules/Admin/App/Services/CacheConfigService.php
Normal file
235
modules/Admin/App/Services/CacheConfigService.php
Normal file
@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Admin\App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
class CacheConfigService
|
||||
{
|
||||
public function getConfig(): array
|
||||
{
|
||||
return [
|
||||
'cache' => $this->getCacheConfig(),
|
||||
'session' => $this->getSessionConfig(),
|
||||
'database' => $this->getDatabaseConfig(),
|
||||
'driver' => $this->getDriverVersion(),
|
||||
'memcachedInUse' => $this->isDriverInUse('memcached'),
|
||||
'redisInUse' => $this->isDriverInUse('redis'),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
private function getCacheConfig(): array
|
||||
{
|
||||
$cacheConfig = Config::get('cache');
|
||||
$driver = $cacheConfig['default'];
|
||||
|
||||
switch ($driver) {
|
||||
case 'redis':
|
||||
$connection = config('database.redis.cache');
|
||||
$cacheConfig['host'] = $connection['host'] ?? 'localhost';
|
||||
$cacheConfig['database'] = $connection['database'] ?? 'N/A';
|
||||
break;
|
||||
|
||||
case 'database':
|
||||
$connection = config('database.connections.' . config('cache.stores.database.connection'));
|
||||
$cacheConfig['host'] = $connection['host'] ?? 'localhost';
|
||||
$cacheConfig['database'] = $connection['database'] ?? 'N/A';
|
||||
break;
|
||||
|
||||
case 'memcached':
|
||||
$servers = config('cache.stores.memcached.servers');
|
||||
$cacheConfig['host'] = $servers[0]['host'] ?? 'localhost';
|
||||
$cacheConfig['database'] = 'N/A';
|
||||
break;
|
||||
|
||||
case 'file':
|
||||
$cacheConfig['host'] = storage_path('framework/cache/data');
|
||||
$cacheConfig['database'] = 'N/A';
|
||||
break;
|
||||
|
||||
default:
|
||||
$cacheConfig['host'] = 'N/A';
|
||||
$cacheConfig['database'] = 'N/A';
|
||||
break;
|
||||
}
|
||||
|
||||
return $cacheConfig;
|
||||
}
|
||||
|
||||
private function getSessionConfig(): array
|
||||
{
|
||||
$sessionConfig = Config::get('session');
|
||||
$driver = $sessionConfig['driver'];
|
||||
|
||||
switch ($driver) {
|
||||
case 'redis':
|
||||
$connection = config('database.redis.sessions');
|
||||
$sessionConfig['host'] = $connection['host'] ?? 'localhost';
|
||||
$sessionConfig['database'] = $connection['database'] ?? 'N/A';
|
||||
break;
|
||||
|
||||
case 'database':
|
||||
$connection = config('database.connections.' . $sessionConfig['connection']);
|
||||
$sessionConfig['host'] = $connection['host'] ?? 'localhost';
|
||||
$sessionConfig['database'] = $connection['database'] ?? 'N/A';
|
||||
break;
|
||||
|
||||
case 'memcached':
|
||||
$servers = config('cache.stores.memcached.servers');
|
||||
$sessionConfig['host'] = $servers[0]['host'] ?? 'localhost';
|
||||
$sessionConfig['database'] = 'N/A';
|
||||
break;
|
||||
|
||||
case 'file':
|
||||
$sessionConfig['host'] = storage_path('framework/sessions');
|
||||
$sessionConfig['database'] = 'N/A';
|
||||
break;
|
||||
|
||||
default:
|
||||
$sessionConfig['host'] = 'N/A';
|
||||
$sessionConfig['database'] = 'N/A';
|
||||
break;
|
||||
}
|
||||
|
||||
return $sessionConfig;
|
||||
}
|
||||
|
||||
private function getDatabaseConfig(): array
|
||||
{
|
||||
$databaseConfig = Config::get('database');
|
||||
$connection = $databaseConfig['default'];
|
||||
|
||||
$connectionConfig = config('database.connections.' . $connection);
|
||||
$databaseConfig['host'] = $connectionConfig['host'] ?? 'localhost';
|
||||
$databaseConfig['database'] = $connectionConfig['database'] ?? 'N/A';
|
||||
|
||||
return $databaseConfig;
|
||||
}
|
||||
|
||||
|
||||
private function getDriverVersion(): array
|
||||
{
|
||||
$drivers = [];
|
||||
$defaultDatabaseDriver = config('database.default'); // Obtén el driver predeterminado
|
||||
|
||||
switch ($defaultDatabaseDriver) {
|
||||
case 'mysql':
|
||||
case 'mariadb':
|
||||
$drivers['mysql'] = [
|
||||
'version' => $this->getMySqlVersion(),
|
||||
'details' => config("database.connections.$defaultDatabaseDriver"),
|
||||
];
|
||||
|
||||
$drivers['mariadb'] = $drivers['mysql'];
|
||||
|
||||
case 'pgsql':
|
||||
$drivers['pgsql'] = [
|
||||
'version' => $this->getPgSqlVersion(),
|
||||
'details' => config("database.connections.pgsql"),
|
||||
];
|
||||
break;
|
||||
|
||||
case 'sqlsrv':
|
||||
$drivers['sqlsrv'] = [
|
||||
'version' => $this->getSqlSrvVersion(),
|
||||
'details' => config("database.connections.sqlsrv"),
|
||||
];
|
||||
break;
|
||||
|
||||
default:
|
||||
$drivers['unknown'] = [
|
||||
'version' => 'No disponible',
|
||||
'details' => 'Driver no identificado',
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
// Opcional: Agrega detalles de Redis y Memcached si están en uso
|
||||
if ($this->isDriverInUse('redis')) {
|
||||
$drivers['redis'] = [
|
||||
'version' => $this->getRedisVersion(),
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->isDriverInUse('memcached')) {
|
||||
$drivers['memcached'] = [
|
||||
'version' => $this->getMemcachedVersion(),
|
||||
];
|
||||
}
|
||||
|
||||
return $drivers;
|
||||
}
|
||||
|
||||
private function getMySqlVersion(): string
|
||||
{
|
||||
try {
|
||||
$version = DB::selectOne('SELECT VERSION() as version');
|
||||
return $version->version ?? 'No disponible';
|
||||
} catch (\Exception $e) {
|
||||
return 'Error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private function getPgSqlVersion(): string
|
||||
{
|
||||
try {
|
||||
$version = DB::selectOne("SHOW server_version");
|
||||
return $version->server_version ?? 'No disponible';
|
||||
} catch (\Exception $e) {
|
||||
return 'Error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private function getSqlSrvVersion(): string
|
||||
{
|
||||
try {
|
||||
$version = DB::selectOne("SELECT @@VERSION as version");
|
||||
return $version->version ?? 'No disponible';
|
||||
} catch (\Exception $e) {
|
||||
return 'Error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private function getMemcachedVersion(): string
|
||||
{
|
||||
try {
|
||||
$memcached = new \Memcached();
|
||||
$memcached->addServer(
|
||||
Config::get('cache.stores.memcached.servers.0.host'),
|
||||
Config::get('cache.stores.memcached.servers.0.port')
|
||||
);
|
||||
|
||||
$stats = $memcached->getStats();
|
||||
foreach ($stats as $serverStats) {
|
||||
return $serverStats['version'] ?? 'No disponible';
|
||||
}
|
||||
|
||||
return 'No disponible';
|
||||
} catch (\Exception $e) {
|
||||
return 'Error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private function getRedisVersion(): string
|
||||
{
|
||||
try {
|
||||
$info = Redis::info();
|
||||
return $info['redis_version'] ?? 'No disponible';
|
||||
} catch (\Exception $e) {
|
||||
return 'Error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function isDriverInUse(string $driver): bool
|
||||
{
|
||||
return in_array($driver, [
|
||||
Config::get('cache.default'),
|
||||
Config::get('session.driver'),
|
||||
Config::get('queue.default'),
|
||||
]);
|
||||
}
|
||||
}
|
389
modules/Admin/App/Services/CacheManagerService.php
Normal file
389
modules/Admin/App/Services/CacheManagerService.php
Normal file
@ -0,0 +1,389 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Admin\App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class CacheManagerService
|
||||
{
|
||||
private string $driver;
|
||||
|
||||
public function __construct(string $driver = null)
|
||||
{
|
||||
$this->driver = $driver ?? config('cache.default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene estadísticas de caché para el driver especificado.
|
||||
*/
|
||||
public function getCacheStats(string $driver = null): array
|
||||
{
|
||||
$driver = $driver ?? $this->driver;
|
||||
|
||||
if (!$this->isSupportedDriver($driver)) {
|
||||
return $this->response('warning', 'Driver no soportado o no configurado.');
|
||||
}
|
||||
|
||||
try {
|
||||
return match ($driver) {
|
||||
'database' => $this->_getDatabaseStats(),
|
||||
'file' => $this->_getFilecacheStats(),
|
||||
'redis' => $this->_getRedisStats(),
|
||||
'memcached' => $this->_getMemcachedStats(),
|
||||
default => $this->response('info', 'No hay estadísticas disponibles para este driver.'),
|
||||
};
|
||||
} catch (\Exception $e) {
|
||||
return $this->response('danger', 'Error al obtener estadísticas: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function clearCache(string $driver = null): array
|
||||
{
|
||||
$driver = $driver ?? $this->driver;
|
||||
|
||||
if (!$this->isSupportedDriver($driver)) {
|
||||
return $this->response('warning', 'Driver no soportado o no configurado.');
|
||||
}
|
||||
|
||||
try {
|
||||
switch ($driver) {
|
||||
case 'redis':
|
||||
$keysCleared = $this->clearRedisCache();
|
||||
|
||||
return $keysCleared
|
||||
? $this->response('warning', 'Se ha purgado toda la caché de Redis.')
|
||||
: $this->response('info', 'No se encontraron claves en Redis para eliminar.');
|
||||
|
||||
case 'memcached':
|
||||
$keysCleared = $this->clearMemcachedCache();
|
||||
|
||||
return $keysCleared
|
||||
? $this->response('warning', 'Se ha purgado toda la caché de Memcached.')
|
||||
: $this->response('info', 'No se encontraron claves en Memcached para eliminar.');
|
||||
|
||||
case 'database':
|
||||
$rowsDeleted = $this->clearDatabaseCache();
|
||||
|
||||
return $rowsDeleted
|
||||
? $this->response('warning', 'Se ha purgado toda la caché almacenada en la base de datos.')
|
||||
: $this->response('info', 'No se encontraron registros en la caché de la base de datos.');
|
||||
|
||||
case 'file':
|
||||
$filesDeleted = $this->clearFilecache();
|
||||
|
||||
return $filesDeleted
|
||||
? $this->response('warning', 'Se ha purgado toda la caché de archivos.')
|
||||
: $this->response('info', 'No se encontraron archivos en la caché para eliminar.');
|
||||
|
||||
default:
|
||||
Cache::flush();
|
||||
|
||||
return $this->response('warning', 'Caché purgada.');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->response('danger', 'Error al limpiar la caché: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function getRedisStats()
|
||||
{
|
||||
try {
|
||||
if (!Redis::ping()) {
|
||||
return $this->response('warning', 'No se puede conectar con el servidor Redis.');
|
||||
}
|
||||
|
||||
$info = Redis::info();
|
||||
|
||||
$databases = $this->getRedisDatabases();
|
||||
|
||||
$redisInfo = [
|
||||
'server' => config('database.redis.default.host'),
|
||||
'redis_version' => $info['redis_version'] ?? 'N/A',
|
||||
'os' => $info['os'] ?? 'N/A',
|
||||
'tcp_port' => $info['tcp_port'] ?? 'N/A',
|
||||
'connected_clients' => $info['connected_clients'] ?? 'N/A',
|
||||
'blocked_clients' => $info['blocked_clients'] ?? 'N/A',
|
||||
'maxmemory' => $info['maxmemory'] ?? 0,
|
||||
'used_memory_human' => $info['used_memory_human'] ?? 'N/A',
|
||||
'used_memory_peak' => $info['used_memory_peak'] ?? 'N/A',
|
||||
'used_memory_peak_human' => $info['used_memory_peak_human'] ?? 'N/A',
|
||||
'total_system_memory' => $info['total_system_memory'] ?? 0,
|
||||
'total_system_memory_human' => $info['total_system_memory_human'] ?? 'N/A',
|
||||
'maxmemory_human' => $info['maxmemory_human'] !== '0B' ? $info['maxmemory_human'] : 'Sin Límite',
|
||||
'total_connections_received' => number_format($info['total_connections_received']) ?? 'N/A',
|
||||
'total_commands_processed' => number_format($info['total_commands_processed']) ?? 'N/A',
|
||||
'maxmemory_policy' => $info['maxmemory_policy'] ?? 'N/A',
|
||||
'role' => $info['role'] ?? 'N/A',
|
||||
'cache_database' => '',
|
||||
'sessions_database' => '',
|
||||
'general_database' => ',',
|
||||
'keys' => $databases['total_keys'],
|
||||
'used_memory' => $info['used_memory'] ?? 0,
|
||||
'uptime' => gmdate('H\h i\m s\s', $info['uptime_in_seconds'] ?? 0),
|
||||
'databases' => $databases,
|
||||
];
|
||||
|
||||
return $this->response('success', 'Se a recargado las estadísticas de Redis.', ['info' => $redisInfo]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->response('danger', 'Error al conectar con el servidor Redis: ' . Redis::getLastError());
|
||||
}
|
||||
}
|
||||
|
||||
public function getMemcachedStats()
|
||||
{
|
||||
try {
|
||||
$memcachedStats = [];
|
||||
|
||||
// Crear instancia del cliente Memcached
|
||||
$memcached = new \Memcached();
|
||||
$memcached->addServer(config('memcached.host'), config('memcached.port'));
|
||||
|
||||
// Obtener estadísticas del servidor
|
||||
$stats = $memcached->getStats();
|
||||
|
||||
foreach ($stats as $server => $data) {
|
||||
$server = explode(':', $server);
|
||||
|
||||
$memcachedStats[] = [
|
||||
'server' => $server[0],
|
||||
'tcp_port' => $server[1],
|
||||
'uptime' => $data['uptime'] ?? 'N/A',
|
||||
'version' => $data['version'] ?? 'N/A',
|
||||
'libevent' => $data['libevent'] ?? 'N/A',
|
||||
'max_connections' => $data['max_connections'] ?? 0,
|
||||
'total_connections' => $data['total_connections'] ?? 0,
|
||||
'rejected_connections' => $data['rejected_connections'] ?? 0,
|
||||
'curr_items' => $data['curr_items'] ?? 0, // Claves almacenadas
|
||||
'bytes' => $data['bytes'] ?? 0, // Memoria usada
|
||||
'limit_maxbytes' => $data['limit_maxbytes'] ?? 0, // Memoria máxima
|
||||
'cmd_get' => $data['cmd_get'] ?? 0, // Comandos GET ejecutados
|
||||
'cmd_set' => $data['cmd_set'] ?? 0, // Comandos SET ejecutados
|
||||
'get_hits' => $data['get_hits'] ?? 0, // GET exitosos
|
||||
'get_misses' => $data['get_misses'] ?? 0, // GET fallidos
|
||||
'evictions' => $data['evictions'] ?? 0, // Claves expulsadas
|
||||
'bytes_read' => $data['bytes_read'] ?? 0, // Bytes leídos
|
||||
'bytes_written' => $data['bytes_written'] ?? 0, // Bytes escritos
|
||||
'total_items' => $data['total_items'] ?? 0,
|
||||
];
|
||||
}
|
||||
|
||||
return $this->response('success', 'Se a recargado las estadísticas de Memcached.', ['info' => $memcachedStats]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->response('danger', 'Error al conectar con el servidor Memcached: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtiene estadísticas para caché en base de datos.
|
||||
*/
|
||||
private function _getDatabaseStats(): array
|
||||
{
|
||||
try {
|
||||
$recordCount = DB::table('cache')->count();
|
||||
$tableInfo = DB::select("SHOW TABLE STATUS WHERE Name = 'cache'");
|
||||
|
||||
$memory_usage = isset($tableInfo[0]) ? $this->formatBytes($tableInfo[0]->Data_length + $tableInfo[0]->Index_length) : 'N/A';
|
||||
|
||||
return $this->response('success', 'Se ha recargado la información de la caché de base de datos.', ['item_count' => $recordCount, 'memory_usage' => $memory_usage]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->response('danger', 'Error al obtener estadísticas de la base de datos: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene estadísticas para caché en archivos.
|
||||
*/
|
||||
private function _getFilecacheStats(): array
|
||||
{
|
||||
try {
|
||||
$cachePath = config('cache.stores.file.path');
|
||||
$files = glob($cachePath . '/*');
|
||||
|
||||
$memory_usage = $this->formatBytes(array_sum(array_map('filesize', $files)));
|
||||
|
||||
return $this->response('success', 'Se ha recargado la información de la caché de archivos.', ['item_count' => count($files), 'memory_usage' => $memory_usage]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->response('danger', 'Error al obtener estadísticas de archivos: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function _getRedisStats()
|
||||
{
|
||||
try {
|
||||
$prefix = config('cache.prefix'); // Asegúrate de agregar el sufijo correcto si es necesario
|
||||
|
||||
$info = Redis::info();
|
||||
$keys = Redis::connection('cache')->keys($prefix . '*');
|
||||
|
||||
$memory_usage = $this->formatBytes($info['used_memory'] ?? 0);
|
||||
|
||||
return $this->response('success', 'Se ha recargado la información de la caché de Redis.', ['item_count' => count($keys), 'memory_usage' => $memory_usage]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->response('danger', 'Error al obtener estadísticas de Redis: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function _getMemcachedStats(): array
|
||||
{
|
||||
try {
|
||||
// Obtener estadísticas generales del servidor
|
||||
$stats = Cache::getStore()->getMemcached()->getStats();
|
||||
|
||||
if (empty($stats)) {
|
||||
return $this->response('error', 'No se pudieron obtener las estadísticas del servidor Memcached.', ['item_count' => 0, 'memory_usage' => 0]);
|
||||
}
|
||||
|
||||
// Usar el primer servidor configurado (en la mayoría de los casos hay uno)
|
||||
$serverStats = array_shift($stats);
|
||||
|
||||
return $this->response(
|
||||
'success',
|
||||
'Estadísticas del servidor Memcached obtenidas correctamente.',
|
||||
[
|
||||
'item_count' => $serverStats['curr_items'] ?? 0, // Número total de claves
|
||||
'memory_usage' => $this->formatBytes($serverStats['bytes'] ?? 0), // Memoria usada
|
||||
'max_memory' => $this->formatBytes($serverStats['limit_maxbytes'] ?? 0), // Memoria máxima asignada
|
||||
]
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
return $this->response('danger', 'Error al obtener estadísticas de Memcached: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function getRedisDatabases(): array
|
||||
{
|
||||
// Verificar si Redis está en uso
|
||||
$isRedisUsed = collect([
|
||||
config('cache.default'),
|
||||
config('session.driver'),
|
||||
config('queue.default'),
|
||||
])->contains('redis');
|
||||
|
||||
if (!$isRedisUsed) {
|
||||
return []; // Si Redis no está en uso, devolver un arreglo vacío
|
||||
}
|
||||
|
||||
// Configuraciones de bases de datos de Redis según su uso
|
||||
$databases = [
|
||||
'default' => config('database.redis.default.database', 0), // REDIS_DB
|
||||
'cache' => config('database.redis.cache.database', 0), // REDIS_CACHE_DB
|
||||
'sessions' => config('database.redis.sessions.database', 0), // REDIS_SESSION_DB
|
||||
];
|
||||
|
||||
$result = [];
|
||||
$totalKeys = 0;
|
||||
|
||||
// Recorrer solo las bases configuradas y activas
|
||||
foreach ($databases as $type => $db) {
|
||||
Redis::select($db); // Seleccionar la base de datos
|
||||
|
||||
$keys = Redis::dbsize(); // Contar las claves en la base
|
||||
|
||||
if ($keys > 0) {
|
||||
$result[$type] = [
|
||||
'database' => $db,
|
||||
'keys' => $keys,
|
||||
];
|
||||
|
||||
$totalKeys += $keys;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($result)) {
|
||||
$result['total_keys'] = $totalKeys;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
private function clearDatabaseCache(): bool
|
||||
{
|
||||
$count = DB::table(config('cache.stores.database.table'))->count();
|
||||
|
||||
if ($count > 0) {
|
||||
DB::table(config('cache.stores.database.table'))->truncate();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function clearFilecache(): bool
|
||||
{
|
||||
$cachePath = config('cache.stores.file.path');
|
||||
$files = glob($cachePath . '/*');
|
||||
|
||||
if (!empty($files)) {
|
||||
File::deleteDirectory($cachePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function clearRedisCache(): bool
|
||||
{
|
||||
$prefix = config('cache.prefix', '');
|
||||
$keys = Redis::connection('cache')->keys($prefix . '*');
|
||||
|
||||
if (!empty($keys)) {
|
||||
Redis::connection('cache')->flushdb();
|
||||
|
||||
// Simulate cache clearing delay
|
||||
sleep(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function clearMemcachedCache(): bool
|
||||
{
|
||||
// Obtener el cliente Memcached directamente
|
||||
$memcached = Cache::store('memcached')->getStore()->getMemcached();
|
||||
|
||||
// Ejecutar flush para eliminar todo
|
||||
if ($memcached->flush()) {
|
||||
// Simulate cache clearing delay
|
||||
sleep(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verifica si un driver es soportado.
|
||||
*/
|
||||
private function isSupportedDriver(string $driver): bool
|
||||
{
|
||||
return in_array($driver, ['redis', 'memcached', 'database', 'file']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convierte bytes en un formato legible.
|
||||
*/
|
||||
private function formatBytes($bytes)
|
||||
{
|
||||
$sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
$factor = floor((strlen($bytes) - 1) / 3);
|
||||
|
||||
return sprintf('%.2f', $bytes / pow(1024, $factor)) . ' ' . $sizes[$factor];
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera una respuesta estandarizada.
|
||||
*/
|
||||
private function response(string $status, string $message, array $data = []): array
|
||||
{
|
||||
return array_merge(compact('status', 'message'), $data);
|
||||
}
|
||||
}
|
244
modules/Admin/App/Services/GlobalSettingsService.php
Normal file
244
modules/Admin/App/Services/GlobalSettingsService.php
Normal file
@ -0,0 +1,244 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Admin\App\Services;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Modules\Admin\App\Models\Setting;
|
||||
|
||||
class GlobalSettingsService
|
||||
{
|
||||
/**
|
||||
* Tiempo de vida del caché en minutos (30 días).
|
||||
*/
|
||||
private $cacheTTL = 60 * 24 * 30;
|
||||
|
||||
/**
|
||||
* Actualiza o crea una configuración.
|
||||
*/
|
||||
public function updateSetting(string $key, string $value): bool
|
||||
{
|
||||
$setting = Setting::updateOrCreate(
|
||||
['key' => $key],
|
||||
['value' => trim($value)]
|
||||
);
|
||||
|
||||
return $setting->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Carga y sobrescribe las configuraciones del sistema.
|
||||
*/
|
||||
public function loadSystemConfig(): void
|
||||
{
|
||||
try {
|
||||
$config = Cache::remember('global_system_config', $this->cacheTTL, function () {
|
||||
$settings = Setting::global()
|
||||
->where('key', 'LIKE', 'config.%')
|
||||
->pluck('value', 'key')
|
||||
->toArray();
|
||||
|
||||
return [
|
||||
'servicesFacebook' => $this->buildServiceConfig($settings, 'config.services.facebook.', 'services.facebook'),
|
||||
'servicesGoogle' => $this->buildServiceConfig($settings, 'config.services.google.', 'services.google'),
|
||||
'custom' => $this->buildVuexyCustomConfig($settings),
|
||||
];
|
||||
});
|
||||
|
||||
Config::set('services.facebook', $config['servicesFacebook']);
|
||||
Config::set('services.google', $config['servicesGoogle']);
|
||||
Config::set('custom', $config['custom']);
|
||||
} catch (\Exception $e) {
|
||||
echo __METHOD__;
|
||||
echo "<br>" . $e->getMessage() . "<br><br>";
|
||||
die('You must configure the database.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifica si un bloque de configuraciones está presente.
|
||||
*/
|
||||
protected function hasBlockConfig(array $settings, string $blockPrefix): bool
|
||||
{
|
||||
return array_key_exists($blockPrefix, array_filter($settings, fn($key) => str_starts_with($key, $blockPrefix), ARRAY_FILTER_USE_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construye la configuración de un servicio (Facebook, Google, etc.).
|
||||
*/
|
||||
protected function buildServiceConfig(array $settings, string $blockPrefix, string $defaultConfigKey): array
|
||||
{
|
||||
if (!$this->hasBlockConfig($settings, $blockPrefix)) {
|
||||
return config($defaultConfigKey);
|
||||
}
|
||||
|
||||
return [
|
||||
'client_id' => $settings["{$blockPrefix}client_id"] ?? '',
|
||||
'client_secret' => $settings["{$blockPrefix}client_secret"] ?? '',
|
||||
'redirect' => $settings["{$blockPrefix}redirect"] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Construye la configuración personalizada de Vuexy.
|
||||
*/
|
||||
protected function buildVuexyCustomConfig(array $settings): array
|
||||
{
|
||||
// Configuración predeterminada del sistema
|
||||
$defaultCustomConfig = config('custom', []);
|
||||
|
||||
// Convertimos las claves planas a un array multidimensional
|
||||
$settingsNested = Arr::undot($settings);
|
||||
|
||||
// Navegamos hasta la parte relevante del array desanidado
|
||||
$customSettings = $settingsNested['config']['custom'] ?? [];
|
||||
|
||||
// Fusionamos la configuración predeterminada con los valores del sistema
|
||||
$mergedConfig = array_replace_recursive($defaultCustomConfig, $customSettings);
|
||||
|
||||
// Normalizamos los valores booleanos
|
||||
return $this->normalizeBooleanFields($mergedConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normaliza los campos booleanos.
|
||||
*/
|
||||
protected function normalizeBooleanFields(array $config): array
|
||||
{
|
||||
$booleanFields = [
|
||||
'myRTLSupport',
|
||||
'myRTLMode',
|
||||
'hasCustomizer',
|
||||
'displayCustomizer',
|
||||
'footerFixed',
|
||||
'menuFixed',
|
||||
'menuCollapsed',
|
||||
'showDropdownOnHover',
|
||||
];
|
||||
|
||||
foreach ($booleanFields as $field) {
|
||||
if (isset($config['custom'][$field])) {
|
||||
$config['custom'][$field] = (bool) $config['custom'][$field];
|
||||
}
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limpia el caché de la configuración del sistema.
|
||||
*/
|
||||
public static function clearSystemConfigCache(): void
|
||||
{
|
||||
Cache::forget('global_system_config');
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina las claves config.custom.* y limpia global_system_config
|
||||
*/
|
||||
public static function clearVuexyCustomConfig(): void
|
||||
{
|
||||
Setting::where('key', 'LIKE', 'config.custom.%')->delete();
|
||||
Cache::forget('global_system_config');
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene y sobrescribe la configuración de correo electrónico.
|
||||
*/
|
||||
public function getMailSystemConfig(): array
|
||||
{
|
||||
return Cache::remember('mail_system_config', $this->cacheTTL, function () {
|
||||
$settings = Setting::global()
|
||||
->where('key', 'LIKE', 'mail.%')
|
||||
->pluck('value', 'key')
|
||||
->toArray();
|
||||
|
||||
$defaultMailersSmtpVars = config('mail.mailers.smtp');
|
||||
|
||||
return [
|
||||
'mailers' => [
|
||||
'smtp' => array_merge($defaultMailersSmtpVars, [
|
||||
'url' => $settings['mail.mailers.smtp.url'] ?? $defaultMailersSmtpVars['url'],
|
||||
'host' => $settings['mail.mailers.smtp.host'] ?? $defaultMailersSmtpVars['host'],
|
||||
'port' => $settings['mail.mailers.smtp.port'] ?? $defaultMailersSmtpVars['port'],
|
||||
'encryption' => $settings['mail.mailers.smtp.encryption'] ?? $defaultMailersSmtpVars['encryption'],
|
||||
'username' => $settings['mail.mailers.smtp.username'] ?? $defaultMailersSmtpVars['username'],
|
||||
'password' => isset($settings['mail.mailers.smtp.password']) && !empty($settings['mail.mailers.smtp.password'])
|
||||
? Crypt::decryptString($settings['mail.mailers.smtp.password'])
|
||||
: $defaultMailersSmtpVars['password'],
|
||||
'timeout' => $settings['mail.mailers.smtp.timeout'] ?? $defaultMailersSmtpVars['timeout'],
|
||||
]),
|
||||
],
|
||||
'from' => [
|
||||
'address' => $settings['mail.from.address'] ?? config('mail.from.address'),
|
||||
'name' => $settings['mail.from.name'] ?? config('mail.from.name'),
|
||||
],
|
||||
'reply_to' => [
|
||||
'method' => $settings['mail.reply_to.method'] ?? config('mail.reply_to.method'),
|
||||
'email' => $settings['mail.reply_to.email'] ?? config('mail.reply_to.email'),
|
||||
'name' => $settings['mail.reply_to.name'] ?? config('mail.reply_to.name'),
|
||||
],
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Limpia el caché de la configuración de correo electrónico.
|
||||
*/
|
||||
public static function clearMailSystemConfigCache(): void
|
||||
{
|
||||
Cache::forget('mail_system_config');
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
protected function buildFortifyFeatures(array $settings): array
|
||||
{
|
||||
return array_filter([
|
||||
!empty($settings['config.fortify.features.registration']) && $settings['config.fortify.features.registration'] == 1
|
||||
? \Laravel\Fortify\Features::registration()
|
||||
: null,
|
||||
|
||||
!empty($settings['config.fortify.features.resetPasswords']) && $settings['config.fortify.features.resetPasswords'] == 1
|
||||
? \Laravel\Fortify\Features::resetPasswords()
|
||||
: null,
|
||||
|
||||
!empty($settings['config.fortify.features.emailVerification']) && $settings['config.fortify.features.emailVerification'] == 1
|
||||
? \Laravel\Fortify\Features::emailVerification()
|
||||
: null,
|
||||
|
||||
!empty($settings['config.fortify.features.updateProfileInformation']) && $settings['config.fortify.features.updateProfileInformation'] == 1
|
||||
? \Laravel\Fortify\Features::updateProfileInformation()
|
||||
: null,
|
||||
|
||||
!empty($settings['config.fortify.features.updatePasswords']) && $settings['config.fortify.features.updatePasswords'] == 1
|
||||
? \Laravel\Fortify\Features::updatePasswords()
|
||||
: null,
|
||||
|
||||
!empty($settings['config.fortify.features.twoFactorAuthentication.confirm']) && $settings['config.fortify.features.twoFactorAuthentication.confirm'] == 1
|
||||
? \Laravel\Fortify\Features::twoFactorAuthentication([
|
||||
'confirm' => true,
|
||||
'confirmPassword' => !empty($settings['config.fortify.features.twoFactorAuthentication.confirmPassword'])
|
||||
&& $settings['config.fortify.features.twoFactorAuthentication.confirmPassword'] == 1,
|
||||
'window' => $settings['config.fortify.features.twoFactorAuthentication.window'] ?? 1,
|
||||
])
|
||||
: null,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function loadUserSettings()
|
||||
{
|
||||
if (Auth::check()) {
|
||||
$userId = Auth::id();
|
||||
// Cargar configuraciones del usuario desde la caché
|
||||
return Cache::remember("user_settings_{$userId}", $this->cacheTTL, function () use ($userId) {
|
||||
return \App\Models\Setting::forUser($userId)->pluck('value', 'key')->toArray();
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
*/
|
||||
}
|
153
modules/Admin/App/Services/SessionManagerService.php
Normal file
153
modules/Admin/App/Services/SessionManagerService.php
Normal file
@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Admin\App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
class SessionManagerService
|
||||
{
|
||||
private string $driver;
|
||||
|
||||
public function __construct(string $driver = null)
|
||||
{
|
||||
$this->driver = $driver ?? config('session.driver');
|
||||
}
|
||||
|
||||
public function getSessionStats(string $driver = null): array
|
||||
{
|
||||
$driver = $driver ?? $this->driver;
|
||||
|
||||
if (!$this->isSupportedDriver($driver))
|
||||
return $this->response('warning', 'Driver no soportado o no configurado.', ['session_count' => 0]);
|
||||
|
||||
try {
|
||||
switch ($driver) {
|
||||
case 'redis':
|
||||
return $this->getRedisStats();
|
||||
|
||||
case 'database':
|
||||
return $this->getDatabaseStats();
|
||||
|
||||
case 'file':
|
||||
return $this->getFileStats();
|
||||
|
||||
default:
|
||||
return $this->response('warning', 'Driver no reconocido.', ['session_count' => 0]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->response('danger', 'Error al obtener estadísticas: ' . $e->getMessage(), ['session_count' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
public function clearSessions(string $driver = null): array
|
||||
{
|
||||
$driver = $driver ?? $this->driver;
|
||||
|
||||
if (!$this->isSupportedDriver($driver)) {
|
||||
return $this->response('warning', 'Driver no soportado o no configurado.');
|
||||
}
|
||||
|
||||
try {
|
||||
switch ($driver) {
|
||||
case 'redis':
|
||||
return $this->clearRedisSessions();
|
||||
|
||||
case 'memcached':
|
||||
Cache::getStore()->flush();
|
||||
return $this->response('success', 'Se eliminó la memoria caché de sesiones en Memcached.');
|
||||
|
||||
case 'database':
|
||||
DB::table('sessions')->truncate();
|
||||
return $this->response('success', 'Se eliminó la memoria caché de sesiones en la base de datos.');
|
||||
|
||||
case 'file':
|
||||
return $this->clearFileSessions();
|
||||
|
||||
default:
|
||||
return $this->response('warning', 'Driver no reconocido.');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->response('danger', 'Error al limpiar las sesiones: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function getRedisStats()
|
||||
{
|
||||
$prefix = config('cache.prefix'); // Asegúrate de agregar el sufijo correcto si es necesario
|
||||
$keys = Redis::connection('sessions')->keys($prefix . '*');
|
||||
|
||||
return $this->response('success', 'Se ha recargado la información de la caché de Redis.', ['session_count' => count($keys)]);
|
||||
}
|
||||
|
||||
private function getDatabaseStats(): array
|
||||
{
|
||||
$sessionCount = DB::table('sessions')->count();
|
||||
|
||||
return $this->response('success', 'Se ha recargado la información de la base de datos.', ['session_count' => $sessionCount]);
|
||||
}
|
||||
|
||||
private function getFileStats(): array
|
||||
{
|
||||
$cachePath = config('session.files');
|
||||
$files = glob($cachePath . '/*');
|
||||
|
||||
return $this->response('success', 'Se ha recargado la información de sesiones de archivos.', ['session_count' => count($files)]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Limpia sesiones en Redis.
|
||||
*/
|
||||
private function clearRedisSessions(): array
|
||||
{
|
||||
$prefix = config('cache.prefix', '');
|
||||
$keys = Redis::connection('sessions')->keys($prefix . '*');
|
||||
|
||||
if (!empty($keys)) {
|
||||
Redis::connection('sessions')->flushdb();
|
||||
|
||||
// Simulate cache clearing delay
|
||||
sleep(1);
|
||||
|
||||
return $this->response('success', 'Se eliminó la memoria caché de sesiones en Redis.');
|
||||
}
|
||||
|
||||
return $this->response('info', 'No se encontraron claves para eliminar en Redis.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Limpia sesiones en archivos.
|
||||
*/
|
||||
private function clearFileSessions(): array
|
||||
{
|
||||
$cachePath = config('session.files');
|
||||
$files = glob($cachePath . '/*');
|
||||
|
||||
if (!empty($files)) {
|
||||
foreach ($files as $file) {
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
return $this->response('success', 'Se eliminó la memoria caché de sesiones en archivos.');
|
||||
}
|
||||
|
||||
return $this->response('info', 'No se encontraron sesiones en archivos para eliminar.');
|
||||
}
|
||||
|
||||
|
||||
private function isSupportedDriver(string $driver): bool
|
||||
{
|
||||
return in_array($driver, ['redis', 'memcached', 'database', 'file']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera una respuesta estandarizada.
|
||||
*/
|
||||
private function response(string $status, string $message, array $data = []): array
|
||||
{
|
||||
return array_merge(compact('status', 'message'), $data);
|
||||
}
|
||||
}
|
1198
modules/Admin/App/Services/VuexyAdminService.php
Normal file
1198
modules/Admin/App/Services/VuexyAdminService.php
Normal file
File diff suppressed because it is too large
Load Diff
213
modules/Admin/App/Services/WebsiteSettingsService.php
Normal file
213
modules/Admin/App/Services/WebsiteSettingsService.php
Normal file
@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Admin\App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Intervention\Image\ImageManager;
|
||||
use Modules\Admin\App\Models\Setting;
|
||||
|
||||
class WebsiteSettingsService
|
||||
{
|
||||
private $driver;
|
||||
private $imageDisk = 'public';
|
||||
private $favicon_basePath = 'favicon/';
|
||||
private $image_logo_basePath = 'images/logo/';
|
||||
|
||||
private $faviconsSizes = [
|
||||
'180x180' => [180, 180],
|
||||
'192x192' => [192, 192],
|
||||
'152x152' => [152, 152],
|
||||
'120x120' => [120, 120],
|
||||
'76x76' => [76, 76],
|
||||
'16x16' => [16, 16],
|
||||
];
|
||||
|
||||
private $imageLogoMaxPixels1 = 22500; // Primera versión (px^2)
|
||||
private $imageLogoMaxPixels2 = 75625; // Segunda versión (px^2) en Base64
|
||||
private $imageLogoMaxPixels3 = 230400; // Tercera versión (px^2)
|
||||
|
||||
protected $cacheTTL = 60 * 24 * 30; // 30 días en minutos
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->driver = config('image.driver', 'gd');
|
||||
}
|
||||
|
||||
public function updateSetting(string $key, string $value): bool
|
||||
{
|
||||
$setting = Setting::updateOrCreate(
|
||||
['key' => $key],
|
||||
['value' => trim($value)]
|
||||
);
|
||||
|
||||
return $setting->save();
|
||||
}
|
||||
|
||||
public function processAndSaveFavicon($image): void
|
||||
{
|
||||
Storage::makeDirectory($this->imageDisk . '/' . $this->favicon_basePath);
|
||||
|
||||
// Eliminar favicons antiguos
|
||||
$this->deleteOldFavicons();
|
||||
|
||||
// Guardar imagen original
|
||||
$imageManager = new ImageManager($this->driver);
|
||||
|
||||
$imageName = uniqid('website_favicon_');
|
||||
|
||||
$image = $imageManager->read($image->getRealPath());
|
||||
|
||||
foreach ($this->faviconsSizes as $size => [$width, $height]) {
|
||||
$resizedPath = $this->favicon_basePath . $imageName . "_{$size}.png";
|
||||
|
||||
$image->cover($width, $height);
|
||||
|
||||
Storage::disk($this->imageDisk)->put($resizedPath, $image->toPng(indexed: true));
|
||||
}
|
||||
|
||||
$this->updateSetting('website_favicon_ns', $this->favicon_basePath . $imageName);
|
||||
}
|
||||
|
||||
protected function deleteOldFavicons(): void
|
||||
{
|
||||
// Obtener el favicon actual desde la base de datos
|
||||
$currentFavicon = Setting::where('key', 'website_favicon')->value('value');
|
||||
|
||||
if ($currentFavicon) {
|
||||
$filePaths = [
|
||||
$this->imageDisk . '/' . $currentFavicon,
|
||||
$this->imageDisk . '/' . $currentFavicon . '_16x16.png',
|
||||
$this->imageDisk . '/' . $currentFavicon . '_192x192.png',
|
||||
$this->imageDisk . '/' . $currentFavicon . '_76x76.png',
|
||||
$this->imageDisk . '/' . $currentFavicon . '_120x120.png',
|
||||
$this->imageDisk . '/' . $currentFavicon . '_152x152.png',
|
||||
$this->imageDisk . '/' . $currentFavicon . '_180x180.png',
|
||||
];
|
||||
|
||||
foreach ($filePaths as $filePath) {
|
||||
if (Storage::exists($filePath)) {
|
||||
Storage::delete($filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function processAndSaveImageLogo($image, string $type = ''): void
|
||||
{
|
||||
// Crear directorio si no existe
|
||||
Storage::makeDirectory($this->imageDisk . '/' . $this->image_logo_basePath);
|
||||
|
||||
// Eliminar imágenes antiguas
|
||||
$this->deleteOldImageWebapp($type);
|
||||
|
||||
// Leer imagen original
|
||||
$imageManager = new ImageManager($this->driver);
|
||||
$image = $imageManager->read($image->getRealPath());
|
||||
|
||||
// Generar tres versiones con diferentes áreas máximas
|
||||
$this->generateAndSaveImage($image, $type, $this->imageLogoMaxPixels1, 'small'); // Versión 1
|
||||
$this->generateAndSaveImage($image, $type, $this->imageLogoMaxPixels2, 'medium'); // Versión 2
|
||||
$this->generateAndSaveImage($image, $type, $this->imageLogoMaxPixels3); // Versión 3
|
||||
$this->generateAndSaveImageAsBase64($image, $type, $this->imageLogoMaxPixels3); // Versión 3
|
||||
}
|
||||
|
||||
private function generateAndSaveImage($image, string $type, int $maxPixels, string $suffix = ''): void
|
||||
{
|
||||
$imageClone = clone $image;
|
||||
|
||||
// Escalar imagen conservando aspecto
|
||||
$this->resizeImageToMaxPixels($imageClone, $maxPixels);
|
||||
|
||||
$imageName = 'website_image_logo' . ($suffix ? '_' . $suffix : '') . ($type == 'dark' ? '_dark' : '');
|
||||
|
||||
// Generar nombre y ruta
|
||||
$imageNameUid = uniqid($imageName . '_', ".png");
|
||||
$resizedPath = $this->image_logo_basePath . $imageNameUid;
|
||||
|
||||
// Guardar imagen en PNG
|
||||
Storage::disk($this->imageDisk)->put($resizedPath, $imageClone->toPng(indexed: true));
|
||||
|
||||
// Actualizar configuración
|
||||
$this->updateSetting($imageName, $resizedPath);
|
||||
}
|
||||
|
||||
private function resizeImageToMaxPixels($image, int $maxPixels)
|
||||
{
|
||||
// Obtener dimensiones originales de la imagen
|
||||
$originalWidth = $image->width(); // Método para obtener el ancho
|
||||
$originalHeight = $image->height(); // Método para obtener el alto
|
||||
|
||||
// Calcular el aspecto
|
||||
$aspectRatio = $originalWidth / $originalHeight;
|
||||
|
||||
// Calcular dimensiones redimensionadas conservando aspecto
|
||||
if ($aspectRatio > 1) { // Ancho es dominante
|
||||
$newWidth = sqrt($maxPixels * $aspectRatio);
|
||||
$newHeight = $newWidth / $aspectRatio;
|
||||
} else { // Alto es dominante
|
||||
$newHeight = sqrt($maxPixels / $aspectRatio);
|
||||
$newWidth = $newHeight * $aspectRatio;
|
||||
}
|
||||
|
||||
// Redimensionar la imagen
|
||||
$image->resize(
|
||||
round($newWidth), // Redondear para evitar problemas con números decimales
|
||||
round($newHeight),
|
||||
function ($constraint) {
|
||||
$constraint->aspectRatio();
|
||||
$constraint->upsize();
|
||||
}
|
||||
);
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
|
||||
private function generateAndSaveImageAsBase64($image, string $type, int $maxPixels): void
|
||||
{
|
||||
$imageClone = clone $image;
|
||||
|
||||
// Redimensionar imagen conservando el aspecto
|
||||
$this->resizeImageToMaxPixels($imageClone, $maxPixels);
|
||||
|
||||
// Convertir a Base64
|
||||
$base64Image = (string) $imageClone->toJpg(40)->toDataUri();
|
||||
|
||||
// Guardar como configuración
|
||||
$this->updateSetting(
|
||||
"website_image_logo_base64" . ($type === 'dark' ? '_dark' : ''),
|
||||
$base64Image // Ya incluye "data:image/png;base64,"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
protected function deleteOldImageWebapp(string $type = ''): void
|
||||
{
|
||||
// Determinar prefijo según el tipo (normal o dark)
|
||||
$suffix = $type === 'dark' ? '_dark' : '';
|
||||
|
||||
// Claves relacionadas con las imágenes que queremos limpiar
|
||||
$imageKeys = [
|
||||
"website_image_logo{$suffix}",
|
||||
"website_image_logo_small{$suffix}",
|
||||
"website_image_logo_medium{$suffix}",
|
||||
"website_image_logo_base64{$suffix}",
|
||||
];
|
||||
|
||||
foreach ($imageKeys as $key) {
|
||||
// Obtener la ruta de la imagen actual desde la base de datos
|
||||
$currentImage = Setting::where('key', $key)->value('value');
|
||||
|
||||
// Si es una imagen en disco, eliminarla
|
||||
if ($currentImage && !str_starts_with($currentImage, 'data:image')) {
|
||||
$filePath = $this->imageDisk . '/' . $currentImage;
|
||||
if (Storage::exists($filePath)) {
|
||||
Storage::delete($filePath);
|
||||
}
|
||||
}
|
||||
|
||||
// Opcional: Eliminar la configuración de la base de datos
|
||||
Setting::where('key', $key)->delete();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user