diff --git a/Kiri.php b/Kiri.php index ad6c9298..d0bef238 100644 --- a/Kiri.php +++ b/Kiri.php @@ -6,7 +6,6 @@ error_reporting(0); use JetBrains\PhpStorm\Pure; -use Kiri\Abstracts\Config; use Kiri\Di\Container; use Kiri\Di\LocalService; use Kiri\Environmental; @@ -92,7 +91,7 @@ class Kiri if (Kiri::getPlatform()->isMac()) { return; } - $name = '[' . Config::get('id', 'system-service') . ']'; + $name = '[' . \config('id', 'system-service') . ']'; if (!empty($prefix)) { $name .= '.' . $prefix; } @@ -107,7 +106,7 @@ class Kiri public static function getStoragePath(): string { $default = APP_PATH . 'storage' . DIRECTORY_SEPARATOR; - $path = Config::get('storage', $default); + $path = \config('storage', $default); if (!is_dir($path)) { mkdir($path, 0777, true); } diff --git a/composer.json b/composer.json index 90d11bf2..8d9b96b4 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ ], "license": "MIT", "require": { - "php": ">=8.0", + "php": ">=8.1", "ext-json": "*", "ext-fileinfo": "*", "ext-pdo": "*", diff --git a/function.php b/function.php index 2fa8a0fd..fa8dde30 100644 --- a/function.php +++ b/function.php @@ -4,7 +4,7 @@ defined('APP_PATH') or define('APP_PATH', realpath(__DIR__ . '/../../')); use JetBrains\PhpStorm\Pure; -use Kiri\Abstracts\Config; +use Kiri\Config\ConfigProvider; use Kiri\Core\ArrayAccess; use Kiri\Error\StdoutLogger; use Kiri\Events\EventDispatch; @@ -16,7 +16,6 @@ use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; -use Psr\Log\LoggerInterface; use Swoole\Process; if (!function_exists('make')) { @@ -890,7 +889,7 @@ if (!function_exists('name')) { return; } - $name = Config::get('id', 'system') . '[' . $pid . ']'; + $name = \config('id', 'system') . '[' . $pid . ']'; if (!empty($prefix)) { $name .= '.' . $prefix; } @@ -934,9 +933,27 @@ if (!function_exists('config')) { * @param null $default * @return array|string|null */ - #[Pure] function config($key, $default = NULL): null|array|string + function config($key, $default = NULL): null|array|string { - return Config::get($key, $default); + return make(ConfigProvider::class)->get($key, $default); + } + +} + + + +if (!function_exists('created')) { + + /** + * @param $key + * @param array $construct + * @param array $config + * @return array|string|null + * @throws ReflectionException + */ + function created($key, array $construct = [], array $config = []): null|array|string + { + return Kiri::getDi()->make($key,$construct, $config); } } diff --git a/kiri-engine/Abstracts/BaseApplication.php b/kiri-engine/Abstracts/BaseApplication.php new file mode 100644 index 00000000..ff8c5768 --- /dev/null +++ b/kiri-engine/Abstracts/BaseApplication.php @@ -0,0 +1,182 @@ +localService = make(LocalService::class); + + /** @var ConfigProvider $config */ + $config = instance(ConfigProvider::class, [sweep(APP_PATH . '/config')]); + + $this->mapping($config); + $this->parseStorage($config); + $this->parseEvents($config); + parent::__construct(); + } + + + /** + * @param ConfigProvider $config + * @return void + */ + public function mapping(ConfigProvider $config): void + { + $di = Kiri::getDi(); + $di->set(LoggerInterface::class, StdoutLogger::class); + foreach ($config->get('mapping', []) as $interface => $class) { + $di->set($interface, $class); + } + + foreach ($config->get('components', []) as $id => $component) { + $this->set($id, $component); + } + } + + + /** + * @param ConfigProvider $config + * @return void + * @throws InitException + */ + public function parseStorage(ConfigProvider $config): void + { + if ($storage = $config->get('storage', 'storage')) { + if (!str_contains($storage, APP_PATH)) { + $storage = APP_PATH . $storage . '/'; + } + if (!is_dir($storage)) { + mkdir($storage, 0777, true); + } + if (!is_dir($storage) || !is_writeable($storage)) { + throw new InitException("Directory {$storage} does not have write permission"); + } + } + } + + + /** + * @param ConfigProvider $config + * @return void + * @throws Exception + */ + public function parseEvents(ConfigProvider $config): void + { + $events = $config->get('events', []); + foreach ($events as $key => $value) { + if (is_string($value)) { + $value = Kiri::createObject($value); + } + $this->addEvent($key, $value); + } + } + + + /** + * @param $key + * @param $value + * @return void + * @throws InitException + * @throws Exception + */ + private function addEvent($key, $value): void + { + $provider = Kiri::getDi()->get(EventProvider::class); + if ($value instanceof \Closure || is_object($value)) { + $provider->on($key, $value, 0); + return; + } + if (!is_array($value)) { + return; + } + if (is_object($value[0]) && !($value[0] instanceof \Closure)) { + $provider->on($key, $value, 0); + return; + } else if (is_string($value[0])) { + $value[0] = Kiri::createObject($value[0]); + $provider->on($key, $value, 0); + return; + } + foreach ($value as $item) { + if (!is_callable($item, true)) { + throw new InitException("Class does not hav callback."); + } + $provider->on($key, $item, 0); + } + } + + + /** + * @param string $name + * @return mixed|null + * @throws Exception + */ + public function __get(string $name) + { + if ($this->localService->has($name)) { + return $this->localService->get($name); + } + return parent::__get($name); // TODO: Change the autogenerated stub + } + + + /** + * @param $id + * @param $definition + */ + public function set($id, $definition): void + { + $this->localService->set($id, $definition); + } + + + /** + * @param $id + * @return bool + */ + public function has($id): bool + { + return $this->localService->has($id); + } +} diff --git a/kiri-engine/Abstracts/BaseMain.php b/kiri-engine/Abstracts/BaseMain.php deleted file mode 100644 index 00d613f7..00000000 --- a/kiri-engine/Abstracts/BaseMain.php +++ /dev/null @@ -1,263 +0,0 @@ -mapping($config['mapping'] ?? [], $config['components']); - $this->parseInt($config); - $this->parseEvents($config); - $this->enableEnvConfig(); - parent::__construct(); - } - - - /** - * @param array $mapping - * @param array $components - * @throws ReflectionException - */ - public function mapping(array $mapping, array $components) - { - $di = Kiri::getDi(); - $di->set(LoggerInterface::class, StdoutLogger::class); - foreach ($mapping as $interface => $class) { - $di->set($interface, $class); - } - - foreach ($components as $id => $component) { - $this->set($id, $component); - } - } - - - /** - * @return array - */ - public function enableEnvConfig(): array - { - if (!file_exists($this->envPath)) { - return []; - } - $lines = $this->readLinesFromFile($this->envPath); - foreach ($lines as $line) { - if (!$this->isComment($line) && $this->looksLikeSetter($line)) { - [$key, $value] = explode('=', $line); - putenv(trim($key) . '=' . trim($value)); - } - } - return $lines; - } - - - /** - * Read lines from the file, auto detecting line endings. - * - * @param string $filePath - * - * @return array - */ - protected function readLinesFromFile(string $filePath): array - { - // Read file into an array of lines with auto-detected line endings -// $autodetect = ini_get('auto_detect_line_endings'); -// ini_set('auto_detect_line_endings', '1'); - // ini_set('auto_detect_line_endings', $autodetect); - - return file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - } - - /** - * Determine if the line in the file is a comment, e.g. begins with a #. - * - * @param string $line - * - * @return bool - */ - protected function isComment(string $line): bool - { - $line = ltrim($line); - - return isset($line[0]) && $line[0] === '#'; - } - - /** - * Determine if the given line looks like it's setting a variable. - * - * @param string $line - * - * @return bool - */ - protected function looksLikeSetter(string $line): bool - { - return str_contains($line, '='); - } - - - /** - * @param $config - * - * @throws - */ - public function parseInt($config) - { - Config::sets($config); - if ($storage = Config::get('storage', 'storage')) { - if (!str_contains($storage, APP_PATH)) { - $storage = APP_PATH . $storage . '/'; - } - if (!is_dir($storage)) { - mkdir($storage); - } - if (!is_dir($storage) || !is_writeable($storage)) { - throw new InitException("Directory {$storage} does not have write permission"); - } - } - } - - /** - * @param $config - * - * @throws - */ - public function parseEvents($config) - { - if (!isset($config['events']) || !is_array($config['events'])) { - return; - } - foreach ($config['events'] as $key => $value) { - if (is_string($value)) { - $value = Kiri::createObject($value); - } - $this->addEvent($key, $value); - } - } - - - /** - * @param $key - * @param $value - * @return void - * @throws InitException - * @throws Exception - */ - private function addEvent($key, $value): void - { - $provider = Kiri::getDi()->get(EventProvider::class); - if ($value instanceof \Closure || is_object($value)) { - $provider->on($key, $value, 0); - return; - } - if (!is_array($value)) { - return; - } - if (is_object($value[0]) && !($value[0] instanceof \Closure)) { - $provider->on($key, $value, 0); - return; - } else if (is_string($value[0])) { - $value[0] = Kiri::createObject($value[0]); - $provider->on($key, $value, 0); - return; - } - foreach ($value as $item) { - if (!is_callable($item, true)) { - throw new InitException("Class does not hav callback."); - } - $provider->on($key, $item, 0); - } - } - - - /** - * @return mixed - */ - public function getLocalIps(): mixed - { - return swoole_get_local_ip(); - } - - - /** - * @return mixed - */ - public function getFirstLocal(): mixed - { - return current($this->getLocalIps()); - } - - - /** - * @param string $name - * @return mixed|null - * @throws Exception - */ - public function __get(string $name) - { - $localService = Kiri::getDi()->get(LocalService::class); - if ($localService->has($name)) { - return $localService->get($name); - } - return parent::__get($name); // TODO: Change the autogenerated stub - } - - - /** - * @param $id - * @param $definition - * @throws ReflectionException - */ - public function set($id, $definition): void - { - Kiri::getDi()->get(LocalService::class)->set($id, $definition); - } - - - /** - * @param $id - * @return bool - * @throws ReflectionException - */ - public function has($id): bool - { - return Kiri::getDi()->get(LocalService::class)->has($id); - } -} diff --git a/kiri-engine/Abstracts/Component.php b/kiri-engine/Abstracts/Component.php index 8fad7d81..4bbdac3e 100644 --- a/kiri-engine/Abstracts/Component.php +++ b/kiri-engine/Abstracts/Component.php @@ -13,7 +13,6 @@ namespace Kiri\Abstracts; use Exception; use JetBrains\PhpStorm\Pure; use Kiri; -use Kiri\Error\StdoutLoggerInterface; /** * Class Component diff --git a/kiri-engine/Abstracts/Config.php b/kiri-engine/Abstracts/Config.php deleted file mode 100644 index 0cb67a81..00000000 --- a/kiri-engine/Abstracts/Config.php +++ /dev/null @@ -1,142 +0,0 @@ -levels = Config::get('log.level', Logger::LOGGER_LEVELS); + $this->levels = \config('log.level', Logger::LOGGER_LEVELS); } diff --git a/kiri-engine/Main.php b/kiri-engine/Application.php similarity index 89% rename from kiri-engine/Main.php rename to kiri-engine/Application.php index 87c6cc25..e28040a1 100644 --- a/kiri-engine/Main.php +++ b/kiri-engine/Application.php @@ -12,7 +12,7 @@ namespace Kiri; use Exception; use Kiri; -use Kiri\Abstracts\{BaseMain, Config, Kernel}; +use Kiri\Abstracts\{BaseApplication, Config, Kernel}; use Kiri\Di\LocalService; use Kiri\Di\Scanner; use Kiri\Error\ErrorHandler; @@ -34,7 +34,7 @@ use Symfony\Component\Console\{Application as ConsoleApplication, * * @property-read Config $config */ -class Main extends BaseMain +class Application extends BaseApplication { /** @@ -53,10 +53,10 @@ class Main extends BaseMain public function init(): void { $error = Kiri::getDi()->get(ErrorHandler::class); - $error->registerShutdownHandler(Config::get('error.shutdown', [])); - $error->registerExceptionHandler(Config::get('error.exception', [])); - $error->registerErrorHandler(Config::get('error.error', [])); - $this->id = Config::get('id', uniqid('id.')); + $error->registerShutdownHandler(\config('error.shutdown', [])); + $error->registerExceptionHandler(\config('error.exception', [])); + $error->registerErrorHandler(\config('error.error', [])); + $this->id = \config('id', uniqid('id.')); } /** diff --git a/kiri-engine/Config/ConfigProvider.php b/kiri-engine/Config/ConfigProvider.php new file mode 100644 index 00000000..a8627f61 --- /dev/null +++ b/kiri-engine/Config/ConfigProvider.php @@ -0,0 +1,121 @@ +hashMap = new HashMap(); + $this->load($config); + + $this->enableEnvConfig(APP_PATH . '.env'); + } + + + /** + * @param string $key + * @param int|string|bool|array|null $default + * @return int|string|bool|array|null + */ + public function get(string $key, int|string|bool|null|array $default = null): int|string|bool|null|array + { + $keys = explode($key, '.'); + + $hashMap = $this->hashMap->get(array_unshift($keys)); + if (is_null($hashMap)) { + return $default; + } + if (count($keys) < 1 || !is_array($hashMap)) { + return $hashMap; + } + foreach ($keys as $string) { + if (!isset($hashMap[$string])) { + return $default; + } + $hashMap = $hashMap[$string]; + } + return $hashMap; + } + + + /** + * @param array $config + * @return void + */ + private function load(array $config): void + { + foreach ($config as $key => $value) { + $this->hashMap->put($key, $value); + } + } + + + /** + * @param $envPath + * @return void + */ + private function enableEnvConfig($envPath): void + { + if (!file_exists($envPath)) { + return; + } + $lines = $this->readLinesFromFile($envPath); + foreach ($lines as $line) { + if (!$this->isComment($line) && $this->looksLikeSetter($line)) { + [$key, $value] = explode('=', $line); + putenv(trim($key) . '=' . trim($value)); + } + } + } + + + /** + * Read lines from the file, auto detecting line endings. + * + * @param string $filePath + * + * @return array + */ + protected function readLinesFromFile(string $filePath): array + { + // Read file into an array of lines with auto-detected line endings + return file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + } + + /** + * Determine if the line in the file is a comment, e.g. begins with a #. + * + * @param string $line + * + * @return bool + */ + protected function isComment(string $line): bool + { + $line = ltrim($line); + + return isset($line[0]) && $line[0] === '#'; + } + + /** + * Determine if the given line looks like it's setting a variable. + * + * @param string $line + * + * @return bool + */ + protected function looksLikeSetter(string $line): bool + { + return str_contains($line, '='); + } + +} \ No newline at end of file diff --git a/kiri-engine/Core/HashMap.php b/kiri-engine/Core/HashMap.php index dcacd736..e2c1c1af 100644 --- a/kiri-engine/Core/HashMap.php +++ b/kiri-engine/Core/HashMap.php @@ -61,14 +61,15 @@ class HashMap implements \ArrayAccess, \IteratorAggregate } - /** - * @param string $key - * @return mixed - */ - #[Pure] public function get(string $key): mixed + /** + * @param string $key + * @param mixed|null $default + * @return mixed + */ + #[Pure] public function get(string $key, mixed $default = null): mixed { if (!$this->has($key)) { - return null; + return $default; } return $this->lists[$key]; } diff --git a/kiri-engine/Redis/Redis.php b/kiri-engine/Redis/Redis.php index b9f80db3..2499b841 100644 --- a/kiri-engine/Redis/Redis.php +++ b/kiri-engine/Redis/Redis.php @@ -12,7 +12,6 @@ namespace Kiri\Redis; use Exception; use Kiri; use Kiri\Abstracts\Component; -use Kiri\Abstracts\Config; use Kiri\Events\EventProvider; use Kiri\Di\Inject\Container; use Kiri\Exception\ConfigException; @@ -67,7 +66,7 @@ class Redis extends Component { $config = $this->get_config(); - $length = Config::get('cache.redis.pool.max', 10); + $length = \config('cache.redis.pool.max', 10); on(OnWorkerExit::class, [$this, 'destroy']); Kiri::getPool()->initConnections($config['host'], $length, static function () use ($config) { $redis = new \Redis();