Files
web/app/Core/Kernel.php

244 lines
6.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/*
* Copyright (c) 2025, Антон Аксенов
* This file is part of iptv.axenov.dev web interface
* MIT License: https://git.axenov.dev/IPTV/web/src/branch/master/LICENSE
*/
declare(strict_types=1);
namespace App\Core;
use App\Core\TwigExtention as IptvTwigExtension;
use Dotenv\Dotenv;
use GuzzleHttp\Client;
use InvalidArgumentException;
use Redis;
use Slim\App;
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
use Twig\Error\LoaderError;
use Twig\Extension\DebugExtension;
/**
* Загрузчик приложения
*/
final class Kernel
{
/**
* Версия приложения
*/
public const string VERSION = '1.0.0';
/**
* @var Kernel
*/
private static Kernel $instance;
/**
* @var App
*/
protected App $app;
/**
* @var IniFile
*/
protected IniFile $iniFile;
/**
* @var array Конфигурация приложения
*/
protected array $config = [];
/**
* @var Redis|null
*/
protected ?Redis $cache = null;
/**
* @var Client|null
*/
protected ?Client $httpClient = null;
/**
* Закрытый конструктор
*
* @throws LoaderError
*/
private function __construct()
{
$this->app = AppFactory::create();
$this->loadSettings();
$this->loadRoutes();
$this->loadTwig();
return $this->app;
}
/**
* Возвращает объект приложения
*
* @return Kernel
*/
public static function instance(): Kernel
{
return self::$instance ??= new self();
}
/**
* Загружает файл .env или .env.$env
*
* @param string $env
* @return array
*/
protected function loadDotEnvFile(string $env = ''): array
{
$filename = empty($env) ? '.env' : ".env.$env";
if (!file_exists(root_path($filename))) {
return [];
}
$dotenv = Dotenv::createMutable(root_path(), $filename);
return $dotenv->safeLoad();
}
/**
* Загружает конфигурационные файлы
*
* @return void
*/
protected function loadSettings(): void
{
$env = $this->loadDotEnvFile();
if (!empty($env['APP_ENV'])) {
$this->loadDotEnvFile($env['APP_ENV']);
}
foreach (glob(config_path() . '/*.php') as $file) {
$key = basename($file, '.php');
$this->config += [$key => require_once $file];
}
date_default_timezone_set($this->config['app']['timezone'] ?? 'GMT');
}
/**
* Загружает маршруты
*
* @return void
* @see https://www.slimframework.com/docs/v4/objects/routing.html
*/
protected function loadRoutes(): void
{
foreach ($this->config['routes'] as $route) {
if (is_array($route['method'])) {
$definition = $this->app->map($route['method'], $route['path'], $route['handler']);
} else {
$method = trim($route['method']);
$isPossible = in_array($method, ['GET', 'POST', 'OPTIONS', 'PUT', 'PATCH', 'DELETE']);
$func = match (true) {
$method === '*' => 'any',
$isPossible => strtolower($method),
default => throw new InvalidArgumentException(sprintf('Неверный HTTP метод %s', $method))
};
$definition = $this->app->$func($route['path'], $route['handler']);
}
if (!empty($route['name'])) {
$definition->setName($route['name']);
}
}
}
/**
* Загружает шаблонизатор и его расширения
*
* @return void
* @throws LoaderError
* @see https://www.slimframework.com/docs/v4/features/twig-view.html
*/
protected function loadTwig(): void
{
$twig = Twig::create(root_path('views'), $this->config['twig']);
$twig->addExtension(new IptvTwigExtension());
$this->app->add(TwigMiddleware::create($this->app, $twig));
if ($this->config['twig']['debug']) {
$twig->addExtension(new DebugExtension());
}
}
/**
* Возвращает объект подключения к Redis
*
* @return Redis
* @see https://github.com/phpredis/phpredis/?tab=readme-ov-file
*/
public function redis(): Redis
{
if (!empty($this->cache)) {
return $this->cache;
}
$options = [
'host' => $this->config['cache']['host'],
'port' => (int)$this->config['cache']['port'],
];
if (!empty($this->config['cache']['password'])) {
$options['auth'] = $this->config['cache']['password'];
}
$this->cache = new Redis($options);
$this->cache->select((int)$this->config['cache']['db']);
$this->cache->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_JSON);
return $this->cache;
}
/**
* Возвращает объект http-клиента
*
* @return Client
*/
public function guzzle(): Client
{
return $this->httpClient ??= new Client($this->config['http']);
}
/**
* Возвращает значение из конфига
*
* @param string $key Ключ в формате "config.key"
* @param mixed|null $default Значение по умолчанию
* @return mixed
*/
public function config(string $key, mixed $default = null): mixed
{
$parts = explode('.', $key);
return $this->config[$parts[0]][$parts[1]] ?? $default;
}
/**
* Возвращает объект приложения
*
* @return App
*/
public function app(): App
{
return $this->app;
}
/**
* Возвращает объект ini-файла
*
* @return IniFile
*/
public function ini(): IniFile
{
return $this->iniFile ??= new IniFile();
}
}